0
|
1 #!bin/python
|
|
2 """
|
|
3 talks to shiftbrite driver on dash, plus future arduino stuff
|
|
4 """
|
|
5
|
|
6 from __future__ import division
|
|
7
|
|
8 import cyclone.web, sys, bitstring
|
|
9 from twisted.python import log
|
|
10 from twisted.internet import reactor
|
|
11 from rdflib import Namespace
|
|
12 sys.path.append("/my/proj/house/frontdoor")
|
|
13 from loggingserial import LoggingSerial
|
|
14 sys.path.append("/my/site/magma")
|
|
15 from stategraph import StateGraph
|
|
16 sys.path.append("/my/proj/homeauto/lib")
|
|
17 from cycloneerr import PrettyErrorHandler
|
|
18
|
|
19 ROOM = Namespace("http://projects.bigasterisk.com/room/")
|
|
20 DEV = Namespace("http://projects.bigasterisk.com/device/")
|
|
21
|
|
22 from webcolors import hex_to_rgb, rgb_to_hex
|
|
23
|
|
24 def rgbFromHex(h):
|
|
25 """returns tuple of 0..1023"""
|
|
26 norm = hex_to_rgb(h)
|
|
27 return tuple([x * 4 for x in norm])
|
|
28
|
|
29 def hexFromRgb(rgb):
|
|
30 return rgb_to_hex(tuple([x // 4 for x in rgb]))
|
|
31
|
|
32 class ArduinoDesk(object):
|
|
33 def __init__(self, ports=['/dev/ttyUSB0', '/dev/ttyUSB1']):
|
|
34 self.ser = LoggingSerial(ports=ports, baudrate=115200, timeout=1)
|
|
35
|
|
36 def ping(self):
|
|
37 self.ser.write("\x60\x00")
|
|
38 msg = self.ser.readJson()
|
|
39 assert msg == {"ok":"ping"}, msg
|
|
40
|
|
41 def shiftbrite(self, colors):
|
|
42 """
|
|
43 shift out this sequence of (r,g,b) triples of 10-bit ints
|
|
44 """
|
|
45 out = "".join(bitstring.pack("0b00, uint:10, uint:10, uint:10",
|
|
46 b, r, g).bytes
|
|
47 for r,g,b in colors)
|
|
48
|
|
49 self.ser.write("\x60\x01" + chr(len(out)) + out)
|
|
50 msg = self.ser.readJson()
|
|
51 assert msg == {"ok":1}, msg
|
|
52
|
|
53 class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
|
|
54 def get(self):
|
|
55 self.settings.arduino.ping()
|
|
56
|
|
57 self.set_header("Content-Type", "application/xhtml+xml")
|
|
58 self.write(open("index.html").read())
|
|
59
|
|
60 class GraphPage(PrettyErrorHandler, cyclone.web.RequestHandler):
|
|
61 def get(self):
|
|
62 self.set_header("Content-Type", "application/x-trig")
|
|
63 g = StateGraph(ROOM['deskArduino'])
|
|
64 # g.add((s,p,o)) for colors and stuff
|
|
65 self.write(g.asTrig())
|
|
66
|
|
67 class Brite(PrettyErrorHandler, cyclone.web.RequestHandler):
|
|
68 def get(self, chan):
|
|
69 self.set_header("Content-Type", "text/plain")
|
|
70 self.write(hexFromRgb(self.settings.colors[int(chan)]))
|
|
71
|
|
72 def put(self, chan):
|
|
73 s = self.settings
|
|
74 s.colors[int(chan)] = rgbFromHex(self.request.body)
|
|
75 s.arduino.shiftbrite(s.colors)
|
|
76 post = put
|
|
77
|
|
78 class Application(cyclone.web.Application):
|
|
79 def __init__(self, arduino):
|
|
80 handlers = [
|
|
81 (r"/", Index),
|
|
82 (r"/graph", GraphPage),
|
|
83 (r"/brite/(\d+)", Brite),
|
|
84 ]
|
|
85 colors = [(0,0,0)] * 2 # stored 10-bit
|
|
86 cyclone.web.Application.__init__(self, handlers,
|
|
87 arduino=arduino, colors=colors)
|
|
88
|
|
89 if __name__ == '__main__':
|
|
90 config = { # to be read from a file
|
|
91 'servePort' : 9014,
|
|
92 }
|
|
93
|
|
94 #log.startLogging(sys.stdout)
|
|
95
|
|
96 arduino = ArduinoDesk()
|
|
97
|
|
98 reactor.listenTCP(config['servePort'], Application(arduino))
|
|
99 reactor.run()
|