spejsiot-mdc/spejsmdc.py

129 lines
4.1 KiB
Python

import paho.mqtt.client as mqtt
import serial
import mdc
import logging
import threading
import time
class SpejsIoTClient(mqtt.Client):
def __init__(self, device_id=None, name=None, *args, **kwargs):
super(SpejsIoTClient, self).__init__(*args, **kwargs)
self.logger = logging.getLogger(self.__class__.__name__)
self.endpoints = {}
self.device_id = device_id or 'testdevice'
self.name = name or self.device_id
@property
def topic_prefix(self):
return 'iot/{}/'.format(self.device_id)
def on_connect(self, client, userdata, flags, rc):
self.logger.info('Connected')
self.subscribe(self.topic_prefix + '+/+/set')
self.publish(self.topic_prefix + '$online', 'true')
self.publish(self.topic_prefix + '$name', self.name)
for name, e in self.endpoints.items():
self.notify(name, '$type', e._type)
def on_message(self, client, userdata, msg):
topic = msg.topic[len(self.topic_prefix):]
self.logger.info('mqtt -> %r %r', topic, msg.payload)
node, attrib, _ = topic.split('/')
self.logger.info('Got %r %r', node, attrib)
if node in self.endpoints:
self.logger.info('Passing to %r', self.endpoints[node])
try:
self.endpoints[node].process(attrib, msg.payload.decode())
except Exception:
self.logger.exception('Error occured')
def register_endpoint(self, name, cls):
self.endpoints[name] = cls()
self.endpoints[name].bind(self, name)
def run(self):
self.will_set(self.topic_prefix + '$online', 'false')
self.connect('iot.waw.hackerspace.pl')
self.loop_forever()
def notify(self, node, attribute, value, retain=True):
if type(value) in [int, float, bool]:
value = str(value).lower()
elif type(value) not in [str, bytes]:
value = str(value)
self.publish('{}{}/{}'.format(self.topic_prefix, node, attribute), value, retain=retain)
class SpejsIoTEndpoint(object):
def __init__(self, _type=None):
self._type = _type
self.logger = logging.getLogger(self.__class__.__name__)
def bind(self, parent, name):
self._name = name
self._parent = parent
def process(self, attribute, value):
pass
def notify(self, attribute, value):
self._parent.notify(self._name, attribute, value)
class MDCEndpoint(SpejsIoTEndpoint):
def __init__(self):
super(MDCEndpoint, self).__init__('mdc')
self.mdc = mdc.MDC('/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0', 9600, timeout=1.0)
self.lock = threading.Lock()
self.th = threading.Thread(target=self.poll_mdc)
self.th.daemon = True
self.th.start()
def poll_mdc(self):
state = None
while True:
try:
with self.lock:
new_state = {
'power': bool(self.mdc.request(0x11, [])[1][2]),
'mute': bool(self.mdc.request(0x13, [])[1][2])
}
for k in new_state.keys():
if state is None or state[k] != new_state[k]:
self.notify(k, new_state[k])
state = new_state
except:
self.logger.exception('oops?')
time.sleep(5)
def process(self, attribute, value):
with self.lock:
if attribute == 'power':
value = value in ['true', '1']
self.mdc.command(0x11, [1 if value else 0])
self.mdc.read_frame()
self.notify('power', value)
elif attribute == 'mute':
value = value in ['true', '1']
self.mdc.command(0x13, [1 if value else 0])
self.mdc.read_frame()
self.notify('mute', value)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
s = SpejsIoTClient('samsungtv')
s.register_endpoint('mdc', MDCEndpoint)
s.run()