comparison service/rdf_to_mqtt/mqtt_graph_bridge.py @ 1532:7cc7700302c2

more service renaming; start a lot more serv.n3 job files Ignore-this: 635aaefc7bd2fa5558eefb8b3fc9ec75 darcs-hash:2c8b587cbefa4db427f9a82676abdb47e651187e
author drewp <drewp@bigasterisk.com>
date Thu, 06 Feb 2020 16:36:35 -0800
parents
children
comparison
equal deleted inserted replaced
1531:a3dc6a31590f 1532:7cc7700302c2
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
9 from docopt import docopt
10 from rdflib import Namespace, Literal
11 from twisted.internet import reactor
12 import cyclone.web
13
14 from mqtt_client import MqttClient
15 from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
16 from standardservice.logsetup import log, verboseLogging
17 import rdf_over_http
18
19 ROOM = Namespace('http://projects.bigasterisk.com/room/')
20
21 devs = {
22 ROOM['kitchenLight']: {
23 'root': 'h801_skylight',
24 'ctx': ROOM['kitchenH801']
25 },
26 ROOM['kitchenCounterLight']: {
27 'root': 'h801_counter',
28 'ctx': ROOM['kitchenH801']
29 },
30 ROOM['livingLampShelf']: {
31 'root': 'sonoff_0/switch/sonoff_basic_relay/command',
32 'ctx': ROOM['sonoff_0'],
33 'values': 'binary',
34 },
35 }
36
37
38 class OutputPage(cyclone.web.RequestHandler):
39 def put(self):
40 for stmt in rdf_over_http.rdfStatementsFromRequest(
41 self.request.arguments,
42 self.request.body,
43 self.request.headers):
44 self._onStatement(stmt)
45
46 def _onStatement(self, stmt):
47 log.info(f'incoming statement: {stmt}')
48 ignored = True
49 for dev, attrs in devs.items():
50 if stmt[0] == ROOM['frontWindow']:
51 ignored = ignored and self._publishFrontScreenText(stmt)
52
53 if stmt[0:2] == (dev, ROOM['brightness']):
54 log.info(f'brightness request: {stmt}')
55 brightness = stmt[2].toPython()
56
57 if attrs.get('values', '') == 'binary':
58 self._publishOnOff(attrs, brightness)
59 else:
60 self._publishRgbw(attrs, brightness)
61 # try to stop saving this; let the device be the master usually
62 self.settings.masterGraph.patchObject(
63 attrs['ctx'],
64 stmt[0], stmt[1], stmt[2])
65 ignored = False
66 if ignored:
67 log.warn("ignoring %s", stmt)
68
69 def _publishOnOff(self, attrs, brightness):
70 msg = 'OFF'
71 if brightness > 0:
72 msg = 'ON'
73 self._publish(topic=attrs['root'], message=msg)
74
75 def _publishRgbw(self, attrs, brightness):
76 for chan, scale in [('w1', 1),
77 ('r', 1),
78 ('g', .8),
79 ('b', .8)]:
80 self._publish(
81 topic=f"{attrs['root']}/light/kit_{chan}/command",
82 messageJson={
83 'state': 'ON',
84 'brightness': int(brightness * 255)
85 })
86
87 def _publishFrontScreenText(self, stmt):
88 ignored = True
89 for line in ['line1', 'line2', 'line3', 'line4']:
90 if stmt[1] == ROOM[line]:
91 ignored = False
92 self.settings.mqtt.publish(
93 b'frontwindow/%s' % line.encode('ascii'),
94 stmt[2].toPython())
95 return ignored
96
97 def _publish(self, topic: str, messageJson: object=None,
98 message: str=None):
99 if messageJson is not None:
100 message = json.dumps(messageJson)
101 self.settings.mqtt.publish(
102 topic.encode('ascii'),
103 message.encode('ascii'))
104
105
106 if __name__ == '__main__':
107 arg = docopt("""
108 Usage: mqtt_graph_bridge.py [options]
109
110 -v Verbose
111 """)
112 verboseLogging(arg['-v'])
113
114 masterGraph = PatchableGraph()
115
116 mqtt = MqttClient(clientId='mqtt_graph_bridge', brokerPort=1883)
117
118 port = 10008
119 reactor.listenTCP(port, cyclone.web.Application([
120 (r"/()", cyclone.web.StaticFileHandler,
121 {"path": ".", "default_filename": "index.html"}),
122 (r'/output', OutputPage),
123 ], mqtt=mqtt, debug=arg['-v']), interface='::')
124 log.warn('serving on %s', port)
125
126 for dev, attrs in devs.items():
127 masterGraph.patchObject(attrs['ctx'],
128 dev, ROOM['brightness'], Literal(0.0))
129
130 reactor.run()