Watch state change
This commit is contained in:
parent
cb03c12d16
commit
b9fd9c40ae
@ -1,18 +1,44 @@
|
|||||||
from .action import Action, Publish, TasmotaShutter
|
import json
|
||||||
|
|
||||||
from .scene import Scene
|
from .scene import Scene
|
||||||
|
from .action import Publish, TasmotaShutter
|
||||||
|
from .watch import Watch
|
||||||
|
|
||||||
class Sleep(Scene):
|
class Sleep(Scene):
|
||||||
|
|
||||||
ON = [
|
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),
|
.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('Bedroom1x1').Close(),
|
||||||
TasmotaShutter('Bedroom1x2').Close(),
|
TasmotaShutter('Bedroom1x2').Close(),
|
||||||
TasmotaShutter('Staircase1').Close(),
|
TasmotaShutter('Staircase1').Close(),
|
||||||
TasmotaShutter('Bathroom').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 = [
|
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),
|
||||||
]
|
]
|
||||||
|
@ -8,10 +8,10 @@ from citadel.mqtt import Configuration
|
|||||||
from . import Sleep
|
from . import Sleep
|
||||||
|
|
||||||
def main(\
|
def main(\
|
||||||
mqtt_user: str = typer.Option(... , envvar="DEVICES_MQTT_USER"),\
|
mqtt_user: str = typer.Option(... , envvar="SCENE_MQTT_USER"),\
|
||||||
mqtt_pwd: str = typer.Option(... , envvar="DEVICES_MQTT_PWD"),\
|
mqtt_pwd: str = typer.Option(... , envvar="SCENE_MQTT_PWD"),\
|
||||||
mqtt_host: str = typer.Option(... , envvar="DEVICES_MQTT_HOST"),\
|
mqtt_host: str = typer.Option(... , envvar="SCENE_MQTT_HOST"),\
|
||||||
mqtt_port: int = typer.Option(... , envvar="DEVICES_MQTT_PORT"),\
|
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")\
|
is_systemd: bool = typer.Option(False, help="Is running as systemd unit", envvar="LAUNCHED_BY_SYSTEMD")\
|
||||||
):
|
):
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import paho.mqtt.client as mqtt
|
|||||||
from citadel.mqtt import Configuration
|
from citadel.mqtt import Configuration
|
||||||
|
|
||||||
from .action import Action
|
from .action import Action
|
||||||
|
from .watch import Watch
|
||||||
|
|
||||||
class Scene(threading.Thread, mqtt.Client):
|
class Scene(threading.Thread, mqtt.Client):
|
||||||
""" A scene run as a thread, has his own mqtt session
|
""" 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)
|
logger = logging.getLogger('scene.%s' % self.mqtt_name)
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
|
# we need a queue for publishing message from different thread
|
||||||
self.__pub_queue = queue.Queue()
|
self.__pub_queue = queue.Queue()
|
||||||
self.__state = Scene.STATE_DEACTIVATE
|
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)
|
self.subscribe(self.TOPIC_CMND.format(mqtt_name=self.mqtt_name), 2)
|
||||||
|
|
||||||
for watch in self.WATCH:
|
for watch in self.WATCH:
|
||||||
self.subscribe(watch[0], 1)
|
self.subscribe(watch.topic, 1)
|
||||||
|
|
||||||
run = True
|
run = True
|
||||||
while run:
|
while run:
|
||||||
#Mqtt client loop
|
|
||||||
self.loop()
|
|
||||||
|
|
||||||
#Check publish queue
|
#Check publish queue
|
||||||
try:
|
try:
|
||||||
(args, kwargs) = self.__pub_queue.get(block=False)
|
(args, kwargs) = self.__pub_queue.get(block=False)
|
||||||
@ -104,20 +103,23 @@ class Scene(threading.Thread, mqtt.Client):
|
|||||||
self.__state = Scene.STATE_ACTIVATE
|
self.__state = Scene.STATE_ACTIVATE
|
||||||
self.__send_state()
|
self.__send_state()
|
||||||
|
|
||||||
|
#Mqtt client loop
|
||||||
|
self.loop()
|
||||||
|
|
||||||
|
|
||||||
def threaded_publish(self, *args, **kwargs):
|
def threaded_publish(self, *args, **kwargs):
|
||||||
self.__pub_queue.put((args, kwargs))
|
self.__pub_queue.put((args, kwargs))
|
||||||
|
|
||||||
def on_message(self, mqttc, obj, msg):
|
def on_message(self, mqttc, obj, msg):
|
||||||
payload = msg.payload.decode().lower()
|
payload = msg.payload.decode()
|
||||||
topic = msg.topic
|
topic = msg.topic
|
||||||
|
|
||||||
# on CMND
|
# on CMND
|
||||||
if topic == self.TOPIC_CMND.format(mqtt_name=self.mqtt_name):
|
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.logger.info('CMND activate ON')
|
||||||
self.__activate()
|
self.__activate()
|
||||||
elif payload == 'off':
|
elif payload.lower() == 'off':
|
||||||
self.logger.info('CMND activate OFF')
|
self.logger.info('CMND activate OFF')
|
||||||
self.__deactivate()
|
self.__deactivate()
|
||||||
elif payload == '':
|
elif payload == '':
|
||||||
@ -126,18 +128,12 @@ class Scene(threading.Thread, mqtt.Client):
|
|||||||
else:
|
else:
|
||||||
self.logger.warn('CMND activate invalide')
|
self.logger.warn('CMND activate invalide')
|
||||||
|
|
||||||
elif self.scene_state and self.__check_watched(topic, payload):
|
elif self.scene_state == Scene.STATE_ACTIVATE:
|
||||||
self.logger.info('Watched topic %s with invalid payload %s deactivating', topic, payload)
|
for watch in self.WATCH:
|
||||||
self.__deactivate()
|
if topic == watch.topic and not watch.check(topic, payload):
|
||||||
|
self.logger.info('Watched topic %s with invalid payload %s deactivating', topic, payload)
|
||||||
def __check_watched(self, topic, payload):
|
self.__deactivate()
|
||||||
""" return True if is a watched topic with an invalid payload """
|
break
|
||||||
for watch in self.WATCH:
|
|
||||||
if topic == watch[0]:
|
|
||||||
if payload != watch[1].lower():
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __activate(self):
|
def __activate(self):
|
||||||
if self.scene_state:
|
if self.scene_state:
|
||||||
|
23
src/citadel/scene/watch.py
Normal file
23
src/citadel/scene/watch.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user