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
77 changes: 77 additions & 0 deletions OWNd/message/lighting.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,83 @@ def switch_off(cls, where: str | int, _transition: int | None = None) -> OWNLigh
message._human_readable_log = f"Switching OFF light or switch {message._where}{message._interface_log_text}."
return message

@classmethod
def set_brightness_preset(cls, where: str | int, preset: int) -> OWNLightingCommand:
"""Dimmer preset WHAT 2..10 (20 %..100 %), the frame libqtdevices
DimmerDevice::setLevel100 sends (lighting_device.cpp:240-245)."""
preset = int(preset)
if not 2 <= preset <= 10:
raise ValueError("preset must be between 2 and 10")
message = cls(f"*1*{preset}*{where}##")
message._human_readable_log = f"Setting light {message._where}{message._interface_log_text} to preset level {preset}." # pylint: disable=line-too-long
return message

@classmethod
def step_up(
cls, where: str | int, delta: int | None = None, speed: int | None = None
) -> OWNLightingCommand:
"""One level up (WHAT 30), or ``30#delta#speed`` for a dimmer 100
(libqtdevices lighting_device.cpp:230-233, 409-412)."""
return cls._step(where, 30, "up", delta, speed)

@classmethod
def step_down(
cls, where: str | int, delta: int | None = None, speed: int | None = None
) -> OWNLightingCommand:
"""One level down (WHAT 31), or ``31#delta#speed`` for a dimmer 100
(libqtdevices lighting_device.cpp:235-238, 414-417)."""
return cls._step(where, 31, "down", delta, speed)

@classmethod
def _step(
cls, where: str | int, what: int, direction: str, delta: int | None, speed: int | None
) -> OWNLightingCommand:
if delta is None:
message = cls(f"*1*{what}*{where}##")
message._human_readable_log = f"Dimming light {message._where}{message._interface_log_text} one level {direction}." # pylint: disable=line-too-long
return message
delta = int(delta)
speed = int(speed if speed is not None else 0)
if not 1 <= delta <= 100 or not 0 <= speed <= 255:
raise ValueError("delta must be 1..100 and speed 0..255")
message = cls(f"*1*{what}#{delta}#{speed}*{where}##")
message._human_readable_log = f"Dimming light {message._where}{message._interface_log_text} {direction} by {delta}% at speed {speed}." # pylint: disable=line-too-long
return message

_FIXED_TIMERS = {11: 60, 12: 120, 13: 180, 14: 240, 15: 300, 16: 900, 17: 30, 18: 0.5}

@classmethod
def switch_on_timed(cls, where: str | int, what: int) -> OWNLightingCommand:
"""Fixed timer WHAT 11..18 (1, 2, 3, 4, 5, 15 min, 30 s, 0.5 s), the
frame libqtdevices LightingDevice::fixedTiming sends (lighting_device.cpp:110-117)."""
what = int(what)
if what not in cls._FIXED_TIMERS:
raise ValueError("timer WHAT must be between 11 and 18")
message = cls(f"*1*{what}*{where}##")
message._human_readable_log = f"Switching ON light {message._where}{message._interface_log_text} for {cls._FIXED_TIMERS[what]}s." # pylint: disable=line-too-long
return message

@classmethod
def set_variable_timer(
cls, where: str | int, hours: int, minutes: int, seconds: int
) -> OWNLightingCommand:
"""``*#1*W*#2*H*M*S##`` (libqtdevices LightingDevice::variableTiming,
lighting_device.cpp:119-124)."""
h, m, s = int(hours), int(minutes), int(seconds)
if not (0 <= h <= 255 and 0 <= m <= 59 and 0 <= s <= 59):
raise ValueError("hours 0..255, minutes and seconds 0..59")
message = cls(f"*#1*{where}*#2*{h}*{m}*{s}##")
message._human_readable_log = f"Setting light {message._where}{message._interface_log_text} timer to {h}h {m}m {s}s." # pylint: disable=line-too-long
return message

@classmethod
def get_variable_timer(cls, where: str | int) -> OWNLightingCommand:
"""``*#1*W*2##`` (libqtdevices LightingDevice::requestVariableTiming,
lighting_device.cpp:131-134)."""
message = cls(f"*#1*{where}*2##")
message._human_readable_log = f"Requesting light {message._where}{message._interface_log_text} timer."
return message

@classmethod
def set_brightness(
cls, where: str | int, _level: int = 30, _transition: int = 0
Expand Down
47 changes: 47 additions & 0 deletions tests/test_who1_ts10_builders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""WHO 1 commands libqtdevices TS10_1_0_23 sends (lighting_device.cpp:34-39
FIXED_TIMING_MIN/MAX = 11/18, DIMMER_INC/DEC = 30/31; :110-124 fixedTiming,
variableTiming; :131-134 requestVariableTiming; :230-245 increase/decrease/
setLevel100; :409-417 Dimmer100 increaseLevel100/decreaseLevel100).
Firmware replay on bt_luci (MyHomeServer1, F454, F459): *1*2*11## ACK bus
11 00 12 1D, *1*5*11## 4D, *1*10*11## 9D, *1*30*11## 03, *1*31*11## 04,
*1*30#20#1*11## D1 11 01 42 0D 03 14 01, *1*31#20#255*11## ... 0D 04 14 FF,
*1*11*11## 16, *1*18*11## 86, *#1*11*#2*0*1*0## D1 11 01 42 06 00 01 00,
*#1*11*2## request frame D1 11 01 43 06 00 00 00."""

import pytest

from OWNd.message import OWNLightingCommand


def test_presets():
assert str(OWNLightingCommand.set_brightness_preset(11, 2)) == "*1*2*11##"
assert str(OWNLightingCommand.set_brightness_preset(11, 10)) == "*1*10*11##"
with pytest.raises(ValueError):
OWNLightingCommand.set_brightness_preset(11, 1)
with pytest.raises(ValueError):
OWNLightingCommand.set_brightness_preset(11, 11)


def test_steps():
assert str(OWNLightingCommand.step_up(11)) == "*1*30*11##"
assert str(OWNLightingCommand.step_down(11)) == "*1*31*11##"
assert str(OWNLightingCommand.step_up(11, 20, 1)) == "*1*30#20#1*11##"
assert str(OWNLightingCommand.step_down(11, 20, 255)) == "*1*31#20#255*11##"
with pytest.raises(ValueError):
OWNLightingCommand.step_up(11, 0)
with pytest.raises(ValueError):
OWNLightingCommand.step_up(11, 10, 256)


def test_fixed_timers():
assert str(OWNLightingCommand.switch_on_timed(11, 11)) == "*1*11*11##"
assert str(OWNLightingCommand.switch_on_timed(11, 18)) == "*1*18*11##"
with pytest.raises(ValueError):
OWNLightingCommand.switch_on_timed(11, 19)


def test_variable_timer():
assert str(OWNLightingCommand.set_variable_timer(11, 0, 1, 0)) == "*#1*11*#2*0*1*0##"
assert str(OWNLightingCommand.get_variable_timer(11)) == "*#1*11*2##"
with pytest.raises(ValueError):
OWNLightingCommand.set_variable_timer(11, 0, 60, 0)
Loading