diff --git a/src/citadel/scene/__init__.py b/src/citadel/scene/__init__.py index d5c36c8..9d33e2a 100644 --- a/src/citadel/scene/__init__.py +++ b/src/citadel/scene/__init__.py @@ -167,6 +167,58 @@ class Scene(threading.Thread, mqtt.Client): qos=2, retain=False) +class WaitForTopic(threading.Thread, mqtt.Client): + + def __init__(self, + config: Configuration, + topic: str, + payload: str=None, + logger: logging.Logger=None): + + threading.Thread.__init__(self) + mqtt.Client.__init__(self) + + self.configuration = config + + self.topic = topic + self.payload = payload + + self.daemon = True + + if not logger: + logger = logging.getLogger('watcher') + self.logger = logger + + self.__run = True + + self.username_pw_set(self.configuration.user, + self.configuration.password) + self.connect(self.configuration.host, + self.configuration.port) + + self.subscribe(self.topic, 1) + + self.start() + + def on_message(self, mqttc, obj, msg): + payload = msg.payload.decode() + topic = msg.topic + self.logger.info('Topic: %s, Payload: %s', topic, payload) + + if topic != self.topic: + self.logger.error('Invaliad topic: %s', topic) + return + + if self.payload and payload != self.payload: + return + + self.__run = False + + def run(self): + while self.__run: + self.loop() + self.disconnect() + class Action(object): SUCCESS = 0 FAILED = 1 @@ -196,6 +248,8 @@ class Publish(Action): self.payload = '' self.qos = 0 + self.check_response = None + def Payload(self, payload): self.payload = payload return self @@ -204,16 +258,47 @@ class Publish(Action): self.qos = qos return self + def CheckResponse(self, topic: str, payload: str=None, timeout: int=None): + self.check_response= {'topic': topic, 'payload':payload, 'timeout': timeout} + return self + def run(self): + checker = None + if self.check_response: + checker = WaitForTopic(self.proxy.configuration, + self.check_response['topic'], + self.check_response['payload']) + self.proxy.threaded_publish(self.topic, payload=self.payload, qos=self.qos, retain=False) + + if self.check_response: + checker.join(timeout=self.check_response['timeout']) + if checker.is_alive(): #timeout occur + return self.failed() + return self.ok() +class Shutter(Action): + + def __init__(self, shutter_name: str): + Action.__init__(self) + pass + + def Close(self): + return self + + def Open(self): + return self + + def run(self): + return self.ok() class Sleep(Scene): ON = [ - Publish('cmnd/tasmota/screen/Screen/POWER').Payload('OFF').Qos(2), + Publish('cmnd/tasmota/screen/Screen/POWER').Payload('OFF').Qos(2)\ + .CheckResponse('stat/tasmota/screen/Screen/POWER', 'OFF', 3), Publish('cmnd/tasmota/light/LivingroomFireplace/POWER').Payload('OFF').Qos(2), ]