pflanzen-box/code/lib/homie/property.py
2021-01-17 12:10:21 +01:00

138 lines
3.8 KiB
Python

import uasyncio as asyncio
from homie.constants import STRING, T_SET, TRUE, FALSE
from homie.validator import payload_is_valid
class BaseProperty:
def __init__(
self,
id,
name=None,
settable=False,
retained=True,
unit=None,
datatype=STRING,
format=None,
default=None,
restore=True,
on_message=None,
):
self._value = default
self.id = id
self.name = name
self.settable = settable
self.retained = retained
self.unit = unit
self.datatype = datatype
self.format = format
self.restore = restore
self.on_message = on_message
self.topic = None
self.node = None
# Keep for backward compatibility
@property
def data(self):
return self._value
# Keep for backward compatibility
@data.setter
def data(self, value):
self.value = value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
""" Set value if changed and publish to mqtt """
if value != self._value:
self._value = value
self.publish()
def set_topic(self):
self.topic = "{}/{}/{}".format(
self.node.device.dtopic,
self.node.id,
self.id
)
def publish(self):
asyncio.create_task(
self.node.device.publish(
self.topic,
self.value,
self.retained
)
)
async def subscribe(self):
# Restore from topic with retained message on device start
if self.restore and self.node.device.first_start is True:
self.node.device.callback_topics[self.topic] = self.restore_handler
await self.node.device.subscribe(self.topic)
# Subscribe to settable (/set) topics
if self.settable is True:
topic = "{}/set".format(self.topic)
self.node.device.callback_topics[topic] = self.message_handler
await self.node.device.subscribe(topic)
def restore_handler(self, topic, payload, retained):
""" Gets called when the property should be restored from mqtt """
# Retained messages are not allowed on /set topics
if topic.endswith(T_SET):
return
# Unsubscribe from topic and remove the callback handler
asyncio.create_task(self.node.device.unsubscribe(topic))
del self.node.device.callback_topics[topic]
if payload_is_valid(self, payload):
if payload != self._value:
if self.on_message:
self.on_message(topic, payload, retained)
self._value = payload
def message_handler(self, topic, payload, retained):
""" Gets called when the property receive a message on /set topic """
# No reatained messages allowed on /set topics
if retained:
return
if payload_is_valid(self, payload):
if self.on_message:
self.on_message(topic, payload, retained)
self.value = payload
async def publish_properties(self):
topic = self.topic
publish = self.node.device.publish
await publish("{}/$name".format(topic), self.name)
await publish("{}/$datatype".format(topic), self.datatype)
if self.format is not None:
await publish("{}/$format".format(topic), self.format)
if self.settable is True:
await publish("{}/$settable".format(topic), TRUE)
if self.retained is False:
await publish("{}/$retained".format(topic), FALSE)
if self.unit is not None:
await publish("{}/$unit".format(topic), self.unit)
HomieProperty = BaseProperty
# Keep for backward compatibility
HomieNodeProperty = BaseProperty