-
Notifications
You must be signed in to change notification settings - Fork 0
/
am2320.py
121 lines (102 loc) · 4.42 KB
/
am2320.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
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python3
# Modified from https://github.com/Shoe-Pi/AM2320_Pi
#These are needed for talking to the i2c bus
import os
import fcntl
import time
class AM2320:
#Constructor to set up the class
def __init__(self):
#Set the i2c address
self.address = 0x5c
#I *think* this is about setting the address for i2c
# slave requests in the Linux kernel (?)
self.slave = 0x0703
#Open the i2c bus in read/write mode as a file object
self.fd = os.open("/dev/i2c-1", os.O_RDWR)
fcntl.ioctl(self.fd, self.slave, self.address)
#List for holding raw read data
self.raw_data = [0,0,0,0]
#Initial values for variables
self.temperature = 0
self.humidity = 0
#Initial value for CRC check
self.CRC = 0xFFFF
#A function to read data from the sensor, calculate temp and
#humidity and store in the variables in the object
def get_data(self):
#Reset the CRC variable
self.CRC = 0xFFFF
#The AM2320 drops into sleep mode when not interacted
#with for a while. It wakes up when poked across the i2c bus
#but doesn't return data immediately, so poke it to wake it
#and ignore the fact that no acknowledgement is recieved.
try:
os.write(self.fd, b'\0x00')
except:
pass
#Tell the sensor you want to read data (0x03), starting at register 0
#(0x00), and that you want 4 bytes of sensor data. This starts the read
#at the humidity most significant byte, passes through the humidity least
#significant and temperature most significant bytes and stops after
#reading the temperature least significant byt.
try:
os.write(self.fd, b'\x03\x00\x04')
except:
raise AM2320Error("No response from sensor")
#Wait 1ms (min 800us, max 3ms) to allow the sensor to take measurements
time.sleep(0.001)
#Read the data into the list called "raw_data". Bytes 0 and 1 are the
#instructions given to the device (0x03 and 0x04), given to check that
#what was read is what was asked for. Bytes 2 and 3 are the
# humidity high and low bytes respectively. Bytes 4 and 5 are the
# temperature high and low bytes respectively. Bytes 6 and 7 are the CRC
# high and low bytes respectively (see below).
self.raw_data = bytearray(os.read(self.fd, 8))
#Do the Cyclic Redundancy Code (CRC) check. This progressively combines
#the first 6 bytes recieved (raw_data bytes 0-5) with a variable of value
#0xFFFF in a way which should eventually result in a value which is equal
#to the combined CRC bytes. If this check fails then something has been
#corrupted during transmission.
for byte in self.raw_data[0:6]:
self.CRC = self.CRC ^ byte
for x in range (0,8):
if (self.CRC & 0x01 == 0x01):
self.CRC = self.CRC >> 1
self.CRC = self.CRC ^ 0xA001
else:
self.CRC = self.CRC >> 1
#If raw_data 0 + 1 (the returned intruction codes) don't match 0x03 and
#0x04 (the instructions which were given) alert the user to the error
if ((self.raw_data[0] != 0x03) or (self.raw_data[1] != 0x04)):
raise AM2320Error("Recieved bytes 0 and 1 corrupt")
#If the CRC bytes don't equal the calculated CRC code alert the user to
#the error.
elif (self.CRC != ((self.raw_data[7] << 8) + self.raw_data[6])):
raise AM2320Error("CRC error, data corrupt")
#Otherwise, everything is fine and calculate the temp/humidity values
else:
#Bitshift the temperature most significant byte left by 8 bits
#and combine with the least significant byte. If bit 15 is 1 the
#temperature is negative, so get rid of b.t 15 (by bitwise AND
#with 0x7f) and then make the value negative before dividing by 10
#according to the datasheet. If bit 15 is zero, the temperature
#is positive so just divide it by 10 to get the temperature in
#degrees Celsius/
self.temperature = ((self.raw_data[4] << 8)\
+ self.raw_data[5])
if ((self.temperature & 0x8000) == 0x8000):
self.temperature = self.temperature & 0x7fff
self.temperature = -self.temperature/10.0
else:
self.temperature = self.temperature / 10.0
#Bitshift the humidity most significant byte left by 8 bits and add
#it to the least significant byte. Divide this by 10 to give the
#humidity in % relative humidity, according to the datasheet.
self.humidity = ((self.raw_data[2] << 8) \
+ self.raw_data[3])/10.0
class AM2320Error(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)