Skip to content

Commit febcd51

Browse files
authored
Merge pull request #22 from jraber/master
Add class attributes to allow more control over the sensor
2 parents a18166d + 0a10d86 commit febcd51

File tree

2 files changed

+277
-18
lines changed

2 files changed

+277
-18
lines changed

adafruit_bme280.py

Lines changed: 240 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
# THE SOFTWARE.
2222
"""
23-
`adafruit_bme280` - Adafruit BME680 - Temperature, Humidity, Pressure & Gas Sensor
24-
====================================================================================
23+
`adafruit_bme280` - Adafruit BME280 - Temperature, Humidity & Barometic Pressure Sensor
24+
=========================================================================================
2525
2626
CircuitPython driver from BME280 Temperature, Humidity and Barometic Pressure sensor
2727
2828
* Author(s): ladyada
2929
"""
3030
import math
31-
import time
31+
from time import sleep
3232
from micropython import const
3333
try:
3434
import struct
@@ -67,34 +67,83 @@
6767
_BME280_HUMIDITY_MIN = const(0)
6868
_BME280_HUMIDITY_MAX = const(100)
6969

70+
"""iir_filter values"""
71+
IIR_FILTER_DISABLE = const(0)
72+
IIR_FILTER_X2 = const(0x01)
73+
IIR_FILTER_X4 = const(0x02)
74+
IIR_FILTER_X8 = const(0x03)
75+
IIR_FILTER_X16 = const(0x04)
76+
77+
_BME280_IIR_FILTERS = frozenset((IIR_FILTER_DISABLE, IIR_FILTER_X2,
78+
IIR_FILTER_X4, IIR_FILTER_X8, IIR_FILTER_X16))
79+
80+
"""overscan values for temperature, pressure, and humidity"""
81+
OVERSCAN_DISABLE = const(0x00)
82+
OVERSCAN_X1 = const(0x01)
83+
OVERSCAN_X2 = const(0x02)
84+
OVERSCAN_X4 = const(0x03)
85+
OVERSCAN_X8 = const(0x04)
86+
OVERSCAN_X16 = const(0x05)
87+
88+
_BME280_OVERSCANS = {OVERSCAN_DISABLE:0, OVERSCAN_X1:1, OVERSCAN_X2:2,
89+
OVERSCAN_X4:4, OVERSCAN_X8:8, OVERSCAN_X16:16}
90+
91+
"""mode values"""
92+
MODE_SLEEP = const(0x00)
93+
MODE_FORCE = const(0x01)
94+
MODE_NORMAL = const(0x03)
95+
96+
_BME280_MODES = frozenset((MODE_SLEEP, MODE_FORCE, MODE_NORMAL))
97+
"""
98+
standby timeconstant values
99+
TC_X[_Y] where X=milliseconds and Y=tenths of a millisecond
100+
"""
101+
STANDBY_TC_0_5 = const(0x00) #0.5ms
102+
STANDBY_TC_10 = const(0x06) #10ms
103+
STANDBY_TC_20 = const(0x07) #20ms
104+
STANDBY_TC_62_5 = const(0x01) #62.5ms
105+
STANDBY_TC_125 = const(0x02) #125ms
106+
STANDBY_TC_250 = const(0x03) #250ms
107+
STANDBY_TC_500 = const(0x04) #500ms
108+
STANDBY_TC_1000 = const(0x05) #1000ms
109+
110+
_BME280_STANDBY_TCS = frozenset((STANDBY_TC_0_5, STANDBY_TC_10, STANDBY_TC_20,
111+
STANDBY_TC_62_5, STANDBY_TC_125, STANDBY_TC_250,
112+
STANDBY_TC_500, STANDBY_TC_1000))
113+
70114
class Adafruit_BME280:
71115
"""Driver from BME280 Temperature, Humidity and Barometic Pressure sensor"""
116+
# pylint: disable=too-many-instance-attributes
72117
def __init__(self):
73-
"""Check the BME280 was found, read the coefficients and enable the sensor for continuous
74-
reads"""
118+
"""Check the BME280 was found, read the coefficients and enable the sensor"""
75119
# Check device ID.
76120
chip_id = self._read_byte(_BME280_REGISTER_CHIPID)
77121
if _BME280_CHIPID != chip_id:
78122
raise RuntimeError('Failed to find BME280! Chip ID 0x%x' % chip_id)
79-
self._write_register_byte(_BME280_REGISTER_SOFTRESET, 0xB6)
80-
time.sleep(0.5)
123+
#Set some reasonable defaults.
124+
self._iir_filter = IIR_FILTER_DISABLE
125+
self._overscan_humidity = OVERSCAN_X1
126+
self._overscan_temperature = OVERSCAN_X1
127+
self._overscan_pressure = OVERSCAN_X16
128+
self._t_standby = STANDBY_TC_125
129+
self._mode = MODE_SLEEP
130+
self._reset()
81131
self._read_coefficients()
132+
self._write_ctrl_meas()
133+
self._write_config()
82134
self.sea_level_pressure = 1013.25
83135
"""Pressure in hectoPascals at sea level. Used to calibrate `altitude`."""
84-
# turn on humidity oversample 16x
85-
self._write_register_byte(_BME280_REGISTER_CTRL_HUM, 0x03)
86136
self._t_fine = None
87137

88138
def _read_temperature(self):
89139
# perform one measurement
90-
self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, 0xFE) # high res, forced mode
91-
92-
# Wait for conversion to complete
93-
while self._read_byte(_BME280_REGISTER_STATUS) & 0x08:
94-
time.sleep(0.002)
95-
raw_temperature = self._read24(_BME280_REGISTER_TEMPDATA) / 16 # lowest 4 bits get dropped
140+
if self.mode != MODE_NORMAL:
141+
self.mode = MODE_FORCE
142+
# Wait for conversion to complete
143+
while self._get_status() & 0x08:
144+
sleep(0.002)
145+
raw_temperature = self._read24(_BME280_REGISTER_TEMPDATA) / 16 # lowest 4 bits get dropped
96146
#print("raw temp: ", UT)
97-
98147
var1 = (raw_temperature / 16384.0 - self._temp_calib[0] / 1024.0) * self._temp_calib[1]
99148
#print(var1)
100149
var2 = ((raw_temperature / 131072.0 - self._temp_calib[0] / 8192.0) * (
@@ -104,6 +153,173 @@ def _read_temperature(self):
104153
self._t_fine = int(var1 + var2)
105154
#print("t_fine: ", self.t_fine)
106155

156+
def _reset(self):
157+
"""Soft reset the sensor"""
158+
self._write_register_byte(_BME280_REGISTER_SOFTRESET, 0xB6)
159+
sleep(0.004) #Datasheet says 2ms. Using 4ms just to be safe
160+
161+
def _write_ctrl_meas(self):
162+
"""
163+
Write the values to the ctrl_meas and ctrl_hum registers in the device
164+
ctrl_meas sets the pressure and temperature data acquistion options
165+
ctrl_hum sets the humidty oversampling and must be written to first
166+
"""
167+
self._write_register_byte(_BME280_REGISTER_CTRL_HUM, self.overscan_humidity)
168+
self._write_register_byte(_BME280_REGISTER_CTRL_MEAS, self._ctrl_meas)
169+
170+
def _get_status(self):
171+
"""Get the value from the status register in the device """
172+
return self._read_byte(_BME280_REGISTER_STATUS)
173+
174+
def _read_config(self):
175+
"""Read the value from the config register in the device """
176+
return self._read_byte(_BME280_REGISTER_CONFIG)
177+
178+
def _write_config(self):
179+
"""Write the value to the config register in the device """
180+
normal_flag = False
181+
if self._mode == MODE_NORMAL:
182+
#Writes to the config register may be ignored while in Normal mode
183+
normal_flag = True
184+
self.mode = MODE_SLEEP #So we switch to Sleep mode first
185+
self._write_register_byte(_BME280_REGISTER_CONFIG, self._config)
186+
if normal_flag:
187+
self.mode = MODE_NORMAL
188+
189+
@property
190+
def mode(self):
191+
"""
192+
Operation mode
193+
Allowed values are the constants MODE_*
194+
"""
195+
return self._mode
196+
197+
@mode.setter
198+
def mode(self, value):
199+
if not value in _BME280_MODES:
200+
raise ValueError('Mode \'%s\' not supported' % (value))
201+
self._mode = value
202+
self._write_ctrl_meas()
203+
204+
@property
205+
def standby_period(self):
206+
"""
207+
Control the inactive period when in Normal mode
208+
Allowed standby periods are the constants STANDBY_TC_*
209+
"""
210+
return self._t_standby
211+
212+
@standby_period.setter
213+
def standby_period(self, value):
214+
if not value in _BME280_STANDBY_TCS:
215+
raise ValueError('Standby Period \'%s\' not supported' % (value))
216+
if self._t_standby == value:
217+
return
218+
self._t_standby = value
219+
self._write_config()
220+
221+
@property
222+
def overscan_humidity(self):
223+
"""
224+
Humidity Oversampling
225+
Allowed values are the constants OVERSCAN_*
226+
"""
227+
return self._overscan_humidity
228+
229+
@overscan_humidity.setter
230+
def overscan_humidity(self, value):
231+
if not value in _BME280_OVERSCANS:
232+
raise ValueError('Overscan value \'%s\' not supported' % (value))
233+
self._overscan_humidity = value
234+
self._write_ctrl_meas()
235+
236+
@property
237+
def overscan_temperature(self):
238+
"""
239+
Temperature Oversampling
240+
Allowed values are the constants OVERSCAN_*
241+
"""
242+
return self._overscan_temperature
243+
244+
@overscan_temperature.setter
245+
def overscan_temperature(self, value):
246+
if not value in _BME280_OVERSCANS:
247+
raise ValueError('Overscan value \'%s\' not supported' % (value))
248+
self._overscan_temperature = value
249+
self._write_ctrl_meas()
250+
251+
@property
252+
def overscan_pressure(self):
253+
"""
254+
Pressure Oversampling
255+
Allowed values are the constants OVERSCAN_*
256+
"""
257+
return self._overscan_pressure
258+
259+
@overscan_pressure.setter
260+
def overscan_pressure(self, value):
261+
if not value in _BME280_OVERSCANS:
262+
raise ValueError('Overscan value \'%s\' not supported' % (value))
263+
self._overscan_pressure = value
264+
self._write_ctrl_meas()
265+
266+
@property
267+
def iir_filter(self):
268+
"""
269+
Controls the time constant of the IIR filter
270+
Allowed values are the constants IIR_FILTER_*
271+
"""
272+
return self._iir_filter
273+
274+
@iir_filter.setter
275+
def iir_filter(self, value):
276+
if not value in _BME280_IIR_FILTERS:
277+
raise ValueError('IIR Filter \'%s\' not supported' % (value))
278+
self._iir_filter = value
279+
self._write_config()
280+
281+
@property
282+
def _config(self):
283+
"""Value to be written to the device's config register """
284+
config = 0
285+
if self.mode == MODE_NORMAL:
286+
config += (self._t_standby << 5)
287+
if self._iir_filter:
288+
config += (self._iir_filter << 2)
289+
return config
290+
291+
@property
292+
def _ctrl_meas(self):
293+
"""Value to be written to the device's ctrl_meas register """
294+
ctrl_meas = (self.overscan_temperature << 5)
295+
ctrl_meas += (self.overscan_pressure << 2)
296+
ctrl_meas += self.mode
297+
return ctrl_meas
298+
299+
@property
300+
def measurement_time_typical(self):
301+
"""Typical time in milliseconds required to complete a measurement in normal mode"""
302+
meas_time_ms = 1.0
303+
if self.overscan_temperature != OVERSCAN_DISABLE:
304+
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_temperature))
305+
if self.overscan_pressure != OVERSCAN_DISABLE:
306+
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_pressure) + 0.5)
307+
if self.overscan_humidity != OVERSCAN_DISABLE:
308+
meas_time_ms += (2 * _BME280_OVERSCANS.get(self.overscan_humidity) + 0.5)
309+
return meas_time_ms
310+
311+
@property
312+
def measurement_time_max(self):
313+
"""Maximum time in milliseconds required to complete a measurement in normal mode"""
314+
meas_time_ms = 1.25
315+
if self.overscan_temperature != OVERSCAN_DISABLE:
316+
meas_time_ms += (2.3 * _BME280_OVERSCANS.get(self.overscan_temperature))
317+
if self.overscan_pressure != OVERSCAN_DISABLE:
318+
meas_time_ms += (2.3 * _BME280_OVERSCANS.get(self.overscan_pressure) + 0.575)
319+
if self.overscan_humidity != OVERSCAN_DISABLE:
320+
meas_time_ms += (2.3 * _BME280_OVERSCANS.get(self.overscan_humidity) + 0.575)
321+
return meas_time_ms
322+
107323
@property
108324
def temperature(self):
109325
"""The compensated temperature in degrees celsius."""
@@ -112,7 +328,10 @@ def temperature(self):
112328

113329
@property
114330
def pressure(self):
115-
"""The compensated pressure in hectoPascals."""
331+
"""
332+
The compensated pressure in hectoPascals.
333+
returns None if pressure measurement is disabled
334+
"""
116335
self._read_temperature()
117336

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

146365
@property
147366
def humidity(self):
148-
"""The relative humidity in RH %"""
367+
"""
368+
The relative humidity in RH %
369+
returns None if humidity measurement is disabled
370+
"""
149371
self._read_temperature()
150372
hum = self._read_register(_BME280_REGISTER_HUMIDDATA, 2)
151373
#print("Humidity data: ", hum)

examples/bme280_normal_mode.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Example showing how the BME280 library can be used to set the various
3+
parameters supported by the sensor.
4+
Refer to the BME280 datasheet to understand what these parameters do
5+
"""
6+
import time
7+
8+
import board
9+
import busio
10+
import adafruit_bme280
11+
12+
# Create library object using our Bus I2C port
13+
i2c = busio.I2C(board.SCL, board.SDA)
14+
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
15+
16+
# OR create library object using our Bus SPI port
17+
#spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
18+
#bme_cs = digitalio.DigitalInOut(board.D10)
19+
#bme280 = adafruit_bme280.Adafruit_BME280_SPI(spi, bme_cs)
20+
21+
# change this to match the location's pressure (hPa) at sea level
22+
bme280.sea_level_pressure = 1013.25
23+
bme280.mode = adafruit_bme280.MODE_NORMAL
24+
bme280.standby_period = adafruit_bme280.STANDBY_TC_500
25+
bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16
26+
bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
27+
bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1
28+
bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2
29+
#The sensor will need a moment to gather inital readings
30+
time.sleep(1)
31+
32+
while True:
33+
print("\nTemperature: %0.1f C" % bme280.temperature)
34+
print("Humidity: %0.1f %%" % bme280.humidity)
35+
print("Pressure: %0.1f hPa" % bme280.pressure)
36+
print("Altitude = %0.2f meters" % bme280.altitude)
37+
time.sleep(2)

0 commit comments

Comments
 (0)