Mercurial > code > home > repos > homeauto
annotate service/rdf_to_mqtt/rdf_to_mqtt.py @ 1564:ffbebd7902ee
stats page
Ignore-this: b59d958287c2381c908ec9583706966
darcs-hash:97af26702e35e41ae4a1e01cb3287cb17878dead
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Fri, 14 Feb 2020 16:47:10 -0800 |
parents | 71eec31da919 |
children | de145b8129d8 |
rev | line source |
---|---|
1539 | 1 """ |
2 We get output statements that are like light9's deviceAttrs (:dev1 :color "#ff0000"), | |
3 convert those to outputAttrs (:dev1 :red 255; :green 0; :blue 0) and post them to mqtt. | |
4 | |
5 This is like light9/bin/collector. | |
6 """ | |
7 import json | |
8 from mqtt_client import MqttClient | |
9 from docopt import docopt | |
1564 | 10 from rdflib import Namespace |
1539 | 11 from twisted.internet import reactor |
12 import cyclone.web | |
1564 | 13 from greplin import scales |
14 from greplin.scales.cyclonehandler import StatsHandler | |
1539 | 15 |
16 from standardservice.logsetup import log, verboseLogging | |
17 import rdf_over_http | |
1563
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
18 from cycloneerr import PrettyErrorHandler |
1539 | 19 |
20 ROOM = Namespace('http://projects.bigasterisk.com/room/') | |
21 | |
1564 | 22 STATS = scales.collection('/root', |
23 scales.PmfStat('putRequests'), | |
24 scales.PmfStat('statement'), | |
25 scales.PmfStat('mqttPublish'), | |
26 ) | |
27 | |
1539 | 28 devs = { |
29 ROOM['kitchenLight']: { | |
30 'root': 'h801_skylight', | |
31 }, | |
32 ROOM['kitchenCounterLight']: { | |
33 'root': 'h801_counter', | |
34 }, | |
35 ROOM['livingLampShelf']: { | |
36 'root': 'sonoff_0/switch/sonoff_basic_relay/command', | |
37 'values': 'binary', | |
38 }, | |
1540 | 39 ROOM['livingLamp1']: { |
40 'root': 'sonoff_1/switch/sonoff_basic_relay/command', | |
41 'values': 'binary', | |
42 }, | |
43 ROOM['livingLamp2']: { | |
44 'root': 'sonoff_2/switch/sonoff_basic_relay/command', | |
45 'values': 'binary', | |
46 }, | |
47 ROOM['livingLamp3']: { | |
48 'root': 'sonoff_3/switch/sonoff_basic_relay/command', | |
49 'values': 'binary', | |
50 }, | |
51 ROOM['livingLamp4']: { | |
52 'root': 'sonoff_4/switch/sonoff_basic_relay/command', | |
53 'values': 'binary', | |
54 }, | |
55 ROOM['livingLamp5']: { | |
56 'root': 'sonoff_5/switch/sonoff_basic_relay/command', | |
57 'values': 'binary', | |
58 }, | |
1563
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
59 ROOM['theater']: { |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
60 'root': 'theater_blaster/ir_out', |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
61 'values': 'theaterOutputs', |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
62 }, |
1540 | 63 #-t theater_blaster/ir_out -m 'input_game' |
64 #-t theater_blaster/ir_out -m 'input_bd' | |
65 #-t theater_blaster/ir_out -m 'input_cbl' | |
66 #-t theater_blaster/ir_out -m 'input_pc' | |
67 #-t theater_blaster/ir_out/volume_up -m '{"times":1}' | |
68 #-t theater_blaster/ir_out/volume_down -m '{"times":1}' | |
1539 | 69 } |
70 | |
71 | |
1563
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
72 class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler): |
1564 | 73 @STATS.putRequests.time() |
1539 | 74 def put(self): |
75 for stmt in rdf_over_http.rdfStatementsFromRequest( | |
76 self.request.arguments, | |
77 self.request.body, | |
78 self.request.headers): | |
79 self._onStatement(stmt) | |
80 | |
1564 | 81 @STATS.statement.time() |
1539 | 82 def _onStatement(self, stmt): |
83 log.info(f'incoming statement: {stmt}') | |
84 ignored = True | |
85 for dev, attrs in devs.items(): | |
86 if stmt[0] == ROOM['frontWindow']: | |
87 ignored = ignored and self._publishFrontScreenText(stmt) | |
88 if stmt[0:2] == (dev, ROOM['brightness']): | |
89 log.info(f'brightness request: {stmt}') | |
90 brightness = stmt[2].toPython() | |
91 | |
92 if attrs.get('values', '') == 'binary': | |
93 self._publishOnOff(attrs, brightness) | |
94 else: | |
95 self._publishRgbw(attrs, brightness) | |
96 ignored = False | |
1563
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
97 if stmt[0:2] == (dev, ROOM['inputSelector']): |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
98 self._publish(topic=attrs['root'], |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
99 message='input_'+str(stmt[2].toPython())) |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
100 ignored = False |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
101 if stmt[0:2] == (dev, ROOM['volumeChange']): |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
102 delta = int(stmt[2].toPython()) |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
103 which = 'up' if delta > 0 else 'down' |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
104 self._publish(topic=f'theater_blaster/ir_out/volume_{which}', |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
105 message=json.dumps({'timed': abs(delta)})) |
71eec31da919
more theater output controls
drewp <drewp@bigasterisk.com>
parents:
1541
diff
changeset
|
106 ignored = False |
1539 | 107 if ignored: |
108 log.warn("ignoring %s", stmt) | |
109 | |
110 def _publishOnOff(self, attrs, brightness): | |
111 msg = 'OFF' | |
112 if brightness > 0: | |
113 msg = 'ON' | |
114 self._publish(topic=attrs['root'], message=msg) | |
115 | |
116 def _publishRgbw(self, attrs, brightness): | |
117 for chan, scale in [('w1', 1), | |
118 ('r', 1), | |
119 ('g', .8), | |
120 ('b', .8)]: | |
121 self._publish( | |
122 topic=f"{attrs['root']}/light/kit_{chan}/command", | |
123 messageJson={ | |
124 'state': 'ON', | |
125 'brightness': int(brightness * 255) | |
126 }) | |
127 | |
128 def _publishFrontScreenText(self, stmt): | |
129 ignored = True | |
130 for line in ['line1', 'line2', 'line3', 'line4']: | |
131 if stmt[1] == ROOM[line]: | |
132 ignored = False | |
133 self.settings.mqtt.publish( | |
134 b'frontwindow/%s' % line.encode('ascii'), | |
135 stmt[2].toPython()) | |
136 return ignored | |
137 | |
1564 | 138 @STATS.mqttPublish.time() |
1539 | 139 def _publish(self, topic: str, messageJson: object=None, |
140 message: str=None): | |
141 if messageJson is not None: | |
142 message = json.dumps(messageJson) | |
143 self.settings.mqtt.publish( | |
144 topic.encode('ascii'), | |
145 message.encode('ascii')) | |
146 | |
147 | |
148 if __name__ == '__main__': | |
149 arg = docopt(""" | |
150 Usage: rdf_to_mqtt.py [options] | |
151 | |
152 -v Verbose | |
153 """) | |
154 verboseLogging(arg['-v']) | |
155 | |
156 mqtt = MqttClient(clientId='rdf_to_mqtt', brokerPort=1883) | |
157 | |
158 port = 10008 | |
159 reactor.listenTCP(port, cyclone.web.Application([ | |
160 (r"/()", cyclone.web.StaticFileHandler, | |
161 {"path": ".", "default_filename": "index.html"}), | |
162 (r'/output', OutputPage), | |
1564 | 163 (r'/stats/(.*)', StatsHandler, {'serverName': 'rdf_to_mqtt'}), |
1539 | 164 ], mqtt=mqtt, debug=arg['-v']), interface='::') |
165 log.warn('serving on %s', port) | |
166 | |
167 reactor.run() |