Mercurial > code > home > repos > homeauto
annotate service/colplay/colplay.py @ 1058:2dfd367f7113
move code from nightlight.py into new colplay.py
Ignore-this: ca60cb8905438b9c9b876422618f526f
darcs-hash:e6920524032f6e3edb6ba93ddf9bf5f82ebec65a
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Mon, 21 Mar 2016 04:17:57 -0700 |
parents | |
children | 33883457d1c2 |
rev | line source |
---|---|
1058
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
1 """ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
2 Color player: emits many color values that change over time, by |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
3 scanning across images and creating new images by blending other |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
4 patterns. |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
5 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
6 Rewrite of pixel/nightlight.py |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
7 """ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
8 from __future__ import division |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
9 import time, os, logging, json, traceback |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
10 from PIL import Image |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
11 from datetime import datetime, timedelta |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
12 from twisted.internet import reactor, task |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
13 import cyclone.web |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
14 from dateutil.tz import tzlocal |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
15 from cyclone.httpclient import fetch |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
16 from webcolors import rgb_to_hex |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
17 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
18 logging.basicConfig(level=logging.DEBUG) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
19 log = logging.getLogger() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
20 logging.getLogger('restkit.client').setLevel(logging.WARN) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
21 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
22 class Img(object): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
23 def __init__(self, filename): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
24 self.filename = filename |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
25 self.reread() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
26 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
27 def reread(self): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
28 try: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
29 self.img = Image.open(self.filename) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
30 except IOError: # probably mid-write |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
31 time.sleep(.5) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
32 self.img = Image.open(self.filename) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
33 self.mtime = os.path.getmtime(self.filename) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
34 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
35 def getColor(self, x, y): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
36 """10-bit rgb""" |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
37 if os.path.getmtime(self.filename) > self.mtime: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
38 self.reread() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
39 return [v * 4 for v in self.img.getpixel((x, y))[:3]] |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
40 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
41 lightResource = { |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
42 'theater0': 'http://bang:9059/output?s=http://bigasterisk.com/homeauto/board0/rgb_right_top_2&p=http://projects.bigasterisk.com/room/color', |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
43 } |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
44 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
45 lightYPos = { |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
46 'theater0' : 135, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
47 } |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
48 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
49 def hexFromRgb(rgb): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
50 return rgb_to_hex(tuple([x // 4 for x in rgb])).encode('ascii') |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
51 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
52 def setColor(lightName, rgb, _req): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
53 """takes 10-bit r,g,b |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
54 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
55 returns even if the server is down |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
56 """ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
57 log.debug("setColor(%r,%r)", lightName, rgb) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
58 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
59 serv = lightResource[lightName] |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
60 try: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
61 h = hexFromRgb(rgb) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
62 log.debug("put %r to %r", h, serv) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
63 r = _req(method='PUT', url=serv, body=h, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
64 headers={"content-type":"text/plain"}) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
65 return r |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
66 except Exception, e: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
67 log.warn("Talking to: %r" % serv) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
68 log.warn(e) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
69 return None |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
70 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
71 def setColorAsync(lightName, rgb): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
72 """ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
73 uses twisted http, return deferred or sometimes None when there |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
74 was a warning |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
75 """ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
76 def _req(method, url, body, headers): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
77 d = fetch(url=url, method=method, postdata=body, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
78 headers=dict((k,[v]) for k,v in headers.items())) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
79 @d.addErrback |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
80 def err(e): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
81 log.warn("http client error on %s: %s" % (url, e)) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
82 raise e |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
83 return d |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
84 setColor(lightName, rgb, _req=_req) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
85 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
86 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
87 class LightState(object): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
88 def __init__(self): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
89 self.lastUpdateTime = 0 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
90 self.lastErrorTime = 0 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
91 self.lastError = "" |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
92 self.img = Img("pattern.png") |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
93 self.autosetAfter = dict.fromkeys(lightYPos.keys(), |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
94 datetime.fromtimestamp(0, tzlocal())) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
95 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
96 def mute(self, name, secs): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
97 """don't autoset this light for a few seconds""" |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
98 self.autosetAfter[name] = datetime.now(tzlocal()) + timedelta(seconds=secs) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
99 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
100 def step(self): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
101 try: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
102 now = datetime.now(tzlocal()) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
103 hr = now.hour + now.minute / 60 + now.second / 3600 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
104 x = int(((hr - 12) % 24) * 50) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
105 log.debug("x = %s", x) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
106 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
107 for name, ypos in lightYPos.items(): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
108 if now > self.autosetAfter[name]: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
109 c = self.img.getColor(x, ypos) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
110 setColorAsync(name, c) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
111 self.lastUpdateTime = time.time() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
112 except Exception: |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
113 self.lastError = traceback.format_exc() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
114 self.lastErrorTime = time.time() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
115 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
116 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
117 class IndexHandler(cyclone.web.RequestHandler): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
118 def get(self): |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
119 ls = self.settings.lightState |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
120 now = time.time() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
121 self.set_header("content-type", "application/json") |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
122 self.set_status(200 if ls.lastUpdateTime > ls.lastErrorTime else 500) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
123 self.write(json.dumps(dict( |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
124 secsSinceLastUpdate=now - ls.lastUpdateTime, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
125 secsSinceLastError=now - ls.lastErrorTime, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
126 lastError=ls.lastError, |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
127 ), indent=4)) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
128 |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
129 lightState = LightState() |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
130 task.LoopingCall(lightState.step).start(1) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
131 log.info("listening http on 9051") |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
132 reactor.listenTCP(9051, cyclone.web.Application([ |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
133 (r'/', IndexHandler), |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
134 ], lightState=lightState)) |
2dfd367f7113
move code from nightlight.py into new colplay.py
drewp <drewp@bigasterisk.com>
parents:
diff
changeset
|
135 reactor.run() |