Last active
June 26, 2021 15:42
-
-
Save slaiyer/530e3c280a46a591402fc02f661f0906 to your computer and use it in GitHub Desktop.
Yeelight flow controller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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