Mercurial > code > home > repos > homeauto
changeset 778:acf58b83022f
rdf_to_mqtt sylvania bulbs and code cleanup and k8s updates
author | drewp@bigasterisk.com |
---|---|
date | Sat, 08 Aug 2020 13:56:39 -0700 |
parents | df7035db28f1 |
children | bad87b7dc608 |
files | service/rdf_to_mqtt/.style.yapf service/rdf_to_mqtt/Dockerfile service/rdf_to_mqtt/index.html service/rdf_to_mqtt/rdf_to_mqtt.py service/rdf_to_mqtt/requirements.txt |
diffstat | 5 files changed, 153 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rdf_to_mqtt/.style.yapf Sat Aug 08 13:56:39 2020 -0700 @@ -0,0 +1,4 @@ +# overwritten by /home/drewp/bin/setup_home_venv +[style] +based_on_style = google +column_limit = 130
--- a/service/rdf_to_mqtt/Dockerfile Sat Aug 08 13:14:49 2020 -0700 +++ b/service/rdf_to_mqtt/Dockerfile Sat Aug 08 13:56:39 2020 -0700 @@ -1,13 +1,14 @@ -FROM bang6:5000/base_x86 +FROM bang5:5000/base_x86 WORKDIR /opt COPY requirements.txt ./ RUN pip3 install --index-url https://projects.bigasterisk.com/ --extra-index-url https://pypi.org/simple -r requirements.txt RUN pip3 install -U 'https://github.com/drewp/cyclone/archive/python3.zip?v3' +RUN pip3 install -U attrs COPY *.py *.html *.js ./ EXPOSE 10011:10011 -CMD [ "python3", "./rdf_to_mqtt.py" ] +CMD [ "python3", "./rdf_to_mqtt.py", "-v" ]
--- a/service/rdf_to_mqtt/index.html Sat Aug 08 13:14:49 2020 -0700 +++ b/service/rdf_to_mqtt/index.html Sat Aug 08 13:56:39 2020 -0700 @@ -1,62 +1,102 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> <title>rdf_to_mqtt</title> - <meta charset="utf-8"> + <meta charset="utf-8" /> <script src="/lib/polymer/1.0.9/webcomponentsjs/webcomponents.min.js"></script> <script src="/lib/require/require-2.3.3.js"></script> <script src="/rdf/common_paths_and_ns.js"></script> - <link rel="stylesheet" href="/rdf/browse/style.css"> - + <link rel="stylesheet" href="/rdf/browse/style.css" /> + <style> + button { + min-height: 50px; + } + section { + margin: 5px; + display: inline-block; + vertical-align: top; + } + </style> </head> <body class="rdfBrowsePage"> rdf_to_mqtt - <p>Send demo statements to bridge:</p> - <div><button data-post="output?s=:kitchenLight&p=:brightness" data-body="0.0">Send (:kitchenLight :brightness 0.0)</button></div> - <div><button data-post="output?s=:kitchenLight&p=:brightness" data-body="1.0">Send (:kitchenLight :brightness 1.0)</button></div> - <div><button data-post="output?s=:kitchenCounterLight&p=:brightness" data-body="0.0">Send (:kitchenCounterLight :brightness 0.0)</button></div> - <div><button data-post="output?s=:kitchenCounterLight&p=:brightness" data-body="1.0">Send (:kitchenCounterLight :brightness 1.0)</button></div> - <div><button data-post="output?s=:livingLampShelf&p=:brightness" data-body="0.0">Send (:livingLampShelf :brightness 0.0)</button></div> - <div><button data-post="output?s=:livingLampShelf&p=:brightness" data-body="1.0">Send (:livingLampShelf :brightness 1.0)</button></div> - <div><button data-post="output?s=:livingLampMantleEntry&p=:brightness" data-body="0.0">Send (:livingLamp1 :brightness 0.0)</button></div> - <div><button data-post="output?s=:livingLampMantleEntry&p=:brightness" data-body="1.0">Send (:livingLamp1 :brightness 1.0)</button></div> - <div><button data-post="output?s=:livingLampMantleChair&p=:brightness" data-body="0.0">Send (:livingLamp2 :brightness 0.0)</button></div> - <div><button data-post="output?s=:livingLampMantleChair&p=:brightness" data-body="1.0">Send (:livingLamp2 :brightness 1.0)</button></div> - <div><button data-post="output?s=:livingLampToyShelf&p=:brightness" data-body="0.0">Send (:livingLamp3 :brightness 0.0)</button></div> - <div><button data-post="output?s=:livingLampToyShelf&p=:brightness" data-body="1.0">Send (:livingLamp3 :brightness 1.0)</button></div> - <div><button data-post="output?s=:livingLampPiano&p=:brightness" data-body="0.0">Send (:livingLamp4 :brightness 0.0)</button></div> - <div><button data-post="output?s=:livingLampPiano&p=:brightness" data-body="1.0">Send (:livingLamp4 :brightness 1.0)</button></div> - - <div><button data-post="output?s=:theater&p=:inputSelector" data-body="bd">Theater to chromecast</button></div> - <div><button data-post="output?s=:theater&p=:inputSelector" data-body="game">Theater to PS4</button></div> - <div><button data-post="output?s=:theater&p=:inputSelector" data-body="pc">Theater to VR</button></div> - <div><button data-post="output?s=:theater&p=:inputSelector" data-body="cbl">Theater to PS3</button></div> - <div><button data-post="output?s=:theater&p=:volumeChange" data-body="3">Theater volume up</button></div> - <div><button data-post="output?s=:theater&p=:volumeChange" data-body="-3">Theater volume down</button></div> - - <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#ffffff">headboard white</button></div> - <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#000000">headboard black</button></div> - <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#ff0000">headboard red</button></div> - <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#00ff00">headboard green</button></div> - <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#0000ff">headboard blue</button></div> + <section> + <div><button data-post="output?s=:kitchenLight&p=:brightness" data-body="0.0">Send (:kitchenLight :brightness 0.0)</button></div> + <div><button data-post="output?s=:kitchenLight&p=:brightness" data-body="1.0">Send (:kitchenLight :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:kitchenCounterLight&p=:brightness" data-body="0.0">Send (:kitchenCounterLight :brightness 0.0)</button></div> + <div><button data-post="output?s=:kitchenCounterLight&p=:brightness" data-body="1.0">Send (:kitchenCounterLight :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:livingLampShelf&p=:brightness" data-body="0.0">Send (:livingLampShelf :brightness 0.0)</button></div> + <div><button data-post="output?s=:livingLampShelf&p=:brightness" data-body="1.0">Send (:livingLampShelf :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:livingLampMantleEntry&p=:brightness" data-body="0.0">Send (:livingLamp1 :brightness 0.0)</button></div> + <div><button data-post="output?s=:livingLampMantleEntry&p=:brightness" data-body="1.0">Send (:livingLamp1 :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:livingLampMantleChair&p=:brightness" data-body="0.0">Send (:livingLamp2 :brightness 0.0)</button></div> + <div><button data-post="output?s=:livingLampMantleChair&p=:brightness" data-body="1.0">Send (:livingLamp2 :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:livingLampToyShelf&p=:brightness" data-body="0.0">Send (:livingLamp3 :brightness 0.0)</button></div> + <div><button data-post="output?s=:livingLampToyShelf&p=:brightness" data-body="1.0">Send (:livingLamp3 :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:livingLampPiano&p=:brightness" data-body="0.0">Send (:livingLamp4 :brightness 0.0)</button></div> + <div><button data-post="output?s=:livingLampPiano&p=:brightness" data-body="1.0">Send (:livingLamp4 :brightness 1.0)</button></div> + </section> + <section> + <div><button data-post="output?s=:theater&p=:inputSelector" data-body="bd">Theater to chromecast</button></div> + <div><button data-post="output?s=:theater&p=:inputSelector" data-body="game">Theater to PS4</button></div> + <div><button data-post="output?s=:theater&p=:inputSelector" data-body="pc">Theater to VR</button></div> + <div><button data-post="output?s=:theater&p=:inputSelector" data-body="cbl">Theater to PS3</button></div> + <div><button data-post="output?s=:theater&p=:volumeChange" data-body="3">Theater volume up</button></div> + <div><button data-post="output?s=:theater&p=:volumeChange" data-body="-3">Theater volume down</button></div> + </section> + <section> + <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#ffffff">headboard white</button></div> + <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#000000">headboard black</button></div> + <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#ff0000">headboard red</button></div> + <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#00ff00">headboard green</button></div> + <div><button data-post="output?s=:bedHeadboard&p=:color" data-body="#0000ff">headboard blue</button></div> + </section> + <section> + <div><button data-post="output?s=:syl1&p=:color" data-body="#000000">Send (:syl1 :color black)</button></div> + <div><button data-post="output?s=:syl1&p=:color" data-body="#ffffff">Send (:syl1 :color white)</button></div> + </section> + <section> + <div><button data-post="output?s=:syl2&p=:color" data-body="#000000">Send (:syl2 :color black)</button></div> + <div><button data-post="output?s=:syl2&p=:color" data-body="#ffffff">Send (:syl2 :color white)</button></div> + </section> + <section> + <div><button data-post="output?s=:syl3&p=:color" data-body="#000000">Send (:syl3 :color black)</button></div> + <div><button data-post="output?s=:syl3&p=:color" data-body="#ffffff">Send (:syl3 :color white)</button></div> + </section> + <section> + <div><button data-post="output?s=:syl4&p=:color" data-body="#000000">Send (:syl4 :color black)</button></div> + <div><button data-post="output?s=:syl4&p=:color" data-body="#ffffff">Send (:syl4 :color white)</button></div> + </section> <script> - Array.from(document.querySelectorAll("button")).forEach((el) => { - el.addEventListener("click", (ev) => { - fetch(el.dataset.post, { - method: "PUT", - body: el.dataset.body - }); - }); - }); + Array.from(document.querySelectorAll("button")).forEach((el) => { + el.addEventListener("click", (ev) => { + fetch(el.dataset.post, { + method: "PUT", + body: el.dataset.body, + }); + }); + }); </script> - <div class="served-resources"> - <a href="stats/">/stats/</a> - <a href="output">/output (post)</a> - </div> + <div class="served-resources"> + <a href="stats/">/stats/</a> + <a href="output">/output (post)</a> + </div> </body> </html>
--- a/service/rdf_to_mqtt/rdf_to_mqtt.py Sat Aug 08 13:14:49 2020 -0700 +++ b/service/rdf_to_mqtt/rdf_to_mqtt.py Sat Aug 08 13:56:39 2020 -0700 @@ -30,9 +30,11 @@ devs = { ROOM['kitchenLight']: { 'root': 'h801_skylight', + 'hasWhite': True, }, ROOM['kitchenCounterLight']: { 'root': 'h801_counter', + 'hasWhite': True, }, ROOM['livingLampShelf']: { 'root': 'sonoff_0/switch/sonoff_basic_relay/command', @@ -60,22 +62,45 @@ }, ROOM['bedHeadboard']: { 'root': 'bed/light/headboard/command', + 'hasWhite': True, }, - #-t theater_blaster/ir_out -m 'input_game' - #-t theater_blaster/ir_out -m 'input_bd' - #-t theater_blaster/ir_out -m 'input_cbl' - #-t theater_blaster/ir_out -m 'input_pc' - #-t theater_blaster/ir_out/volume_up -m '{"times":1}' - #-t theater_blaster/ir_out/volume_down -m '{"times":1}' + # https://github.com/Koenkk/zigbee2mqtt.io/blob/new_api/docs/information/mqtt_topics_and_message_structure.md#general + ROOM['syl1']: { + 'root': 'zigbee2mqtt/syl1/set', + 'hasBrightness': True, + 'defaults': { + 'transition': 0, + } + }, + ROOM['syl2']: { + 'root': 'zigbee2mqtt/syl2/set', + 'hasBrightness': True, + 'defaults': { + 'transition': 0, + } + }, + ROOM['syl3']: { + 'root': 'zigbee2mqtt/syl3/set', + 'hasBrightness': True, + 'defaults': { + 'transition': 0, + } + }, + ROOM['syl4']: { + 'root': 'zigbee2mqtt/syl4/set', + 'hasBrightness': True, + 'defaults': { + 'transition': 0, + } + }, } class OutputPage(PrettyErrorHandler, cyclone.web.RequestHandler): + @STATS.putRequests.time() def put(self): - for stmt in rdf_over_http.rdfStatementsFromRequest( - self.request.arguments, self.request.body, - self.request.headers): + for stmt in rdf_over_http.rdfStatementsFromRequest(self.request.arguments, self.request.body, self.request.headers): self._onStatement(stmt) @STATS.statement.time() @@ -101,25 +126,34 @@ if stmt[0:2] == (dev, ROOM['volumeChange']): delta = int(stmt[2].toPython()) which = 'up' if delta > 0 else 'down' - self._publish(topic=f'theater_blaster/ir_out/volume_{which}', - message=json.dumps({'timed': abs(delta)})) + self._publish(topic=f'theater_blaster/ir_out/volume_{which}', message=json.dumps({'timed': abs(delta)})) ignored = False if stmt[0:2] == (dev, ROOM['color']): h = stmt[2].toPython() r, g, b = int(h[1:3], 16), int(h[3:5], 16), int(h[5:7], 16) - self._publish(topic=attrs['root'], - message=json.dumps({ - 'state': - 'ON' if r or g or b else 'OFF', - 'color': { - 'r': r, - 'g': g, - 'b': b - }, - 'white_value': - max(r, g, b) - })) + msg = { + 'state': 'ON' if r or g or b else 'OFF', + 'color': { + 'r': r, + 'g': g, + 'b': b + }, + } + if attrs.get('hasBrightness', False): + # todo- still not right for sylvania bulbs; they want color x-y. + # see https://www.zigbee2mqtt.io/information/mqtt_topics_and_message_structure.html#zigbee2mqttfriendly_nameset + msg['brightness'] = max(r, g, b) + if msg['brightness'] != 0: + scl = msg['brightness'] / 255 + for chan in ['r', 'g', 'b']: + msg['color'][chan] = int(msg['color'][chan] / 255.0 / scl * 255) + + if attrs.get('hasWhite', False): + msg['white_value'] = max(r, g, b) + msg.update(attrs.get('defaults', {})) + self._publish(topic=attrs['root'], message=json.dumps(msg)) ignored = False + if ignored: log.warn("ignoring %s", stmt) @@ -142,21 +176,15 @@ 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()) + self.settings.mqtt.publish(b'frontwindow/%s' % line.encode('ascii'), stmt[2].toPython()) return ignored @STATS.mqttPublish.time() - def _publish(self, - topic: str, - messageJson: object = None, - message: str = None): + def _publish(self, topic: str, messageJson: object = None, message: str = None): log.debug(f'mqtt.publish {topic} {message} {messageJson}') if messageJson is not None: message = json.dumps(messageJson) - self.settings.mqtt.publish(topic.encode('ascii'), - message.encode('ascii')) + self.settings.mqtt.publish(topic.encode('ascii'), message.encode('ascii')) if __name__ == '__main__': @@ -167,9 +195,7 @@ """) verboseLogging(arg['-v']) - mqtt = MqttClient(clientId='rdf_to_mqtt', - brokerHost='mosquitto-ext.default.svc.cluster.local', - brokerPort=1883) + mqtt = MqttClient(clientId='rdf_to_mqtt', brokerHost='mosquitto-ext.default.svc.cluster.local', brokerPort=1883) port = 10008 reactor.listenTCP(port,
--- a/service/rdf_to_mqtt/requirements.txt Sat Aug 08 13:14:49 2020 -0700 +++ b/service/rdf_to_mqtt/requirements.txt Sat Aug 08 13:56:39 2020 -0700 @@ -4,6 +4,7 @@ twisted-mqtt==0.3.6 rx==1.6.1 git+http://github.com/drewp/scales.git@448d59fb491b7631877528e7695a93553bfaaa93#egg=scales +docopt cycloneerr patchablegraph==0.11.0