BOSCH temperature / humidity / barometric pressure sensor BME280 temperature / humidity / barometric pressure data is acquired by I2C communication.
Use the smbus module to control I2C in Python on the Raspberry Pi.
If the smbus module is not installed, install it with the following command.
pip install smbus
Although bme280.py is imported and used as a package, temperature / humidity / barometric pressure data can be obtained by itself for testing. bme280.py (compressed with ZIP)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
BM280 script.
=============
Temperature: -40 to +85 [degC]
Dumidity: 0 ot 100[%]
barometer: 300 to 1100[hPa]
"""
i2c_enable = False
try:
    import smbus
    i2c_enable = True
except:
    i2c_enable = False
import random
import time
class BME280():
    def __init__(self):
        self.bus_number  = 1
        self.i2c_address = 0x76
        self.i2c_enable = i2c_enable
        if self.i2c_enable:
            self.bus = smbus.SMBus(self.bus_number)
        else:
            self.bus = self.SMBus(self.bus_number)
            return
        self.digT = []
        self.digP = []
        self.digH = []
        self.t_fine = 0.0
        self.setup()
        self.get_calib_param()
    @property
    def barometer(self):
        result = float(f'{random.uniform(1020.0, 1040.0):.2f}')
        if self.i2c_enable == False:
            return result
        # For I2C error at pushed power switch.
        try:
            pres_raw = self._read_bus_data('barometer')
        except:
            return result
        pressure = 0.0
        
        v1 = (self.t_fine / 2.0) - 64000.0
        v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * self.digP[5]
        v2 = v2 + ((v1 * self.digP[4]) * 2.0)
        v2 = (v2 / 4.0) + (self.digP[3] * 65536.0)
        v1 = (((self.digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((self.digP[1] * v1) / 2.0)) / 262144
        v1 = ((32768 + v1) * self.digP[0]) / 32768
        
        if v1 == 0:
            return 0
        pressure = ((1048576 - pres_raw) - (v2 / 4096)) * 3125
        if pressure < 0x80000000:
            pressure = (pressure * 2.0) / v1
        else:
            pressure = (pressure / v1) * 2
        v1 = (self.digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
        v2 = ((pressure / 4.0) * self.digP[7]) / 8192.0
        pressure = pressure + ((v1 + v2 + self.digP[6]) / 16.0)  
    
        #print('pressure : %7.2f hPa' % (pressure/100))
        result = float(f'{pressure/100:7.2f}')
        return result
    def get_calib_param(self):
        if self.i2c_enable == False:
            return
        calib = []
        for i in range (0x88,0x88+24):
            calib.append(self.bus.read_byte_data(self.i2c_address,i))
        calib.append(self.bus.read_byte_data(self.i2c_address,0xA1))
        for i in range (0xE1,0xE1+7):
            calib.append(self.bus.read_byte_data(self.i2c_address,i))
        self.digT.append((calib[1] << 8) | calib[0])
        self.digT.append((calib[3] << 8) | calib[2])
        self.digT.append((calib[5] << 8) | calib[4])
        self.digP.append((calib[7] << 8) | calib[6])
        self.digP.append((calib[9] << 8) | calib[8])
        self.digP.append((calib[11]<< 8) | calib[10])
        self.digP.append((calib[13]<< 8) | calib[12])
        self.digP.append((calib[15]<< 8) | calib[14])
        self.digP.append((calib[17]<< 8) | calib[16])
        self.digP.append((calib[19]<< 8) | calib[18])
        self.digP.append((calib[21]<< 8) | calib[20])
        self.digP.append((calib[23]<< 8) | calib[22])
        self.digH.append( calib[24] )
        self.digH.append((calib[26]<< 8) | calib[25])
        self.digH.append( calib[27] )
        self.digH.append((calib[28]<< 4) | (0x0F & calib[29]))
        self.digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
        self.digH.append( calib[31] )
        for i in range(1,2):
            if self.digT[i] & 0x8000:
                self.digT[i] = (-self.digT[i] ^ 0xFFFF) + 1
        for i in range(1,8):
            if self.digP[i] & 0x8000:
                self.digP[i] = (-self.digP[i] ^ 0xFFFF) + 1
        for i in range(0,6):
            if self.digH[i] & 0x8000:
                self.digH[i] = (-self.digH[i] ^ 0xFFFF) + 1 
    @property
    def humidity(self):
        result = float(f'{random.uniform(10.0, 60.0):.2f}')
        if self.i2c_enable == False:
            return result
        # For I2C error at pushed power switch.
        try:
            hum_raw = self._read_bus_data('humidity')
        except:
            return result
        var_h = self.t_fine - 76800.0
        if var_h != 0:
            var_h = (hum_raw - (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)))
        else:
            return 0
        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
        #print('hum : %6.2f %' % (var_h))
        result = float(f'{var_h:.2f}')
        return result
    def _read_bus_data(self, data_type):
        """
        data_tpye: 'temperature' or 'hidumity' or 'barometer'
        """
        data = []
        for i in range (0xF7, 0xF7+8):
            data.append(self.bus.read_byte_data(self.i2c_address,i))
        if data_type == 'barometer':
            return (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
        elif data_type == 'humidity':
            return (data[6] << 8) | data[7]
        elif data_type == 'temperature':
            return (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
        else:
            return [0]
    def read_data(self):
        t = self.temperature
        h = self.humidity
        p = self.barometer
        return [t, h, p]
    def setup(self, ):
        osrs_t = 1            #Temperature oversampling x 1
        osrs_p = 1            #Pressure oversampling x 1
        osrs_h = 1            #Humidity oversampling x 1
        mode   = 3            #Normal mode
        t_sb   = 5            #Tstandby 1000ms
        filter = 0            #Filter off
        spi3w_en = 0          #3-wire SPI Disable
    
        ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
        config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
        ctrl_hum_reg  = osrs_h
    
        self.write_reg(0xF2,ctrl_hum_reg)
        self.write_reg(0xF4,ctrl_meas_reg)
        self.write_reg(0xF5,config_reg)
    # Dummy SMBus.
    class SMBus():
        def __init__(self, *args, **kwargs):
            pass
    @property
    def temperature(self):
        result = float(f'{random.uniform(20.0, 40.0):.2f}')
        if self.i2c_enable == False:
            return result
        # For I2C error at pushed power switch.
        try:
            temp_raw = self._read_bus_data('temperature')
        except:
            return result
        v1 = (temp_raw / 16384.0 - self.digT[0] / 1024.0) * self.digT[1]
        v2 = (temp_raw / 131072.0 - self.digT[0] / 8192.0) * (temp_raw / 131072.0 - self.digT[0] / 8192.0) * self.digT[2]
        self.t_fine = v1 + v2
        temperature = self.t_fine / 5120.0
        result = float(f'{temperature:.2f}')
        return result
    def write_reg(self, reg_address, data):
        if self.i2c_enable == False:
            return
        try:
            self.bus.write_byte_data(self.i2c_address, reg_address, data)
        except:
            self.i2c_enable = False
            self.bus = self.SMBus(self.bus_number)
if __name__ == '__main__':
    em = BME280()
    while True:
        print(em.read_data())
        #print(em.barometer)
        #print(em.humidity)
        #print(em.temperature)
        time.sleep(0.5)
YouTube: Thermal Camera (Thermo AI Device TiD) Python Edition web: Thermo AI device TiD Python BME280 (URL is subject to change)
Recommended Posts