Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/haclient/domains/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,85 @@ def rgb_color(self) -> tuple[int, int, int] | None:
return (int(value[0]), int(value[1]), int(value[2]))
return None

async def set_brightness(self, brightness: int, *, transition: float | None = None) -> None:
"""Set the brightness (0--255), turning the light on if needed.

Parameters
----------
brightness : int
Brightness value (0--255).
transition : float or None, optional
Transition time in seconds.
"""
await self.turn_on(brightness=brightness, transition=transition)

async def set_kelvin(self, kelvin: int, *, transition: float | None = None) -> None:
"""Set the color temperature in Kelvin, turning the light on if needed.

Parameters
----------
kelvin : int
Color temperature in Kelvin.
transition : float or None, optional
Transition time in seconds.
"""
await self.turn_on(kelvin=kelvin, transition=transition)

async def set_rgb(
self,
r: int,
g: int,
b: int,
*,
transition: float | None = None,
) -> None:
"""Set the RGB color, turning the light on if needed.

Parameters
----------
r : int
Red component (0--255).
g : int
Green component (0--255).
b : int
Blue component (0--255).
transition : float or None, optional
Transition time in seconds.
"""
await self.turn_on(rgb_color=(r, g, b), transition=transition)

async def set_color(
self,
*,
rgb: tuple[int, int, int] | None = None,
kelvin: int | None = None,
transition: float | None = None,
) -> None:
"""Set the light color by RGB or Kelvin, turning the light on if needed.

Exactly one of *rgb* or *kelvin* must be provided.

Parameters
----------
rgb : tuple of int or None, optional
RGB color as a 3-element tuple.
kelvin : int or None, optional
Color temperature in Kelvin.
transition : float or None, optional
Transition time in seconds.

Raises
------
ValueError
If neither or both of *rgb* and *kelvin* are provided.
"""
if (rgb is None) == (kelvin is None):
raise ValueError("Exactly one of 'rgb' or 'kelvin' must be provided")
if rgb is not None:
await self.turn_on(rgb_color=rgb, transition=transition)
else:
await self.turn_on(kelvin=kelvin, transition=transition)

async def turn_on(
self,
*,
Expand Down
55 changes: 55 additions & 0 deletions tests/test_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,61 @@ async def test_light_state_properties() -> None:
await ha.close()


async def test_light_set_brightness(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
await light.set_brightness(200)
await light.set_brightness(100, transition=2.0)
calls = fake_ha.ws_service_calls
assert calls[0]["service"] == "turn_on"
assert calls[0]["service_data"]["brightness"] == 200
assert "transition" not in calls[0]["service_data"]
assert calls[1]["service_data"]["brightness"] == 100
assert calls[1]["service_data"]["transition"] == 2.0


async def test_light_set_kelvin(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
await light.set_kelvin(4000)
await light.set_kelvin(3000, transition=1.0)
calls = fake_ha.ws_service_calls
assert calls[0]["service_data"]["color_temp_kelvin"] == 4000
assert calls[1]["service_data"]["color_temp_kelvin"] == 3000
assert calls[1]["service_data"]["transition"] == 1.0


async def test_light_set_rgb(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
await light.set_rgb(255, 0, 128)
await light.set_rgb(0, 255, 0, transition=0.5)
calls = fake_ha.ws_service_calls
assert calls[0]["service_data"]["rgb_color"] == [255, 0, 128]
assert calls[1]["service_data"]["rgb_color"] == [0, 255, 0]
assert calls[1]["service_data"]["transition"] == 0.5


async def test_light_set_color_rgb(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
await light.set_color(rgb=(10, 20, 30))
call = fake_ha.ws_service_calls[0]
assert call["service_data"]["rgb_color"] == [10, 20, 30]


async def test_light_set_color_kelvin(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
await light.set_color(kelvin=5000, transition=1.0)
call = fake_ha.ws_service_calls[0]
assert call["service_data"]["color_temp_kelvin"] == 5000
assert call["service_data"]["transition"] == 1.0


async def test_light_set_color_requires_exactly_one(client: HAClient, fake_ha: FakeHA) -> None:
light = client.light("kitchen")
with pytest.raises(ValueError, match="Exactly one"):
await light.set_color()
with pytest.raises(ValueError, match="Exactly one"):
await light.set_color(rgb=(1, 2, 3), kelvin=4000)


async def test_switch_actions(client: HAClient, fake_ha: FakeHA) -> None:
sw = client.switch("outlet")
await sw.turn_on()
Expand Down
Loading
Loading