diff service/rdf_to_mqtt/rdf_to_mqtt.py @ 739:03bad43bbcb3

more renaming, build updates Ignore-this: 94a0df55a1d8a74d90ec84bb7351d3ef
author drewp@bigasterisk.com
date Mon, 10 Feb 2020 23:56:42 -0800
parents service/rdf_to_mqtt/mqtt_graph_bridge.py@fdddbdaf07b5
children 1f8abec7f687
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/rdf_to_mqtt/rdf_to_mqtt.py	Mon Feb 10 23:56:42 2020 -0800
@@ -0,0 +1,127 @@
+"""
+We get output statements that are like light9's deviceAttrs (:dev1 :color "#ff0000"),
+convert those to outputAttrs (:dev1 :red 255; :green 0; :blue 0) and post them to mqtt.
+
+This is like light9/bin/collector.
+"""
+import json
+from mqtt_client import MqttClient
+from docopt import docopt
+from rdflib import Namespace, Literal
+from twisted.internet import reactor
+import cyclone.web
+
+from patchablegraph import PatchableGraph, CycloneGraphHandler, CycloneGraphEventsHandler
+from standardservice.logsetup import log, verboseLogging
+import rdf_over_http
+
+ROOM = Namespace('http://projects.bigasterisk.com/room/')
+
+devs = {
+    ROOM['kitchenLight']: {
+        'root': 'h801_skylight',
+        'ctx': ROOM['kitchenH801']
+    },
+    ROOM['kitchenCounterLight']: {
+        'root': 'h801_counter',
+        'ctx': ROOM['kitchenH801']
+    },
+    ROOM['livingLampShelf']: {
+        'root': 'sonoff_0/switch/sonoff_basic_relay/command',
+        'ctx': ROOM['sonoff_0'],
+        'values': 'binary',
+    },
+}
+
+
+class OutputPage(cyclone.web.RequestHandler):
+    def put(self):
+        for stmt in rdf_over_http.rdfStatementsFromRequest(
+                self.request.arguments,
+                self.request.body,
+                self.request.headers):
+            self._onStatement(stmt)
+
+    def _onStatement(self, stmt):
+        log.info(f'incoming statement: {stmt}')
+        ignored = True
+        for dev, attrs in devs.items():
+            if stmt[0] == ROOM['frontWindow']:
+                ignored = ignored and self._publishFrontScreenText(stmt)
+
+            if stmt[0:2] == (dev, ROOM['brightness']):
+                log.info(f'brightness request: {stmt}')
+                brightness = stmt[2].toPython()
+
+                if attrs.get('values', '') == 'binary':
+                    self._publishOnOff(attrs, brightness)
+                else:
+                    self._publishRgbw(attrs, brightness)
+                    # try to stop saving this; let the device be the master usually
+                    self.settings.masterGraph.patchObject(
+                        attrs['ctx'],
+                        stmt[0], stmt[1], stmt[2])
+                ignored = False
+        if ignored:
+            log.warn("ignoring %s", stmt)
+
+    def _publishOnOff(self, attrs, brightness):
+        msg = 'OFF'
+        if brightness > 0:
+            msg = 'ON'
+        self._publish(topic=attrs['root'], message=msg)
+
+    def _publishRgbw(self, attrs, brightness):
+        for chan, scale in [('w1', 1),
+                            ('r', 1),
+                            ('g', .8),
+                            ('b', .8)]:
+            self._publish(
+                topic=f"{attrs['root']}/light/kit_{chan}/command",
+                messageJson={
+                    'state': 'ON',
+                    'brightness': int(brightness * 255)
+                })
+
+    def _publishFrontScreenText(self, stmt):
+        ignored = True
+        for line in ['line1', 'line2', 'line3', 'line4']:
+            if stmt[1] == ROOM[line]:
+                ignored = False
+                self.settings.mqtt.publish(
+                    b'frontwindow/%s' % line.encode('ascii'),
+                    stmt[2].toPython())
+        return ignored
+
+    def _publish(self, topic: str, messageJson: object=None,
+                 message: str=None):
+        if messageJson is not None:
+            message = json.dumps(messageJson)
+        self.settings.mqtt.publish(
+            topic.encode('ascii'),
+            message.encode('ascii'))
+
+
+if __name__ == '__main__':
+    arg = docopt("""
+    Usage: rdf_to_mqtt.py [options]
+
+    -v   Verbose
+    """)
+    verboseLogging(arg['-v'])
+
+    mqtt = MqttClient(clientId='rdf_to_mqtt', brokerPort=1883)
+
+    port = 10008
+    reactor.listenTCP(port, cyclone.web.Application([
+        (r"/()", cyclone.web.StaticFileHandler,
+         {"path": ".", "default_filename": "index.html"}),
+        (r'/output', OutputPage),
+        ], mqtt=mqtt, debug=arg['-v']), interface='::')
+    log.warn('serving on %s', port)
+
+    for dev, attrs in devs.items():
+        masterGraph.patchObject(attrs['ctx'],
+                                dev, ROOM['brightness'], Literal(0.0))
+
+    reactor.run()