Skip to content

Instantly share code, notes, and snippets.

@slaiyer
Last active June 26, 2021 15:42
Show Gist options
  • Save slaiyer/530e3c280a46a591402fc02f661f0906 to your computer and use it in GitHub Desktop.
Save slaiyer/530e3c280a46a591402fc02f661f0906 to your computer and use it in GitHub Desktop.
Yeelight flow controller
#!/usr/bin/env python3
"""Yeelight flow controller."""
import argparse as arg
import functools as func
import pathlib as path
import sys
from typing import Sequence
import numpy as np
import yeelight as y
def main(
args: arg.Namespace,
) -> int:
"""Entry point."""
start_flow_bulb = func.partial(
start_flow,
hues=get_progression(
begin=args.hue_begin,
end=args.hue_end,
),
saturation=args.saturation,
lightness=args.lightness,
duration=args.duration,
)
bulb_ip_file = path.Path(__file__).parent / 'bulb-ip'
try:
with open(bulb_ip_file, 'r') as file:
bulb_ip = file.readline().strip()
start_flow_bulb(bulb_ip=bulb_ip)
except (FileNotFoundError, y.BulbException):
bulb_ip = next(iter(
y.discover_bulbs(),
))['ip'].strip()
start_flow_bulb(bulb_ip=bulb_ip)
with open(bulb_ip_file, 'w') as file:
file.write(bulb_ip)
return 0
@func.cache
def get_progression(
begin: int,
end: int,
num_points_one_way: int = 10,
) -> Sequence[int]:
"""Generates a two-way sequence of interpolated integers between limits."""
hues = [
round(hue) for hue in np.linspace(
begin - 1,
end - 1,
num=num_points_one_way + 1,
)
]
hues.extend(
tuple(
reversed(hues),
)[1:-1],
)
return hues
def start_flow(
bulb_ip: str,
hues: Sequence[int],
saturation: int,
lightness: int,
duration: int,
) -> None:
"""Starts a flow."""
y.Bulb(
bulb_ip,
power_mode=y.PowerMode.HSV,
duration=duration,
auto_on=True,
).start_flow(
y.Flow(
transitions=[
y.HSVTransition(
hue=hue,
saturation=saturation,
brightness=lightness,
duration=duration,
) for hue in hues
],
),
)
if __name__ == '__main__':
hue_range = range(1, 361)
percent_range = range(1, 101)
parser = arg.ArgumentParser()
parser.add_argument(
'--hue-begin',
'-b',
type=int,
choices=hue_range,
default=260,
help=f'Beginning hue ({hue_range.start}-{hue_range.stop})',
)
parser.add_argument(
'--hue-end',
'-e',
type=int,
choices=hue_range,
default=360,
help=f'Ending hue ({hue_range.start}-{hue_range.stop})',
)
parser.add_argument(
'--saturation',
'-s',
type=int,
choices=percent_range,
default=percent_range.stop - 1,
help='Saturation (%%)',
)
parser.add_argument(
'--lightness',
'-l',
type=int,
choices=percent_range,
default=percent_range.start,
help='Lightness (%%)',
)
parser.add_argument(
'--duration',
'-d',
type=int,
default=30,
help='Duration (s)',
)
arguments = parser.parse_args()
arguments.duration *= 1_000
if not 50 <= arguments.duration < (1 << 32):
raise arg.ArgumentTypeError('Invalid duration')
sys.exit(
main(args=arguments),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment