Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 240 additions & 18 deletions adafruit_bme280.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_bme280` - Adafruit BME680 - Temperature, Humidity, Pressure & Gas Sensor
====================================================================================
`adafruit_bme280` - Adafruit BME280 - Temperature, Humidity & Barometic Pressure Sensor
=========================================================================================

CircuitPython driver from BME280 Temperature, Humidity and Barometic Pressure sensor

* Author(s): ladyada
"""
import math
import time
from time import sleep
from micropython import const
try:
import struct
Expand Down Expand Up @@ -67,34 +67,83 @@
_BME280_HUMIDITY_MIN = const(0)
_BME280_HUMIDITY_MAX = const(100)

"""iir_filter values"""
IIR_FILTER_DISABLE = const(0)
IIR_FILTER_X2 = const(0x01)
IIR_FILTER_X4 = const(0x02)
IIR_FILTER_X8 = const(0x03)
IIR_FILTER_X16 = const(0x04)

_BME280_IIR_FILTERS = frozenset((IIR_FILTER_DISABLE, IIR_FILTER_X2,
IIR_FILTER_X4, IIR_FILTER_X8, IIR_FILTER_X16))

"""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 = frozenset((MODE_SLEEP, MODE_FORCE, MODE_NORMAL))
"""
standby timeconstant values
TC_X[_Y] where X=milliseconds and Y=tenths of a millisecond
"""
STANDBY_TC_0_5 = const(0x00) #0.5ms
STANDBY_TC_10 = const(0x06) #10ms
STANDBY_TC_20 = const(0x07) #20ms
STANDBY_TC_62_5 = const(0x01) #62.5ms
STANDBY_TC_125 = const(0x02) #125ms
STANDBY_TC_250 = const(0x03) #250ms
STANDBY_TC_500 = const(0x04) #500ms
STANDBY_TC_1000 = const(0x05) #1000ms

_BME280_STANDBY_TCS = frozenset((STANDBY_TC_0_5, STANDBY_TC_10, STANDBY_TC_20,
STANDBY_TC_62_5, STANDBY_TC_125, STANDBY_TC_250,
STANDBY_TC_500, STANDBY_TC_1000))

class Adafruit_BME280:
"""Driver from BME280 Temperature, Humidity and Barometic Pressure sensor"""
# pylint: disable=too-many-instance-attributes
def __init__(self):
"""Check the BME280 was found, read the coefficients and enable the sensor for continuous
reads"""
"""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)
self._write_register_byte(_BME280_REGISTER_SOFTRESET, 0xB6)
time.sleep(0.5)
#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`."""
# turn on humidity oversample 16x
self._write_register_byte(_BME280_REGISTER_CTRL_HUM, 0x03)
self._t_fine = None

def _read_temperature(self):
# perform one measurement
self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, 0xFE) # high res, forced mode

# Wait for conversion to complete
while self._read_byte(_BME280_REGISTER_STATUS) & 0x08:
time.sleep(0.002)
raw_temperature = self._read24(_BME280_REGISTER_TEMPDATA) / 16 # lowest 4 bits get dropped
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) * (
Expand All @@ -104,6 +153,173 @@ def _read_temperature(self):
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 acquistion options
ctrl_hum sets the humidty 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()

@property
def standby_period(self):
"""
Control the inactive period when in Normal mode
Allowed standby periods are the constants STANDBY_TC_*
"""
return self._t_standby

@standby_period.setter
def standby_period(self, value):
if not value in _BME280_STANDBY_TCS:
raise ValueError('Standby Period \'%s\' not supported' % (value))
if self._t_standby == value:
return
self._t_standby = value
self._write_config()

@property
def overscan_humidity(self):
"""
Humidity Oversampling
Allowed values are the constants OVERSCAN_*
"""
return self._overscan_humidity

@overscan_humidity.setter
def overscan_humidity(self, value):
if not value in _BME280_OVERSCANS:
raise ValueError('Overscan value \'%s\' not supported' % (value))
self._overscan_humidity = value
self._write_ctrl_meas()

@property
def overscan_temperature(self):
"""
Temperature Oversampling
Allowed values are the constants OVERSCAN_*
"""
return self._overscan_temperature

@overscan_temperature.setter
def overscan_temperature(self, value):
if not value in _BME280_OVERSCANS:
raise ValueError('Overscan value \'%s\' not supported' % (value))
self._overscan_temperature = value
self._write_ctrl_meas()

@property
def overscan_pressure(self):
"""
Pressure Oversampling
Allowed values are the constants OVERSCAN_*
"""
return self._overscan_pressure

@overscan_pressure.setter
def overscan_pressure(self, value):
if not value in _BME280_OVERSCANS:
raise ValueError('Overscan value \'%s\' not supported' % (value))
self._overscan_pressure = value
self._write_ctrl_meas()

@property
def iir_filter(self):
"""
Controls the time constant of the IIR filter
Allowed values are the constants IIR_FILTER_*
"""
return self._iir_filter

@iir_filter.setter
def iir_filter(self, value):
if not value in _BME280_IIR_FILTERS:
raise ValueError('IIR Filter \'%s\' not supported' % (value))
self._iir_filter = value
self._write_config()

@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 measurement_time_typical(self):
"""Typical time in milliseconds required to complete a measurement in normal mode"""
meas_time_ms = 1.0
if self.overscan_temperature != OVERSCAN_DISABLE:
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_temperature))
if self.overscan_pressure != OVERSCAN_DISABLE:
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_pressure) + 0.5)
if self.overscan_humidity != OVERSCAN_DISABLE:
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_humidity) + 0.5)
return meas_time_ms

@property
def measurement_time_max(self):
"""Maximum time in milliseconds required to complete a measurement in normal mode"""
meas_time_ms = 1.25
if self.overscan_temperature != OVERSCAN_DISABLE:
meas_time_ms += (2.3 * _BME280_OVERSCANS.get(self.overscan_temperature))
if self.overscan_pressure != OVERSCAN_DISABLE:
meas_time_ms += (2.3 * _BME280_OVERSCANS.get(self.overscan_pressure) + 0.575)
if self.overscan_humidity != OVERSCAN_DISABLE:
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."""
Expand All @@ -112,7 +328,10 @@ def temperature(self):

@property
def pressure(self):
"""The compensated pressure in hectoPascals."""
"""
The compensated pressure in hectoPascals.
returns None if pressure measurement is disabled
"""
self._read_temperature()

# Algorithm from the BME280 driver
Expand Down Expand Up @@ -145,7 +364,10 @@ def pressure(self):

@property
def humidity(self):
"""The relative humidity in RH %"""
"""
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)
Expand Down
37 changes: 37 additions & 0 deletions examples/bme280_normal_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Example showing how the BME280 library can be used to set the various
parameters supported by the sensor.
Refer to the BME280 datasheet to understand what these parameters do
"""
import time

import board
import busio
import adafruit_bme280

# Create library object using our Bus I2C port
i2c = busio.I2C(board.SCL, board.SDA)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)

# OR create library object using our Bus SPI port
#spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
#bme_cs = digitalio.DigitalInOut(board.D10)
#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 = 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 inital readings
time.sleep(1)

while True:
print("\nTemperature: %0.1f C" % bme280.temperature)
print("Humidity: %0.1f %%" % bme280.humidity)
print("Pressure: %0.1f hPa" % bme280.pressure)
print("Altitude = %0.2f meters" % bme280.altitude)
time.sleep(2)