From bb0d7e02de64a21549aba0bd5cbeaf39846c780c Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Mon, 5 Dec 2016 13:28:16 +0100 Subject: [PATCH] Update to Homie v2 --- main.py | 85 +++++++++++++++++++++------- templates/endpoints/output.html | 5 ++ templates/endpoints/temperature.html | 4 ++ templates/index.html | 18 +++--- 4 files changed, 80 insertions(+), 32 deletions(-) create mode 100644 templates/endpoints/output.html create mode 100644 templates/endpoints/temperature.html diff --git a/main.py b/main.py index c9d1ae3..b066af2 100644 --- a/main.py +++ b/main.py @@ -2,17 +2,23 @@ import flask import paho.mqtt.client as mqtt import logging import json +from collections import defaultdict logging.basicConfig(level=logging.DEBUG, format='[%(asctime)-15s] %(name)-10s %(levelname)7s: %(message)s') class SpejsiotDevice(object): - metadata = None - online = False node_id = None + properties = None + endpoints = None def __init__(self, node_id): self.node_id = node_id + self.properties = {} + self.endpoints = defaultdict(dict) + + def dictify(self): + return dict(self.properties, **self.endpoints) class SpejsiotManager(mqtt.Client): @@ -28,44 +34,79 @@ class SpejsiotManager(mqtt.Client): def on_connect(self, client, userdata, flags, rc): self.logger.info('Connected, rc: %d', rc) - self.subscribe('iot/+/state') - self.subscribe('iot/+/metadata') + self.subscribe('iot/+/+') + self.subscribe('iot/+/+/+') def on_message(self, client, userdata, msg): - self.logger.info('Message received %s: %s', msg.topic, msg.payload) - _, node_id, topic = msg.topic.split('/', 2) + try: + self.logger.info('Message received %s: %s', msg.topic, msg.payload) + _, node_id, topic = msg.topic.split('/', 2) - if node_id not in self.devices.keys(): - self.devices[node_id] = SpejsiotDevice(node_id) + if node_id not in self.devices.keys(): + self.devices[node_id] = SpejsiotDevice(node_id) - if topic == 'state': - self.devices[node_id].online = msg.payload == 'online' - elif topic == 'metadata': - metadata = json.loads(msg.payload) - self.devices[node_id].metadata = metadata - self.devices[node_id].endpoints = { - e['name']: {'type': e['type'], 'value': None} - for e in metadata['endpoints'] - } + if topic.startswith('$'): + self.devices[node_id].properties[topic] = msg.payload + else: + endpoint, prop = topic.split('/', 1) + self.devices[node_id].endpoints[endpoint][prop] = msg.payload - for e in self.devices[node_id].endpoints.keys(): - self.subscribe('iot/%s/%s' % (node_id, e)) + print(topic) + except: + self.logger.exception('fuckup') - elif topic in self.devices[node_id].endpoints: - self.devices[node_id].endpoints[topic]['value'] = msg.payload + def handle_request(self, node_id, endpoint, prop, value): + self.publish('iot/%s/%s/%s/set' % (node_id, endpoint, prop), value, retain=True) + return True manager = SpejsiotManager() app = flask.Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True + +class EndpointRenderer(object): + @classmethod + def render(cls, device, endpoint): + return '' + + +class DefaultRenderer(EndpointRenderer): + @classmethod + def render(cls, device, endpoint): + return flask.Markup(flask.render_template( + 'endpoints/%s.html' % endpoint.get('$type'), + endpoint=endpoint, device=device)) + + +endpoint_renderers = { + None: DefaultRenderer + } + + +@app.context_processor +def utility_processor(): + def render_endpoint(device, endpoint): + t = endpoint.get('$type', None) + if t in endpoint_renderers: + return endpoint_renderers[t].render(device, endpoint) + else: + return endpoint_renderers[None].render(device, endpoint) + return { + 'render_endpoint': render_endpoint, + } + @app.route('/') def index(): return flask.render_template('index.html', devices=manager.devices) @app.route('/api/1/devices') def api_devices(): - return flask.jsonify({k: v.metadata for k, v in manager.devices.items()}) + return flask.jsonify({k: v.dictify() for k, v in manager.devices.items()}) + +@app.route('/api/1/device////') +def device_write(node_id, endpoint, prop, value): + return flask.jsonify(manager.handle_request(node_id, endpoint, prop, value)) if __name__ == "__main__": diff --git a/templates/endpoints/output.html b/templates/endpoints/output.html new file mode 100644 index 0000000..e3b5fdf --- /dev/null +++ b/templates/endpoints/output.html @@ -0,0 +1,5 @@ +{% if endpoint['on'] == 'true' %} + +{% else %} + +{% endif %} diff --git a/templates/endpoints/temperature.html b/templates/endpoints/temperature.html new file mode 100644 index 0000000..59a8f22 --- /dev/null +++ b/templates/endpoints/temperature.html @@ -0,0 +1,4 @@ +

{{ endpoint['degrees'] }}°{{ endpoint.get('unit', 'C') }}

+{% if endpoint['humidity'] %} +{{ endpoint['humidity'] }}% RH +{% endif %} diff --git a/templates/index.html b/templates/index.html index b9adc54..e98db2c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -18,18 +18,16 @@
{% for name, dev in devices.items() %} {% for name, obj in dev.endpoints.items() %} - {% if obj['type'] != 'control' %} -
-
-
-

{{ dev.node_id }} / {{ dev.metadata['device_type'] }} {{ name }}

-
-
-

{{ obj['value'] }}unit

-
+
+
+
+

{{ dev.node_id }} / {{ dev.properties['$name'] }} {{ name }}

+
+
+ {{ render_endpoint(dev, obj) }}
- {% endif %} +
{% endfor %} {% endfor %}