diff --git a/custom_components/localthings/registry/by_type/refrigerator.py b/custom_components/localthings/registry/by_type/refrigerator.py index fad8516..29af8ce 100644 --- a/custom_components/localthings/registry/by_type/refrigerator.py +++ b/custom_components/localthings/registry/by_type/refrigerator.py @@ -16,9 +16,6 @@ REGISTRY = DeviceRegistry( fridge.AIR_FILTER, fridge.DEODOR_FILTER, fridge.AUTO_DOOR_TIMER, - fridge.AUTO_DOOR_SINGLE, - fridge.AUTO_DOOR_KIMCHI, - fridge.AUTO_DOOR_WINECELLAR, fridge.WINECELLAR_PANTRY_ZONE, fridge.WINECELLAR_INFO, dishwasher.DIAGNOSIS, @@ -51,5 +48,6 @@ REGISTRY = DeviceRegistry( fridge.DOOR_GENERIC, fridge.KIMCHI_ZONE, fridge.KIMCHI_DOOR_GENERIC, + fridge.AUTO_DOOR_VARIANT, ], ) diff --git a/custom_components/localthings/registry/capabilities/fridge.py b/custom_components/localthings/registry/capabilities/fridge.py index 03e4780..91d2e47 100644 --- a/custom_components/localthings/registry/capabilities/fridge.py +++ b/custom_components/localthings/registry/capabilities/fridge.py @@ -383,16 +383,27 @@ AUTO_DOOR_TIMER = Capability( ) # /autodoor//vs/0 -- one per fridge sub-type sharing the Auto Door -# Open feature (single-door, kimchi, winecellar; issue #328). Each reports -# only x.com.samsung.da.ado.openOptions, declaring which open styles that -# variant supports -- every dump seen so far carries exactly one option -# ('Single') with no paired desired/current field to make a choice against, -# the same "no real choice to expose yet" shape as ignored.py's /mode/0. -# Bound with no entities to record the three hrefs as coverage; revisit if -# a device ever reports more than one option. -AUTO_DOOR_SINGLE = Capability(href="/autodoor/single/vs/0") -AUTO_DOOR_KIMCHI = Capability(href="/autodoor/kimchi/vs/0") -AUTO_DOOR_WINECELLAR = Capability(href="/autodoor/winecellar/vs/0") +# Open feature (single-door, kimchi, winecellar seen so far; issue #328). +# Each reports only x.com.samsung.da.ado.openOptions, declaring which open +# styles that variant supports -- every dump seen so far carries exactly +# one option ('Single') with no paired desired/current field to make a +# choice against, the same "no real choice to expose yet" shape as +# ignored.py's /mode/0. Bound with no entities to record coverage; revisit +# if a device ever reports more than one option. +# +# A pattern cap rather than one entry per variant: match_fn (not just the +# prefix) is what actually gates this, so a future variant href needs no +# code change to stay covered, and /autodoor/timer/vs/0's own exact-href +# AUTO_DOOR_TIMER above always wins for that href regardless (discover() +# only falls through to pattern caps when no exact cap matched). This is +# registry-scoped, not global -- unlike ignored.IGNORED, the unknown- +# device-type fallback never reaches it, so the prefix caveat in +# ignored.py's own docstring doesn't apply here. +AUTO_DOOR_VARIANT = Capability( + href=None, + href_prefix="/autodoor/", + match_fn=lambda rep, resources: "x.com.samsung.da.ado.openOptions" in rep, +) # Wine-cellar variant (x.com.st.d.winecellar, issue #328) of the same # deodorizing filter AIR_FILTER models -- filterUsage/filterStatus at a diff --git a/tests/test_refrigerator_tp1x_ref_21k_autodoor_capabilities.py b/tests/test_refrigerator_tp1x_ref_21k_autodoor_capabilities.py index 69b49b7..345a715 100644 --- a/tests/test_refrigerator_tp1x_ref_21k_autodoor_capabilities.py +++ b/tests/test_refrigerator_tp1x_ref_21k_autodoor_capabilities.py @@ -3,7 +3,7 @@ `/status/lock/vs/0`'s ado.devicecontrol switch was already modeled (STATUS_LOCK.auto_door_opener); this dump adds the paired voice-feedback toggle, the door-hold timer, and the per-variant capability declaration -href -- see fridge.py's AUTO_DOOR_TIMER/AUTO_DOOR_SINGLE comments. +href -- see fridge.py's AUTO_DOOR_TIMER/AUTO_DOOR_VARIANT comments. """ from custom_components.localthings.registry.adapter import flatten @@ -67,5 +67,8 @@ def test_auto_door_timer_reads_its_own_options(): def test_auto_door_single_variant_href_bound_with_no_entities(): """/autodoor/single/vs/0 only ever declares openOptions=['Single'] -- - no paired current/desired field to expose, so it's coverage-only.""" - assert fridge.AUTO_DOOR_SINGLE.entities == () + no paired current/desired field to expose, so it's coverage-only via + the shared AUTO_DOOR_VARIANT pattern cap, not an entry of its own.""" + assert fridge.AUTO_DOOR_VARIANT.entities == () + _reg, resources = _fridge() + assert fridge.AUTO_DOOR_VARIANT.match_fn(resources["/autodoor/single/vs/0"], resources) diff --git a/tests/test_refrigerator_tp1x_ref_21k_kimchi_capabilities.py b/tests/test_refrigerator_tp1x_ref_21k_kimchi_capabilities.py index 39c20c3..5961012 100644 --- a/tests/test_refrigerator_tp1x_ref_21k_kimchi_capabilities.py +++ b/tests/test_refrigerator_tp1x_ref_21k_kimchi_capabilities.py @@ -51,4 +51,6 @@ def test_auto_door_opener_present(): def test_auto_door_kimchi_variant_href_bound_with_no_entities(): - assert fridge.AUTO_DOOR_KIMCHI.entities == () + assert fridge.AUTO_DOOR_VARIANT.entities == () + _reg, resources = _fridge() + assert fridge.AUTO_DOOR_VARIANT.match_fn(resources["/autodoor/kimchi/vs/0"], resources) diff --git a/tests/test_refrigerator_winecellar_capabilities.py b/tests/test_refrigerator_winecellar_capabilities.py index 895896b..6bd2cba 100644 --- a/tests/test_refrigerator_winecellar_capabilities.py +++ b/tests/test_refrigerator_winecellar_capabilities.py @@ -74,5 +74,7 @@ def test_winecellar_pantry_zone_mode_options_and_write(): def test_winecellar_variant_and_info_hrefs_bound_with_no_entities(): - assert fridge.AUTO_DOOR_WINECELLAR.entities == () + assert fridge.AUTO_DOOR_VARIANT.entities == () assert fridge.WINECELLAR_INFO.entities == () + _reg, resources = _fridge() + assert fridge.AUTO_DOOR_VARIANT.match_fn(resources["/autodoor/winecellar/vs/0"], resources)