]> git.somenet.org - pub/jan/pyWH1080.git/blob - fetch_data.py
remove human readable wind dir.
[pub/jan/pyWH1080.git] / fetch_data.py
1 #!/usr/bin/env python3
2 # Model Dreamlink WH1080
3 #
4
5 import usb.core
6 import time
7 import struct
8 import math
9 import datetime
10
11 VENDOR = 0x1941
12 PRODUCT = 0x8021
13 #WIND_DIRS = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
14
15
16 def open_ws():
17     '''
18     Open a connection to the device, using the PRODUCT and VENDOR information
19     @return reference to the device
20     '''
21     usb_device = usb.core.find(idVendor=VENDOR, idProduct=PRODUCT)
22
23     if usb_device is None:
24         raise ValueError('Device not found')
25
26     usb_device.get_active_configuration()
27
28     # If we don't detach the kernel driver we get I/O errors
29     if usb_device.is_kernel_driver_active(0):
30         usb_device.detach_kernel_driver(0)
31
32     return usb_device
33
34
35 def read_block(device, offset):
36     '''
37     Read a block of data from the specified device, starting at the given offset.
38     @Inputs
39     device
40         - usb_device
41     offset
42         - int value
43     @Return byte array
44     '''
45
46     least_significant_bit = offset & 0xFF
47     most_significant_bit = offset >> 8 & 0xFF
48
49     # Construct a binary message
50     tbuf = struct.pack('BBBBBBBB',
51                        0xA1,
52                        most_significant_bit,
53                        least_significant_bit,
54                        32,
55                        0xA1,
56                        most_significant_bit,
57                        least_significant_bit,
58                        32)
59
60     timeout = 1000  # Milliseconds
61     retval = device.ctrl_transfer(0x21,  # USB Requesttype
62                                0x09,  # USB Request
63                                0x200,  # Value
64                                0,  # Index
65                                tbuf,  # Message
66                                timeout)
67
68     return device.read(0x81, 32, timeout)
69
70
71 def main():
72     dev = open_ws()
73     dev.set_configuration()
74
75
76     ########### Read data
77     # Get the first 32 Bytes of the fixed
78     fixed_block = read_block(dev, 0)
79
80     # Check that we have good data
81     if (fixed_block[0] != 0x55):
82         raise ValueError('Bad data returned')
83
84     # Bytes 31 and 32 when combined create an unsigned short int that tells us where to find the weather data we want
85     curpos = struct.unpack('H', fixed_block[30:32])[0]
86     current_block = read_block(dev, curpos)
87
88     # Indoor information
89     indoor_humidity = current_block[1]
90     tlsb = current_block[2]
91     tmsb = current_block[3] & 0x7f
92     tsign = current_block[3] >> 7
93     indoor_temperature = (tmsb * 256 + tlsb) * 0.1
94     # Check if temperature is less than zero
95     if tsign:
96         indoor_temperature *= -1
97
98     # Outdoor information
99     outdoor_humidity = current_block[4]
100     tlsb = current_block[5]
101     tmsb = current_block[6] & 0x7f
102     tsign = current_block[6] >> 7
103     outdoor_temperature = (tmsb * 256 + tlsb) * 0.1
104     # Check if temperature is less than zero
105     if tsign:
106         outdoor_temperature *= -1
107
108     # Bytes 8 and 9 when combined create an unsigned short int that we multiply by 0.1 to find the absolute pressure
109     abs_pressure = struct.unpack('H', current_block[7:9])[0]*0.1
110
111     wind = current_block[9]
112     gust = current_block[10]
113     wind_extra = current_block[11]
114     wind_dir = current_block[12]
115
116     # Bytes 14 and 15  when combined create an unsigned short int
117     # that we multiply by 0.3 to find the total rain
118     # I'm not confident that this is correct. Neither abs_pressure nor
119     # total_rain are returning sane values. In fact total_rain has
120     # stayed static despite rainfall
121     # Looks like I fixed it. They used fixed_block instead of current_block
122     total_rain = struct.unpack('H', current_block[13:15])[0]*0.3
123
124     # Calculate wind speeds
125     wind_speed = (wind + ((wind_extra & 0x0F) << 8)) * 0.38  # Was 0.1
126     gust_speed = (gust + ((wind_extra & 0xF0) << 4)) * 0.38  # Was 0.1
127
128
129     ############### print data
130     print('{')
131     print('"indoor_humidity": "%i",' %indoor_humidity)
132     print('"indoor_temperature": "%2.1f",' %indoor_temperature)
133     print('"outdoor_humidity": "%i",' %outdoor_humidity)
134     print('"outdoor_temperature": "%2.1f",' %outdoor_temperature)
135     print('"abs_pressure": "%4.1f",' %abs_pressure)
136     print('"total_rain": "%3.1f",' %total_rain)
137     print('"wind_speed": "%2.1f",' %wind_speed)
138     print('"gust_speed": "%2.1f",' %gust_speed)
139     if wind_dir != 128:
140         print('"wind_dir_deg": "%s",' %(wind_dir*22.5))
141 #        print('"wind_dir": "%s",' %WIND_DIRS[wind_dir])
142     print('"TS": "%s"' %(datetime.datetime.utcnow().isoformat()))
143     print('}')
144
145
146 if __name__ == "__main__":
147     main()