Update to Homie v2

master
informatic 2016-12-05 13:28:16 +01:00
parent ec584a804b
commit bb0d7e02de
4 changed files with 80 additions and 32 deletions

85
main.py
View File

@ -2,17 +2,23 @@ import flask
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
import logging import logging
import json import json
from collections import defaultdict
logging.basicConfig(level=logging.DEBUG, format='[%(asctime)-15s] %(name)-10s %(levelname)7s: %(message)s') logging.basicConfig(level=logging.DEBUG, format='[%(asctime)-15s] %(name)-10s %(levelname)7s: %(message)s')
class SpejsiotDevice(object): class SpejsiotDevice(object):
metadata = None
online = False
node_id = None node_id = None
properties = None
endpoints = None
def __init__(self, node_id): def __init__(self, node_id):
self.node_id = 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): class SpejsiotManager(mqtt.Client):
@ -28,44 +34,79 @@ class SpejsiotManager(mqtt.Client):
def on_connect(self, client, userdata, flags, rc): def on_connect(self, client, userdata, flags, rc):
self.logger.info('Connected, rc: %d', rc) self.logger.info('Connected, rc: %d', rc)
self.subscribe('iot/+/state') self.subscribe('iot/+/+')
self.subscribe('iot/+/metadata') self.subscribe('iot/+/+/+')
def on_message(self, client, userdata, msg): def on_message(self, client, userdata, msg):
self.logger.info('Message received %s: %s', msg.topic, msg.payload) try:
_, node_id, topic = msg.topic.split('/', 2) 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(): if node_id not in self.devices.keys():
self.devices[node_id] = SpejsiotDevice(node_id) self.devices[node_id] = SpejsiotDevice(node_id)
if topic == 'state': if topic.startswith('$'):
self.devices[node_id].online = msg.payload == 'online' self.devices[node_id].properties[topic] = msg.payload
elif topic == 'metadata': else:
metadata = json.loads(msg.payload) endpoint, prop = topic.split('/', 1)
self.devices[node_id].metadata = metadata self.devices[node_id].endpoints[endpoint][prop] = msg.payload
self.devices[node_id].endpoints = {
e['name']: {'type': e['type'], 'value': None}
for e in metadata['endpoints']
}
for e in self.devices[node_id].endpoints.keys(): print(topic)
self.subscribe('iot/%s/%s' % (node_id, e)) except:
self.logger.exception('fuckup')
elif topic in self.devices[node_id].endpoints: def handle_request(self, node_id, endpoint, prop, value):
self.devices[node_id].endpoints[topic]['value'] = msg.payload self.publish('iot/%s/%s/%s/set' % (node_id, endpoint, prop), value, retain=True)
return True
manager = SpejsiotManager() manager = SpejsiotManager()
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True 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('/') @app.route('/')
def index(): def index():
return flask.render_template('index.html', devices=manager.devices) return flask.render_template('index.html', devices=manager.devices)
@app.route('/api/1/devices') @app.route('/api/1/devices')
def api_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/<node_id>/<endpoint>/<prop>/<value>')
def device_write(node_id, endpoint, prop, value):
return flask.jsonify(manager.handle_request(node_id, endpoint, prop, value))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -0,0 +1,5 @@
{% if endpoint['on'] == 'true' %}
<button class="btn btn-success btn-lg">ON</button>
{% else %}
<button class="btn btn-dange btn-lg">OFF</button>
{% endif %}

View File

@ -0,0 +1,4 @@
<h1>{{ endpoint['degrees'] }}<small>°{{ endpoint.get('unit', 'C') }}</small></h1>
{% if endpoint['humidity'] %}
<small>{{ endpoint['humidity'] }}% RH</small>
{% endif %}

View File

@ -18,18 +18,16 @@
<div class="container"> <div class="container">
{% for name, dev in devices.items() %} {% for name, dev in devices.items() %}
{% for name, obj in dev.endpoints.items() %} {% for name, obj in dev.endpoints.items() %}
{% if obj['type'] != 'control' %} <div class="col-md-3">
<div class="col-md-3"> <div class="panel {% if dev.online %}panel-primary{% else %}panel-default{% endif %}">
<div class="panel {% if dev.online %}panel-primary{% else %}panel-default{% endif %}"> <div class="panel-heading">
<div class="panel-heading"> <h3 class="panel-title"><small>{{ dev.node_id }} / {{ dev.properties['$name'] }}</small> {{ name }}</h3>
<h3 class="panel-title"><small>{{ dev.node_id }} / {{ dev.metadata['device_type'] }}</small> {{ name }}</h3> </div>
</div> <div class="panel-body" style="text-align:center">
<div class="panel-body"> {{ render_endpoint(dev, obj) }}
<h1>{{ obj['value'] }}<small>unit</small></h1>
</div>
</div> </div>
</div> </div>
{% endif %} </div>
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
</div> </div>