Compare commits

...

2 Commits

Author SHA1 Message Date
5c12b69409 Flake update 2024-06-15 11:29:37 +02:00
00ab4ab6b3 Improve color parsing 2024-06-15 11:29:22 +02:00
3 changed files with 45 additions and 24 deletions

View File

@ -59,11 +59,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1716948383, "lastModified": 1718318537,
"narHash": "sha256-SzDKxseEcHR5KzPXLwsemyTR/kaM9whxeiJohbL04rs=", "narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ad57eef4ef0659193044870c731987a6df5cf56b", "rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -84,11 +84,11 @@
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
"lastModified": 1717171636, "lastModified": 1718285706,
"narHash": "sha256-SwqzDI7ddN8SkfJ0moYMRu9iastqI25YAHPpmI2PlYM=", "narHash": "sha256-DScsBM+kZvxOva7QegfdtleebMXh30XPxDQr/1IGKYo=",
"owner": "nix-community", "owner": "nix-community",
"repo": "poetry2nix", "repo": "poetry2nix",
"rev": "3bad7d0f33e6fd09205a19aab01e10af532198f9", "rev": "a5be1bbbe0af0266147a88e0ec43b18c722f2bb9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -156,11 +156,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1715940852, "lastModified": 1717850719,
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=", "narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b", "rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -1,5 +1,6 @@
import os import os
from enum import Enum from enum import Enum
from typing import NamedTuple
from typing_extensions import Annotated from typing_extensions import Annotated
import typer import typer
import json import json
@ -10,6 +11,10 @@ class LightState(str, Enum):
on = "off" on = "off"
off = "on" off = "on"
class XYColor(NamedTuple):
x: float
y: float
NAME_TO_ID = { NAME_TO_ID = {
"bedroom": "0x001788010d1b599a", "bedroom": "0x001788010d1b599a",
@ -70,7 +75,7 @@ def complete_state(incomplete: str):
return completion 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 """conversion of RGB colors to CIE1931 XY colors
Formulas implemented from: https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d 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 # TODO check color gamut if known
return [x, y] return XYColor(x, y)
app = typer.Typer() app = typer.Typer()
@ -126,17 +131,12 @@ def set_color(
""" """
str_id = NAME_TO_ID[id] str_id = NAME_TO_ID[id]
topic = f"zigbee2mqtt/{str_id}/set" topic = f"zigbee2mqtt/{str_id}/set"
if color in COLOR_MAP: xy = parse_color(color)
payload_raw = { payload_raw= {
"color": {"x": COLOR_MAP[color][0], "y": COLOR_MAP[color][1]}, "color": {"x": xy[0], "y": xy[1]},
"color_mode": "xy", "color_mode": "xy",
} }
payload = json.dumps(payload_raw) 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)
pub.single(topic, payload, hostname=get_mqtt_broker()) pub.single(topic, payload, hostname=get_mqtt_broker())
@ -173,6 +173,27 @@ def set_brightness(
payload = json.dumps({"brightness": brightness}) payload = json.dumps({"brightness": brightness})
pub.single(topic, payload, hostname=get_mqtt_broker()) 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(): def main():
app() app()

View File

@ -1,7 +1,7 @@
[tool.poetry] [tool.poetry]
name = "huecli" name = "huecli"
version = "0.1.0" version = "0.1.1"
description = "" description = "Set Philips Hue lights using MQTT"
authors = ["Torjus Håkestad <torjus@uio.no>"] authors = ["Torjus Håkestad <torjus@uio.no>"]
license = "MIT" license = "MIT"
readme = "README.md" readme = "README.md"