This commit is contained in:
Nicolas Duhamel 2021-03-16 09:08:08 +01:00
parent 7e4094d6aa
commit 3f5b4bedee
2 changed files with 37 additions and 4 deletions
src/citadel/devices

@ -7,6 +7,7 @@ class Light:
def __init__(self, _id: str, client: Client, **kwargs):
self._state = None
self._change_callback = None
self._available = False
self._id = _id
@ -18,12 +19,28 @@ class Light:
self.CMND_ON_PAYLOAD = kwargs.get('CMND_ON_PAYLOAD', 'ON')
self.CMND_OFF_PAYLOAD = kwargs.get('CMND_OFF_PAYLOAD', 'OFF')
self.LWT_TOPIC = kwargs.get('LWT_TOPIC', 'tele/tasmota/light/{id}/LWT')
self._client = client
self._client.subscribe_callback(self.STATE_TOPIC.format(id=self.id), self.onStateChange)
self._client.subscribe_callback(self.LWT_TOPIC.format(id=self.id), self.onLWTChange)
def setChangeCallback(self, callback: typing.Callable):
self._change_callback = callback
def onLWTChange(self, client, userdata, msg):
state = msg.payload.decode()
if state == "Online":
self._available = True
elif state == "Offline":
self._available = False
self._state = False
else:
raise Exception("Unexpected value %s for LWT topic" % state)
if self._change_callback:
self._change_callback(self)
def onStateChange(self, client, userdata, msg):
state = msg.payload.decode()
@ -47,6 +64,10 @@ class Light:
def state(self):
return self._state
@property
def available(self):
return self._available
@property
def id(self):
return self._id
@ -58,7 +79,7 @@ class LightsGroup:
""" Create a virtual mqtt device that handle multiple light """
self._id = _id
self._lights = lights
for l in self._lights:
l.setChangeCallback(self.onLightStateChange)
@ -66,6 +87,12 @@ class LightsGroup:
self._client.subscribe_callback('cmnd/devices/light/%s/POWER' % self._id, self.cmndPower)
self._previous_state = all([l.state for l in self._lights])
self._previous_available = all([l.available for l in self._lights])
self._client.add_on_connect_callback(self.on_connect)
def on_connect(self, *args):
self._client.publish('stat/devices/light/%s/AVAILABLE' % self.id, 'TRUE' if self._previous_available else 'FALSE')
def cmndPower(self, client, userdata, msg):
value = msg.payload.decode()
@ -79,11 +106,16 @@ class LightsGroup:
raise Exception("Unexpected value %s for stat topic" % value)
def onLightStateChange(self, light):
available = all([l.available for l in self._lights])
if available != self._previous_available:
self._previous_available = available
self._client.publish('stat/devices/light/%s/AVAILABLE' % self.id, 'TRUE' if available else 'FALSE')
state = all([l.state for l in self._lights])
if state != self._previous_state:
self._client.publish('stat/devices/light/%s/POWER' % self.id, 'ON' if state else 'OFF')
self._previous_state = state
def on(self):
for l in self._lights:
l.on()
@ -95,7 +127,7 @@ class LightsGroup:
@property
def state(self):
return self._previous_state
@property
def id(self):
return self._id

@ -36,7 +36,6 @@ def main(\
STATE_TOPIC='stat/tasmota/light/{id}/POWER2',
CMND_TOPIC='cmnd/tasmota/light/{id}/POWER2')])
client.loop_forever()
if is_systemd:
logger = logging.getLogger('')
@ -55,5 +54,7 @@ def main(\
# add ch to logger
logger.addHandler(ch)
client.loop_forever()
if __name__ == "__main__":
typer.run(main)