Skip to content

Commit d2689d0

Browse files
authored
Merge pull request #7 from chickadee-tech/fix_bme680
Fix temperature readings and speed things up.
2 parents d8843dc + 8f79053 commit d2689d0

File tree

1 file changed

+44
-31
lines changed

1 file changed

+44
-31
lines changed

adafruit_bme680.py

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -87,36 +87,43 @@ def _read24(arr):
8787

8888

8989
class Adafruit_BME680:
90-
"""Driver from BME680 air quality sensor"""
91-
def __init__(self):
90+
"""Driver from BME680 air quality sensor
91+
92+
:param int refresh_rate: Maximum number of readings per second. Faster property reads
93+
will be from the previous reading."""
94+
def __init__(self, *, refresh_rate=10):
9295
"""Check the BME680 was found, read the coefficients and enable the sensor for continuous
93-
reads"""
96+
reads."""
9497
self._write(_BME680_REG_SOFTRESET, [0xB6])
95-
time.sleep(0.5)
98+
time.sleep(0.005)
9699

97100
# Check device ID.
98101
chip_id = self._read_byte(_BME680_REG_CHIPID)
99-
if _BME680_CHIPID != chip_id:
100-
raise RuntimeError('Failed to find BME680! Chip ID 0x%x' % id)
102+
if chip_id != _BME680_CHIPID:
103+
raise RuntimeError('Failed to find BME680! Chip ID 0x%x' % chip_id)
101104

102105
self._read_calibration()
103106

104107
# set up heater
105108
self._write(_BME680_BME680_RES_WAIT_0, [0x73, 0x64, 0x65])
106109
self.sea_level_pressure = 1013.25
107110
"""Pressure in hectoPascals at sea level. Used to calibrate ``altitude``."""
108-
self._pressure_oversample = 4
109-
self._temp_oversample = 8
110-
self._humidity_oversample = 2
111-
self._filter = 3
111+
112+
# Default oversampling and filter register values.
113+
self._pressure_oversample = 0b011
114+
self._temp_oversample = 0b100
115+
self._humidity_oversample = 0b010
116+
self._filter = 0b010
112117

113118
self._adc_pres = None
114119
self._adc_temp = None
115120
self._adc_hum = None
116121
self._adc_gas = None
117122
self._gas_range = None
118123
self._t_fine = None
119-
self._status = 0
124+
125+
self._last_reading = 0
126+
self._min_refresh_time = 1 / refresh_rate
120127

121128
@property
122129
def pressure_oversample(self):
@@ -241,6 +248,8 @@ def gas(self):
241248
def _perform_reading(self):
242249
"""Perform a single-shot reading from the sensor and fill internal data structure for
243250
calculations"""
251+
if time.monotonic() - self._last_reading < self._min_refresh_time:
252+
return
244253

245254
# set filter
246255
self._write(_BME680_REG_CONFIG, [self._filter << 2])
@@ -252,25 +261,21 @@ def _perform_reading(self):
252261
# gas measurements enabled
253262
self._write(_BME680_REG_CTRL_GAS, [_BME680_RUNGAS])
254263

255-
ctrl = self._read(_BME680_REG_CTRL_MEAS, 1)[0]
264+
ctrl = self._read_byte(_BME680_REG_CTRL_MEAS)
256265
ctrl = (ctrl & 0xFC) | 0x01 # enable single shot!
257266
self._write(_BME680_REG_CTRL_MEAS, [ctrl])
258-
time.sleep(0.5)
259-
data = self._read(_BME680_REG_STATUS, 15)
260-
self._status = data[0] & 0x80
261-
#gas_idx = data[0] & 0x0F
262-
#meas_idx = data[1]
263-
#print("status 0x%x gas_idx %d meas_idx %d" % (self._status, gas_idx, meas_idx))
264-
265-
#print([hex(i) for i in data])
267+
new_data = False
268+
while not new_data:
269+
data = self._read(_BME680_REG_STATUS, 15)
270+
new_data = data[0] & 0x80 != 0
271+
time.sleep(0.005)
272+
self._last_reading = time.monotonic()
273+
266274
self._adc_pres = _read24(data[2:5]) / 16
267275
self._adc_temp = _read24(data[5:8]) / 16
268276
self._adc_hum = struct.unpack('>H', bytes(data[8:10]))[0]
269277
self._adc_gas = int(struct.unpack('>H', bytes(data[13:15]))[0] / 64)
270278
self._gas_range = data[14] & 0x0F
271-
#print(self._adc_hum)
272-
#print(self._adc_gas)
273-
self._status |= data[14] & 0x30 # VALID + STABILITY mask
274279

275280
var1 = (self._adc_temp / 8) - (self._temp_calibration[0] * 2)
276281
var2 = (var1 * self._temp_calibration[1]) / 2048
@@ -296,9 +301,9 @@ def _read_calibration(self):
296301
self._humidity_calibration[1] += self._humidity_calibration[0] % 16
297302
self._humidity_calibration[0] /= 16
298303

299-
self._heat_range = (self._read(0x02, 1)[0] & 0x30) / 16
300-
self._heat_val = self._read(0x00, 1)[0]
301-
self._sw_err = (self._read(0x04, 1)[0] & 0xF0) / 16
304+
self._heat_range = (self._read_byte(0x02) & 0x30) / 16
305+
self._heat_val = self._read_byte(0x00)
306+
self._sw_err = (self._read_byte(0x04) & 0xF0) / 16
302307

303308
def _read_byte(self, register):
304309
"""Read a byte register value and return it"""
@@ -311,13 +316,18 @@ def _write(self, register, values):
311316
raise NotImplementedError()
312317

313318
class Adafruit_BME680_I2C(Adafruit_BME680):
314-
"""Driver for I2C connected BME680."""
315-
def __init__(self, i2c, address=0x77, debug=False):
319+
"""Driver for I2C connected BME680.
320+
321+
:param int address: I2C device address
322+
:param bool debug: Print debug statements when True.
323+
:param int refresh_rate: Maximum number of readings per second. Faster property reads
324+
will be from the previous reading."""
325+
def __init__(self, i2c, address=0x77, debug=False, *, refresh_rate=10):
316326
"""Initialize the I2C device at the 'address' given"""
317327
import adafruit_bus_device.i2c_device as i2c_device
318328
self._i2c = i2c_device.I2CDevice(i2c, address)
319329
self._debug = debug
320-
super().__init__()
330+
super().__init__(refresh_rate=refresh_rate)
321331

322332
def _read(self, register, length):
323333
"""Returns an array of 'length' bytes from the 'register'"""
@@ -332,7 +342,10 @@ def _read(self, register, length):
332342
def _write(self, register, values):
333343
"""Writes an array of 'length' bytes to the 'register'"""
334344
with self._i2c as i2c:
335-
values = [(v & 0xFF) for v in [register]+values]
336-
i2c.write(bytes(values))
345+
buffer = bytearray(2 * len(values))
346+
for i, value in enumerate(values):
347+
buffer[2 * i] = register + i
348+
buffer[2 * i + 1] = value
349+
i2c.write(buffer)
337350
if self._debug:
338351
print("\t$%02X <= %s" % (values[0], [hex(i) for i in values[1:]]))

0 commit comments

Comments
 (0)