1 '''This module implements a driver for the Si7021 humidity and temperature
5 https://www.silabs.com/Support%20Documents%2FTechnicalDocs%2FSi7021-A20.pdf
11 class CRCError(Exception):
12 'Data failed a CRC check.'
17 'Driver for the Si7021 temperature sensor.'
18 SI7021_DEFAULT_ADDRESS
= 0x40
19 SI7021_MEASTEMP_NOHOLD_CMD
= bytearray([0xF3])
20 SI7021_MEASRH_NOHOLD_CMD
= bytearray([0xF5])
21 SI7021_RESET_CMD
= bytearray([0xFE])
22 SI7021_ID1_CMD
= bytearray([0xFA, 0x0F])
23 SI7021_ID2_CMD
= bytearray([0xFC, 0xC9])
27 def __init__(self
, i2c
, address
=SI7021_DEFAULT_ADDRESS
):
28 'Initialize an Si7021 sensor object.'
30 self
.address
= address
31 self
.serial
, self
.identifier
= self
._get
_device
_info
()
35 def temperature(self
):
36 'Return the temperature in Celcius.'
37 temperature
= self
._get
_data
(self
.SI7021_MEASTEMP_NOHOLD_CMD
)
38 celcius
= temperature
* 175.72 / 65536 - 46.85
43 def temperature(self
, value
):
44 raise AttributeError('can\'t set attribute')
48 def relative_humidity(self
):
49 'Return the relative humidity as a percentage. i.e. 35.59927'
50 relative_humidity
= self
._get
_data
(self
.SI7021_MEASRH_NOHOLD_CMD
)
51 relative_humidity
= relative_humidity
* 125 / 65536 - 6
52 return relative_humidity
55 @relative_humidity.setter
56 def relative_humidity(self
, value
):
57 raise AttributeError('can\'t set attribute')
62 self
.i2c
.writeto(self
.address
, self
.SI7021_RESET_CMD
)
63 sleep(self
.I2C_WAIT_TIME
)
66 def _get_data(self
, command
):
67 'Retrieve data from the sensor and verify it with a CRC check.'
69 self
.i2c
.writeto(self
.address
, command
)
70 sleep(self
.I2C_WAIT_TIME
)
72 self
.i2c
.readfrom_into(self
.address
, data
)
73 value
= self
._convert
_to
_integer
(data
[:2])
75 verified
= self
._verify
_checksum
(data
)
77 raise CRCError('Data read off i2c bus failed CRC check.',
83 def _get_device_info(self
):
84 '''Get the serial number and the sensor identifier. The identifier is
85 part of the bytes returned for the serial number.
89 self
.i2c
.writeto(self
.address
, self
.SI7021_ID1_CMD
)
91 sleep(self
.I2C_WAIT_TIME
)
92 self
.i2c
.readfrom_into(self
.address
, id1
)
95 self
.i2c
.writeto(self
.address
, self
.SI7021_ID2_CMD
)
97 sleep(self
.I2C_WAIT_TIME
)
98 self
.i2c
.readfrom_into(self
.address
, id2
)
100 combined_id
= bytearray([id1
[0], id1
[2], id1
[4], id1
[6],
101 id2
[0], id2
[1], id2
[3], id2
[4]])
103 serial
= self
._convert
_to
_integer
(combined_id
)
104 identifier
= self
._get
_device
_identifier
(id2
[0])
106 return serial
, identifier
108 def _convert_to_integer(self
, bytes_to_convert
):
109 'Use bitwise operators to convert the bytes into integers.'
111 for chunk
in bytes_to_convert
:
115 integer
= integer
<< 8
116 integer
= integer | chunk
120 def _get_device_identifier(self
, identifier_byte
):
121 '''Convert the identifier byte to a device identifier. Values are based
122 on the information from page 24 of the datasheet.
125 if identifier_byte
== 0x00 or identifier_byte
== 0xFF:
126 return 'engineering sample'
127 elif identifier_byte
== 0x0D:
129 elif identifier_byte
== 0x14:
131 elif identifier_byte
== 0x15:
137 def _verify_checksum(self
, data
):
138 ''''Verify the checksum using the polynomial from page 19 of the
141 x8 + x5 + x4 + 1 = 0x131 = 0b100110001
144 byte1: 0x67 [01100111]
145 byte2: 0x8c [10001100]
146 byte3: 0xfc [11111100] (CRC byte)
151 checksum
= int(data
[-1])
154 for _
in range(8, 0, -1):
155 if crc
& 0x80: #10000000
157 crc ^
= 0x131 #100110001
165 def convert_celcius_to_fahrenheit(celcius
):
166 'Convert a Celcius measurement into a Fahrenheit measurement.'
167 return celcius
* 1.8 + 32