WIP todo: timeout
This commit is contained in:
parent
98bfac1dc3
commit
c0446c8c7f
@ -2,6 +2,10 @@ import time
|
|||||||
import threading
|
import threading
|
||||||
import queue
|
import queue
|
||||||
import logging
|
import logging
|
||||||
|
from concurrent.futures import wait, ALL_COMPLETED
|
||||||
|
|
||||||
|
import pebble
|
||||||
|
|
||||||
|
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
@ -26,12 +30,15 @@ class Scene(threading.Thread, mqtt.Client):
|
|||||||
TOPIC_CMND = "cmnd/scene/{mqtt_name}/activate"
|
TOPIC_CMND = "cmnd/scene/{mqtt_name}/activate"
|
||||||
TOPIC_STAT = "stat/scene/{mqtt_name}/activate"
|
TOPIC_STAT = "stat/scene/{mqtt_name}/activate"
|
||||||
|
|
||||||
|
STATE_DEACTIVATE = 0
|
||||||
|
STATE_ACTIVATE = 1
|
||||||
|
STATE_ACTIVATING = 2
|
||||||
|
|
||||||
def __init__(self, config: Configuration, logger: logging.Logger=None):
|
def __init__(self, config: Configuration, logger: logging.Logger=None):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
mqtt.Client.__init__(self)
|
mqtt.Client.__init__(self)
|
||||||
|
|
||||||
self.configuration = config
|
self.configuration = config
|
||||||
self._scene_state = False
|
|
||||||
|
|
||||||
if not hasattr(self, 'mqtt_name'):
|
if not hasattr(self, 'mqtt_name'):
|
||||||
self.mqtt_name = self.__class__.__name__.lower()
|
self.mqtt_name = self.__class__.__name__.lower()
|
||||||
@ -40,11 +47,15 @@ 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
|
||||||
|
|
||||||
self._pub_queue = queue.Queue()
|
self.__pub_queue = queue.Queue()
|
||||||
|
self.__state = Scene.STATE_DEACTIVATE
|
||||||
|
|
||||||
|
self.__executor = None
|
||||||
|
self.__activating_r_futures = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scene_state(self):
|
def scene_state(self):
|
||||||
return self._scene_state
|
return self.__state
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.username_pw_set(self.configuration.user,
|
self.username_pw_set(self.configuration.user,
|
||||||
@ -59,15 +70,27 @@ class Scene(threading.Thread, mqtt.Client):
|
|||||||
|
|
||||||
run = True
|
run = True
|
||||||
while run:
|
while run:
|
||||||
|
#Mqtt client loop
|
||||||
self.loop()
|
self.loop()
|
||||||
|
|
||||||
|
#Check publish queue
|
||||||
try:
|
try:
|
||||||
(args, kwargs) = self._pub_queue.get(block=False)
|
(args, kwargs) = self.__pub_queue.get(block=False)
|
||||||
self.publish(*args, **kwargs)
|
self.publish(*args, **kwargs)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
continue
|
pass
|
||||||
|
|
||||||
|
# Check for futures if activating
|
||||||
|
if self.scene_state == Scene.STATE_ACTIVATING:
|
||||||
|
if self.__activating_r_futures:
|
||||||
|
r = wait(self.__activating_r_futures, timeout=1, return_when=ALL_COMPLETED)
|
||||||
|
self.__activating_r_futures = []
|
||||||
|
self.__state = Scene.STATE_ACTIVATE
|
||||||
|
for r in r.done:
|
||||||
|
print(r.result())
|
||||||
|
|
||||||
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().lower()
|
||||||
@ -101,59 +124,45 @@ class Scene(threading.Thread, mqtt.Client):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def __activate(self):
|
def __activate(self):
|
||||||
#activate scene
|
if self.scene_state:
|
||||||
# lock for activate again or deactivate
|
self.logger.info('Already activate/activating ignore cmnd')
|
||||||
# start all activate action concurently
|
return
|
||||||
# start result catcher thread
|
|
||||||
# result catcher set active if ok else log error
|
|
||||||
|
|
||||||
results = queue.Queue()
|
|
||||||
|
|
||||||
|
with pebble.ThreadPool() as executor:
|
||||||
for a in self.ON:
|
for a in self.ON:
|
||||||
a.setup(self, results).start()
|
self.__activating_r_futures.append(
|
||||||
|
executor.schedule(a.setup(self).run))
|
||||||
|
|
||||||
self._scene_state = True
|
self.__state = Scene.STATE_ACTIVATING
|
||||||
self.publish(self.TOPIC_STAT.format(mqtt_name=self.mqtt_name),
|
self.__send_state()
|
||||||
payload='ON',
|
|
||||||
qos=2,
|
|
||||||
retain=False)
|
|
||||||
|
|
||||||
def __deactivate(self):
|
def __deactivate(self):
|
||||||
#deactivate scene
|
#TODO cancel activating...
|
||||||
self._scene_state = False
|
self.__state = Scene.STATE_DEACTIVATE
|
||||||
self.publish(self.TOPIC_STAT.format(mqtt_name=self.mqtt_name),
|
self.__send_state()
|
||||||
payload='OFF',
|
|
||||||
qos=2,
|
|
||||||
retain=False)
|
|
||||||
|
|
||||||
def __send_state(self):
|
def __send_state(self):
|
||||||
print(self._scene_state)
|
|
||||||
self.publish(self.TOPIC_STAT.format(mqtt_name=self.mqtt_name),
|
self.publish(self.TOPIC_STAT.format(mqtt_name=self.mqtt_name),
|
||||||
payload='ON' if self.scene_state else 'OFF',
|
payload='ON' if self.scene_state else 'OFF',
|
||||||
qos=2,
|
qos=2,
|
||||||
retain=False)
|
retain=False)
|
||||||
|
|
||||||
class Action(threading.Thread):
|
class Action(object):
|
||||||
OK = 0
|
OK = 0
|
||||||
FAILED = 1
|
FAILED = 1
|
||||||
|
|
||||||
def __init__(self):
|
def setup(self, proxy: Scene):
|
||||||
threading.Thread.__init__(self)
|
|
||||||
|
|
||||||
def setup(self, proxy: Scene, result: queue.Queue):
|
|
||||||
"""
|
"""
|
||||||
proxy: a thread safe proxy object with publish, subscribe method
|
proxy: a thread safe proxy object with publish, subscribe method
|
||||||
result: a queue for put result
|
|
||||||
"""
|
"""
|
||||||
self.scene = proxy
|
self.proxy = proxy
|
||||||
self.result = result
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def ok(self):
|
def ok(self):
|
||||||
self.result.put(Action.OK)
|
return Action.OK
|
||||||
|
|
||||||
def failed(self):
|
def failed(self):
|
||||||
self.result.put(Action.FAILED)
|
return Action.FAILED
|
||||||
|
|
||||||
class Publish(Action):
|
class Publish(Action):
|
||||||
|
|
||||||
@ -172,9 +181,9 @@ class Publish(Action):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.scene.threaded_publish(self.topic,
|
self.proxy.threaded_publish(self.topic,
|
||||||
payload=self.payload, qos=self.qos, retain=False)
|
payload=self.payload, qos=self.qos, retain=False)
|
||||||
self.ok()
|
return self.ok()
|
||||||
|
|
||||||
|
|
||||||
class Sleep(Scene):
|
class Sleep(Scene):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user