27
27
_BME680_REG_TDATA = const (0x22 )
28
28
_BME680_REG_HDATA = const (0x25 )
29
29
30
- _BME280_PRESSURE_MIN_HPA = const (300 )
31
- _BME280_PRESSURE_MAX_HPA = const (1100 )
32
- _BME280_HUMIDITY_MIN = const (0 )
33
- _BME280_HUMIDITY_MAX = const (100 )
34
30
_BME680_SAMPLERATES = (0 , 1 , 2 , 4 , 8 , 16 )
31
+ _BME680_FILTERSIZES = (0 , 1 , 3 , 7 , 15 , 31 , 63 , 127 )
35
32
36
33
_BME680_RUNGAS = const (0x10 )
37
34
35
+ lookupTable1 = (2147483647.0 , 2147483647.0 , 2147483647.0 , 2147483647.0 , 2147483647.0 , 2126008810.0 , 2147483647.0 , 2130303777.0 , 2147483647.0 , 2147483647.0 , 2143188679.0 , 2136746228.0 , 2147483647.0 , 2126008810.0 , 2147483647.0 , 2147483647.0 )
36
+
37
+ lookupTable2 = (4096000000.0 , 2048000000.0 , 1024000000.0 , 512000000.0 , 255744255.0 , 127110228.0 , 64000000.0 , 32258064.0 , 16016016.0 , 8000000.0 , 4000000.0 , 2000000.0 , 1000000.0 , 500000.0 , 250000.0 , 125000.0 )
38
+
39
+
38
40
class Adafruit_BME680 :
39
41
def __init__ (self ):
40
42
"""Check the BME680 was found, read the coefficients and enable the sensor for continuous reads"""
@@ -51,51 +53,63 @@ def __init__(self):
51
53
# set up heater
52
54
self ._write (_BME680_BME680_RES_WAIT_0 , [0x73 , 0x64 , 0x65 ])
53
55
self .seaLevelhPa = 1013.25
54
- #self.pressure_oversample = 16
55
- #self.temp_oversample = 2
56
- #self.hum_oversample = 1
57
- self .osrs_h = 2
58
- self .osrs_t = 4
59
- self .osrs_p = 3
56
+ self .pres_oversample = 4
57
+ self .temp_oversample = 8
58
+ self .hum_oversample = 2
60
59
self .filter = 2
61
60
62
- # set filter
63
- self ._write (_BME680_REG_CONFIG , [self .filter << 2 ])
64
- # turn on temp oversample & pressure oversample
65
- self ._write (_BME680_REG_CTRL_MEAS , [(self .osrs_t << 5 )| (self .osrs_p << 2 )])
66
- # turn on humidity oversample
67
- self ._write (_BME680_REG_CTRL_HUM , [self .osrs_h ])
68
- # gas measurements enabled
69
- self ._write (_BME680_REG_CTRL_GAS , [_BME680_RUNGAS ])
61
+ @property
62
+ def pres_oversample (self ):
63
+ return _BME680_SAMPLERATES [self .osrs_p ]
64
+
65
+ @pres_oversample .setter
66
+ def pres_oversample (self , os ):
67
+ """Set the oversampling for pressure sensor"""
68
+ if os in _BME680_SAMPLERATES :
69
+ self .osrs_p = _BME680_SAMPLERATES .index (os )
70
+ else :
71
+ raise RuntimeError ("Invalid oversample" )
70
72
71
- def reading (self ):
72
- print ("\n \n Reading data" );
73
- v = self ._read (_BME680_REG_CTRL_MEAS , 1 )[0 ]
74
- v = (v & 0xFC ) | 0x01 # enable single shot!
75
- self ._write (_BME680_REG_CTRL_MEAS , [v ])
76
-
77
- time .sleep (0.5 )
73
+ @property
74
+ def hum_oversample (self ):
75
+ return _BME680_SAMPLERATES [self .osrs_h ]
76
+
77
+ @hum_oversample .setter
78
+ def hum_oversample (self , os ):
79
+ """Set the oversampling for humidity sensor"""
80
+ if os in _BME680_SAMPLERATES :
81
+ self .osrs_h = _BME680_SAMPLERATES .index (os )
82
+ else :
83
+ raise RuntimeError ("Invalid oversample" )
78
84
79
- data = self ._read (_BME680_REG_STATUS , 15 )
80
- print ([hex (i ) for i in data ])
81
- print ("" )
82
- self ._status = data [0 ] & 0x80
83
- gas_idx = data [0 ] & 0x0F
84
- meas_idx = data [1 ]
85
- #print("status 0x%x gas_idx %d meas_idx %d" % (status, gas_idx, meas_idx))
86
-
87
- self ._adc_pres = self ._read24 (data [2 :5 ]) / 16
88
- self ._adc_temp = self ._read24 (data [5 :8 ]) / 16
89
- self ._adc_hum = struct .unpack ('>H' , bytes (data [8 :10 ]))[0 ]
90
- self ._adc_gas = int (struct .unpack ('>H' , bytes (data [13 :15 ]))[0 ] / 64 )
91
- #print(self._adc_hum)
92
- #print(self._adc_gas)
93
- self ._status |= data [14 ] & 0x30 # VALID + STABILITY mask
85
+ @property
86
+ def temp_oversample (self ):
87
+ return _BME680_SAMPLERATES [self .osrs_p ]
88
+
89
+ @temp_oversample .setter
90
+ def temp_oversample (self , os ):
91
+ """Set the oversampling for temperature sensor"""
92
+ if os in _BME680_SAMPLERATES :
93
+ self .osrs_t = _BME680_SAMPLERATES .index (os )
94
+ else :
95
+ raise RuntimeError ("Invalid oversample" )
96
+
97
+ @property
98
+ def filter_size (self ):
99
+ return _BME680_FILTERSIZES [self .filter ]
100
+
101
+ @filter_size .setter
102
+ def filter_size (self , fs ):
103
+ """Set the filter size for the built in IIR filter"""
104
+ if fs in _BME680_FILTERSIZES :
105
+ self .filter = _BME680_FILTERSIZES (fs )
106
+ else :
107
+ raise RuntimeError ("Invalid size" )
94
108
95
109
@property
96
110
def temperature (self ):
97
- """Gets the compensated temperature in degrees celsius."""
98
- self .reading ()
111
+ """The compensated temperature in degrees celsius."""
112
+ self ._perform_reading ()
99
113
var1 = (self ._adc_temp / 8 ) - (self ._T1 * 2 )
100
114
var2 = (var1 * self ._T2 ) / 2048
101
115
var3 = ((var1 / 2 ) * (var1 / 2 )) / 4096
@@ -106,6 +120,7 @@ def temperature(self):
106
120
107
121
@property
108
122
def pressure (self ):
123
+ """The barometric pressure in hectoPascals"""
109
124
self .temperature
110
125
var1 = (self .t_fine / 2 ) - 64000
111
126
var2 = ((var1 / 4 ) * (var1 / 4 )) / 2048
@@ -127,6 +142,7 @@ def pressure(self):
127
142
128
143
@property
129
144
def humidity (self ):
145
+ """The relative humidity in RH %"""
130
146
self .temperature
131
147
temp_scaled = ((self .t_fine * 5 ) + 128 ) / 256
132
148
var1 = (self ._adc_hum - (self ._H1 * 16 )) - ((temp_scaled * self ._H3 ) / 200 )
@@ -137,15 +153,60 @@ def humidity(self):
137
153
var5 = ((var3 / 16384 ) * (var3 / 16384 )) / 1024
138
154
var6 = (var4 * var5 ) / 2
139
155
calc_hum = (((var3 + var6 ) / 1024 ) * 1000 ) / 4096
140
- print (calc_hum )
141
156
calc_hum /= 1000 # get back to RH
142
157
143
158
if calc_hum > 100 : calc_hum = 100
144
159
if calc_hum < 0 : calc_hum = 0
145
160
return calc_hum
146
161
162
+ @property
163
+ def altitude (self ):
164
+ """calculate the altitude based on the sea level pressure (seaLevelhPa) - which you must enter ahead of time)"""
165
+ p = self .pressure # in Si units for hPascal
166
+ return 44330 * (1.0 - math .pow (p / self .seaLevelhPa , 0.1903 ));
167
+
168
+ @property
169
+ def gas (self ):
170
+ """Return the gas resistance in ohms"""
171
+ var1 = ((1340 + (5 * self ._sw_err )) * (lookupTable1 [self ._gas_range ])) / 65536
172
+ var2 = ((self ._adc_gas * 32768 ) - 16777216 ) + var1
173
+ var3 = (lookupTable2 [self ._gas_range ] * var1 ) / 512
174
+ calc_gas_res = (var3 + (var2 / 2 )) / var2
175
+ return int (calc_gas_res )
176
+
177
+ def _perform_reading (self ):
178
+ """Perform a single-shot reading from the sensor and fill internal data structure for calculations"""
179
+
180
+ # set filter
181
+ self ._write (_BME680_REG_CONFIG , [self .filter << 2 ])
182
+ # turn on temp oversample & pressure oversample
183
+ self ._write (_BME680_REG_CTRL_MEAS , [(self .osrs_t << 5 )| (self .osrs_p << 2 )])
184
+ # turn on humidity oversample
185
+ self ._write (_BME680_REG_CTRL_HUM , [self .osrs_h ])
186
+ # gas measurements enabled
187
+ self ._write (_BME680_REG_CTRL_GAS , [_BME680_RUNGAS ])
188
+
189
+ v = self ._read (_BME680_REG_CTRL_MEAS , 1 )[0 ]
190
+ v = (v & 0xFC ) | 0x01 # enable single shot!
191
+ self ._write (_BME680_REG_CTRL_MEAS , [v ])
192
+ time .sleep (0.5 )
193
+ data = self ._read (_BME680_REG_STATUS , 15 )
194
+ self ._status = data [0 ] & 0x80
195
+ gas_idx = data [0 ] & 0x0F
196
+ meas_idx = data [1 ]
197
+ #print("status 0x%x gas_idx %d meas_idx %d" % (status, gas_idx, meas_idx))
198
+
199
+ self ._adc_pres = self ._read24 (data [2 :5 ]) / 16
200
+ self ._adc_temp = self ._read24 (data [5 :8 ]) / 16
201
+ self ._adc_hum = struct .unpack ('>H' , bytes (data [8 :10 ]))[0 ]
202
+ self ._adc_gas = int (struct .unpack ('>H' , bytes (data [13 :15 ]))[0 ] / 64 )
203
+ self ._gas_range = data [14 ] & 0x0F
204
+ #print(self._adc_hum)
205
+ #print(self._adc_gas)
206
+ self ._status |= data [14 ] & 0x30 # VALID + STABILITY mask
207
+
147
208
def _read24 (self , arr ):
148
- """Read an unsigned 24-bit value as a floating point and return it."""
209
+ """Parse an unsigned 24-bit value as a floating point and return it."""
149
210
ret = 0.0
150
211
#print([hex(i) for i in arr])
151
212
for b in arr :
@@ -167,9 +228,9 @@ def _read_coefficients(self):
167
228
self ._H2 = h2m * 16 + (self ._H1 % 16 )
168
229
self ._H1 /= 16
169
230
170
- self ._HEATRANGE = (self ._read (0x02 , 1 )[0 ] & 0x30 ) / 16
171
- self ._HEATVAL = self ._read (0x00 , 1 )[0 ]
172
- self ._SWERR = (self ._read (0x04 , 1 )[0 ] & 0xF0 ) / 16
231
+ self ._heat_range = (self ._read (0x02 , 1 )[0 ] & 0x30 ) / 16
232
+ self ._heat_val = self ._read (0x00 , 1 )[0 ]
233
+ self ._sw_err = (self ._read (0x04 , 1 )[0 ] & 0xF0 ) / 16
173
234
174
235
#print("T1-3: %d %d %d" % (self._T1, self._T2, self._T3))
175
236
#print("P1-3: %d %d %d" % (self._P1, self._P2, self._P3))
@@ -186,21 +247,27 @@ def _read_byte(self, register):
186
247
return self ._read (register , 1 )[0 ]
187
248
188
249
class Adafruit_BME680_I2C (Adafruit_BME680 ):
189
- def __init__ (self , i2c , address = _BME680_ADDRESS ):
250
+ def __init__ (self , i2c , address = _BME680_ADDRESS , debug = False ):
251
+ """Initialize the I2C device at the 'address' given"""
190
252
import adafruit_bus_device .i2c_device as i2c_device
191
253
self ._i2c = i2c_device .I2CDevice (i2c , address )
254
+ self ._debug = debug
192
255
super ().__init__ ()
193
256
194
257
def _read (self , register , length ):
258
+ """Returns an array of 'length' bytes from the 'register'"""
195
259
with self ._i2c as i2c :
196
260
i2c .write (bytes ([register & 0xFF ]))
197
261
result = bytearray (length )
198
262
i2c .read_into (result )
199
- print ("$%02X => %s" % (register , [hex (i ) for i in result ]))
263
+ if self ._debug :
264
+ print ("\t $%02X => %s" % (register , [hex (i ) for i in result ]))
200
265
return result
201
266
202
267
def _write (self , register , values ):
268
+ """Writes an array of 'length' bytes to the 'register'"""
203
269
with self ._i2c as i2c :
204
270
values = [(v & 0xFF ) for v in [register ]+ values ]
205
271
i2c .write (bytes (values ))
206
- print ("$%02X <= %s" % (values [0 ], [hex (i ) for i in values [1 :]]))
272
+ if self ._debug :
273
+ print ("\t $%02X <= %s" % (values [0 ], [hex (i ) for i in values [1 :]]))
0 commit comments