Initial commit
commit
07d20593af
|
@ -0,0 +1,46 @@
|
|||
import serial
|
||||
|
||||
BROADCAST = 0xfe
|
||||
|
||||
|
||||
class MDC(serial.Serial):
|
||||
def command(self, command, data=[], target_id=BROADCAST):
|
||||
if target_id == 0:
|
||||
target_id = 0xff
|
||||
|
||||
payload = bytearray([0xaa, command, target_id, len(data)] + data)
|
||||
|
||||
# Checksum
|
||||
payload.append(sum(payload[1:]) & 0xff)
|
||||
|
||||
self.write(payload)
|
||||
|
||||
def read_frame(self):
|
||||
payload = bytearray([])
|
||||
|
||||
payload.extend(self.read(4))
|
||||
if payload[0] != 0xaa:
|
||||
raise Exception('Invalid preamble %r' % payload[0])
|
||||
|
||||
if payload[1] != 0xff:
|
||||
raise Exception('Unexpected command field? %r' % command)
|
||||
|
||||
payload.extend(self.read(payload[3]))
|
||||
|
||||
checksum = ord(self.read(1))
|
||||
expected_checksum = sum(payload[1:]) & 0xff
|
||||
|
||||
if checksum != expected_checksum:
|
||||
raise Exception('Invalid checksum %r != %r' % (checksum, expected_checksum))
|
||||
|
||||
return payload[2], payload[4:]
|
||||
|
||||
def request(self, *args, **kwargs):
|
||||
self.command(*args, **kwargs)
|
||||
return self.read_frame()
|
||||
|
||||
if __name__ == '__main__':
|
||||
mdc = MDC('/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0', 9600)
|
||||
mdc.command(0x10, [])
|
||||
while True:
|
||||
print(mdc.read_frame())
|
|
@ -0,0 +1,128 @@
|
|||
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)
|
||||
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, unicode]:
|
||||
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()
|
Loading…
Reference in New Issue