forked from agners/micropython-sgp40
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sgp40.py
executable file
·110 lines (91 loc) · 3.76 KB
/
sgp40.py
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
from machine import I2C
import utime
import struct
import math
class SGP40:
class NotFoundException(Exception):
pass
class NotSupportedException(Exception):
pass
class CRCException(Exception):
pass
MEASUREMENT_RAW = 0x260f
MEASUREMENT_TEST = 0x280e
HEATER_OFF = 0x3615
RESET = 0x0006
GET_SERIAL_ID = 0x3682
GET_FEATURESET = 0x202f
# Generated using
# crc_table = []
# for crc in range(256):
# for crc_bit in range(8):
# if crc & 0x80:
# crc = (crc << 1) ^ CRC8_POLYNOMIAL;
# else:
# crc = (crc << 1);
# crc = crc%256
# crc_table.append(crc)
CRC_TABLE = [
0, 49, 98, 83, 196, 245, 166, 151, 185, 136, 219, 234, 125, 76, 31, 46,
67, 114, 33, 16, 135, 182, 229, 212, 250, 203, 152, 169, 62, 15, 92, 109,
134, 183, 228, 213, 66, 115, 32, 17, 63, 14, 93, 108, 251, 202, 153, 168,
197, 244, 167, 150, 1, 48, 99, 82, 124, 77, 30, 47, 184, 137, 218, 235,
61, 12, 95, 110, 249, 200, 155, 170, 132, 181, 230, 215, 64, 113, 34, 19,
126, 79, 28, 45, 186, 139, 216, 233, 199, 246, 165, 148, 3, 50, 97, 80,
187, 138, 217, 232, 127, 78, 29, 44, 2, 51, 96, 81, 198, 247, 164, 149,
248, 201, 154, 171, 60, 13, 94, 111, 65, 112, 35, 18, 133, 180, 231, 214,
122, 75, 24, 41, 190, 143, 220, 237, 195, 242, 161, 144, 7, 54, 101, 84,
57, 8, 91, 106, 253, 204, 159, 174, 128, 177, 226, 211, 68, 117, 38, 23,
252, 205, 158, 175, 56, 9, 90, 107, 69, 116, 39, 22, 129, 176, 227, 210,
191, 142, 221, 236, 123, 74, 25, 40, 6, 55, 100, 85, 194, 243, 160, 145,
71, 118, 37, 20, 131, 178, 225, 208, 254, 207, 156, 173, 58, 11, 88, 105,
4, 53, 102, 87, 192, 241, 162, 147, 189, 140, 223, 238, 121, 72, 27, 42,
193, 240, 163, 146, 5, 52, 103, 86, 120, 73, 26, 43, 188, 141, 222, 239,
130, 179, 224, 209, 70, 119, 36, 21, 59, 10, 89, 104, 255, 206, 157, 172
]
def __init__(self, i2c, addr=0x59):
self.i2c = i2c
self.addr = addr
if not addr in i2c.scan():
raise self.NotFoundException
def measure_raw(self, humidity=50, temperature=25):
paramh = struct.pack(">H", math.ceil(humidity * 0xffff / 100))
crch = self.__crc(paramh[0], paramh[1])
paramt = struct.pack(">H", math.ceil((temperature + 45) * 0xffff / 175))
crct = self.__crc(paramt[0], paramt[1])
data = paramh + bytes([crch]) + paramt + bytes([crct])
self.i2c.writeto_mem(self.addr, self.MEASUREMENT_RAW, data, addrsize=16)
utime.sleep_ms(30)
raw = self.i2c.readfrom(self.addr, 3)
self.__check_crc(raw)
return struct.unpack('>H', raw[:2])[0]
def measure_test(self):
raw = self.__read_bytes(self.MEASUREMENT_TEST, 3, 250000)
self.__check_crc(raw)
return struct.unpack('>H', raw[:2])[0]
def reset(self):
self.__write_command(self.RESET)
def heater_off(self):
self.__write_command(self.HEATER_OFF)
def get_serial_id(self):
data = self.__read_bytes(self.GET_SERIAL_ID, 6, 500)
return data
def __write_command(self, cmd):
bcmd = struct.pack('>H', cmd)
self.i2c.writeto(self.addr, bcmd)
def __read_bytes(self, cmd, count, pause):
self.__write_command(cmd)
utime.sleep_us(pause)
return self.i2c.readfrom(self.addr, count)
def __check_crc(self, arr):
assert (len(arr) == 3)
if self.__crc(arr[0], arr[1]) != arr[2]:
raise self.CRCException
def __crc(self, msb, lsb):
crc = 0xff
crc ^= msb
crc = self.CRC_TABLE[crc]
if lsb is not None:
crc ^= lsb
crc = self.CRC_TABLE[crc]
return crc