summaryrefslogtreecommitdiff
path: root/BME280.py
blob: af9afac4ce985ace68ec8f3f4f6c345e2569dcbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
import time
import smbus

to_s16 = lambda x: (x + 2**15) % 2**16 - 2**15
to_u16 = lambda x: x % 2**16

BME280_I2C_ADDR = 0x76
BME280_CHIP_ID = 0x60

power_mode = {
        "BME280_SLEEP_MODE"         : 0x00,
        "BME280_FORCED_MODE"        : 0x01,
        "BME280_NORMAL_MODE"        : 0x03,
        "BME280_SOFT_RESET_CODE"    : 0xB6,
}

regs = {
        "BME280_CHIP_ID_REG"            : 0xD0,
        "BME280_RST_REG"                : 0xE0,
        "BME280_STAT_REG"               : 0xF3,
        "BME280_CTRL_MEAS_REG"          : 0xF4,
        "BME280_CTRL_HUMIDITY_REG"      : 0xF2,
        "BME280_CONFIG_REG"             : 0xF5,
        "BME280_PRESSURE_MSB_REG"       : 0xF7,
        "BME280_PRESSURE_LSB_REG"       : 0xF8,
        "BME280_PRESSURE_XLSB_REG"      : 0xF9,
        "BME280_TEMPERATURE_MSB_REG"    : 0xFA,
        "BME280_TEMPERATURE_LSB_REG"    : 0xFB,
        "BME280_TEMPERATURE_XLSB_REG"   : 0xFC,
        "BME280_HUMIDITY_MSB_REG"       : 0xFD,
        "BME280_HUMIDITY_LSB_REG"       : 0xFE,
}

cali_regs = {
        "BME280_TEMPERATURE_CALIB_DIG_T1_LSB_REG"   : 0x88,
        "BME280_TEMPERATURE_CALIB_DIG_T1_MSB_REG"   : 0x89,
        "BME280_TEMPERATURE_CALIB_DIG_T2_LSB_REG"   : 0x8A,
        "BME280_TEMPERATURE_CALIB_DIG_T2_MSB_REG"   : 0x8B,
        "BME280_TEMPERATURE_CALIB_DIG_T3_LSB_REG"   : 0x8C,
        "BME280_TEMPERATURE_CALIB_DIG_T3_MSB_REG"   : 0x8D,
        "BME280_PRESSURE_CALIB_DIG_P1_LSB_REG"      : 0x8E,
        "BME280_PRESSURE_CALIB_DIG_P1_MSB_REG"      : 0x8F,
        "BME280_PRESSURE_CALIB_DIG_P2_LSB_REG"      : 0x90,
        "BME280_PRESSURE_CALIB_DIG_P2_MSB_REG"      : 0x91,
        "BME280_PRESSURE_CALIB_DIG_P3_LSB_REG"      : 0x92,
        "BME280_PRESSURE_CALIB_DIG_P3_MSB_REG"      : 0x93,
        "BME280_PRESSURE_CALIB_DIG_P4_LSB_REG"      : 0x94,
        "BME280_PRESSURE_CALIB_DIG_P4_MSB_REG"      : 0x95,
        "BME280_PRESSURE_CALIB_DIG_P5_LSB_REG"      : 0x96,
        "BME280_PRESSURE_CALIB_DIG_P5_MSB_REG"      : 0x97,
        "BME280_PRESSURE_CALIB_DIG_P6_LSB_REG"      : 0x98,
        "BME280_PRESSURE_CALIB_DIG_P6_MSB_REG"      : 0x99,
        "BME280_PRESSURE_CALIB_DIG_P7_LSB_REG"      : 0x9A,
        "BME280_PRESSURE_CALIB_DIG_P7_MSB_REG"      : 0x9B,
        "BME280_PRESSURE_CALIB_DIG_P8_LSB_REG"      : 0x9C,
        "BME280_PRESSURE_CALIB_DIG_P8_MSB_REG"      : 0x9D,
        "BME280_PRESSURE_CALIB_DIG_P9_LSB_REG"      : 0x9E,
        "BME280_PRESSURE_CALIB_DIG_P9_MSB_REG"      : 0x9F,
        "BME280_HUMIDITY_CALIB_DIG_H1_REG"          : 0xA1,
        "BME280_HUMIDITY_CALIB_DIG_H2_LSB_REG"      : 0xE1,
        "BME280_HUMIDITY_CALIB_DIG_H2_MSB_REG"      : 0xE2,
        "BME280_HUMIDITY_CALIB_DIG_H3_REG"          : 0xE3,
        "BME280_HUMIDITY_CALIB_DIG_H4_MSB_REG"      : 0xE4,
        "BME280_HUMIDITY_CALIB_DIG_H4_LSB_REG"      : 0xE5,
        "BME280_HUMIDITY_CALIB_DIG_H5_MSB_REG"      : 0xE6,
        "BME280_HUMIDITY_CALIB_DIG_H6_REG"          : 0xE7,
}

class BME280:
    param = {}

    def __init__(self, i2c_dev, p_mode, h_samp, p_samp, t_samp):
        self.bus = smbus.SMBus(int(i2c_dev.split('-')[-1]))
        self.chip_id = self.read(regs['BME280_CHIP_ID_REG'], 1)[0]
        if self.chip_id != BME280_CHIP_ID:
            print("Wrong Device ID [", hex(self.chip_id), "]")
            exit()

        self.config_reg = 0
        self.ctrl_meas_reg = 0
        self.ctrl_hum_reg = 0
        self.oversamp_humidity = 0
        self.oversamp_pressure = 0

        self.get_cal_param()
        self.set_power_mode(p_mode)
        self.set_oversamp_humidity(h_samp)
        self.set_oversamp_pressure(p_samp)
        self.set_oversamp_temperature(t_samp)
        time.sleep(0.01)
        self.t_fine = 0.0

    def read(self, reg, cnt):
        val = [0 for x in range(cnt)]
        for i in range(cnt):
            val[i] = self.bus.read_byte_data(BME280_I2C_ADDR, reg + i)
        return val

    def write(self, reg, val):
        for i in range(len(val)):
            self.bus.write_byte_data(BME280_I2C_ADDR, reg + i, val[i])

    def get_cal_param(self):
        params = self.read(cali_regs['BME280_TEMPERATURE_CALIB_DIG_T1_LSB_REG'], 26)
        self.param['dig_T1'] = to_u16((params[1] << 8) | params[0])
        self.param['dig_T2'] = to_s16((params[3] << 8) | params[2])
        self.param['dig_T3'] = to_s16((params[5] << 8) | params[4])
        self.param['dig_P1'] = to_u16((params[7] << 8) | params[6])
        self.param['dig_P2'] = to_s16((params[9] << 8) | params[8])
        self.param['dig_P3'] = to_s16((params[11] << 8) | params[10])
        self.param['dig_P4'] = to_s16((params[13] << 8) | params[12])
        self.param['dig_P5'] = to_s16((params[15] << 8) | params[14])
        self.param['dig_P6'] = to_s16((params[17] << 8) | params[16])
        self.param['dig_P7'] = to_s16((params[19] << 8) | params[18])
        self.param['dig_P8'] = to_s16((params[21] << 8) | params[20])
        self.param['dig_P9'] = to_s16((params[23] << 8) | params[22])
        self.param['dig_H1'] = params[25]

        params = self.read(cali_regs['BME280_HUMIDITY_CALIB_DIG_H2_LSB_REG'], 7)
        self.param['dig_H2'] = to_s16((params[1] << 8) | params[0])
        self.param['dig_H3'] = params[2]
        self.param['dig_H4'] = to_s16((params[3] << 4) | (params[4] & 0x0f))
        self.param['dig_H5'] = to_s16((params[5] << 4) | (params[4] >> 4))
        self.param['dig_H6'] = params[6]

    def get_power_mode(self):
        return self.read(regs['BME280_CTRL_MEAS_REG'], 1)[0] & 0x03

    def set_power_mode(self, p_mode):
        if p_mode <= power_mode['BME280_NORMAL_MODE']:
            v_mode = (self.ctrl_meas_reg & ~0x03) | (p_mode & 0x03)

            if self.get_power_mode() != power_mode['BME280_SLEEP_MODE']:
                self.soft_rst()
                time.sleep(0.003)
                self.write(regs['BME280_CONFIG_REG'], [self.config_reg])
                self.write(regs['BME280_CTRL_HUMIDITY_REG'], [self.ctrl_hum_reg])
                self.write(regs['BME280_CTRL_MEAS_REG'], [v_mode])
            else:
                self.write(regs['BME280_CTRL_MEAS_REG'], [v_mode])

            self.ctrl_meas_reg = self.read(regs['BME280_CTRL_MEAS_REG'], 1)[0]
            self.ctrl_hum_reg = self.read(regs['BME280_CTRL_HUMIDITY_REG'], 1)[0]
            self.config_reg = self.read(regs['BME280_CONFIG_REG'], 1)[0]
        else:
            print("Wrong Power Mode [", hex(p_mode), "]")
            exit()

    def soft_rst(self):
        self.write(regs['BME280_RST_REG'], [power_mode['BME280_SOFT_RESET_CODE']])

    def set_oversamp_humidity(self, sampling):
        v_data = (self.ctrl_hum_reg & ~0x07) | (sampling & 0x07)

        if self.get_power_mode() != power_mode['BME280_SLEEP_MODE']:
            self.soft_rst()
            time.sleep(0.003)
            self.write(regs['BME280_CONFIG_REG'], [self.config_reg])
            self.write(regs['BME280_CTRL_HUMIDITY_REG'], [v_data])
            self.write(regs['BME280_CTRL_MEAS_REG'], [self.ctrl_meas_reg])
        else:
            self.write(regs['BME280_CTRL_HUMIDITY_REG'], [v_data])
            self.write(regs['BME280_CTRL_MEAS_REG'], [self.ctrl_hum_reg])

        self.oversamp_humidity = sampling
        self.ctrl_meas_reg = self.read(regs['BME280_CTRL_MEAS_REG'], 1)[0]
        self.ctrl_hum_reg = self.read(regs['BME280_CTRL_HUMIDITY_REG'], 1)[0]
        self.config_reg = self.read(regs['BME280_CONFIG_REG'], 1)[0]

    def set_oversamp_pressure(self, sampling):
        v_data = (self.ctrl_meas_reg & ~0x1c) | ((sampling << 2) & 0x1c)

        if self.get_power_mode != power_mode['BME280_SLEEP_MODE']:
            self.soft_rst()
            time.sleep(0.003)
            self.write(regs['BME280_CONFIG_REG'], [self.config_reg])
            self.write(regs['BME280_CTRL_HUMIDITY_REG'], [self.ctrl_hum_reg])
            self.write(regs['BME280_CTRL_MEAS_REG'], [v_data])
        else:
            self.write(regs['BME280_CTRL_MEAS_REG'], [v_data])

        self.oversamp_pressure = sampling
        self.ctrl_meas_reg = self.read(regs['BME280_CTRL_MEAS_REG'], 1)[0]
        self.ctrl_hum_reg = self.read(regs['BME280_CTRL_HUMIDITY_REG'], 1)[0]
        self.config_reg = self.read(regs['BME280_CONFIG_REG'], 1)[0]

    def set_oversamp_temperature(self, sampling):
        v_data = (self.ctrl_meas_reg & ~0xe0) | ((sampling << 5) & 0xe0)

        if self.get_power_mode != power_mode['BME280_SLEEP_MODE']:
            self.soft_rst()
            time.sleep(0.003)
            self.write(regs['BME280_CONFIG_REG'], [self.config_reg])
            self.write(regs['BME280_CTRL_HUMIDITY_REG'], [self.ctrl_hum_reg])
            self.write(regs['BME280_CTRL_MEAS_REG'], [v_data])
        else:
            self.write(regs['BME280_CTRL_MEAS_REG'], [v_data])

        self.oversamp_temperature = sampling
        self.ctrl_meas_reg = self.read(regs['BME280_CTRL_MEAS_REG'], 1)[0]
        self.ctrl_hum_reg = self.read(regs['BME280_CTRL_HUMIDITY_REG'], 1)[0]
        self.config_reg = self.read(regs['BME280_CONFIG_REG'], 1)[0]

    def read_humidity(self):
        vals = self.read(regs['BME280_PRESSURE_MSB_REG'], 8)
        raw_val = float((vals[6] << 8) | vals[7])
        """
        x1 = self.t_fine - 76800
        x1 = ((((raw_val << 14) - (self.param['dig_H4'] << 20) - (self.param['dig_H5'] * x1)) + 16384) >> 15) * \
            (((((((x1 * self.param['dig_H6']) >> 10) * (((x1 * self.param['dig_H3']) >> 11) + 32768)) >> 10) + 2097152) * \
            self.param['dig_H2'] + 8192) >> 14)
        x1 = x1 - (((((x1 >> 15) ** 2) >> 7) * self.param['dig_H1']) >> 4)
        if x1 < 0:
            x1 = 0
        if x1 > 419430400:
            x1 = 419430400

        return (x1 >> 12) / 1024.0
        """
        h = float(self.t_fine) - 76800.0
        h = (raw_val - (float(self.param['dig_H4']) * 64.0 + float(self.param['dig_H5']) / 16384.0 * h)) * (
        float(self.param['dig_H2']) / 65536.0 * (1.0 + float(self.param['dig_H6']) / 67108864.0 * h * (
        1.0 + float(self.param['dig_H3']) / 67108864.0 * h)))
        h = h * (1.0 - float(self.param['dig_H1']) * h / 524288.0)
        if h > 100:
            h = 100
        elif h < 0:
            h = 0
        return h

    def read_pressure(self):
        vals = self.read(regs['BME280_PRESSURE_MSB_REG'], 8)
        raw_val = float((vals[0] << 12) | (vals[1] << 4) | (vals[2] >> 4))
        """
        x1 = (self.t_fine >> 1) - 64000
        x2 = (((x1 >> 2) ** 2) >> 11) * self.param['dig_P6']
        x2 = x2 + ((x1 * self.param['dig_P5']) << 1)
        x2 = (x2 >> 2) + (self.param['dig_P4'] << 16)
        x1 = ((self.param['dig_P3'] * (((x1 >> 2) ** 2) >> 13)) >> 3 + \
             ((self.param['dig_P2'] * x1) >> 1)) >> 18
        x1 = ((32768 + x1) * self.param['dig_P1']) >> 15
        p = ((1048576 - raw_val) - (x2 >> 12)) * 3125
        if x1 == 0:
            return 0
        if p < 0x80000000:
            p = (p << 1) / x1
        else:
            p = (p / x1) * 2

        x1 = (self.param['dig_P9'] * (((p >> 3) ** 2) >> 13)) >> 12
        x2 = ((p >> 2) * self.param['dig_P8']) >> 13
        p = p + ((x1 + x2 + self.param['dig_P7']) >> 4)
        return p / 100.0
        """
        var1 = float(self.t_fine) / 2.0 - 64000.0
        var2 = var1 * var1 * float(self.param['dig_P6']) / 32768.0
        var2 = var2 + var1 * float(self.param['dig_P5']) * 2.0
        var2 = var2 / 4.0 + float(self.param['dig_P4']) * 65536.0
        var1 = (
             float(self.param['dig_P3']) * var1 * var1 / 524288.0 + float(self.param['dig_P2']) * var1) / 524288.0
        var1 = (1.0 + var1 / 32768.0) * float(self.param['dig_P1'])
        if var1 == 0:
            return 0
        p = 1048576.0 - raw_val
        p = ((p - var2 / 4096.0) * 6250.0) / var1
        var1 = float(self.param['dig_P9']) * p * p / 2147483648.0
        var2 = p * float(self.param['dig_P8']) / 32768.0
        p = p + (var1 + var2 + float(self.param['dig_P7'])) / 16.0
        return p

    def read_temperature(self):
        vals = self.read(regs['BME280_PRESSURE_MSB_REG'], 8)
        raw_val = float((vals[3] << 12) | (vals[4] << 4) | (vals[5] >> 4))
        """
        x1 = (((raw_val >> 3) - (self.param['dig_T1'] << 1)) * self.param['dig_T2']) >> 11
        x2 = (((((raw_val >> 4) - self.param['dig_T1']) * ((raw_val >> 4) - self.param['dig_T1'])) >> 12) * self.param['dig_T3']) >> 14
        self.t_fine = x1 + x2
        temp = (self.t_fine * 5 + 128) >> 8

        return temp / 100.0
        """
        var1 = (raw_val / 16384.0 - float(self.param['dig_T1']) / 1024.0) * float(self.param['dig_T2'])
        var2 = ((raw_val / 131072.0 - float(self.param['dig_T1']) / 8192.0) * (
        raw_val / 131072.0 - float(self.param['dig_T1']) / 8192.0)) * float(self.param['dig_T3'])
        self.t_fine = int(var1 + var2)
        temp = (var1 + var2) / 5120.0
        return temp