De-duplicate the legacy ARTIK051 AC board-generation test (#161)
capabilities/airconditioner.py's is_legacy_board() (renamed from the private _is_legacy_board -- it's now a cross-module helper) and climate.py's _legacy_airflow() implemented the same "does this board have /airflow/vs/0 but no /wind/strength/vs/0" test independently, one via literal href strings and the other via coordinator.resource() truthiness. is_legacy_board() now uses the module's own HREF_AIRFLOW/HREF_WIND_STRENGTH constants, and _legacy_airflow() delegates to it via a minimal two-key presence dict (cheaper than a full last_resources snapshot copy) instead of re-implementing the check, so the token entities and the climate card's legacy read/write paths can't drift apart on which board generation is in play.
This commit is contained in:
3 files changed
+39
-9
No files matched your search
@@ -51,6 +51,7 @@ from .registry.capabilities.airconditioner import (
|
|||||||
HREF_WIND_OSCILLATION as WIND_OSCILLATION_HREF,
|
HREF_WIND_OSCILLATION as WIND_OSCILLATION_HREF,
|
||||||
HREF_CONVENIENT as CONVENIENT_HREF,
|
HREF_CONVENIENT as CONVENIENT_HREF,
|
||||||
HREF_AIRFLOW as AIRFLOW_HREF,
|
HREF_AIRFLOW as AIRFLOW_HREF,
|
||||||
|
is_legacy_board,
|
||||||
)
|
)
|
||||||
from .registry.capabilities.common import normalize_temp_unit
|
from .registry.capabilities.common import normalize_temp_unit
|
||||||
|
|
||||||
@@ -247,10 +248,23 @@ class LocalThingsClimate(LocalThingsEntity, ClimateEntity):
|
|||||||
|
|
||||||
def _legacy_airflow(self) -> dict:
|
def _legacy_airflow(self) -> dict:
|
||||||
"""The /airflow/vs/0 rep, but only when it is the fan/swing channel to
|
"""The /airflow/vs/0 rep, but only when it is the fan/swing channel to
|
||||||
use -- i.e. this board has no /wind/strength/vs/0."""
|
use -- i.e. this board has no /wind/strength/vs/0.
|
||||||
if self.coordinator.resource(WIND_STRENGTH_HREF):
|
|
||||||
return {}
|
Delegates the board-generation test to is_legacy_board (the same
|
||||||
return self.coordinator.resource(AIRFLOW_HREF) or {}
|
test capabilities/airconditioner.py's token entities are gated on)
|
||||||
|
instead of re-implementing it, via a minimal presence dict built
|
||||||
|
from the two hrefs it actually inspects -- cheaper than
|
||||||
|
last_resources' full snapshot copy, since is_legacy_board only
|
||||||
|
checks key membership.
|
||||||
|
"""
|
||||||
|
airflow = self.coordinator.resource(AIRFLOW_HREF)
|
||||||
|
wind_strength = self.coordinator.resource(WIND_STRENGTH_HREF)
|
||||||
|
presence = {}
|
||||||
|
if airflow:
|
||||||
|
presence[AIRFLOW_HREF] = airflow
|
||||||
|
if wind_strength:
|
||||||
|
presence[WIND_STRENGTH_HREF] = wind_strength
|
||||||
|
return airflow if is_legacy_board(presence) else {}
|
||||||
|
|
||||||
def _legacy_preset(self) -> bool:
|
def _legacy_preset(self) -> bool:
|
||||||
"""Whether presets come from the Comode_* token rather than a resource.
|
"""Whether presets come from the Comode_* token rather than a resource.
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ def _option_token(rep, prefix):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _is_legacy_board(resources):
|
def is_legacy_board(resources):
|
||||||
"""True for the board generation whose airflow lives in /airflow/vs/0.
|
"""True for the board generation whose airflow lives in /airflow/vs/0.
|
||||||
|
|
||||||
Newer families carry several of the same option tokens (Volume, Sleep,
|
Newer families carry several of the same option tokens (Volume, Sleep,
|
||||||
@@ -163,13 +163,12 @@ def _is_legacy_board(resources):
|
|||||||
/airflow/vs/0. Same test as climate.py's _legacy_airflow(), so the entities
|
/airflow/vs/0. Same test as climate.py's _legacy_airflow(), so the entities
|
||||||
below and the climate entity can never disagree about the generation.
|
below and the climate entity can never disagree about the generation.
|
||||||
"""
|
"""
|
||||||
return ('/airflow/vs/0' in resources
|
return HREF_AIRFLOW in resources and HREF_WIND_STRENGTH not in resources
|
||||||
and '/wind/strength/vs/0' not in resources)
|
|
||||||
|
|
||||||
|
|
||||||
def _has_option_token(prefix):
|
def _has_option_token(prefix):
|
||||||
return lambda rep, resources: (
|
return lambda rep, resources: (
|
||||||
_is_legacy_board(resources) and _option_token(rep, prefix) is not None)
|
is_legacy_board(resources) and _option_token(rep, prefix) is not None)
|
||||||
|
|
||||||
|
|
||||||
def _option_token_on(prefix):
|
def _option_token_on(prefix):
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ from custom_components.localthings.registry.by_type import (
|
|||||||
airconditioner, for_device_by_model,
|
airconditioner, for_device_by_model,
|
||||||
)
|
)
|
||||||
from custom_components.localthings.registry.capabilities.airconditioner import (
|
from custom_components.localthings.registry.capabilities.airconditioner import (
|
||||||
HREF_AIRFLOW, _option_number_write, _option_switch_write,
|
HREF_AIRFLOW, HREF_WIND_STRENGTH, _option_number_write,
|
||||||
|
_option_switch_write, is_legacy_board,
|
||||||
)
|
)
|
||||||
from custom_components.localthings.registry.discovery import discover
|
from custom_components.localthings.registry.discovery import discover
|
||||||
from custom_components.localthings.registry.entities import ClimateDesc
|
from custom_components.localthings.registry.entities import ClimateDesc
|
||||||
@@ -119,6 +120,22 @@ def test_token_entities_stay_off_newer_boards():
|
|||||||
assert key not in state, key
|
assert key not in state, key
|
||||||
|
|
||||||
|
|
||||||
|
def test_climate_legacy_airflow_gate_agrees_with_is_legacy_board():
|
||||||
|
"""issue #161: climate.py's _legacy_airflow() delegates to
|
||||||
|
capabilities/airconditioner.py's is_legacy_board() instead of
|
||||||
|
re-implementing the same presence/absence check, so the token entities
|
||||||
|
and the climate card's legacy read/write paths can't drift apart on
|
||||||
|
which board generation is in play."""
|
||||||
|
legacy_resources = _load_device(FIXTURE)
|
||||||
|
assert is_legacy_board(legacy_resources) is True
|
||||||
|
assert _climate(legacy_resources)._legacy_airflow() == legacy_resources[HREF_AIRFLOW]
|
||||||
|
|
||||||
|
newer_resources = _load_device('airconditioner_tp1x_rac')
|
||||||
|
assert is_legacy_board(newer_resources) is False
|
||||||
|
assert _climate(newer_resources)._legacy_airflow() == {}
|
||||||
|
assert HREF_WIND_STRENGTH in newer_resources
|
||||||
|
|
||||||
|
|
||||||
def test_absent_token_yields_no_entity():
|
def test_absent_token_yields_no_entity():
|
||||||
"""The issue #136 unit of this same model reports no Spi token."""
|
"""The issue #136 unit of this same model reports no Spi token."""
|
||||||
resources = _load_device(FIXTURE)
|
resources = _load_device(FIXTURE)
|
||||||
|
|||||||
Reference in new issue
Block a user