Mercurial > code > home > repos > homeauto
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rdf_to_mqtt/mqtt_graph_bridge.py Thu Feb 06 16:36:35 2020 -0800 @@ -0,0 +1,130 @@ +""" +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 docopt import docopt +from rdflib import Namespace, Literal +from twisted.internet import reactor +import cyclone.web + +from mqtt_client import MqttClient +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: mqtt_graph_bridge.py [options] + + -v Verbose + """) + verboseLogging(arg['-v']) + + masterGraph = PatchableGraph() + + mqtt = MqttClient(clientId='mqtt_graph_bridge', 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()