annotate wh1080.py @ 0:de9fe8d30147

Initial commit. Seems to work for the basics.
author Daniel O'Connor <darius@dons.net.au>
date Sat, 13 Feb 2010 18:19:42 +1030
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 #!/usr/bin/env python
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 import struct
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 import usb
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 WH1080_VENDOR = 0x1941
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 WH1080_DEVICE = 0x8021
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 WH1080_TIMEOUT = 100
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 WH1080_RECORD_SIZE = 32
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 WH1080_PAGE_SIZE = 32
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 WH1080_BASE = 0x100
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 WH1080_PAGE0_MAGIC1A = 0xffffffffffffaa55
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 WH1080_PAGE0_MAGIC1B = 0xffffffffffaaaa55
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 WH1080_PAGE0_MAGIC2 = 0xffffffffffffffff
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 WH1080_WIND_DIRECTIONS = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"]
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 def apparent_temp(Ta, rh, ws, Q = None):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 """Compute apparent temperature. Obtained from the Australian BOM at http://www.bom.gov.au/info/thermal_stress/
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 Ta = dry bulb temperature (Celcius)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25 rh = relative humidity (percentage)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 ws = Wind speed (m/s)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 Q = net radiation absorbed by body (W/m2) (optional)"""
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 e = rh / 100 * 6.105 * exp(17.27 * Ta / (237.7 + Ta))
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 if Q == None:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 return(Ta + 0.33 * e - 0.70 * ws - 4.00)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 else:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33 return(Ta + 0.33 * e - 0.70 * ws + 0.70 * Q/(ws + 10) - 4.25)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 def list2uintN(l, size):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36 res = 0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 for i in xrange(size):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 res += l[i] << 8 * i
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 return res
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 class WH1080(object):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42 def __init__(self):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 busses = usb.busses()
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46 #
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 # Search for the device we want
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 #
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 self.handle = None
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 for bus in busses:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51 for dev in bus.devices:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 #print "Looking at 0x%04x 0x%04x" % (dev.idVendor, dev.idProduct)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 if dev.idVendor == WH1080_VENDOR and dev.idProduct == WH1080_DEVICE:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 # Open the device and claim the USB interface that supports the spec
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 self.handle = dev.open()
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56 self.dev = dev
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 break
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59 if self.handle == None:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 raise "Could not find a suitable USB device"
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 self.handle.claimInterface(0)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 def get_current_record(self):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 page0 = Page0(self.read_page(0))
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 return(page0.current_record)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 def read_current_record(self):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68 return self.read_record(self.get_current_record())
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 def read_record(self, record):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 """Read the nominated record from the device"""
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 # Calculate offset for this record
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74 ofs = (record * WH1080_PAGE_SIZE) + WH1080_BASE
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 # 32 bytes covers 2 records.
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 # We don't want to read past the end of memory so we start at
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 # the even page then pick what we need.
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78 ofs &= ~WH1080_RECORD_SIZE
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 data = self.read_page(ofs)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81 #print "Reading record %d => 0x%04x" % (record, ofs)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 if record % 2:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 data = data[0:16]
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 else:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 data = data[16:32]
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87 return Reading(data)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 def read_page(self, ofs):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 """Read a page from the device at ofs
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 Due to apparent hardware bugs / race conditions we read a few times until we have 2 identical reads"""
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 for t in xrange(10):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 pageA = self._read_page(ofs)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 pageB = self._read_page(ofs)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95 if pageA == pageB:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96 break
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 else:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 raise IOError("Could not read page cleanly")
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100 return pageA
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 def _read_page(self, ofs):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 """Read a page from from the device at ofs (no retries)"""
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 msb = (ofs >> 8) & 0xff
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105 lsb = ofs & 0xff
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 req = [0xa1, msb, lsb, 0x20] * 2
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 if self.handle.controlMsg(usb.TYPE_CLASS | usb.RECIP_INTERFACE, 0x9, req, value = 0x200, timeout = WH1080_TIMEOUT) != 8:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 raise IOError("Unable to send control message")
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 data = self.handle.interruptRead(usb.ENDPOINT_IN | usb.RECIP_INTERFACE, WH1080_PAGE_SIZE, WH1080_TIMEOUT)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 if len(data) != WH1080_PAGE_SIZE:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 raise IOError("Unable to read from endpoint expected %d bytes got %d" %
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 (WH1080_PAGE_SIZE, len(data)))
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116 data = map(chr, data)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 return reduce(lambda a, b: a + b, data)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 class Page0(object):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 """Decode page 0, which contains a pointer to the current page"""
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 def __init__(self, data):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 (magic1, magic2, current_offset) = struct.unpack('< Q Q 14x H', data)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 if (magic1 != WH1080_PAGE0_MAGIC1A and magic1 != WH1080_PAGE0_MAGIC1B) or magic2 != WH1080_PAGE0_MAGIC2:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124 raise ValueError("page0 magic not valid")
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 self.current_record = (current_offset - WH1080_BASE) / WH1080_PAGE_SIZE
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 #print "Offset 0x%04x => %d" % (current_offset, self.current_record)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 class Reading(object):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 def __init__(self, data):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 (self.last_save_mins, self.inside_humidity, self.inside_temp,
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 self.outside_humidity, self.outside_temp, self.pressure,
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133 self.wind_speed, self.wind_gust, foo, self.wind_direction,
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134 self.rain, bar) = struct.unpack('< B B h B h H B B B B H B', data)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136 #print "foo = 0x%02x, bar = 0x%02x" % (foo, bar)
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 self.inside_temp /= 10.0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138 self.outside_temp /= 10.0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139 self.wind_speed /= 10.0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 self.pressure /= 10.0
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 if self.wind_direction == 0x80 or self.wind_direction == 0xff:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
142 self.wind_direction = None
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 else:
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 self.wind_direction = WH1080_WIND_DIRECTIONS[self.wind_direction]
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
146 def __str__(self):
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147 return "%2d %4.1f %3d %4.1f %3d %6.1f %5.1f %5.1f %s %4.1f" % (
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
148 self.last_save_mins, self.inside_temp, self.inside_humidity, self.outside_temp,
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 self.outside_humidity, self.pressure, self.wind_speed, self.wind_gust,
de9fe8d30147 Initial commit.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150 self.wind_direction, self.rain)