"""Command-line interface to interact with wizlight devices.""" import asyncio from functools import wraps from typing import Any, Callable, Coroutine, TypeVar import click from pywizlight import PilotBuilder, discovery, wizlight T = TypeVar("T") def coro(f: Callable[..., Coroutine[Any, Any, T]]) -> Callable[..., T]: """Allow to use async in click.""" @wraps(f) def wrapper(*args: Any, **kwargs: Any) -> T: """Async wrapper.""" return asyncio.run(f(*args, **kwargs)) return wrapper @click.group() @click.version_option() def main() -> None: """Command-line tool to interact with Wizlight bulbs.""" @main.command("discover") @coro @click.option( "--b", prompt="Set the broadcast address", help="Define the broadcast address like 192.168.1.255.", ) async def discover(b: str) -> None: """Discover bulb in the local network.""" click.echo(f"Search for bulbs in {b} ... ") bulbs = await discovery.find_wizlights(broadcast_address=b) for bulb in bulbs: click.echo(bulb.__dict__) @main.command("on") @coro @click.option("--ip", prompt="IP address of the bulb", help="IP address of the bulb.") @click.option( "--k", prompt="Kelvin for temperature.", help="Kelvin value (1000-8000) for turn on. Default 3000", default=3000, type=int, ) @click.option( "--brightness", prompt="Set the brightness value 0-255", help="Brightness for turn on. Default 128", default=128, type=int, ) async def turn_on(ip: str, k: int, brightness: int) -> None: """Turn a given bulb on.""" click.echo(f"Turning on {ip}") bulb = wizlight(ip) if bulb and 1000 <= k <= 6800 and 0 <= brightness <= 255: await bulb.turn_on(PilotBuilder(colortemp=k, brightness=brightness)) else: click.echo("Error - values are not correct. Type --help for help.") await bulb.async_close() @main.command("set-state") @coro @click.option("--ip", prompt="IP address of the bulb", help="IP address of the bulb.") @click.option( "--k", prompt="Kelvin for temperature.", help="Kelvin value (1000-8000) for turn on. Default 3000", default=3000, ) @click.option( "--brightness", prompt="Set the brightness value 0-255", help="Brightness for turn on. Default 128", default=128, ) async def set_state(ip: str, k: int, brightness: int) -> None: """Set the current state of a given bulb.""" click.echo(f"Turning on {ip}") bulb = wizlight(ip) if bulb and 1000 <= k <= 6800 and 0 <= brightness <= 255: await bulb.set_state(PilotBuilder(colortemp=k, brightness=brightness)) else: click.echo("Error - values are not correct. Type --help for help.") await bulb.async_close() @main.command("off") @coro @click.option("--ip", prompt="IP address of the bulb", help="IP address of the bulb.") async def turn_off(ip: str) -> None: """Turn a given bulb off.""" click.echo(f"Turning off {ip}") bulb = wizlight(ip) await bulb.turn_off() await bulb.async_close() @main.command("state") @coro @click.option("--ip", prompt="IP address of the bulb", help="IP address of the bulb.") async def state(ip: str) -> None: """Get the current state of a given bulb.""" click.echo(f"Get the state from {ip}") bulb = wizlight(ip) bulb_state = await bulb.updateState() if bulb_state: click.echo(bulb_state.pilotResult) else: click.echo("Did not get state from bulb") await bulb.async_close() if __name__ == "__main__": main()