diff --git a/cli.py b/cli.py new file mode 100755 index 0000000..ba06e33 --- /dev/null +++ b/cli.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +import asyncio +import json +import re +import sys + +from twinkly_client import TwinklyClient + + +async def twinkly_wrapper(host, calls): + c = TwinklyClient(host) + response = {} + for func_name, args, kwargs in calls: + try: + f = getattr(c, func_name) + except AttributeError: + print(f"No such function: {func_name}") + exit(1) + response[func_name] = await f(*args, **kwargs) + await c._session.close() + return response + + +def main(): + commands = { + "get_mode": "", + "set_mode": "off|color|movie|effect|rt|demo", + "get_brightness": "", + "set_brightness": "1-100", + "get_color": "", + "set_color": "hue=0-360,saturation=0-255,value=0-255,red=0-255,green=0-255,blue=0-255,white=0-255", + "get_device_info": "", + } + args = sys.argv[1:] + + if not args or args[0] == "-h": + print("Usage: cli.py [(:arg1,kwarg=7),...]") + print("Available functions:") + for cmd, cmd_args in commands.items(): + print(f"{cmd}:{cmd_args}") + print( + "\nExample: cli.py 192.168.0.123 get_mode set_mode:color set_color:red=5,blue=10,green=255 " + "set_brightness:50 get_brightness" + ) + exit(0) + + host = args.pop(0) + + calls = [] + args_matches = re.findall("(\w+):?([\w=,]+)?", " ".join(args)) + for cmd, cmd_args in args_matches: + if cmd not in commands: + continue + call_args = [] + call_kwargs = {} + if cmd_args: + for cmd_arg in cmd_args.split(","): + if "=" in cmd_arg: + k, v = cmd_arg.split("=") + call_kwargs[k] = int(v) if v.isdigit() else v + else: + call_args.append(int(cmd_arg) if cmd_arg.isdigit() else cmd_arg) + calls.append((cmd, call_args, call_kwargs)) + + print(json.dumps(asyncio.run(twinkly_wrapper(host, calls)))) + + +if __name__ == "__main__": + main() diff --git a/twinkly_client/client.py b/twinkly_client/client.py index aadcb4f..5d9a448 100644 --- a/twinkly_client/client.py +++ b/twinkly_client/client.py @@ -7,6 +7,7 @@ from .const import ( EP_BRIGHTNESS, + EP_COLOR, EP_DEVICE_INFO, EP_LOGIN, EP_MODE, @@ -45,12 +46,20 @@ async def get_device_info(self) -> Any: async def get_is_on(self) -> bool: """Get a boolean which indicates the current state of the device.""" - return (await self.__send_request(EP_MODE))["mode"] != "off" + return await self.get_mode() != "off" async def set_is_on(self, is_on: bool) -> None: """Turn the device on / off.""" await self.__send_request(EP_MODE, {"mode": "movie" if is_on else "off"}) + async def get_mode(self) -> str: + """Get the current mode of the device (off,color,demo,effect,movie,playlist,rt).""" + return (await self.__send_request(EP_MODE))["mode"] + + async def set_mode(self, mode: str) -> None: + """Set the device mode (off,color,demo,effect,movie,playlist,rt)""" + await self.__send_request(EP_MODE, {"mode": mode}) + async def get_brightness(self) -> int: """Get the current brightness of the device, between 0 and 100.""" brightness = await self.__send_request(EP_BRIGHTNESS) @@ -60,6 +69,36 @@ async def set_brightness(self, brightness: int) -> None: """Set the brightness of the device.""" await self.__send_request(EP_BRIGHTNESS, {"value": brightness, "type": "A"}) + async def get_color(self) -> dict: + """Get the current color, dict of h,s,v,r,g,b,w ints""" + response_data = await self.__send_request(EP_COLOR) + return response_data + + async def set_color( + self, + hue: int = None, + saturation: int = None, + value: int = None, + red: int = None, + green: int = None, + blue: int = None, + white: int = None + ) -> None: + """Set the color of the device.""" + # Only include set keys + payload = { + k: v for k, v in { + "hue": hue, + "saturation": saturation, + "value": value, + "red": red, + "green": green, + "blue": blue, + "white": white + }.items() if v is not None + } + await self.__send_request(EP_COLOR, payload) + async def __send_request( self, endpoint: str, data: Any = None, retry: int = 1 ) -> Any: diff --git a/twinkly_client/const.py b/twinkly_client/const.py index 8bd5917..270d6d5 100644 --- a/twinkly_client/const.py +++ b/twinkly_client/const.py @@ -6,6 +6,7 @@ EP_DEVICE_INFO = "gestalt" EP_MODE = "led/mode" EP_BRIGHTNESS = "led/out/brightness" +EP_COLOR = "led/color" EP_LOGIN = "login" EP_VERIFY = "verify"