def point_control(group: Group, point_color: ColorTheme, base_theme: Optional[ColorTheme] = None, *, tail_delay_secs: float = 0, head_delay_secs: float = 0): """ move a single point around a group of lights \b use tail_delay_secs to add a trail to your light movement \b use head_delay_secs to increase the transition time of your point \b point_color is a `ColorTheme` that determines what color the light will be as you move around your lights \b base_theme is a `ColorTheme` that sets the background of your lights over which the point moves """ init_grid(group) threads = defaultdict(lambda: ThreadPoolExecutor(1)) base_theme = colors_to_theme(base_theme) or None point_colors = cycle(colors_to_theme(point_color)) with group.reset_to_orig(): group.turn_on() if base_theme: group.set_theme(base_theme) orig_settings = {l.label: copy(l) for l in group} valid_light_names = list(set(grid) & {l.label for l in group}) grid_light = grid[random.choice(valid_light_names)] lights = get_next_light(group, grid_light) try: while True: p = threads[grid_light] set_f = partial(grid_light.light.set_color, next(point_colors), duration=(int(head_delay_secs * 1000))) p.submit(_delay, set_f, head_delay_secs) next_light = next(lights) reset_f = partial(grid_light.light.reset, orig_settings[grid_light.name], int(tail_delay_secs * 1000)) p.submit(reset_f) grid_light = next_light except Exception as e: # wait for all threads to complete in background if necessary so that `reset_to_orig` will be called last exhaust(map(wait, threads.values())) if isinstance(e, KeyboardInterrupt): return raise
def cycle_themes(lifx: Group, *themes: ColorTheme, rotate_secs: Optional[int] = 60, duration_mins: Optional[int] = 20, transition_secs=5, all_lights=True): """ set lights to theme every `rotate_secs`. will round robin `themes`. rotation still works on one theme as it will re-assign the theme each `rotate_secs` """ end_time = arrow.utcnow().shift(minutes=duration_mins or 100000) themes = [colors_to_theme(t) for t in themes] with lifx.reset_to_orig(): for t in cycle(themes): if arrow.utcnow() > end_time: return lifx.set_theme(t, power_on=all_lights, duration=transition_secs * 1000) if rotate_secs: sleep(rotate_secs) else: sleep(duration_mins * 60 or 10000)
def breathe(lifx: Group, breath_time_secs=8, min_brightness_pct=30, max_brightness_pct=60, colors: Optional[ColorTheme] = None, duration_mins: Optional[Union[int, float]] = 20): """whatever lights you pass in will breathe""" theme = colors_to_theme(colors) half_period_ms = int(breath_time_secs * 1000.0) sleep_time = breath_time_secs duration_secs = duration_mins * 60 or float('inf') min_brightness = min_brightness_pct / 100.0 * 65535 max_brightness = max_brightness_pct / 100.0 * 65535 with lifx.reset_to_orig(half_period_ms): lifx.set_brightness(max_brightness, duration=2000) if theme: lifx.set_theme(theme) print("Breathing...") try: start_time = time() while True: with lifx.reset_to_orig(half_period_ms): lifx.set_brightness(min_brightness, half_period_ms) sleep(sleep_time) sleep(sleep_time) if time() - start_time > duration_secs: raise KeyboardInterrupt except KeyboardInterrupt: print("Restoring original color and power to all lights...")
def _parse_color_themes(ctx, param, color_themes) -> Optional[Theme]: if not color_themes: return None try: res = _parse_colors(ctx, param, color_themes) return routines.colors_to_theme(res) except KeyError: res = _parse_themes(ctx, param, color_themes) return res[0]
def replace(self, color_map: Dict[Color, ColorTheme]): """ modifies self replace colors from keys of color_map with colors from values in ColorMatrix """ s = slice(0, 3) color_map = {k[s]: cycle(colors_to_theme(v)) for k, v in color_map.items()} for rc, c in self.by_coords: if c[s] in color_map: self[rc] = next(color_map[c[s]])
def blink_color(lifx: Group, colors: Optional[ColorTheme] = None, blink_time_secs=.5, how_long_secs=8): """change colors on lights every `blink_time_secs`""" num_cycles = math.ceil(how_long_secs / blink_time_secs) theme = colors_to_theme(colors) or (Colors.COPILOT_BLUE, Colors.COPILOT_DARK_BLUE) with lifx.reset_to_orig(): for _, color in zip(range(num_cycles), cycle(theme)): lifx.set_color(color) sleep(blink_time_secs)
def rainbow(lifx: Group, colors: Optional[ColorTheme] = Themes.rainbow, duration_secs=0.5, smooth=False, num_repeats=1): """similar to blink_color""" theme = colors_to_theme(colors) transition_time_ms = duration_secs * 1000 if smooth else 0 rapid = duration_secs < 1 with lifx.reset_to_orig(): for _ in range(num_repeats): for color in theme: lifx.set_color(color, transition_time_ms, rapid) sleep(duration_secs)
def light_eq(lifx: Group, color_theme: Optional[ColorTheme] = None): """ a light equalizer to play with HSBk \b - homerow (aoeu/asdf) controls hue - shift-homerow controls hue even more \b - left/right controls saturation - shift-left/right mins/maxes saturation \b - down/up controls brightness - shift-down/up mins/maxes brightness - jk (dvorak)/cv (qwerty) control kelvin - ctrl-r resets - ctrl-w prints light info to screen """ def _init_lights(): lifx.turn_on() if theme: lifx.set_theme(theme) theme = colors_to_theme(color_theme) with suppress(KeyboardInterrupt), lifx.reset_to_orig(): _init_lights() for ao in _get_offset(): if ao.attr == 'reset': _init_lights() elif ao.attr == 'print': for l in lifx: print(l, l.color) else: getattr(lifx, f'set_{ao.attr}')(ao.value, offset=ao.as_offset)
def _colors(c: ColorTheme): return cycle(colors_to_theme(c))
def _init_board(background_color, shape): colors = to_n_colors(*colors_to_theme(background_color), n=shape.r * shape.c) return ColorMatrix.from_colors(colors, shape)