105 lines
3.9 KiB
Python
105 lines
3.9 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
#
|
||
|
from base import mqtt_base
|
||
|
from base import videv_base
|
||
|
import json
|
||
|
|
||
|
BATTERY_WARN_LEVEL = 10
|
||
|
|
||
|
|
||
|
def is_json(data):
|
||
|
try:
|
||
|
json.loads(data)
|
||
|
except json.decoder.JSONDecodeError:
|
||
|
return False
|
||
|
else:
|
||
|
return True
|
||
|
|
||
|
|
||
|
class base(mqtt_base):
|
||
|
TX_TOPIC = "set"
|
||
|
TX_VALUE = 0
|
||
|
TX_DICT = 1
|
||
|
TX_TYPE = -1
|
||
|
TX_FILTER_DATA_KEYS = []
|
||
|
#
|
||
|
RX_KEYS = []
|
||
|
RX_IGNORE_TOPICS = []
|
||
|
RX_IGNORE_KEYS = []
|
||
|
RX_FILTER_DATA_KEYS = []
|
||
|
#
|
||
|
KEY_WARNING = '__WARNING__'
|
||
|
|
||
|
def __init__(self, mqtt_client, topic):
|
||
|
super().__init__(mqtt_client, topic, default_values=dict.fromkeys(self.RX_KEYS + [self.KEY_WARNING]))
|
||
|
# data storage
|
||
|
# initialisations
|
||
|
mqtt_client.add_callback(topic=self.topic, callback=self.receive_callback)
|
||
|
mqtt_client.add_callback(topic=self.topic+"/#", callback=self.receive_callback)
|
||
|
|
||
|
def set(self, key, data, block_callback=[]):
|
||
|
if key in self.RX_IGNORE_KEYS:
|
||
|
pass # ignore these keys
|
||
|
elif key in self.RX_KEYS or key == self.KEY_WARNING:
|
||
|
return super().set(key, data, block_callback)
|
||
|
else:
|
||
|
self.logger.warning("Unexpected key %s", key)
|
||
|
|
||
|
def receive_callback(self, client, userdata, message):
|
||
|
if message.topic != self.topic + '/' + videv_base.KEY_INFO:
|
||
|
content_key = message.topic[len(self.topic) + 1:]
|
||
|
if content_key not in self.RX_IGNORE_TOPICS and (not message.topic.endswith(self.TX_TOPIC) or len(self.TX_TOPIC) == 0):
|
||
|
self.logger.debug("Unpacking content_key \"%s\" from message.", content_key)
|
||
|
if is_json(message.payload):
|
||
|
data = json.loads(message.payload)
|
||
|
if type(data) is dict:
|
||
|
for key in data:
|
||
|
self.set(key, self.__device_to_instance_filter__(key, data[key]))
|
||
|
else:
|
||
|
self.set(content_key, self.__device_to_instance_filter__(content_key, data))
|
||
|
# String
|
||
|
else:
|
||
|
self.set(content_key, self.__device_to_instance_filter__(content_key, message.payload.decode('utf-8')))
|
||
|
else:
|
||
|
self.logger.debug("Ignoring topic %s", content_key)
|
||
|
|
||
|
def __device_to_instance_filter__(self, key, data):
|
||
|
if key in self.RX_FILTER_DATA_KEYS:
|
||
|
if data in [1, 'on', 'ON']:
|
||
|
return True
|
||
|
elif data in [0, 'off', 'OFF']:
|
||
|
return False
|
||
|
return data
|
||
|
|
||
|
def __instance_to_device_filter__(self, key, data):
|
||
|
if key in self.TX_FILTER_DATA_KEYS:
|
||
|
if data is True:
|
||
|
return "on"
|
||
|
elif data is False:
|
||
|
return "off"
|
||
|
return data
|
||
|
|
||
|
def send_command(self, key, data):
|
||
|
data = self.__instance_to_device_filter__(key, data)
|
||
|
if self.TX_TOPIC is not None:
|
||
|
if self.TX_TYPE < 0:
|
||
|
self.logger.error("Unknown tx type. Set TX_TYPE of class to a known value")
|
||
|
else:
|
||
|
self.logger.debug("Sending data for %s - %s", key, str(data))
|
||
|
if self.TX_TYPE == self.TX_DICT:
|
||
|
try:
|
||
|
self.mqtt_client.send('/'.join([self.topic, self.TX_TOPIC]), json.dumps({key: data}))
|
||
|
except TypeError:
|
||
|
print(self.topic)
|
||
|
print(key.__dict__)
|
||
|
print(key)
|
||
|
print(data)
|
||
|
raise TypeError
|
||
|
else:
|
||
|
if type(data) not in [str, bytes]:
|
||
|
data = json.dumps(data)
|
||
|
self.mqtt_client.send('/'.join([self.topic, key, self.TX_TOPIC] if len(self.TX_TOPIC) > 0 else [self.topic, key]), data)
|
||
|
else:
|
||
|
self.logger.error("Unknown tx toptic. Set TX_TOPIC of class to a known value")
|