Watch state change

This commit is contained in:
Nicolas Duhamel 2021-04-02 11:16:39 +02:00
parent cb03c12d16
commit b9fd9c40ae
4 changed files with 72 additions and 27 deletions

View File

@ -1,18 +1,44 @@
from .action import Action, Publish, TasmotaShutter
import json
from .scene import Scene
from .action import Publish, TasmotaShutter
from .watch import Watch
class Sleep(Scene):
ON = [
Publish('cmnd/tasmota/screen/Screen/POWER').Payload('OFF').Qos(2)\
Publish('cmnd/tasmota/screen/Screen/POWER').Payload('OFF').Qos(1)\
.CheckResponse('stat/tasmota/screen/Screen/POWER', 'OFF', 3),
Publish('cmnd/tasmota/light/LivingroomFireplace/POWER').Payload('OFF').Qos(2),
Publish('cmnd/tasmota/light/LivingroomFireplace/POWER').Payload('OFF').Qos(1),
#Shutter
TasmotaShutter('Bedroom1x1').Close(),
TasmotaShutter('Bedroom1x2').Close(),
TasmotaShutter('Staircase1').Close(),
TasmotaShutter('Bathroom').Close(),
#Chambre
Publish('zwave2mqtt/7/67/1/1/set').Payload('17').Qos(1)\
.CheckResponse('zwave2mqtt/7/67/1/1', lambda p: json.loads(p)['value'] == 17, 3),
#RdC
Publish('zwave2mqtt/6/67/1/1/set').Payload('19').Qos(1)\
.CheckResponse('zwave2mqtt/6/67/1/1', lambda p: json.loads(p)['value'] == 19, 3),
Publish('zwave2mqtt/5/67/1/1/set').Payload('19').Qos(1)\
.CheckResponse('zwave2mqtt/5/67/1/1', lambda p: json.loads(p)['value'] == 19, 3),
]
WATCH = [
('stat/tasmota/screen/Screen/POWER', 'OFF')
#HomeCinema
Watch('stat/tasmota/screen/Screen/POWER', 'OFF'),
#Lights
Watch('stat/tasmota/light/LivingroomFireplace/POWER', 'OFF'),
#Shutter
Watch('cmnd/tasmota/shutter/Bedroom1x1/ShutterOpen'),
Watch('cmnd/tasmota/shutter/Bedroom1x2/ShutterOpen'),
Watch('cmnd/tasmota/shutter/Staircase1/ShutterOpen'),
Watch('cmnd/tasmota/shutter/Bathroom/ShutterOpen'),
#Thermostat
Watch('zwave2mqtt/7/67/1/1', lambda p: json.loads(p)['value'] == 17),
Watch('zwave2mqtt/6/67/1/1', lambda p: json.loads(p)['value'] == 19),
Watch('zwave2mqtt/5/67/1/1', lambda p: json.loads(p)['value'] == 19),
]

View File

@ -8,10 +8,10 @@ from citadel.mqtt import Configuration
from . import Sleep
def main(\
mqtt_user: str = typer.Option(... , envvar="DEVICES_MQTT_USER"),\
mqtt_pwd: str = typer.Option(... , envvar="DEVICES_MQTT_PWD"),\
mqtt_host: str = typer.Option(... , envvar="DEVICES_MQTT_HOST"),\
mqtt_port: int = typer.Option(... , envvar="DEVICES_MQTT_PORT"),\
mqtt_user: str = typer.Option(... , envvar="SCENE_MQTT_USER"),\
mqtt_pwd: str = typer.Option(... , envvar="SCENE_MQTT_PWD"),\
mqtt_host: str = typer.Option(... , envvar="SCENE_MQTT_HOST"),\
mqtt_port: int = typer.Option(... , envvar="SCENE_MQTT_PORT"),\
is_systemd: bool = typer.Option(False, help="Is running as systemd unit", envvar="LAUNCHED_BY_SYSTEMD")\
):

View File

@ -10,6 +10,7 @@ import paho.mqtt.client as mqtt
from citadel.mqtt import Configuration
from .action import Action
from .watch import Watch
class Scene(threading.Thread, mqtt.Client):
""" A scene run as a thread, has his own mqtt session
@ -47,6 +48,7 @@ class Scene(threading.Thread, mqtt.Client):
logger = logging.getLogger('scene.%s' % self.mqtt_name)
self.logger = logger
# we need a queue for publishing message from different thread
self.__pub_queue = queue.Queue()
self.__state = Scene.STATE_DEACTIVATE
@ -66,13 +68,10 @@ class Scene(threading.Thread, mqtt.Client):
self.subscribe(self.TOPIC_CMND.format(mqtt_name=self.mqtt_name), 2)
for watch in self.WATCH:
self.subscribe(watch[0], 1)
self.subscribe(watch.topic, 1)
run = True
while run:
#Mqtt client loop
self.loop()
#Check publish queue
try:
(args, kwargs) = self.__pub_queue.get(block=False)
@ -104,20 +103,23 @@ class Scene(threading.Thread, mqtt.Client):
self.__state = Scene.STATE_ACTIVATE
self.__send_state()
#Mqtt client loop
self.loop()
def threaded_publish(self, *args, **kwargs):
self.__pub_queue.put((args, kwargs))
def on_message(self, mqttc, obj, msg):
payload = msg.payload.decode().lower()
payload = msg.payload.decode()
topic = msg.topic
# on CMND
if topic == self.TOPIC_CMND.format(mqtt_name=self.mqtt_name):
if payload == 'on':
if payload.lower() == 'on':
self.logger.info('CMND activate ON')
self.__activate()
elif payload == 'off':
elif payload.lower() == 'off':
self.logger.info('CMND activate OFF')
self.__deactivate()
elif payload == '':
@ -126,18 +128,12 @@ class Scene(threading.Thread, mqtt.Client):
else:
self.logger.warn('CMND activate invalide')
elif self.scene_state and self.__check_watched(topic, payload):
self.logger.info('Watched topic %s with invalid payload %s deactivating', topic, payload)
self.__deactivate()
def __check_watched(self, topic, payload):
""" return True if is a watched topic with an invalid payload """
for watch in self.WATCH:
if topic == watch[0]:
if payload != watch[1].lower():
return True
return False
return False
elif self.scene_state == Scene.STATE_ACTIVATE:
for watch in self.WATCH:
if topic == watch.topic and not watch.check(topic, payload):
self.logger.info('Watched topic %s with invalid payload %s deactivating', topic, payload)
self.__deactivate()
break
def __activate(self):
if self.scene_state:

View File

@ -0,0 +1,23 @@
from typing import Union, Callable
class Watch(object):
def __init__(self, topic: str, payload: Union[str, Callable[[str],bool]] = None):
self.__topic = topic
if callable(payload):
self.__check_payload = payload
elif payload == None:
self.__check_payload = lambda _: False
else:
self.__check_payload = lambda x: x == payload
@property
def topic(self) -> str:
return self.__topic
def check(self, topic: str, payload: str) -> bool:
if topic == self.topic and self.__check_payload(payload):
return True
else:
return False