This commit is contained in:
parent
7e4094d6aa
commit
3f5b4bedee
@ -7,6 +7,7 @@ class Light:
|
|||||||
def __init__(self, _id: str, client: Client, **kwargs):
|
def __init__(self, _id: str, client: Client, **kwargs):
|
||||||
self._state = None
|
self._state = None
|
||||||
self._change_callback = None
|
self._change_callback = None
|
||||||
|
self._available = False
|
||||||
|
|
||||||
self._id = _id
|
self._id = _id
|
||||||
|
|
||||||
@ -18,12 +19,28 @@ class Light:
|
|||||||
self.CMND_ON_PAYLOAD = kwargs.get('CMND_ON_PAYLOAD', 'ON')
|
self.CMND_ON_PAYLOAD = kwargs.get('CMND_ON_PAYLOAD', 'ON')
|
||||||
self.CMND_OFF_PAYLOAD = kwargs.get('CMND_OFF_PAYLOAD', 'OFF')
|
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 = client
|
||||||
self._client.subscribe_callback(self.STATE_TOPIC.format(id=self.id), self.onStateChange)
|
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):
|
def setChangeCallback(self, callback: typing.Callable):
|
||||||
self._change_callback = callback
|
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):
|
def onStateChange(self, client, userdata, msg):
|
||||||
state = msg.payload.decode()
|
state = msg.payload.decode()
|
||||||
|
|
||||||
@ -47,6 +64,10 @@ class Light:
|
|||||||
def state(self):
|
def state(self):
|
||||||
return self._state
|
return self._state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
return self._available
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self._id
|
return self._id
|
||||||
@ -58,7 +79,7 @@ class LightsGroup:
|
|||||||
""" Create a virtual mqtt device that handle multiple light """
|
""" Create a virtual mqtt device that handle multiple light """
|
||||||
self._id = _id
|
self._id = _id
|
||||||
self._lights = lights
|
self._lights = lights
|
||||||
|
|
||||||
for l in self._lights:
|
for l in self._lights:
|
||||||
l.setChangeCallback(self.onLightStateChange)
|
l.setChangeCallback(self.onLightStateChange)
|
||||||
|
|
||||||
@ -66,6 +87,12 @@ class LightsGroup:
|
|||||||
self._client.subscribe_callback('cmnd/devices/light/%s/POWER' % self._id, self.cmndPower)
|
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_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):
|
def cmndPower(self, client, userdata, msg):
|
||||||
value = msg.payload.decode()
|
value = msg.payload.decode()
|
||||||
@ -79,11 +106,16 @@ class LightsGroup:
|
|||||||
raise Exception("Unexpected value %s for stat topic" % value)
|
raise Exception("Unexpected value %s for stat topic" % value)
|
||||||
|
|
||||||
def onLightStateChange(self, light):
|
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])
|
state = all([l.state for l in self._lights])
|
||||||
if state != self._previous_state:
|
if state != self._previous_state:
|
||||||
self._client.publish('stat/devices/light/%s/POWER' % self.id, 'ON' if state else 'OFF')
|
self._client.publish('stat/devices/light/%s/POWER' % self.id, 'ON' if state else 'OFF')
|
||||||
self._previous_state = state
|
self._previous_state = state
|
||||||
|
|
||||||
def on(self):
|
def on(self):
|
||||||
for l in self._lights:
|
for l in self._lights:
|
||||||
l.on()
|
l.on()
|
||||||
@ -95,7 +127,7 @@ class LightsGroup:
|
|||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
return self._previous_state
|
return self._previous_state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self._id
|
return self._id
|
||||||
|
@ -36,7 +36,6 @@ def main(\
|
|||||||
STATE_TOPIC='stat/tasmota/light/{id}/POWER2',
|
STATE_TOPIC='stat/tasmota/light/{id}/POWER2',
|
||||||
CMND_TOPIC='cmnd/tasmota/light/{id}/POWER2')])
|
CMND_TOPIC='cmnd/tasmota/light/{id}/POWER2')])
|
||||||
|
|
||||||
client.loop_forever()
|
|
||||||
|
|
||||||
if is_systemd:
|
if is_systemd:
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
@ -55,5 +54,7 @@ def main(\
|
|||||||
# add ch to logger
|
# add ch to logger
|
||||||
logger.addHandler(ch)
|
logger.addHandler(ch)
|
||||||
|
|
||||||
|
client.loop_forever()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
typer.run(main)
|
typer.run(main)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user