Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable min/max values for saturation and brightness for the color_loop effect #10

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 37 additions & 8 deletions aiolifx_effects/aiolifx_effects.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import asyncio
import random
import logging
from aiolifx.aiolifx import features_map

from functools import partial

Expand All @@ -9,8 +11,18 @@

NEUTRAL_WHITE = 3500

_LOGGER = logging.getLogger(__name__)

def lifx_white(device):
return device.product and device.product in [10, 11, 18]
"""Return true if the device supports neither color or variable temperature and is not a switch."""
return bool(
features_map[device.product]["color"] is False
and features_map[device.product]["temperature_range"] is None
)

def extended_multizone(device):
"""Return try if the device supports extended multizone messages."""
return features_map[device.product]["extended_multizone"]

class PreState:
"""Structure describing a power/color state."""
Expand Down Expand Up @@ -75,6 +87,7 @@ async def start(self, effect, participants):

async with self.lock:
effect.conductor = self
_LOGGER.debug(f"Starting {effect} on {', '.join(device.label for device in participants)}")

# Restore previous state
await self._stop_nolock(participants, effect)
Expand All @@ -83,10 +96,16 @@ async def start(self, effect, participants):
tasks = []
for device in participants:
if not self.running.get(device.mac_addr):
_LOGGER.debug(f"Storing current light state for {device.label}")
tasks.append(AwaitAioLIFX().wait(device.get_color))
if device.color_zones:
for zone in range(0, len(device.color_zones), 8):
tasks.append(AwaitAioLIFX().wait(partial(device.get_color_zones, start_index=zone)))
if extended_multizone(device):
_LOGGER.debug(f"Storing current zone state for {device.label} using get_extended_color_zones")
tasks.append(AwaitAioLIFX().wait(device.get_extended_color_zones))
else:
_LOGGER.debug(f"Storing current zone state for {device.label} using get_color_zones")
for zone in range(0, len(device.color_zones), 8):
tasks.append(AwaitAioLIFX().wait(partial(device.get_color_zones, start_index=zone)))
if tasks:
await asyncio.wait(tasks)

Expand All @@ -95,8 +114,9 @@ async def start(self, effect, participants):
pre_state = running.pre_state if running else PreState(device)
self.running[device.mac_addr] = RunningEffect(effect, pre_state)

# Powered off zones report zero brightness. Get the real values.
await self._fixup_multizone(participants)
# Powered off zones report zero brightness on older multizone devices. Get the real values.
if extended_multizone(device) is False:
await self._fixup_multizone(participants)

self.loop.create_task(effect.async_perform(participants))

Expand Down Expand Up @@ -196,6 +216,7 @@ async def async_perform(self, participants):
tasks = []
for device in self.participants:
if self.power_on and not device.power_level:
_LOGGER.debug(f"Powering on {device.label} before starting effect.")
tasks.append(self.conductor.loop.create_task(self.poweron(device)))
if tasks:
await asyncio.wait(tasks)
Expand Down Expand Up @@ -321,7 +342,7 @@ async def effect_color(self, device):
class EffectColorloop(LIFXEffect):
"""Representation of a colorloop effect."""

def __init__(self, power_on=True, period=None, change=None, spread=None, brightness=None, transition=None):
def __init__(self, power_on=True, period=None, change=None, spread=None, brightness=None, saturation=None, transition=None):
"""Initialize the colorloop effect."""
super().__init__(power_on)
self.name = 'colorloop'
Expand All @@ -330,6 +351,7 @@ def __init__(self, power_on=True, period=None, change=None, spread=None, brightn
self.change = change if change else 20
self.spread = spread if spread else 30
self.brightness = brightness
self.saturation = saturation
self.transition = transition

def inherit_prestate(self, other):
Expand All @@ -345,10 +367,11 @@ async def async_play(self, **kwargs):
while self.participants:
hue = (hue + direction*self.change) % 360
lhue = hue

_LOGGER.debug(f"Starting color loop on {', '.join(device.label for device in self.participants)}")
random.shuffle(self.participants)

for device in self.participants:

if self.transition is not None:
transition = int(1000*self.transition)
elif device == self.participants[0] or self.spread > 0:
Expand All @@ -359,13 +382,19 @@ async def async_play(self, **kwargs):
else:
brightness = self.running(device).pre_state.color[2]

if self.saturation is not None:
saturation = self.saturation
else:
saturation = int(random.uniform(0.8, 1.0)*65535)

hsbk = [
int(65535/360*lhue),
int(random.uniform(0.8, 1.0)*65535),
saturation,
brightness,
NEUTRAL_WHITE,
]
device.set_color(hsbk, None, transition)
_LOGGER.debug(f"Send set_color({int(65535/360*lhue)}, {saturation}, {brightness}, {NEUTRAL_WHITE}, transition={transition}) to {device.label}")

# Adjust the next light so the full spread is used
if len(self.participants) > 1:
Expand Down