Adafruit_CircuitPython_BME680/adafruit_bme680.py
2017-10-28 23:23:50 -04:00

206 lines
6.9 KiB
Python

import time, math
from micropython import const
try:
import struct
except ImportError:
import ustruct as struct
# I2C ADDRESS/BITS/SETTINGS
# -----------------------------------------------------------------------
_BME680_ADDRESS = const(0x77)
_BME680_CHIPID = const(0x61)
_BME680_REG_CHIPID = const(0xD0)
_BME680_BME680_COEFF_ADDR1 = const(0x89)
_BME680_BME680_COEFF_ADDR2 = const(0xE1)
_BME680_BME680_RES_WAIT_0 = const(0x5A)
_BME680_REG_SOFTRESET = const(0xE0)
_BME680_REG_CTRL_GAS = const(0x71)
_BME680_REG_CTRL_HUM = const(0x72)
_BME280_REG_STATUS = const(0xF3)
_BME680_REG_CTRL_MEAS = const(0x74)
_BME680_REG_CONFIG = const(0x75)
_BME680_REG_STATUS = const(0x1D)
_BME680_REG_PDATA = const(0x1F)
_BME680_REG_TDATA = const(0x22)
_BME680_REG_HDATA = const(0x25)
_BME280_PRESSURE_MIN_HPA = const(300)
_BME280_PRESSURE_MAX_HPA = const(1100)
_BME280_HUMIDITY_MIN = const(0)
_BME280_HUMIDITY_MAX = const(100)
_BME680_SAMPLERATES = (0, 1, 2, 4, 8, 16)
_BME680_RUNGAS = const(0x10)
class Adafruit_BME680:
def __init__(self):
"""Check the BME680 was found, read the coefficients and enable the sensor for continuous reads"""
self._write(_BME680_REG_SOFTRESET, [0xB6])
time.sleep(0.5)
# Check device ID.
id = self._read_byte(_BME680_REG_CHIPID)
if _BME680_CHIPID != id:
raise RuntimeError('Failed to find BME680! Chip ID 0x%x' % id)
self._read_coefficients()
# set up heater
self._write(_BME680_BME680_RES_WAIT_0, [0x73, 0x64, 0x65])
self.seaLevelhPa = 1013.25
#self.pressure_oversample = 16
#self.temp_oversample = 2
#self.hum_oversample = 1
self.osrs_h = 2
self.osrs_t = 4
self.osrs_p = 3
self.filter = 2
# set filter
self._write(_BME680_REG_CONFIG, [self.filter << 2])
# turn on temp oversample & pressure oversample
self._write(_BME680_REG_CTRL_MEAS, [(self.osrs_t << 5)|(self.osrs_p << 2)])
# turn on humidity oversample
self._write(_BME680_REG_CTRL_HUM, [self.osrs_h])
# gas measurements enabled
self._write(_BME680_REG_CTRL_GAS, [_BME680_RUNGAS])
def reading(self):
print("\n\nReading data");
v = self._read(_BME680_REG_CTRL_MEAS, 1)[0]
v = (v & 0xFC) | 0x01 # enable single shot!
self._write(_BME680_REG_CTRL_MEAS, [v])
time.sleep(0.5)
data = self._read(_BME680_REG_STATUS, 15)
print([hex(i) for i in data])
print("")
self._status = data[0] & 0x80
gas_idx = data[0] & 0x0F
meas_idx = data[1]
#print("status 0x%x gas_idx %d meas_idx %d" % (status, gas_idx, meas_idx))
self._adc_pres = self._read24(data[2:5]) / 16
self._adc_temp = self._read24(data[5:8]) / 16
self._adc_hum = struct.unpack('>H', bytes(data[8:10]))[0]
self._adc_gas = int(struct.unpack('>H', bytes(data[13:15]))[0] / 64)
#print(self._adc_hum)
#print(self._adc_gas)
self._status |= data[14] & 0x30 # VALID + STABILITY mask
@property
def temperature(self):
"""Gets the compensated temperature in degrees celsius."""
self.reading()
var1 = (self._adc_temp / 8) - (self._T1 * 2)
var2 = (var1 * self._T2) / 2048
var3 = ((var1 / 2) * (var1 / 2)) / 4096
var3 = (var3 * self._T3 * 16) / 16384
self.t_fine = int(var2 + var3)
calc_temp = (((self.t_fine * 5) + 128) / 256)
return calc_temp / 100
@property
def pressure(self):
self.temperature
var1 = (self.t_fine / 2) - 64000
var2 = ((var1 / 4) * (var1 / 4)) / 2048
var2 = (var2 * self._P6) / 4
var2 = var2 + (var1 * self._P5 * 2)
var2 = (var2 / 4) + (self._P4 * 65536)
var1 = ((var1 / 4) * (var1 / 4)) / 8192
var1 = ((var1 * self._P3 * 32) / 8) + ((self._P2 * var1) / 2)
var1 = var1 / 262144
var1 = ((32768 + var1) * self._P1) / 32768
calc_pres = 1048576 - self._adc_pres
calc_pres = (calc_pres - (var2 / 4096)) * 3125
calc_pres = (calc_pres / var1) * 2
var1 = (self._P9 * (((calc_pres / 8) * (calc_pres / 8)) / 8192)) / 4096
var2 = ((calc_pres / 4) * self._P8) / 8192
var3 = ((calc_pres / 256) * (calc_pres / 256) * (calc_pres / 256) * self._P10) / 131072
calc_pres += ((var1 + var2 + var3 + (self._P7 * 128)) / 16)
return calc_pres/100
@property
def humidity(self):
self.temperature
temp_scaled = ((self.t_fine * 5) + 128) / 256
var1 = (self._adc_hum - (self._H1 * 16)) - ((temp_scaled * self._H3) / 200)
var2 = (self._H2 * (((temp_scaled * self._H4) / 100) + (((temp_scaled * ((temp_scaled * self._H5) / 100)) / 64) / 100) + 16384)) / 1024
var3 = var1 * var2
var4 = self._H6 * 128
var4 = (var4 + ((temp_scaled * self._H7) / 100)) / 16
var5 = ((var3 / 16384) * (var3 / 16384)) / 1024
var6 = (var4 * var5) / 2
calc_hum = (((var3 + var6) / 1024) * 1000) / 4096
print(calc_hum)
calc_hum /= 1000 # get back to RH
if calc_hum > 100: calc_hum = 100
if calc_hum < 0: calc_hum = 0
return calc_hum
def _read24(self, arr):
"""Read an unsigned 24-bit value as a floating point and return it."""
ret = 0.0
#print([hex(i) for i in arr])
for b in arr:
ret *= 256.0
ret += float(b & 0xFF)
return ret
def _read_coefficients(self):
"""Read & save the calibration coefficients"""
coeff = self._read(_BME680_BME680_COEFF_ADDR1, 25)
coeff += self._read(_BME680_BME680_COEFF_ADDR2, 16)
coeff = list(struct.unpack('<hbBHhbBhhbbHhhBBBHbbbBbHhbb', bytes(coeff[1:])))
#print("\n\n",coeff)
coeff = [float(i) for i in coeff]
self._T2,self._T3, skip, self._P1,self._P2,self._P3, skip, self._P4,self._P5,self._P7,self._P6, skip,self._P8,self._P9,self._P10, skip, h2m, self._H1,self._H3,self._H4,self._H5,self._H6,self._H7,self._T1,self._G2,self._G1,self._G3 = coeff
# flip around H1 & H2
self._H2 = h2m * 16 + (self._H1 % 16)
self._H1 /= 16
self._HEATRANGE = (self._read(0x02, 1)[0] & 0x30) / 16
self._HEATVAL = self._read(0x00, 1)[0]
self._SWERR = (self._read(0x04, 1)[0] & 0xF0) / 16
#print("T1-3: %d %d %d" % (self._T1, self._T2, self._T3))
#print("P1-3: %d %d %d" % (self._P1, self._P2, self._P3))
#print("P4-6: %d %d %d" % (self._P4, self._P5, self._P6))
#print("P7-9: %d %d %d" % (self._P7, self._P8, self._P9))
#print("P10: %d" % self._P10)
#print("H1-3: %d %d %d" % (self._H1, self._H2, self._H3))
#print("H4-7: %d %d %d %d" % (self._H4, self._H5, self._H6, self._H7))
#print("G1-3: %d %d %d" % (self._G1, self._G2, self._G3))
#print("HR %d HV %d SWERR %d" % (self._HEATRANGE, self._HEATVAL, self._SWERR))
def _read_byte(self, register):
"""Read a byte register value and return it"""
return self._read(register, 1)[0]
class Adafruit_BME680_I2C(Adafruit_BME680):
def __init__(self, i2c, address=_BME680_ADDRESS):
import adafruit_bus_device.i2c_device as i2c_device
self._i2c = i2c_device.I2CDevice(i2c, address)
super().__init__()
def _read(self, register, length):
with self._i2c as i2c:
i2c.write(bytes([register & 0xFF]))
result = bytearray(length)
i2c.read_into(result)
print("$%02X => %s" % (register, [hex(i) for i in result]))
return result
def _write(self, register, values):
with self._i2c as i2c:
values = [(v & 0xFF) for v in [register]+values]
i2c.write(bytes(values))
print("$%02X <= %s" % (values[0], [hex(i) for i in values[1:]]))