Driver for BME280 humidity/pressure/temperature sensor

175 views
Skip to first unread message

mre...@asvachin.eu

unread,
Apr 27, 2016, 12:14:39 PM4/27/16
to WebIOPi
from webiopi.utils.types import toint, signInteger
from webiopi.devices.i2c import I2C
from webiopi.devices.sensor import Temperature, Pressure, Humidity
from webiopi.utils import logger

class BME280(I2C, Temperature, Pressure, Humidity):
   
def __init__(self, altitude=0, external=None, oversampling=16, filter=0, slave=0x76):
        I2C
.__init__(self, toint(slave))
       
Pressure.__init__(self, altitude, external)

       
self.t1 = self.readUnsigned(0x88, 2)
       
self.t2 = self.readSigned(0x8A, 2)
       
self.t3 = self.readSigned(0x8C, 2)

       
self.p1 = self.readUnsigned(0x8E, 2)
       
self.p2 = self.readSigned(0x90, 2)
       
self.p3 = self.readSigned(0x92, 2)
       
self.p4 = self.readSigned(0x94, 2)
       
self.p5 = self.readSigned(0x96, 2)
       
self.p6 = self.readSigned(0x98, 2)
       
self.p7 = self.readSigned(0x9A, 2)
       
self.p8 = self.readSigned(0x9C, 2)
       
self.p9 = self.readSigned(0x9E, 2)

       
self.h1 = self.readUnsigned(0xA1, 1)
       
self.h2 = self.readSigned(0xE1, 2)
       
self.h3 = self.readUnsigned(0xE3, 1)
       
self.h4 = (self.readUnsigned(0xE4, 1) << 4) | (self.readUnsigned(0xE5, 1) & 0x0F)
       
self.h5 = (self.readSigned(0xE6, 1) << 4) | (self.readSigned(0xE5, 1) >> 4)
       
self.h6 = self.readSigned(0xE7, 1)

        oversamplingBits
= toint(oversampling).bit_length()
       
self.writeRegister(0xF2, oversamplingBits) # Humidity oversampling. Must be set before temp/press oversampling (see datasheet 5.4.3).
       
self.writeRegister(0xF4, (oversamplingBits << 5) | (oversamplingBits << 2) | 0x03) # Pressure, temperature oversampling, sensor normal mode.

        tStandbyBits
= 0 # Default to 0.5ms t_standby
        spiBits
= 0 # No SPI of course.
        filterBits
= toint(filter) >> 1
       
self.writeRegister(0xF5, (tStandbyBits << 5) | (filterBits << 2) | spiBits)

   
def __str__(self):
       
return "BME280"

   
def __family__(self):
       
return [Temperature.__family__(self), Pressure.__family__(self), Humidity.__family__(self)]

   
def readUnsigned(self, address, numBytes, byteOrder='little'):
        d
= self.readRegisters(address, numBytes)
        x
= 0
       
if byteOrder == 'big':
           
for i in range(0, numBytes):
                x
|= d[i] << (8 * (numBytes - (i + 1)))
       
else:
           
for i in range(0, numBytes):
                x
|= d[i] << (8 * i)
       
return x

   
def readSigned(self, address, numBytes, byteOrder = 'little'):
        d
= self.readUnsigned(address, numBytes, byteOrder)
       
return signInteger(d, numBytes * 8)

   
# Reading all ADC registers at once ensures consistency (see datasheet section 4).
   
def readAdc(self):
        raw
= self.readUnsigned(0xF7, 8, 'big')
        adc_P
= raw >> 44
        adc_T
= ((raw >> 16) & 0xFFFFFF) >> 4
        adc_H
= raw & 0xFFFF
       
return (adc_T, adc_P, adc_H)

   
def compensateTfine(self, adc_T):
       
#Taken straight out of the datasheet. Could be rewritten to be clearer.
        var1
= (((adc_T >> 3) - (self.t1 << 1)) * self.t2) >> 11;
        var2
= (((((adc_T >> 4) - self.t1) * ((adc_T >> 4) - self.t1)) >> 12) * self.t3) >> 14;

       
return var1 + var2

   
def compensateT(self, t_fine):
       
#Taken straight out of the datasheet. Could be rewritten to be clearer.
       
return float((t_fine * 5 + 128) >> 8) / 100.0

   
def compensateP(self, t_fine, adc_P):
       
#Taken straight out of the datasheet. Could be rewritten to be clearer.
        var1
= t_fine - 128000
        var2
= var1 * var1 * self.p6
        var2
= var2 + ((var1 * self.p5) << 17)
        var2
= var2 + (self.p4 << 35)
        var1
= ((var1 * var1 * self.p3) >> 8) + ((var1 * self.p2) << 12)
        var1
= ((1 << 47) + var1) * self.p1 >> 33

       
if var1 == 0:
           
return 0

        p
= 1048576 - adc_P
        p
= (((p << 31) - var2) * 3125) // var1
        var1
= (self.p9 * (p >> 13) * (p >> 13)) >> 25
        var2
= (self.p8 * p) >> 19
        p
= ((p + var1 + var2) >> 8) + (self.p7 << 4)

       
return float(p) / 256.0

   
def compensateH(self, t_fine, adc_H):
       
#Taken straight out of the datasheet. Could be rewritten to be clearer.
        v_x1_u32r
= t_fine - 76800
        v_x1_u32r
= ((((adc_H << 14) - (self.h4 << 20) - (self.h5 * v_x1_u32r)) + 16384) >> 15) * (((((((v_x1_u32r * self.h6) >> 10) * (((v_x1_u32r * self.h3) >> 11) + 32768)) >> 10) + 2097152) * self.h2 + 8192) >> 14)
        v_x1_u32r
= v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * self.h1) >> 4)
        v_x1_u32r
= max(v_x1_u32r, 0)
        v_x1_u32r
= min(v_x1_u32r, 419430400)

       
return float(v_x1_u32r >> 12) / 1024.0

   
def __getAll__(self):
        raw
= self.readUnsigned(0xF7, 8, 'big')
        adc_P
= raw >> 44
        adc_T
= ((raw >> 16) & 0xFFFFFF) >> 4
        adc_H
= raw & 0xFFFF
        t_fine
= self.compensateTfine(adc_T)
        T
= self.compensateT(t_fine)
        P
= self.compensateP(t_fine, adc_P)
        H
= self.compensateH(t_fine, adc_H)
       
return (T, P, H)

   
def __getCelsius__(self):
        adc
= self.readAdc()
        t_fine
= self.compensateTfine(adc.T)
       
return self.compensateT(t_fine)

   
def __getKelvin__(self):
       
return self.Celsius2Kelvin()

   
def __getFahrenheit__(self):
       
return self.Celsius2Fahrenheit()

   
def __getPascal__(self):
        adc
= self.readAdc()
        t_fine
= self.compensateTfine(adc.T)
       
return self.compensateP(t_fine, adc.P)

   
def __getHumidity__(self):
        adc
= self.readAdc()
        t_fine
= self.compensateTfine(adc.T)
       
return self.compensateH(t_fine, adc.H) / 100.0
Reply all
Reply to author
Forward
0 new messages