From ec1f27f2c05a20fcc82510c048229d6b829bc684 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Tue, 25 May 2021 06:59:24 -0400 Subject: [PATCH 1/7] memory_optimization --- .../advanced.py | 0 adafruit_bme280/basic.py | 379 ++++++++++++++++++ 2 files changed, 379 insertions(+) rename adafruit_bme280.py => adafruit_bme280/advanced.py (100%) create mode 100644 adafruit_bme280/basic.py diff --git a/adafruit_bme280.py b/adafruit_bme280/advanced.py similarity index 100% rename from adafruit_bme280.py rename to adafruit_bme280/advanced.py diff --git a/adafruit_bme280/basic.py b/adafruit_bme280/basic.py new file mode 100644 index 0000000..3aae496 --- /dev/null +++ b/adafruit_bme280/basic.py @@ -0,0 +1,379 @@ +# SPDX-FileCopyrightText: 2017 ladyada for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +""" +`adafruit_bme280` +========================================================================================= + +CircuitPython driver from BME280 Temperature, Humidity and Barometric +Pressure sensor + +* Author(s): ladyada + +Implementation Notes +-------------------- + +**Hardware:** + +* `Adafruit BME280 Temperature, Humidity and Barometric Pressure sensor + `_ (Product ID: 2652) + + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://circuitpython.org/downloads + +* Adafruit's Bus Device library: + https://github.com/adafruit/Adafruit_CircuitPython_BusDevice + +""" +import math +from time import sleep +from micropython import const + +try: + import struct +except ImportError: + import ustruct as struct + + +__version__ = "2.6.4" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BME280.git" + +# I2C ADDRESS/BITS/SETTINGS +# ----------------------------------------------------------------------- +_BME280_ADDRESS = const(0x77) +_BME280_CHIPID = const(0x60) + +_BME280_REGISTER_CHIPID = const(0xD0) +_BME280_REGISTER_DIG_T1 = const(0x88) +_BME280_REGISTER_DIG_H1 = const(0xA1) +_BME280_REGISTER_DIG_H2 = const(0xE1) +_BME280_REGISTER_DIG_H3 = const(0xE3) +_BME280_REGISTER_DIG_H4 = const(0xE4) +_BME280_REGISTER_DIG_H5 = const(0xE5) +_BME280_REGISTER_DIG_H6 = const(0xE7) + +_BME280_REGISTER_SOFTRESET = const(0xE0) +_BME280_REGISTER_CTRL_HUM = const(0xF2) +_BME280_REGISTER_STATUS = const(0xF3) +_BME280_REGISTER_CTRL_MEAS = const(0xF4) +_BME280_REGISTER_CONFIG = const(0xF5) +_BME280_REGISTER_PRESSUREDATA = const(0xF7) +_BME280_REGISTER_TEMPDATA = const(0xFA) +_BME280_REGISTER_HUMIDDATA = const(0xFD) + +_BME280_HUMIDITY_MIN = const(0) +_BME280_HUMIDITY_MAX = const(100) + +"""iir_filter values""" +IIR_FILTER_DISABLE = const(0) + +"""overscan values for temperature, pressure, and humidity""" +OVERSCAN_DISABLE = const(0x00) +OVERSCAN_X1 = const(0x01) +OVERSCAN_X2 = const(0x02) +OVERSCAN_X4 = const(0x03) +OVERSCAN_X8 = const(0x04) +OVERSCAN_X16 = const(0x05) + +_BME280_OVERSCANS = { + OVERSCAN_DISABLE: 0, + OVERSCAN_X1: 1, + OVERSCAN_X2: 2, + OVERSCAN_X4: 4, + OVERSCAN_X8: 8, + OVERSCAN_X16: 16, +} + +"""mode values""" +MODE_SLEEP = const(0x00) +MODE_FORCE = const(0x01) +MODE_NORMAL = const(0x03) + +_BME280_MODES = (MODE_SLEEP, MODE_FORCE, MODE_NORMAL) + +STANDBY_TC_125 = const(0x02) # 125ms + + +class Adafruit_BME280: + """Driver from BME280 Temperature, Humidity and Barometric Pressure sensor + + .. note:: + The operational range of the BMP280 is 300-1100 hPa. + Pressure measurements outside this range may not be as accurate. + + """ + + # pylint: disable=too-many-instance-attributes + def __init__(self): + """Check the BME280 was found, read the coefficients and enable the sensor""" + # Check device ID. + chip_id = self._read_byte(_BME280_REGISTER_CHIPID) + if _BME280_CHIPID != chip_id: + raise RuntimeError("Failed to find BME280! Chip ID 0x%x" % chip_id) + # Set some reasonable defaults. + self._iir_filter = IIR_FILTER_DISABLE + self.overscan_humidity = 1 + self.overscan_temperature = 1 + self.overscan_pressure = OVERSCAN_X16 + self._t_standby = STANDBY_TC_125 + self._mode = MODE_SLEEP + self._reset() + self._read_coefficients() + self._write_ctrl_meas() + self._write_config() + self.sea_level_pressure = 1013.25 + """Pressure in hectoPascals at sea level. Used to calibrate `altitude`.""" + self._t_fine = None + + def _read_temperature(self): + # perform one measurement + if self.mode != MODE_NORMAL: + self.mode = MODE_FORCE + # Wait for conversion to complete + while self._get_status() & 0x08: + sleep(0.002) + raw_temperature = ( + self._read24(_BME280_REGISTER_TEMPDATA) / 16 + ) # lowest 4 bits get dropped + # print("raw temp: ", UT) + var1 = ( + raw_temperature / 16384.0 - self._temp_calib[0] / 1024.0 + ) * self._temp_calib[1] + # print(var1) + var2 = ( + (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) + * (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) + ) * self._temp_calib[2] + # print(var2) + + self._t_fine = int(var1 + var2) + # print("t_fine: ", self.t_fine) + + def _reset(self): + """Soft reset the sensor""" + self._write_register_byte(_BME280_REGISTER_SOFTRESET, 0xB6) + sleep(0.004) # Datasheet says 2ms. Using 4ms just to be safe + + def _write_ctrl_meas(self): + """ + Write the values to the ctrl_meas and ctrl_hum registers in the device + ctrl_meas sets the pressure and temperature data acquisition options + ctrl_hum sets the humidity oversampling and must be written to first + """ + + self._write_register_byte(_BME280_REGISTER_CTRL_HUM, self.overscan_humidity) + self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, self._ctrl_meas) + + def _get_status(self): + """Get the value from the status register in the device """ + return self._read_byte(_BME280_REGISTER_STATUS) + + def _read_config(self): + """Read the value from the config register in the device """ + return self._read_byte(_BME280_REGISTER_CONFIG) + + def _write_config(self): + """Write the value to the config register in the device """ + + self._write_register_byte(_BME280_REGISTER_CONFIG, self._config) + + @property + def mode(self): + """ + Operation mode + Allowed values are the constants MODE_* + """ + return self._mode + + @mode.setter + def mode(self, value): + if not value in _BME280_MODES: + raise ValueError("Mode '%s' not supported" % (value)) + self._mode = value + self._write_ctrl_meas() + + @property + def _config(self): + """Value to be written to the device's config register """ + config = 0 + if self.mode == MODE_NORMAL: + config += self._t_standby << 5 + if self._iir_filter: + config += self._iir_filter << 2 + return config + + @property + def _ctrl_meas(self): + """Value to be written to the device's ctrl_meas register """ + ctrl_meas = self.overscan_temperature << 5 + ctrl_meas += self.overscan_pressure << 2 + ctrl_meas += self.mode + return ctrl_meas + + @property + def temperature(self): + """The compensated temperature in degrees Celsius.""" + self._read_temperature() + return self._t_fine / 5120.0 + + @property + def pressure(self): + """ + The compensated pressure in hectoPascals. + returns None if pressure measurement is disabled + """ + self._read_temperature() + + # Algorithm from the BME280 driver + # https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c + adc = ( + self._read24(_BME280_REGISTER_PRESSUREDATA) / 16 + ) # lowest 4 bits get dropped + var1 = float(self._t_fine) / 2.0 - 64000.0 + var2 = var1 * var1 * self._pressure_calib[5] / 32768.0 + var2 = var2 + var1 * self._pressure_calib[4] * 2.0 + var2 = var2 / 4.0 + self._pressure_calib[3] * 65536.0 + var3 = self._pressure_calib[2] * var1 * var1 / 524288.0 + var1 = (var3 + self._pressure_calib[1] * var1) / 524288.0 + var1 = (1.0 + var1 / 32768.0) * self._pressure_calib[0] + if not var1: # avoid exception caused by division by zero + raise ArithmeticError( + "Invalid result possibly related to error while reading the calibration registers" + ) + pressure = 1048576.0 - adc + pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1 + var1 = self._pressure_calib[8] * pressure * pressure / 2147483648.0 + var2 = pressure * self._pressure_calib[7] / 32768.0 + pressure = pressure + (var1 + var2 + self._pressure_calib[6]) / 16.0 + + pressure /= 100 + return pressure + + @property + def relative_humidity(self): + """ + The relative humidity in RH % + returns None if humidity measurement is disabled + """ + return self.humidity + + @property + def humidity(self): + """ + The relative humidity in RH % + returns None if humidity measurement is disabled + """ + self._read_temperature() + hum = self._read_register(_BME280_REGISTER_HUMIDDATA, 2) + adc = float(hum[0] << 8 | hum[1]) + + # Algorithm from the BME280 driver + # https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c + var1 = float(self._t_fine) - 76800.0 + var2 = ( + self._humidity_calib[3] * 64.0 + (self._humidity_calib[4] / 16384.0) * var1 + ) + var3 = adc - var2 + var4 = self._humidity_calib[1] / 65536.0 + var5 = 1.0 + (self._humidity_calib[2] / 67108864.0) * var1 + var6 = 1.0 + (self._humidity_calib[5] / 67108864.0) * var1 * var5 + var6 = var3 * var4 * (var5 * var6) + humidity = var6 * (1.0 - self._humidity_calib[0] * var6 / 524288.0) + + if humidity > _BME280_HUMIDITY_MAX: + return _BME280_HUMIDITY_MAX + if humidity < _BME280_HUMIDITY_MIN: + return _BME280_HUMIDITY_MIN + # else... + return humidity + + @property + def altitude(self): + """The altitude based on current ``pressure`` versus the sea level pressure + (``sea_level_pressure``) - which you must enter ahead of time)""" + pressure = self.pressure # in Si units for hPascal + return 44330 * (1.0 - math.pow(pressure / self.sea_level_pressure, 0.1903)) + + def _read_coefficients(self): + """Read & save the calibration coefficients""" + coeff = self._read_register(_BME280_REGISTER_DIG_T1, 24) + coeff = list(struct.unpack("> 4)) + self._humidity_calib[5] = float(coeff[5]) + + def _read_byte(self, register): + """Read a byte register value and return it""" + return self._read_register(register, 1)[0] + + def _read24(self, register): + """Read an unsigned 24-bit value as a floating point and return it.""" + ret = 0.0 + for b in self._read_register(register, 3): + ret *= 256.0 + ret += float(b & 0xFF) + return ret + + def _read_register(self, register, length): + raise NotImplementedError() + + def _write_register_byte(self, register, value): + raise NotImplementedError() + + +class Adafruit_BME280_I2C(Adafruit_BME280): + def __init__(self, i2c, address=_BME280_ADDRESS): + import adafruit_bus_device.i2c_device as i2c_device # pylint: disable=import-outside-toplevel + + self._i2c = i2c_device.I2CDevice(i2c, address) + super().__init__() + + def _read_register(self, register, length): + with self._i2c as i2c: + i2c.write(bytes([register & 0xFF])) + result = bytearray(length) + i2c.readinto(result) + # print("$%02X => %s" % (register, [hex(i) for i in result])) + return result + + def _write_register_byte(self, register, value): + with self._i2c as i2c: + i2c.write(bytes([register & 0xFF, value & 0xFF])) + # print("$%02X <= 0x%02X" % (register, value)) + + +class Adafruit_BME280_SPI(Adafruit_BME280): + + def __init__(self, spi, cs, baudrate=100000): + import adafruit_bus_device.spi_device as spi_device # pylint: disable=import-outside-toplevel + + self._spi = spi_device.SPIDevice(spi, cs, baudrate=baudrate) + super().__init__() + + def _read_register(self, register, length): + register = (register | 0x80) & 0xFF # Read single, bit 7 high. + with self._spi as spi: + spi.write(bytearray([register])) # pylint: disable=no-member + result = bytearray(length) + spi.readinto(result) # pylint: disable=no-member + return result + + def _write_register_byte(self, register, value): + register &= 0x7F # Write, bit 7 low. + with self._spi as spi: + spi.write(bytes([register, value & 0xFF])) # pylint: disable=no-member + From 69c78c5681a69785686200a5fcbab63d38d30fef Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 26 May 2021 14:45:34 -0400 Subject: [PATCH 2/7] updating_class --- README.rst | 13 +- adafruit_bme280/advanced.py | 243 ++--------------------------- adafruit_bme280/basic.py | 205 ++++++++++++++++-------- docs/api.rst | 6 + examples/bme280_normal_mode.py | 18 +-- examples/bme280_simpletest.py | 6 +- examples/bme280_simpletest_pico.py | 6 +- 7 files changed, 173 insertions(+), 324 deletions(-) diff --git a/README.rst b/README.rst index 134772a..6630553 100644 --- a/README.rst +++ b/README.rst @@ -61,20 +61,11 @@ Usage Example import board import time - import adafruit_bme280 + from adafruit_bme280 import basic # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA - bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) - #or with other sensor address - #bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76) - - # OR create sensor object, using the board's default SPI bus. - # SPI setup - # from digitalio import DigitalInOut - #spi = board.SPI() - #bme_cs = digitalio.DigitalInOut(board.D10) - #bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) + bme280 = basic.Adafruit_BME280_I2C(i2c) # change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 diff --git a/adafruit_bme280/advanced.py b/adafruit_bme280/advanced.py index 7990d9e..18191de 100644 --- a/adafruit_bme280/advanced.py +++ b/adafruit_bme280/advanced.py @@ -3,13 +3,13 @@ # SPDX-License-Identifier: MIT """ -`adafruit_bme280` +`adafruit_bme280.advanced` ========================================================================================= CircuitPython driver from BME280 Temperature, Humidity and Barometric Pressure sensor -* Author(s): ladyada +* Author(s): ladyada, Jose David M. Implementation Notes -------------------- @@ -29,15 +29,8 @@ https://github.com/adafruit/Adafruit_CircuitPython_BusDevice """ -import math -from time import sleep from micropython import const - -try: - import struct -except ImportError: - import ustruct as struct - +from adafruit_bme280.basic import Adafruit_BME280 __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BME280.git" @@ -131,7 +124,7 @@ ) -class Adafruit_BME280: +class Adafruit_BME280_Advanced(Adafruit_BME280): """Driver from BME280 Temperature, Humidity and Barometric Pressure sensor .. note:: @@ -143,96 +136,12 @@ class Adafruit_BME280: # pylint: disable=too-many-instance-attributes def __init__(self): """Check the BME280 was found, read the coefficients and enable the sensor""" - # Check device ID. - chip_id = self._read_byte(_BME280_REGISTER_CHIPID) - if _BME280_CHIPID != chip_id: - raise RuntimeError("Failed to find BME280! Chip ID 0x%x" % chip_id) - # Set some reasonable defaults. - self._iir_filter = IIR_FILTER_DISABLE self._overscan_humidity = OVERSCAN_X1 self._overscan_temperature = OVERSCAN_X1 self._overscan_pressure = OVERSCAN_X16 - self._t_standby = STANDBY_TC_125 self._mode = MODE_SLEEP - self._reset() - self._read_coefficients() - self._write_ctrl_meas() - self._write_config() - self.sea_level_pressure = 1013.25 - """Pressure in hectoPascals at sea level. Used to calibrate `altitude`.""" - self._t_fine = None - - def _read_temperature(self): - # perform one measurement - if self.mode != MODE_NORMAL: - self.mode = MODE_FORCE - # Wait for conversion to complete - while self._get_status() & 0x08: - sleep(0.002) - raw_temperature = ( - self._read24(_BME280_REGISTER_TEMPDATA) / 16 - ) # lowest 4 bits get dropped - # print("raw temp: ", UT) - var1 = ( - raw_temperature / 16384.0 - self._temp_calib[0] / 1024.0 - ) * self._temp_calib[1] - # print(var1) - var2 = ( - (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) - * (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) - ) * self._temp_calib[2] - # print(var2) - - self._t_fine = int(var1 + var2) - # print("t_fine: ", self.t_fine) - - def _reset(self): - """Soft reset the sensor""" - self._write_register_byte(_BME280_REGISTER_SOFTRESET, 0xB6) - sleep(0.004) # Datasheet says 2ms. Using 4ms just to be safe - - def _write_ctrl_meas(self): - """ - Write the values to the ctrl_meas and ctrl_hum registers in the device - ctrl_meas sets the pressure and temperature data acquisition options - ctrl_hum sets the humidity oversampling and must be written to first - """ - self._write_register_byte(_BME280_REGISTER_CTRL_HUM, self.overscan_humidity) - self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, self._ctrl_meas) - - def _get_status(self): - """Get the value from the status register in the device """ - return self._read_byte(_BME280_REGISTER_STATUS) - - def _read_config(self): - """Read the value from the config register in the device """ - return self._read_byte(_BME280_REGISTER_CONFIG) - - def _write_config(self): - """Write the value to the config register in the device """ - normal_flag = False - if self._mode == MODE_NORMAL: - # Writes to the config register may be ignored while in Normal mode - normal_flag = True - self.mode = MODE_SLEEP # So we switch to Sleep mode first - self._write_register_byte(_BME280_REGISTER_CONFIG, self._config) - if normal_flag: - self.mode = MODE_NORMAL - - @property - def mode(self): - """ - Operation mode - Allowed values are the constants MODE_* - """ - return self._mode - - @mode.setter - def mode(self, value): - if not value in _BME280_MODES: - raise ValueError("Mode '%s' not supported" % (value)) - self._mode = value - self._write_ctrl_meas() + self._t_standby = STANDBY_TC_125 + super().__init__() @property def standby_period(self): @@ -353,136 +262,8 @@ def measurement_time_max(self): meas_time_ms += 2.3 * _BME280_OVERSCANS.get(self.overscan_humidity) + 0.575 return meas_time_ms - @property - def temperature(self): - """The compensated temperature in degrees Celsius.""" - self._read_temperature() - return self._t_fine / 5120.0 - - @property - def pressure(self): - """ - The compensated pressure in hectoPascals. - returns None if pressure measurement is disabled - """ - self._read_temperature() - - # Algorithm from the BME280 driver - # https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c - adc = ( - self._read24(_BME280_REGISTER_PRESSUREDATA) / 16 - ) # lowest 4 bits get dropped - var1 = float(self._t_fine) / 2.0 - 64000.0 - var2 = var1 * var1 * self._pressure_calib[5] / 32768.0 - var2 = var2 + var1 * self._pressure_calib[4] * 2.0 - var2 = var2 / 4.0 + self._pressure_calib[3] * 65536.0 - var3 = self._pressure_calib[2] * var1 * var1 / 524288.0 - var1 = (var3 + self._pressure_calib[1] * var1) / 524288.0 - var1 = (1.0 + var1 / 32768.0) * self._pressure_calib[0] - if not var1: # avoid exception caused by division by zero - raise ArithmeticError( - "Invalid result possibly related to error while reading the calibration registers" - ) - pressure = 1048576.0 - adc - pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1 - var1 = self._pressure_calib[8] * pressure * pressure / 2147483648.0 - var2 = pressure * self._pressure_calib[7] / 32768.0 - pressure = pressure + (var1 + var2 + self._pressure_calib[6]) / 16.0 - - pressure /= 100 - return pressure - - @property - def relative_humidity(self): - """ - The relative humidity in RH % - returns None if humidity measurement is disabled - """ - return self.humidity - - @property - def humidity(self): - """ - The relative humidity in RH % - returns None if humidity measurement is disabled - """ - self._read_temperature() - hum = self._read_register(_BME280_REGISTER_HUMIDDATA, 2) - # print("Humidity data: ", hum) - adc = float(hum[0] << 8 | hum[1]) - # print("adc:", adc) - - # Algorithm from the BME280 driver - # https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c - var1 = float(self._t_fine) - 76800.0 - # print("var1 ", var1) - var2 = ( - self._humidity_calib[3] * 64.0 + (self._humidity_calib[4] / 16384.0) * var1 - ) - # print("var2 ",var2) - var3 = adc - var2 - # print("var3 ",var3) - var4 = self._humidity_calib[1] / 65536.0 - # print("var4 ",var4) - var5 = 1.0 + (self._humidity_calib[2] / 67108864.0) * var1 - # print("var5 ",var5) - var6 = 1.0 + (self._humidity_calib[5] / 67108864.0) * var1 * var5 - # print("var6 ",var6) - var6 = var3 * var4 * (var5 * var6) - humidity = var6 * (1.0 - self._humidity_calib[0] * var6 / 524288.0) - - if humidity > _BME280_HUMIDITY_MAX: - return _BME280_HUMIDITY_MAX - if humidity < _BME280_HUMIDITY_MIN: - return _BME280_HUMIDITY_MIN - # else... - return humidity - - @property - def altitude(self): - """The altitude based on current ``pressure`` versus the sea level pressure - (``sea_level_pressure``) - which you must enter ahead of time)""" - pressure = self.pressure # in Si units for hPascal - return 44330 * (1.0 - math.pow(pressure / self.sea_level_pressure, 0.1903)) - - def _read_coefficients(self): - """Read & save the calibration coefficients""" - coeff = self._read_register(_BME280_REGISTER_DIG_T1, 24) - coeff = list(struct.unpack("> 4)) - self._humidity_calib[5] = float(coeff[5]) - - def _read_byte(self, register): - """Read a byte register value and return it""" - return self._read_register(register, 1)[0] - - def _read24(self, register): - """Read an unsigned 24-bit value as a floating point and return it.""" - ret = 0.0 - for b in self._read_register(register, 3): - ret *= 256.0 - ret += float(b & 0xFF) - return ret - - def _read_register(self, register, length): - raise NotImplementedError() - - def _write_register_byte(self, register, value): - raise NotImplementedError() - -class Adafruit_BME280_I2C(Adafruit_BME280): +class Adafruit_BME280_I2C(Adafruit_BME280_Advanced): """Driver for BME280 connected over I2C :param ~busio.I2C i2c: The I2C bus the BME280 is connected to. @@ -501,14 +282,14 @@ class Adafruit_BME280_I2C(Adafruit_BME280): .. code-block:: python import board - import adafruit_bme280 + from adafruit_bme280 import advanced Once this is done you can define your `board.I2C` object and define your sensor object .. code-block:: python i2c = board.I2C() # uses board.SCL and board.SDA - bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) + bme280 = advanced.Adafruit_BME280_I2C(i2c) You need to setup the pressure at sea level @@ -548,7 +329,7 @@ def _write_register_byte(self, register, value): # print("$%02X <= 0x%02X" % (register, value)) -class Adafruit_BME280_SPI(Adafruit_BME280): +class Adafruit_BME280_SPI(Adafruit_BME280_Advanced): """Driver for BME280 connected over SPI :param ~busio.SPI spi: SPI device @@ -568,7 +349,7 @@ class Adafruit_BME280_SPI(Adafruit_BME280): import board from digitalio import DigitalInOut - import adafruit_bme280 + from adafruit_bme280 import advanced Once this is done you can define your `board.SPI` object and define your sensor object @@ -576,7 +357,7 @@ class Adafruit_BME280_SPI(Adafruit_BME280): cs = digitalio.DigitalInOut(board.D10) spi = board.SPI() - bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, cs) + bme280 = advanced.Adafruit_BME280_SPI(spi, cs) You need to setup the pressure at sea level diff --git a/adafruit_bme280/basic.py b/adafruit_bme280/basic.py index 3aae496..5dd52d2 100644 --- a/adafruit_bme280/basic.py +++ b/adafruit_bme280/basic.py @@ -3,13 +3,13 @@ # SPDX-License-Identifier: MIT """ -`adafruit_bme280` +`adafruit_bme280.basic` ========================================================================================= CircuitPython driver from BME280 Temperature, Humidity and Barometric Pressure sensor -* Author(s): ladyada +* Author(s): ladyada, Jose David M. Implementation Notes -------------------- @@ -44,65 +44,42 @@ # I2C ADDRESS/BITS/SETTINGS # ----------------------------------------------------------------------- + +"""General Information""" _BME280_ADDRESS = const(0x77) _BME280_CHIPID = const(0x60) - _BME280_REGISTER_CHIPID = const(0xD0) -_BME280_REGISTER_DIG_T1 = const(0x88) -_BME280_REGISTER_DIG_H1 = const(0xA1) -_BME280_REGISTER_DIG_H2 = const(0xE1) -_BME280_REGISTER_DIG_H3 = const(0xE3) -_BME280_REGISTER_DIG_H4 = const(0xE4) -_BME280_REGISTER_DIG_H5 = const(0xE5) -_BME280_REGISTER_DIG_H6 = const(0xE7) - -_BME280_REGISTER_SOFTRESET = const(0xE0) -_BME280_REGISTER_CTRL_HUM = const(0xF2) -_BME280_REGISTER_STATUS = const(0xF3) -_BME280_REGISTER_CTRL_MEAS = const(0xF4) -_BME280_REGISTER_CONFIG = const(0xF5) -_BME280_REGISTER_PRESSUREDATA = const(0xF7) -_BME280_REGISTER_TEMPDATA = const(0xFA) -_BME280_REGISTER_HUMIDDATA = const(0xFD) - -_BME280_HUMIDITY_MIN = const(0) -_BME280_HUMIDITY_MAX = const(100) - -"""iir_filter values""" -IIR_FILTER_DISABLE = const(0) - """overscan values for temperature, pressure, and humidity""" -OVERSCAN_DISABLE = const(0x00) OVERSCAN_X1 = const(0x01) -OVERSCAN_X2 = const(0x02) -OVERSCAN_X4 = const(0x03) -OVERSCAN_X8 = const(0x04) OVERSCAN_X16 = const(0x05) - -_BME280_OVERSCANS = { - OVERSCAN_DISABLE: 0, - OVERSCAN_X1: 1, - OVERSCAN_X2: 2, - OVERSCAN_X4: 4, - OVERSCAN_X8: 8, - OVERSCAN_X16: 16, -} - +"""mode values""" +_BME280_MODES = (0x00, 0x01, 0x03) +"""iir_filter values""" +IIR_FILTER_DISABLE = const(0) +""" +standby timeconstant values +TC_X[_Y] where X=milliseconds and Y=tenths of a millisecond +""" +STANDBY_TC_125 = const(0x02) # 125ms """mode values""" MODE_SLEEP = const(0x00) MODE_FORCE = const(0x01) MODE_NORMAL = const(0x03) - -_BME280_MODES = (MODE_SLEEP, MODE_FORCE, MODE_NORMAL) - -STANDBY_TC_125 = const(0x02) # 125ms +"""Other Registers""" +_BME280_REGISTER_SOFTRESET = const(0xE0) +_BME280_REGISTER_CTRL_HUM = const(0xF2) +_BME280_REGISTER_STATUS = const(0xF3) +_BME280_REGISTER_CTRL_MEAS = const(0xF4) +_BME280_REGISTER_CONFIG = const(0xF5) +_BME280_REGISTER_TEMPDATA = const(0xFA) +_BME280_REGISTER_HUMIDDATA = const(0xFD) class Adafruit_BME280: """Driver from BME280 Temperature, Humidity and Barometric Pressure sensor .. note:: - The operational range of the BMP280 is 300-1100 hPa. + The operational range of the BME280 is 300-1100 hPa. Pressure measurements outside this range may not be as accurate. """ @@ -116,8 +93,8 @@ def __init__(self): raise RuntimeError("Failed to find BME280! Chip ID 0x%x" % chip_id) # Set some reasonable defaults. self._iir_filter = IIR_FILTER_DISABLE - self.overscan_humidity = 1 - self.overscan_temperature = 1 + self.overscan_humidity = OVERSCAN_X1 + self.overscan_temperature = OVERSCAN_X1 self.overscan_pressure = OVERSCAN_X16 self._t_standby = STANDBY_TC_125 self._mode = MODE_SLEEP @@ -139,19 +116,17 @@ def _read_temperature(self): raw_temperature = ( self._read24(_BME280_REGISTER_TEMPDATA) / 16 ) # lowest 4 bits get dropped - # print("raw temp: ", UT) + var1 = ( raw_temperature / 16384.0 - self._temp_calib[0] / 1024.0 ) * self._temp_calib[1] - # print(var1) + var2 = ( (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) * (raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) ) * self._temp_calib[2] - # print(var2) self._t_fine = int(var1 + var2) - # print("t_fine: ", self.t_fine) def _reset(self): """Soft reset the sensor""" @@ -164,7 +139,6 @@ def _write_ctrl_meas(self): ctrl_meas sets the pressure and temperature data acquisition options ctrl_hum sets the humidity oversampling and must be written to first """ - self._write_register_byte(_BME280_REGISTER_CTRL_HUM, self.overscan_humidity) self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, self._ctrl_meas) @@ -178,8 +152,14 @@ def _read_config(self): def _write_config(self): """Write the value to the config register in the device """ - + normal_flag = False + if self._mode == MODE_NORMAL: + # Writes to the config register may be ignored while in Normal mode + normal_flag = True + self.mode = MODE_SLEEP # So we switch to Sleep mode first self._write_register_byte(_BME280_REGISTER_CONFIG, self._config) + if normal_flag: + self.mode = MODE_NORMAL @property def mode(self): @@ -200,7 +180,7 @@ def mode(self, value): def _config(self): """Value to be written to the device's config register """ config = 0 - if self.mode == MODE_NORMAL: + if self.mode == 0x03: # MODE_NORMAL config += self._t_standby << 5 if self._iir_filter: config += self._iir_filter << 2 @@ -231,7 +211,7 @@ def pressure(self): # Algorithm from the BME280 driver # https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c adc = ( - self._read24(_BME280_REGISTER_PRESSUREDATA) / 16 + self._read24(0xF7) / 16 # BME280_REGISTER_PRESSUREDATA ) # lowest 4 bits get dropped var1 = float(self._t_fine) / 2.0 - 64000.0 var2 = var1 * var1 * self._pressure_calib[5] / 32768.0 @@ -268,7 +248,7 @@ def humidity(self): returns None if humidity measurement is disabled """ self._read_temperature() - hum = self._read_register(_BME280_REGISTER_HUMIDDATA, 2) + hum = self._read_register(0xFD, 2) # BME280_REGISTER_HUMIDDATA adc = float(hum[0] << 8 | hum[1]) # Algorithm from the BME280 driver @@ -284,31 +264,31 @@ def humidity(self): var6 = var3 * var4 * (var5 * var6) humidity = var6 * (1.0 - self._humidity_calib[0] * var6 / 524288.0) - if humidity > _BME280_HUMIDITY_MAX: - return _BME280_HUMIDITY_MAX - if humidity < _BME280_HUMIDITY_MIN: - return _BME280_HUMIDITY_MIN + if humidity > 100: + return 100 + if humidity < 0: + return 0 # else... return humidity @property def altitude(self): - """The altitude based on current ``pressure`` versus the sea level pressure + """The altitude based on current :attr:`pressure` versus the sea level pressure (``sea_level_pressure``) - which you must enter ahead of time)""" pressure = self.pressure # in Si units for hPascal return 44330 * (1.0 - math.pow(pressure / self.sea_level_pressure, 0.1903)) def _read_coefficients(self): """Read & save the calibration coefficients""" - coeff = self._read_register(_BME280_REGISTER_DIG_T1, 24) + coeff = self._read_register(0x88, 24) # BME280_REGISTER_DIG_T1 coeff = list(struct.unpack(" %s" % (register, [hex(i) for i in result])) return result def _write_register_byte(self, register, value): @@ -358,6 +383,53 @@ def _write_register_byte(self, register, value): class Adafruit_BME280_SPI(Adafruit_BME280): + """Driver for BME280 connected over SPI + + :param ~busio.SPI spi: SPI device + :param ~digitalio.DigitalInOut cs: Chip Select + :param int baudrate: Clock rate, default is 100000. Can be changed with :meth:`baudrate` + + .. note:: + The operational range of the BMP280 is 300-1100 hPa. + Pressure measurements outside this range may not be as accurate. + + **Quickstart: Importing and using the BME280** + + Here is an example of using the :class:`Adafruit_BME280_SPI` class. + First you will need to import the libraries to use the sensor + + .. code-block:: python + + import board + from digitalio import DigitalInOut + from adafruit_bme280 import basic + + Once this is done you can define your `board.SPI` object and define your sensor object + + .. code-block:: python + + cs = digitalio.DigitalInOut(board.D10) + spi = board.SPI() + bme280 = basic.Adafruit_BME280_SPI(spi, cs) + + You need to setup the pressure at sea level + + .. code-block:: python + + bme280.sea_level_pressure = 1013.25 + + Now you have access to the :attr:`temperature`, :attr:`relative_humidity` + :attr:`pressure` and :attr:`altitude` attributes + + .. code-block:: python + + temperature = bme280.temperature + relative_humidity = bme280.relative_humidity + pressure = bme280.pressure + altitude = bme280.altitude + + """ + def __init__(self, spi, cs, baudrate=100000): import adafruit_bus_device.spi_device as spi_device # pylint: disable=import-outside-toplevel @@ -376,4 +448,3 @@ def _write_register_byte(self, register, value): register &= 0x7F # Write, bit 7 low. with self._spi as spi: spi.write(bytes([register, value & 0xFF])) # pylint: disable=no-member - diff --git a/docs/api.rst b/docs/api.rst index 0622224..8818b61 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -3,3 +3,9 @@ .. automodule:: adafruit_bme280 :members: + +.. automodule:: adafruit_bme280.basic + :members: + +.. automodule:: adafruit_bme280.advanced + :members: diff --git a/examples/bme280_normal_mode.py b/examples/bme280_normal_mode.py index c5f1dd2..53a3f9e 100644 --- a/examples/bme280_normal_mode.py +++ b/examples/bme280_normal_mode.py @@ -8,27 +8,27 @@ """ import time import board -import adafruit_bme280 +from adafruit_bme280 import advanced # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA -bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) +bme280 = advanced.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # SPI setup # from digitalio import DigitalInOut # spi = board.SPI() # bme_cs = digitalio.DigitalInOut(board.D10) -# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = advanced.Adafruit_BME280_SPI(spi, bme_cs) # Change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 -bme280.mode = adafruit_bme280.MODE_NORMAL -bme280.standby_period = adafruit_bme280.STANDBY_TC_500 -bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16 -bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16 -bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1 -bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2 +bme280.mode = advanced.MODE_NORMAL +bme280.standby_period = advanced.STANDBY_TC_500 +bme280.iir_filter = advanced.IIR_FILTER_X16 +bme280.overscan_pressure = advanced.OVERSCAN_X16 +bme280.overscan_humidity = advanced.OVERSCAN_X1 +bme280.overscan_temperature = advanced.OVERSCAN_X2 # The sensor will need a moment to gather initial readings time.sleep(1) diff --git a/examples/bme280_simpletest.py b/examples/bme280_simpletest.py index d653584..285b7e0 100644 --- a/examples/bme280_simpletest.py +++ b/examples/bme280_simpletest.py @@ -3,16 +3,16 @@ import time import board -import adafruit_bme280 +from adafruit_bme280 import basic # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA -bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) +bme280 = basic.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # spi = board.SPI() # bme_cs = digitalio.DigitalInOut(board.D10) -# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = basic.Adafruit_BME280_SPI(spi, bme_cs) # change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 diff --git a/examples/bme280_simpletest_pico.py b/examples/bme280_simpletest_pico.py index d433b44..fdd1fcc 100644 --- a/examples/bme280_simpletest_pico.py +++ b/examples/bme280_simpletest_pico.py @@ -4,16 +4,16 @@ import time import board import busio -import adafruit_bme280 +from adafruit_bme280 import basic # Create sensor object, using the board's default I2C bus. i2c = busio.I2C(board.GP1, board.GP0) # SCL, SDA -bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) +bme280 = basic.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # spi = busio.SPI(board.GP2, MISO=board.GP0, MOSI=board.GP3) # bme_cs = digitalio.DigitalInOut(board.GP1) -# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = basic.Adafruit_BME280_SPI(spi, bme_cs) # change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 From 361109542aa4065760698d5bab01002799473aec Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 26 May 2021 14:48:37 -0400 Subject: [PATCH 3/7] include init.py --- adafruit_bme280/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 adafruit_bme280/__init__.py diff --git a/adafruit_bme280/__init__.py b/adafruit_bme280/__init__.py new file mode 100644 index 0000000..e69de29 From 3e3e5cf6733a140e3e71de926316e48a596699d4 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 26 May 2021 14:59:34 -0400 Subject: [PATCH 4/7] pylint ver --- adafruit_bme280/advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_bme280/advanced.py b/adafruit_bme280/advanced.py index 18191de..f774c6e 100644 --- a/adafruit_bme280/advanced.py +++ b/adafruit_bme280/advanced.py @@ -123,7 +123,7 @@ STANDBY_TC_1000, ) - +# pylint: disable=abstract-method class Adafruit_BME280_Advanced(Adafruit_BME280): """Driver from BME280 Temperature, Humidity and Barometric Pressure sensor From 4254c14fd977865ae5c1d7b0aaabfb104920ec45 Mon Sep 17 00:00:00 2001 From: jposada202020 <34255413+jposada202020@users.noreply.github.com> Date: Tue, 1 Jun 2021 19:14:49 -0400 Subject: [PATCH 5/7] Update examples/bme280_normal_mode.py Co-authored-by: Scott Shawcroft --- examples/bme280_normal_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/bme280_normal_mode.py b/examples/bme280_normal_mode.py index 53a3f9e..8c7cc6b 100644 --- a/examples/bme280_normal_mode.py +++ b/examples/bme280_normal_mode.py @@ -8,7 +8,7 @@ """ import time import board -from adafruit_bme280 import advanced +import adafruit_bme280.advanced as adafruit_bme280 # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA From 3f6f12591eabf221b6bf88e3648f9f807988939d Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 2 Jun 2021 14:10:38 -0400 Subject: [PATCH 6/7] improving_importing_description --- examples/bme280_normal_mode.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/bme280_normal_mode.py b/examples/bme280_normal_mode.py index 8c7cc6b..85dd156 100644 --- a/examples/bme280_normal_mode.py +++ b/examples/bme280_normal_mode.py @@ -12,23 +12,23 @@ # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA -bme280 = advanced.Adafruit_BME280_I2C(i2c) +bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # SPI setup # from digitalio import DigitalInOut # spi = board.SPI() # bme_cs = digitalio.DigitalInOut(board.D10) -# bme280 = advanced.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) # Change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 -bme280.mode = advanced.MODE_NORMAL -bme280.standby_period = advanced.STANDBY_TC_500 -bme280.iir_filter = advanced.IIR_FILTER_X16 -bme280.overscan_pressure = advanced.OVERSCAN_X16 -bme280.overscan_humidity = advanced.OVERSCAN_X1 -bme280.overscan_temperature = advanced.OVERSCAN_X2 +bme280.mode = adafruit_bme280.MODE_NORMAL +bme280.standby_period = adafruit_bme280.STANDBY_TC_500 +bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16 +bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16 +bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1 +bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2 # The sensor will need a moment to gather initial readings time.sleep(1) From 2b0af3c52567a1d8f2d0e02668c4bc5e919e955e Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Wed, 2 Jun 2021 14:24:16 -0400 Subject: [PATCH 7/7] improving_importing_description --- examples/bme280_simpletest.py | 6 +++--- examples/bme280_simpletest_pico.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/bme280_simpletest.py b/examples/bme280_simpletest.py index 285b7e0..2f1c39a 100644 --- a/examples/bme280_simpletest.py +++ b/examples/bme280_simpletest.py @@ -3,16 +3,16 @@ import time import board -from adafruit_bme280 import basic +from adafruit_bme280 import basic as adafruit_bme280 # Create sensor object, using the board's default I2C bus. i2c = board.I2C() # uses board.SCL and board.SDA -bme280 = basic.Adafruit_BME280_I2C(i2c) +bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # spi = board.SPI() # bme_cs = digitalio.DigitalInOut(board.D10) -# bme280 = basic.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) # change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25 diff --git a/examples/bme280_simpletest_pico.py b/examples/bme280_simpletest_pico.py index fdd1fcc..435e41a 100644 --- a/examples/bme280_simpletest_pico.py +++ b/examples/bme280_simpletest_pico.py @@ -4,16 +4,16 @@ import time import board import busio -from adafruit_bme280 import basic +from adafruit_bme280 import basic as adafruit_bme280 # Create sensor object, using the board's default I2C bus. i2c = busio.I2C(board.GP1, board.GP0) # SCL, SDA -bme280 = basic.Adafruit_BME280_I2C(i2c) +bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) # OR create sensor object, using the board's default SPI bus. # spi = busio.SPI(board.GP2, MISO=board.GP0, MOSI=board.GP3) # bme_cs = digitalio.DigitalInOut(board.GP1) -# bme280 = basic.Adafruit_BME280_SPI(spi, bme_cs) +# bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs) # change this to match the location's pressure (hPa) at sea level bme280.sea_level_pressure = 1013.25