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()