-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsi7021.py
More file actions
160 lines (128 loc) · 5.03 KB
/
si7021.py
File metadata and controls
160 lines (128 loc) · 5.03 KB
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
'''This module implements a driver for the Si7021 humidity and temperature
sensor.
Datasheet:
https://www.silabs.com/Support%20Documents%2FTechnicalDocs%2FSi7021-A20.pdf
'''
from time import sleep
class CRCError(Exception):
'Data failed a CRC check.'
pass
class Si7021(object):
'Driver for the Si7021 temperature sensor.'
SI7021_DEFAULT_ADDRESS = 0x40
SI7021_MEASTEMP_NOHOLD_CMD = bytearray([0xF3])
SI7021_MEASRH_NOHOLD_CMD = bytearray([0xF5])
SI7021_RESET_CMD = bytearray([0xFE])
SI7021_ID1_CMD = bytearray([0xFA, 0x0F])
SI7021_ID2_CMD = bytearray([0xFC, 0xC9])
I2C_WAIT_TIME = 0.025
def __init__(self, i2c, address=SI7021_DEFAULT_ADDRESS):
'Initialize an Si7021 sensor object.'
self.i2c = i2c
self.address = address
self.serial, self.identifier = self._get_device_info()
@property
def temperature(self):
'Return the temperature in Celcius.'
temperature = self._get_data(self.SI7021_MEASTEMP_NOHOLD_CMD)
celcius = temperature * 175.72 / 65536 - 46.85
return celcius
@temperature.setter
def temperature(self, value):
raise AttributeError('can\'t set attribute')
@property
def relative_humidity(self):
'Return the relative humidity as a percentage. i.e. 35.59927'
relative_humidity = self._get_data(self.SI7021_MEASRH_NOHOLD_CMD)
relative_humidity = relative_humidity * 125 / 65536 - 6
return relative_humidity
@relative_humidity.setter
def relative_humidity(self, value):
raise AttributeError('can\'t set attribute')
def reset(self):
'Reset the sensor.'
self.i2c.writeto(self.address, self.SI7021_RESET_CMD)
sleep(self.I2C_WAIT_TIME)
def _get_data(self, command):
'Retrieve data from the sensor and verify it with a CRC check.'
data = bytearray(3)
self.i2c.writeto(self.address, command)
sleep(self.I2C_WAIT_TIME)
self.i2c.readfrom_into(self.address, data)
value = self._convert_to_integer(data[:2])
verified = self._verify_checksum(data)
if not verified:
raise CRCError('Data read off i2c bus failed CRC check.',
data[:2],
data[-1])
return value
def _get_device_info(self):
'''Get the serial number and the sensor identifier. The identifier is
part of the bytes returned for the serial number.
'''
# Serial 1st half
self.i2c.writeto(self.address, self.SI7021_ID1_CMD)
id1 = bytearray(8)
sleep(self.I2C_WAIT_TIME)
self.i2c.readfrom_into(self.address, id1)
# Serial 2nd half
self.i2c.writeto(self.address, self.SI7021_ID2_CMD)
id2 = bytearray(6)
sleep(self.I2C_WAIT_TIME)
self.i2c.readfrom_into(self.address, id2)
combined_id = bytearray([id1[0], id1[2], id1[4], id1[6],
id2[0], id2[1], id2[3], id2[4]])
serial = self._convert_to_integer(combined_id)
identifier = self._get_device_identifier(id2[0])
return serial, identifier
def _convert_to_integer(self, bytes_to_convert):
'Use bitwise operators to convert the bytes into integers.'
integer = None
for chunk in bytes_to_convert:
if not integer:
integer = chunk
else:
integer = integer << 8
integer = integer | chunk
return integer
def _get_device_identifier(self, identifier_byte):
'''Convert the identifier byte to a device identifier. Values are based
on the information from page 24 of the datasheet.
'''
if identifier_byte == 0x00 or identifier_byte == 0xFF:
return 'engineering sample'
elif identifier_byte == 0x0D:
return 'Si7013'
elif identifier_byte == 0x14:
return 'Si7020'
elif identifier_byte == 0x15:
return 'Si7021'
else:
return 'unknown'
def _verify_checksum(self, data):
''''Verify the checksum using the polynomial from page 19 of the
datasheet.
x8 + x5 + x4 + 1 = 0x131 = 0b100110001
Valid Example:
byte1: 0x67 [01100111]
byte2: 0x8c [10001100]
byte3: 0xfc [11111100] (CRC byte)
'''
crc = 0
values = data[:2]
checksum = int(data[-1])
for value in values:
crc = crc ^ value
for _ in range(8, 0, -1):
if crc & 0x80: #10000000
crc <<= 1
crc ^= 0x131 #100110001
else:
crc <<= 1
if crc != checksum:
return False
else:
return True
def convert_celcius_to_fahrenheit(celcius):
'Convert a Celcius measurement into a Fahrenheit measurement.'
return celcius * 1.8 + 32