annotate service/frontDoorArduino/frontDoorArduino.py @ 0:6fd208b97616

start Ignore-this: e06ac598970a0d4750f588ab89f56996
author Drew Perttula <drewp@bigasterisk.com>
date Mon, 01 Aug 2011 03:30:30 -0700
parents
children d6c2b9b87f7b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
1 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
2 talks to the arduino outside the front door. Don't write straight to
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
3 this LCD; use frontDoorMessage for that.
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
4
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
5 lcd is this wide
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
6 |-------------------|
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
7 22:05 85F in, 71F out
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
8
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
9 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
10
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
11 from __future__ import division
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
12
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
13 import cyclone.web, json, traceback, os, sys
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
14 from twisted.python import log
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
15 from twisted.internet import reactor, task
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
16 from twisted.web.client import getPage
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
17
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
18 sys.path.append("/my/proj/house/frontdoor")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
19 from loggingserial import LoggingSerial
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
20
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
21 sys.path.append("/my/proj/homeauto/lib")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
22 from cycloneerr import PrettyErrorHandler
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
23
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
24 class Board(object):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
25 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
26 arduino board actions, plus the last values we wrote to it
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
27 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
28 def __init__(self, port):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
29 self.ser = LoggingSerial(port=port)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
30 self.ser.flush()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
31
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
32 self.ser.write("\xff\x00\x00")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
33 self.ser.write("\xff\x03\x00")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
34 self.currentText = ""
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
35 self.currentBrightness = 0
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
36
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
37 def ping(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
38 self.getDoor()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
39
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
40 def getDoor(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
41 self.ser.write("\xff\x01")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
42 ret = self.ser.readJson()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
43 return ret['door']
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
44
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
45 def getLcd(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
46 return self.currentText
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
47
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
48 def setLcd(self, txt):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
49 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
50 up to 8*21 chars
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
51 """
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
52 self.currentText = txt
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
53 self.ser.write("\xff\x00" + txt + "\x00")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
54
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
55 def getLcdBrightness(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
56 return self.currentBrightness
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
57
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
58 def setLcdBrightness(self, b):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
59 """b in 0 to 255"""
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
60 self.currentBrightness = b
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
61 self.ser.write("\xff\x03" + chr(b))
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
62
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
63 def getTemperature(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
64 """returns parsed json from the board"""
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
65 self.ser.write("\xff\x02")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
66 # this can take 1.25 seconds per retry
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
67 f = self.ser.readJson()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
68
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
69 if f['temp'] > 184 or f['temp'] < -100:
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
70 # this fails a lot, maybe 50% of the time. retry if
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
71 # you want
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
72 raise ValueError("out of range temp value (%s)" % f)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
73 return f
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
74
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
75 class index(PrettyErrorHandler, cyclone.web.RequestHandler):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
76 def get(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
77 self.settings.board.ping()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
78
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
79 self.set_header("Content-Type", "application/xhtml+xml")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
80 self.write(open("index.html").read())
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
81
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
82 class Lcd(PrettyErrorHandler, cyclone.web.RequestHandler):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
83 def get(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
84 self.set_header("Content-Type", "text/plain")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
85 self.write(self.settings.board.getLcd())
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
86
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
87 def put(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
88 self.settings.board.setLcd(self.request.body)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
89 self.set_status(204)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
90
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
91 class Backlight(PrettyErrorHandler, cyclone.web.RequestHandler):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
92 def get(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
93 self.set_header("Content-Type", "application/json")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
94 self.write(json.dumps({
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
95 "backlight" : self.settings.board.getLcdBrightness()}))
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
96
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
97 def put(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
98 """param brightness=0 to brightness=255"""
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
99 self.settings.board.setLcdBrightness(
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
100 int(self.get_argument('brightness')))
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
101 self.write("ok")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
102 post = put
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
103
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
104 class Door(PrettyErrorHandler, cyclone.web.RequestHandler):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
105 def get(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
106 self.set_header("Content-Type", "text/plain")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
107 self.write(self.settings.board.getDoor())
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
108
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
109 class Temperature(PrettyErrorHandler, cyclone.web.RequestHandler):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
110 def get(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
111 f = self.settings.board.getTemperature()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
112 self.set_header("Content-Type", "application/json")
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
113 self.write(f)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
114
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
115 class Application(cyclone.web.Application):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
116 def __init__(self, board):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
117 handlers = [
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
118 (r"/", index),
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
119 (r'/lcd', Lcd),
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
120 (r'/door', Door),
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
121 (r'/temperature', Temperature),
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
122 (r'/lcd/backlight', Backlight),
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
123 ]
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
124 settings = {"board" : board}
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
125 cyclone.web.Application.__init__(self, handlers, **settings)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
126
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
127
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
128 class Poller(object):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
129 def __init__(self, board, postUrl, boardName):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
130 self.board = board
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
131 self.postUrl = postUrl
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
132 self.boardName = boardName
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
133 self.last = None
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
134
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
135 def poll(self):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
136 try:
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
137 new = self.board.getDoor()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
138 if new != self.last:
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
139 msg = json.dumps(dict(board=self.boardName,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
140 name="frontDoor", state=new))
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
141 getPage(self.postUrl,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
142 method="POST",
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
143 postdata=msg,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
144 headers={'Content-Type' : 'application/json'}
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
145 ).addErrback(self.reportError, msg)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
146
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
147 self.last = new
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
148 except (IOError, OSError):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
149 os.abort()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
150 except Exception, e:
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
151 print "poll error", e
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
152 traceback.print_exc()
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
153
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
154 def reportError(self, msg, *args):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
155 print "post error", msg, args
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
156
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
157 if __name__ == '__main__':
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
158
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
159 port = '/dev/ttyUSB0'
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
160 if not os.path.exists(port):
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
161 port = '/dev/ttyUSB1'
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
162
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
163 config = { # to be read from a file
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
164 'arduinoPort': port,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
165 'servePort' : 9080,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
166 'pollFrequency' : 1,
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
167 'boardName' : 'frontDoor', # gets sent with updates
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
168 'doorChangePost' : 'http://bang.bigasterisk.com:9069/inputChange',
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
169 # todo: need options to preset inputs/outputs at startup
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
170 }
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
171
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
172 log.startLogging(sys.stdout)
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
173
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
174 board = Board(port=config['arduinoPort'])
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
175
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
176 p = Poller(board, config['doorChangePost'], config['boardName'])
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
177 task.LoopingCall(p.poll).start(1/config['pollFrequency'])
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
178 reactor.listenTCP(config['servePort'], Application(board))
Drew Perttula <drewp@bigasterisk.com>
parents:
diff changeset
179 reactor.run()