mirror of
https://github.com/cmur2/python-bme280.git
synced 2024-12-21 16:54:22 +01:00
Fiat lux
This commit is contained in:
parent
1750cff8b3
commit
d6d215d1f9
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.pyc
|
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
# python-bme280
|
||||||
|
|
||||||
|
A Python library for accessing the [BME280 combined humidity and pressure](https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf) from Bosch via `python-smbus` using the I2C interface.
|
||||||
|
|
||||||
|
Default settings are suitable for Raspberry Pi 2 and 3 and was successfully tested using a [breakout](https://github.com/watterott/BME280-Breakout).
|
||||||
|
|
||||||
|
I created this Python library in style of e.g. [python-veml6070](https://github.com/cmur2/python-veml6070) or [python-tsl2591](https://github.com/maxlklaxl/python-tsl2591) since I found only [python scripts](https://github.com/SWITCHSCIENCE/BME280) with limited functionality and minor bugs and the official driver from Bosch is only in C(++).
|
||||||
|
|
||||||
|
Although, it is heavily based on existing code from Bosch translated to Python and from [SWITCHSCIENCE](https://github.com/SWITCHSCIENCE/BME280).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Consult the data sheet and see [demo.py](demo.py) for clues how to use this library.
|
||||||
|
|
||||||
|
Not all functions of the chip are supported since I focused on the *forced mode* but data readout and parameter setting should work in *normal mode*, too. Please send pull requests for improvements and bug fixes!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Python files in this repository are released under the [MIT license](LICENSE) except those parts from other sources which are indicated where appropriate in the files.
|
4
bme280/__init__.py
Normal file
4
bme280/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
from bme280 import Bme280
|
||||||
|
#from bme280 import HO_SKIPPED, HO_1, HO_2, HO_4, HO_8, HO_16, PO_SKIPPED, PO_1, PO_2, PO_4, PO_8, PO_16, TO_SKIPPED, TO_1, TO_2, TO_4, TO_8, TO_16
|
||||||
|
#from bme280 import MODE_SLEEP, MODE_FORCED, MODE_NORMAL
|
259
bme280/bme280.py
Normal file
259
bme280/bme280.py
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
|
||||||
|
import smbus
|
||||||
|
import time
|
||||||
|
|
||||||
|
ADDR=0x76 # 7bit address of the BME280 for SDO=0, else 0x77
|
||||||
|
|
||||||
|
REGISTER_ID=0xD0
|
||||||
|
REGISTER_RESET=0xE0
|
||||||
|
REGISTER_CTRL_HUM=0xF2
|
||||||
|
REGISTER_STATUS=0xF3
|
||||||
|
REGISTER_CTRL_MEAS=0xF4
|
||||||
|
REGISTER_CONFIG=0xF5
|
||||||
|
|
||||||
|
HO_SKIPPED=0x00
|
||||||
|
HO_1=0x01
|
||||||
|
HO_2=0x02
|
||||||
|
HO_4=0x03
|
||||||
|
HO_8=0x04
|
||||||
|
HO_16=0x05 # and all higher
|
||||||
|
|
||||||
|
PO_SKIPPED=0x00
|
||||||
|
PO_1=0x01
|
||||||
|
PO_2=0x02
|
||||||
|
PO_4=0x03
|
||||||
|
PO_8=0x04
|
||||||
|
PO_16=0x05 # and all higher
|
||||||
|
|
||||||
|
TO_SKIPPED=0x00
|
||||||
|
TO_1=0x01
|
||||||
|
TO_2=0x02
|
||||||
|
TO_4=0x03
|
||||||
|
TO_8=0x04
|
||||||
|
TO_16=0x05 # and all higher
|
||||||
|
|
||||||
|
MODE_SLEEP=0x00
|
||||||
|
MODE_FORCED=0x01 # and 0x02
|
||||||
|
MODE_NORMAL=0x03
|
||||||
|
|
||||||
|
TSTANDBY_0_5=0x00
|
||||||
|
TSTANDBY_62_5=0x01
|
||||||
|
TSTANDBY_125=0x02
|
||||||
|
TSTANDBY_250=0x03
|
||||||
|
TSTANDBY_500=0x04
|
||||||
|
TSTANDBY_1000=0x05
|
||||||
|
TSTANDBY_10=0x06
|
||||||
|
TSTANDBY_20=0x07
|
||||||
|
|
||||||
|
FILTER_OFF=0x00
|
||||||
|
FILTER_2=0x01
|
||||||
|
FILTER_4=0x02
|
||||||
|
FILTER_8=0x03
|
||||||
|
FILTER_16=0x04 # and all higher
|
||||||
|
|
||||||
|
class Bme280:
|
||||||
|
|
||||||
|
def __init__(self, i2c_bus=1, sensor_address=ADDR):
|
||||||
|
self.bus = smbus.SMBus(i2c_bus)
|
||||||
|
self.sensor_address = sensor_address
|
||||||
|
self.ho = HO_1
|
||||||
|
self.po = PO_1
|
||||||
|
self.to = TO_1
|
||||||
|
self.mode = MODE_SLEEP
|
||||||
|
self.tstandy = TSTANDBY_1000
|
||||||
|
self.filter = FILTER_OFF
|
||||||
|
|
||||||
|
self.read_calibration_parameters()
|
||||||
|
|
||||||
|
# initialize once
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_HUM, self.get_reg_ctrl_hum())
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_MEAS, self.get_reg_ctrl_meas())
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CONFIG, self.get_reg_config())
|
||||||
|
|
||||||
|
def get_chip_id(self):
|
||||||
|
return self.bus.read_byte_data(self.sensor_address, REGISTER_ID)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_RESET, 0xB6)
|
||||||
|
|
||||||
|
def is_status_measuring(self):
|
||||||
|
return (self.bus.read_byte_data(self.sensor_address, REGISTER_STATUS) & 0x08) != 0x00
|
||||||
|
|
||||||
|
def is_status_image_register_updating(self):
|
||||||
|
return (self.bus.read_byte_data(self.sensor_address, REGISTER_STATUS) & 0x01) != 0x00
|
||||||
|
|
||||||
|
def set_humidity_oversampling(self, ho):
|
||||||
|
self.ho = ho
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_HUM, self.get_reg_ctrl_hum())
|
||||||
|
# flush (unchanged) CTRL_MEAS to make CTRL_HUM effective!
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_MEAS, self.get_reg_ctrl_meas())
|
||||||
|
|
||||||
|
def get_humidity_oversampling(self):
|
||||||
|
return self.ho
|
||||||
|
|
||||||
|
def set_temperature_oversampling(self, to):
|
||||||
|
self.to = to
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_MEAS, self.get_reg_ctrl_meas())
|
||||||
|
|
||||||
|
def get_temperature_oversampling(self):
|
||||||
|
return self.to
|
||||||
|
|
||||||
|
def set_pressure_oversampling(self, po):
|
||||||
|
self.po = po
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_MEAS, self.get_reg_ctrl_meas())
|
||||||
|
|
||||||
|
def get_pressure_oversampling(self):
|
||||||
|
return self.po
|
||||||
|
|
||||||
|
def set_mode(self, mode):
|
||||||
|
self.mode = mode
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CTRL_MEAS, self.get_reg_ctrl_meas())
|
||||||
|
|
||||||
|
def get_mode(self):
|
||||||
|
return self.mode
|
||||||
|
|
||||||
|
def set_tstandy(self, tstandy):
|
||||||
|
self.tstandy = tstandy
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CONFIG, self.get_reg_config())
|
||||||
|
|
||||||
|
def get_tstandy(self):
|
||||||
|
return self.tstandy
|
||||||
|
|
||||||
|
def set_filter(self, fil):
|
||||||
|
self.filter = fil
|
||||||
|
self.bus.write_byte_data(self.sensor_address, REGISTER_CONFIG, self.get_reg_config())
|
||||||
|
|
||||||
|
def get_filter(self):
|
||||||
|
return self.filter
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
if self.get_mode() == MODE_FORCED:
|
||||||
|
t_measure_max = 1.25 + (2.3 * self.to) + (2.3 * self.po + 0.575) + (2.3 * self.ho + 0.575)
|
||||||
|
time.sleep(t_measure_max/1000.0)
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for i in range(0xF7, 0xF7+8):
|
||||||
|
data.append(self.bus.read_byte_data(self.sensor_address, i))
|
||||||
|
|
||||||
|
pressure_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
|
||||||
|
temperature_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
|
||||||
|
humidity_raw = (data[6] << 8) | data[7]
|
||||||
|
t_fine = self.calc_t_fine(temperature_raw)
|
||||||
|
t = self.calc_compensated_temperature(t_fine)
|
||||||
|
p = self.calc_compensated_pressure(t_fine, pressure_raw)
|
||||||
|
h = self.calc_compensated_humidity(t_fine, humidity_raw)
|
||||||
|
|
||||||
|
if self.get_mode() == MODE_FORCED:
|
||||||
|
# chip returns to sleep after data readout automatically, mirror it
|
||||||
|
self.mode = MODE_SLEEP
|
||||||
|
|
||||||
|
return (t, p, h)
|
||||||
|
|
||||||
|
def get_reg_ctrl_hum(self):
|
||||||
|
"""
|
||||||
|
returns the bit pattern for CTRL_HUM corresponding to the desired state of this class
|
||||||
|
"""
|
||||||
|
return (self.ho & 0x07)
|
||||||
|
|
||||||
|
def get_reg_ctrl_meas(self):
|
||||||
|
"""
|
||||||
|
returns the bit pattern for CTRL_MEAS corresponding to the desired state of this class
|
||||||
|
"""
|
||||||
|
return ((self.to & 0x07) << 5) | ((self.po & 0x07) << 2) | self.mode
|
||||||
|
|
||||||
|
def get_reg_config(self):
|
||||||
|
"""
|
||||||
|
returns the bit pattern for CONFIG corresponding to the desired state of this class
|
||||||
|
"""
|
||||||
|
# SPI permanently disabled
|
||||||
|
return ((self.tstandy & 0x07) << 5) | ((self.filter & 0x07) << 2) | 0x00
|
||||||
|
|
||||||
|
# Bug-fixed code, originally from https://github.com/SWITCHSCIENCE/BME280
|
||||||
|
|
||||||
|
def read_calibration_parameters(self):
|
||||||
|
# read all calibration registers from chip NVM
|
||||||
|
calibration_regs = []
|
||||||
|
for i in range(0x88, 0x88+24):
|
||||||
|
calibration_regs.append(self.bus.read_byte_data(self.sensor_address, i))
|
||||||
|
calibration_regs.append(self.bus.read_byte_data(self.sensor_address, 0xA1))
|
||||||
|
for i in range(0xE1, 0xE1+7):
|
||||||
|
calibration_regs.append(self.bus.read_byte_data(self.sensor_address, i))
|
||||||
|
|
||||||
|
# reorganize 8-bit words into compensation words (without correct sign)
|
||||||
|
self.digT = []
|
||||||
|
self.digT.append((calibration_regs[1] << 8) | calibration_regs[0])
|
||||||
|
self.digT.append((calibration_regs[3] << 8) | calibration_regs[2])
|
||||||
|
self.digT.append((calibration_regs[5] << 8) | calibration_regs[4])
|
||||||
|
|
||||||
|
self.digP = []
|
||||||
|
self.digP.append((calibration_regs[7] << 8) | calibration_regs[6])
|
||||||
|
self.digP.append((calibration_regs[9] << 8) | calibration_regs[8])
|
||||||
|
self.digP.append((calibration_regs[11]<< 8) | calibration_regs[10])
|
||||||
|
self.digP.append((calibration_regs[13]<< 8) | calibration_regs[12])
|
||||||
|
self.digP.append((calibration_regs[15]<< 8) | calibration_regs[14])
|
||||||
|
self.digP.append((calibration_regs[17]<< 8) | calibration_regs[16])
|
||||||
|
self.digP.append((calibration_regs[19]<< 8) | calibration_regs[18])
|
||||||
|
self.digP.append((calibration_regs[21]<< 8) | calibration_regs[20])
|
||||||
|
self.digP.append((calibration_regs[23]<< 8) | calibration_regs[22])
|
||||||
|
|
||||||
|
self.digH = []
|
||||||
|
self.digH.append( calibration_regs[24] )
|
||||||
|
self.digH.append((calibration_regs[26]<< 8) | calibration_regs[25])
|
||||||
|
self.digH.append( calibration_regs[27] )
|
||||||
|
self.digH.append((calibration_regs[28]<< 4) | (0x0F & calibration_regs[29]))
|
||||||
|
self.digH.append((calibration_regs[30]<< 4) | ((calibration_regs[29] >> 4) & 0x0F))
|
||||||
|
self.digH.append( calibration_regs[31] )
|
||||||
|
|
||||||
|
# fix sign for integers in two's complement
|
||||||
|
for i in [1,2]:
|
||||||
|
if self.digT[i] & 0x8000:
|
||||||
|
self.digT[i] = (-self.digT[i] ^ 0xFFFF) + 1
|
||||||
|
|
||||||
|
for i in [1,2,3,4,5,6,7,8]:
|
||||||
|
if self.digP[i] & 0x8000:
|
||||||
|
self.digP[i] = (-self.digP[i] ^ 0xFFFF) + 1
|
||||||
|
|
||||||
|
for i in [1]:
|
||||||
|
if self.digH[i] & 0x8000:
|
||||||
|
self.digH[i] = (-self.digH[i] ^ 0xFFFF) + 1
|
||||||
|
for i in [3,4]:
|
||||||
|
if self.digH[i] & 0x0800:
|
||||||
|
self.digH[i] = (-self.digH[i] ^ 0x0FFF) + 1
|
||||||
|
for i in [5]:
|
||||||
|
if self.digH[i] & 0x0080:
|
||||||
|
self.digH[i] = (-self.digH[i] ^ 0x00FF) + 1
|
||||||
|
|
||||||
|
# Code from Bosch datasheet translated to Python
|
||||||
|
|
||||||
|
def calc_t_fine(self, adc_T):
|
||||||
|
var1 = (adc_T / 16384.0 - self.digT[0] / 1024.0) * self.digT[1]
|
||||||
|
var2 = (adc_T / 131072.0 - self.digT[0] / 8192.0) * (adc_T / 131072.0 - self.digT[0] / 8192.0) * self.digT[2]
|
||||||
|
return var1 + var2
|
||||||
|
|
||||||
|
def calc_compensated_temperature(self, t_fine):
|
||||||
|
return t_fine / 5120.0
|
||||||
|
|
||||||
|
def calc_compensated_pressure(self, t_fine, adc_P):
|
||||||
|
var1 = (t_fine/2.0) - 64000.0
|
||||||
|
var2 = var1 * var1 * (self.digP[5]) / 32768.0
|
||||||
|
var2 = var2 + var1 * (self.digP[4]) * 2.0
|
||||||
|
var2 = (var2/4.0)+(self.digP[3] * 65536.0)
|
||||||
|
var1 = (self.digP[2] * var1 * var1 / 524288.0 + self.digP[1] * var1) / 524288.0
|
||||||
|
var1 = (1.0 + var1 / 32768.0)*self.digP[0]
|
||||||
|
if var1 == 0.0:
|
||||||
|
return 0 # avoid exception caused by division by zero
|
||||||
|
p = 1048576.0 - adc_P
|
||||||
|
p = (p - (var2 / 4096.0)) * 6250.0 / var1
|
||||||
|
var1 = self.digP[8] * p * p / 2147483648.0
|
||||||
|
var2 = p * self.digP[7] / 32768.0
|
||||||
|
return p + (var1 + var2 + self.digP[6]) / 16.0
|
||||||
|
|
||||||
|
def calc_compensated_humidity(self, t_fine, adc_H):
|
||||||
|
var_H = t_fine - 76800.0
|
||||||
|
var_H = (adc_H - (self.digH[3] * 64.0 + self.digH[4] / 16384.0 * var_H)) * (self.digH[1] / 65536.0 * (1.0 + self.digH[5] / 67108864.0 * var_H * (1.0 + self.digH[2] / 67108864.0 * var_H)))
|
||||||
|
var_H = var_H * (1.0 - self.digH[0] * var_H / 524288.0)
|
||||||
|
if var_H > 100.0:
|
||||||
|
var_H = 100.0
|
||||||
|
elif var_H < 0.0:
|
||||||
|
var_H = 0.0
|
||||||
|
return var_H
|
10
demo.py
Normal file
10
demo.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import bme280
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
bme = bme280.Bme280()
|
||||||
|
bme.set_mode(bme280.MODE_FORCED)
|
||||||
|
t, p, h = bme.get_data()
|
||||||
|
print "Temperature: %f °C" % t
|
||||||
|
print "Pressure: %f P" % p
|
||||||
|
print "Humidity: %f %" % h
|
11
setup.py
Normal file
11
setup.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(name='bme280',
|
||||||
|
version='1.0',
|
||||||
|
url='http://github.com/cmur2/python-bme280',
|
||||||
|
author='Christian Nicolai',
|
||||||
|
description='A python library for accessing the BME280 combined humidity and pressure sensor from Bosch.',
|
||||||
|
packages=['bme280'],
|
||||||
|
long_description=open('README.md').read(),
|
||||||
|
requires=['python (>= 2.7)', 'smbus (>= 0.4.1)'],
|
||||||
|
install_requires=['smbus-cffi'])
|
Loading…
Reference in New Issue
Block a user