diff --git a/CHANGELOG.md b/CHANGELOG.md index 51a99e0..f682817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ All notable changes to `OWNd` are documented in this file. - Canonical `libqtdevices` (`TS10_1_0_23`) coarse `WHAT 2..10` $\leftrightarrow$ fine `1..100%` conversion helpers (`COARSE_PRESET_TO_PERCENT`, `brightness_preset_to_percent`, `percent_to_brightness_preset`), `OWNLightingEvent.is_coarse_dimmer`, `OWNLightingEvent.brightness_preset_percent`, and `OWNLightingCommand.set_brightness(..., coarse=..., gateway=...)` (`#134`). - `WHAT 39` end of movement (`*1*39*WHERE##`) from WHO 1 motion detectors: `message_type` `motion_detected` with `motion` `False`, new `OWNLightingEvent.motion_end`, `is_sensor` `True`, `is_on` `None`. It was `unknown_state` `39` before (`MyHOME#777`). +### Fixed +- **WHO 1 (`normalize_where`)**: a 4-digit point address of area 0 (`0004`, `0007#4#01`) normalises to its 2-digit form (`04`, `07#4#01`), the one gateways accept and report: `*#1*0001##` / `*1*1*0001##` are `nack`/`silent` on 11 of 12 emulated gateways (own-firmware-oracle `lights-area0`) and on a live F461 2.0.11, and the MH202 reports the light as `01`. Other 4-digit inputs (`0109`, `0010`) stay as typed (`#123`, `MyHOME#147`). + ## [2.0.0b11] - 2026-10-20 ### Added diff --git a/OWNd/message/lighting.py b/OWNd/message/lighting.py index 0c4352f..6da9cb4 100644 --- a/OWNd/message/lighting.py +++ b/OWNd/message/lighting.py @@ -157,7 +157,20 @@ def normalize_where(where: str | int | None) -> str: return "" parts = where_str.split("#", 1) base = parts[0] - if is_apl_address(base) or base in ("00", "100", "0"): + if ( + len(base) == 4 + and base.isdigit() + and base[:3] == "000" + and base[3] != "0" + ): + # Area 0, PL 1..9 spelled with four digits (0004) is canonically + # 04: `*#1*0001##` and `*1*1*0001##` are nack/silent on 11 of the 12 + # emulated gateways (own-firmware-oracle lights-area0) and the one + # that ACKs them, the MH202, reports the light as `01` + # (`*1*1000#1*01##`); a live F461 2.0.11 NACKs `0001` and ACKs `01`. + # Any other 4-digit input (0109, 0209) is left as typed (OWNd#123). + norm_base = f"{base[1]}{base[3]}" + elif is_apl_address(base) or base in ("00", "100", "0"): norm_base = base elif base.isdigit() and base.startswith("00") and int(base) > 15: norm_base = str(int(base)) diff --git a/tests/test_who1_ts10_builders.py b/tests/test_who1_ts10_builders.py index 7069ead..d9f960c 100644 --- a/tests/test_who1_ts10_builders.py +++ b/tests/test_who1_ts10_builders.py @@ -78,6 +78,42 @@ def test_apl_addressing_helpers(): assert normalize_where(" ") == "" +@pytest.mark.parametrize( + ("where", "expected"), + [ + # Area 0, PL 1..9 written on 4 digits: `*#1*0001##` is nack/silent on + # 11 of the 12 emulated gateways (own-firmware-oracle lights-area0), + # and the MH202, which ACKs it, reports the light as `01`. + ("0004", "04"), + ("0001", "01"), + ("0007#4#01", "07#4#01"), + # Any other 4-digit input is left as typed (OWNd#123). + ("0109", "0109"), + ("0209", "0209"), + ("0809", "0809"), + ("0901", "0901"), + # Real 4-digit addresses stay as written (the MH202 echoes 0010 as 0010). + ("0010", "0010"), + ("0015", "0015"), + ("0112", "0112"), + ("1015", "1015"), + ("1001", "1001"), + # Not point addresses, or already canonical. + ("0000", "0000"), + ("0900", "0900"), + ("04", "04"), + ("29", "29"), + ("00", "00"), + ("0", "0"), + ("#0004", "#0004"), + ], +) +def test_normalize_where_canonicalises_area_0_four_digit_points(where, expected): + from OWNd.message import normalize_where + + assert normalize_where(where) == expected + + def test_lighting_dimension_properties(): from OWNd.message import OWNLightingEvent, OWNMessage