diff --git a/huecli/__main__.py b/huecli/__main__.py index 088121e..b6146e7 100644 --- a/huecli/__main__.py +++ b/huecli/__main__.py @@ -1,5 +1,6 @@ import os from enum import Enum +from typing import NamedTuple from typing_extensions import Annotated import typer import json @@ -10,6 +11,10 @@ class LightState(str, Enum): on = "off" off = "on" +class XYColor(NamedTuple): + x: float + y: float + NAME_TO_ID = { "bedroom": "0x001788010d1b599a", @@ -70,7 +75,7 @@ def complete_state(incomplete: str): return completion -def rgb_to_xy(red, green, blue): +def rgb_to_xy(red, green, blue) -> XYColor: """conversion of RGB colors to CIE1931 XY colors Formulas implemented from: https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d @@ -105,7 +110,7 @@ def rgb_to_xy(red, green, blue): # TODO check color gamut if known - return [x, y] + return XYColor(x, y) app = typer.Typer() @@ -126,17 +131,12 @@ def set_color( """ str_id = NAME_TO_ID[id] topic = f"zigbee2mqtt/{str_id}/set" - if color in COLOR_MAP: - payload_raw = { - "color": {"x": COLOR_MAP[color][0], "y": COLOR_MAP[color][1]}, - "color_mode": "xy", - } - payload = json.dumps(payload_raw) - else: - c = color.split(",") - xy = rgb_to_xy(float(c[0]), float(c[1]), float(c[2])) - raw_payload = {"x": xy[0], "y": xy[1]} - payload = json.dumps(raw_payload) + xy = parse_color(color) + payload_raw= { + "color": {"x": xy[0], "y": xy[1]}, + "color_mode": "xy", + } + payload = json.dumps(payload_raw) pub.single(topic, payload, hostname=get_mqtt_broker()) @@ -173,6 +173,27 @@ def set_brightness( payload = json.dumps({"brightness": brightness}) pub.single(topic, payload, hostname=get_mqtt_broker()) +def parse_color(color: str) -> XYColor: + if color in COLOR_MAP: + return XYColor(COLOR_MAP[color][0], COLOR_MAP[color][1]) + split = color.split(",") + match len(split): + case 2: + return XYColor(float(split[0]), float(split[1])) + case 3: + return _parse_rgb_color(float(split[0]), float(split[1]), float(split[2])) + case _: + raise ValueError("Invalid color format") + +def _parse_rgb_color(r: float, g: float, b: float) -> XYColor: + if any(val > 1 for val in [r,g,b]): + if any(val > 255 for val in [r,g,b]): + raise ValueError("RGB values must be between 0 and 255 or 0.0 and 1.0") + vals = [val/255 for val in [r,g,b]] + return rgb_to_xy(vals[0], vals[1], vals[2]) + if all(val > 0 and val < 1 for val in [r,g,b]): + return rgb_to_xy(r,g,b) + raise ValueError("RGB values must be between 0 and 255 or 0.0 and 1.0") def main(): app() diff --git a/pyproject.toml b/pyproject.toml index eb60ada..7c4249b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "huecli" -version = "0.1.0" -description = "" +version = "0.1.1" +description = "Set Philips Hue lights using MQTT" authors = ["Torjus HÃ¥kestad "] license = "MIT" readme = "README.md"