forked from platypush/platypush
Use a threading Event to synchronize with the Hue animation thread instead of relying on the Redis backend
This commit is contained in:
parent
6d7f1502ce
commit
77530b4a06
1 changed files with 58 additions and 71 deletions
|
@ -3,11 +3,8 @@ import statistics
|
|||
import time
|
||||
|
||||
from enum import Enum
|
||||
from threading import Thread
|
||||
from redis import Redis
|
||||
from redis.exceptions import TimeoutError as QueueTimeoutError
|
||||
from threading import Thread, Event
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.plugins import action
|
||||
from platypush.plugins.light import LightPlugin
|
||||
from platypush.utils import set_thread_name
|
||||
|
@ -58,7 +55,8 @@ class LightHuePlugin(LightPlugin):
|
|||
self.logger.info('Initializing Hue lights plugin - bridge: "{}"'.format(self.bridge_address))
|
||||
|
||||
self.connect()
|
||||
self.lights = []; self.groups = []
|
||||
self.lights = []
|
||||
self.groups = []
|
||||
|
||||
if lights:
|
||||
self.lights = lights
|
||||
|
@ -66,19 +64,20 @@ class LightHuePlugin(LightPlugin):
|
|||
self.groups = groups
|
||||
self._expand_groups()
|
||||
else:
|
||||
self.lights = [l.name for l in self.bridge.lights]
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.lights = [light.name for light in self.bridge.lights]
|
||||
|
||||
self.redis = None
|
||||
self.animation_thread = None
|
||||
self.animations = {}
|
||||
self._animation_stop = Event()
|
||||
self._init_animations()
|
||||
self.logger.info('Configured lights: "{}"'.format(self.lights))
|
||||
|
||||
def _expand_groups(self):
|
||||
groups = [g for g in self.bridge.groups if g.name in self.groups]
|
||||
for g in groups:
|
||||
for l in g.lights:
|
||||
self.lights += [l.name]
|
||||
for group in groups:
|
||||
for light in group.lights:
|
||||
self.lights += [light.name]
|
||||
|
||||
def _init_animations(self):
|
||||
self.animations = {
|
||||
|
@ -86,10 +85,10 @@ class LightHuePlugin(LightPlugin):
|
|||
'lights': {},
|
||||
}
|
||||
|
||||
for g in self.bridge.groups:
|
||||
self.animations['groups'][g.group_id] = None
|
||||
for l in self.bridge.lights:
|
||||
self.animations['lights'][l.light_id] = None
|
||||
for group in self.bridge.groups:
|
||||
self.animations['groups'][group.group_id] = None
|
||||
for light in self.bridge.lights:
|
||||
self.animations['lights'][light.light_id] = None
|
||||
|
||||
@action
|
||||
def connect(self):
|
||||
|
@ -295,7 +294,9 @@ class LightHuePlugin(LightPlugin):
|
|||
self.bridge = None
|
||||
raise e
|
||||
|
||||
lights = []; groups = []
|
||||
lights = []
|
||||
groups = []
|
||||
|
||||
if 'lights' in kwargs:
|
||||
lights = kwargs.pop('lights').split(',').strip() \
|
||||
if isinstance(lights, str) else kwargs.pop('lights')
|
||||
|
@ -515,6 +516,8 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
:param value: xY value
|
||||
:type value: list[float] containing the two values
|
||||
:param lights: List of lights.
|
||||
:param groups: List of groups.
|
||||
"""
|
||||
if groups is None:
|
||||
groups = []
|
||||
|
@ -529,6 +532,8 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
:param value: Temperature value (range: 0-255)
|
||||
:type value: int
|
||||
:param lights: List of lights.
|
||||
:param groups: List of groups.
|
||||
"""
|
||||
if groups is None:
|
||||
groups = []
|
||||
|
@ -550,7 +555,6 @@ class LightHuePlugin(LightPlugin):
|
|||
groups = []
|
||||
if lights is None:
|
||||
lights = []
|
||||
bri = 0
|
||||
|
||||
if lights:
|
||||
bri = statistics.mean([
|
||||
|
@ -595,7 +599,6 @@ class LightHuePlugin(LightPlugin):
|
|||
groups = []
|
||||
if lights is None:
|
||||
lights = []
|
||||
sat = 0
|
||||
|
||||
if lights:
|
||||
sat = statistics.mean([
|
||||
|
@ -640,7 +643,6 @@ class LightHuePlugin(LightPlugin):
|
|||
groups = []
|
||||
if lights is None:
|
||||
lights = []
|
||||
hue = 0
|
||||
|
||||
if lights:
|
||||
hue = statistics.mean([
|
||||
|
@ -693,17 +695,15 @@ class LightHuePlugin(LightPlugin):
|
|||
:returns: True if there is an animation running, false otherwise.
|
||||
"""
|
||||
|
||||
return self.animation_thread is not None
|
||||
return self.animation_thread is not None and self.animation_thread.is_alive()
|
||||
|
||||
@action
|
||||
def stop_animation(self):
|
||||
"""
|
||||
Stop a running animation if any
|
||||
Stop a running animation.
|
||||
"""
|
||||
|
||||
if self.animation_thread and self.animation_thread.is_alive():
|
||||
redis = self._get_redis()
|
||||
redis.rpush(self.ANIMATION_CTRL_QUEUE_NAME, 'STOP')
|
||||
if self.is_animation_running():
|
||||
self._animation_stop.set()
|
||||
self._init_animations()
|
||||
|
||||
@action
|
||||
|
@ -756,10 +756,10 @@ class LightHuePlugin(LightPlugin):
|
|||
if groups:
|
||||
groups = [g for g in self.bridge.groups if g.name in groups or g.group_id in groups]
|
||||
lights = lights or []
|
||||
for g in groups:
|
||||
lights.extend([l.name for l in g.lights])
|
||||
for group in groups:
|
||||
lights.extend([light.name for light in group.lights])
|
||||
elif lights:
|
||||
lights = [l.name for l in self.bridge.lights if l.name in lights or l.light_id in lights]
|
||||
lights = [light.name for light in self.bridge.lights if light.name in lights or light.light_id in lights]
|
||||
else:
|
||||
lights = self.lights
|
||||
|
||||
|
@ -776,26 +776,26 @@ class LightHuePlugin(LightPlugin):
|
|||
}
|
||||
|
||||
if groups:
|
||||
for g in groups:
|
||||
self.animations['groups'][g.group_id] = info
|
||||
for group in groups:
|
||||
self.animations['groups'][group.group_id] = info
|
||||
|
||||
for l in self.bridge.lights:
|
||||
if l.name in lights:
|
||||
self.animations['lights'][l.light_id] = info
|
||||
for light in self.bridge.lights:
|
||||
if light.name in lights:
|
||||
self.animations['lights'][light.light_id] = info
|
||||
|
||||
def _initialize_light_attrs(lights):
|
||||
if animation == self.Animation.COLOR_TRANSITION:
|
||||
return { l: {
|
||||
return {light: {
|
||||
'hue': random.randint(hue_range[0], hue_range[1]),
|
||||
'sat': random.randint(sat_range[0], sat_range[1]),
|
||||
'bri': random.randint(bri_range[0], bri_range[1]),
|
||||
} for l in lights }
|
||||
} for light in lights}
|
||||
elif animation == self.Animation.BLINK:
|
||||
return { l: {
|
||||
return {light: {
|
||||
'on': True,
|
||||
'bri': self.MAX_BRI,
|
||||
'transitiontime': 0,
|
||||
} for l in lights }
|
||||
} for light in lights}
|
||||
|
||||
def _next_light_attrs(lights):
|
||||
if animation == self.Animation.COLOR_TRANSITION:
|
||||
|
@ -827,12 +827,7 @@ class LightHuePlugin(LightPlugin):
|
|||
return lights
|
||||
|
||||
def _should_stop():
|
||||
try:
|
||||
redis = self._get_redis(transition_seconds)
|
||||
redis.blpop(self.ANIMATION_CTRL_QUEUE_NAME)
|
||||
return True
|
||||
except QueueTimeoutError:
|
||||
return False
|
||||
return self._animation_stop.is_set()
|
||||
|
||||
def _animate_thread(lights):
|
||||
set_thread_name('HueAnimate')
|
||||
|
@ -874,24 +869,16 @@ class LightHuePlugin(LightPlugin):
|
|||
|
||||
self.logger.info('Stopping animation')
|
||||
self.animation_thread = None
|
||||
self.redis = None
|
||||
|
||||
self.stop_animation()
|
||||
self._animation_stop.clear()
|
||||
self.animation_thread = Thread(target=_animate_thread,
|
||||
name='HueAnimate',
|
||||
args=(lights,))
|
||||
self.animation_thread.start()
|
||||
|
||||
def _get_redis(self, socket_timeout=1.0):
|
||||
if not self.redis:
|
||||
redis_args = get_backend('redis').redis_args
|
||||
redis_args['socket_timeout'] = socket_timeout
|
||||
self.redis = Redis(**redis_args)
|
||||
return self.redis
|
||||
|
||||
def status(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
Loading…
Reference in a new issue