Files
localthings/tests/test_climate_wind_oscillation_fallback.py
Marc Billow 6f10a3b796 Support 2-axis wind oscillation and overload-protection status on newer WindFree boards (issue #126)
Newer TP1X_DA-AC-RAC-01011_0000 firmware (Bespoke AI WindFree Deluxe,
AR60H10D1JWNME) drops /wind/direction/vs/0 entirely and reports swing
via a separate vertical/horizontal Swing|Fix pair on
/wind/oscillation/vs/0 instead, which left swing_mode/swing_modes
silently empty and the href unbound. climate.py now falls back to the
oscillation resource when /wind/direction/vs/0 is absent, mapping the
same off/vertical/horizontal/both vocabulary the existing swing control
already uses.

Also binds the board's /anomalyload/vs/0 overload-response resource as
read-only diagnostic sensors (operation state + mode) -- the same
"don't guess" precedent as the existing CURRENT_LIMIT capability, since
nothing in the dump confirms the exact behavioral difference between
its 'Alarm' and 'PowerSaving' modes or whether toggling it is safe on
live HVAC hardware.

Most of the other gaps this issue reported (Fan-only mode, WindFree
preset labels, target-temperature channel selection, power on/off via
the vendor resource) turned out to already be fixed by the just-merged
cool-only global RAC work.
2026-07-27 13:41:04 +00:00

34 lines
1.3 KiB
Python

"""Tests for the /wind/oscillation/vs/0 swing fallback helper in climate.py
(issue #126).
`_oscillation_swing` is a pure module-level function, like `_temps_vs_item`
in test_climate_temperature_fallback.py -- testable directly without a
coordinator/entity. This covers the fallback-selection logic that the
registry-level "no unbound hrefs" test in test_golden_regression.py doesn't
reach: newer WindFree firmware reports no /wind/direction/vs/0 at all, so
swing_mode/swing_modes would silently be None/empty without this fallback.
"""
from custom_components.localthings.climate import _oscillation_swing
def test_oscillation_swing_off_when_both_fixed():
assert _oscillation_swing({'vertical': 'Fix', 'horizontal': 'Fix'}) == 'off'
def test_oscillation_swing_vertical_only():
assert _oscillation_swing({'vertical': 'Swing', 'horizontal': 'Fix'}) == 'vertical'
def test_oscillation_swing_horizontal_only():
assert _oscillation_swing({'vertical': 'Fix', 'horizontal': 'Swing'}) == 'horizontal'
def test_oscillation_swing_both():
assert _oscillation_swing({'vertical': 'Swing', 'horizontal': 'Swing'}) == 'both'
def test_oscillation_swing_none_when_resource_absent():
"""Boards with /wind/direction/vs/0 instead don't populate this
resource at all -- callers must fall through cleanly, not raise."""
assert _oscillation_swing({}) is None