diff --git a/custom_components/localthings/registry/capabilities/common.py b/custom_components/localthings/registry/capabilities/common.py index 45889b4..945903a 100644 --- a/custom_components/localthings/registry/capabilities/common.py +++ b/custom_components/localthings/registry/capabilities/common.py @@ -313,12 +313,19 @@ KIDS_LOCK_VS_FALLBACK = Capability( href='/kidslock/vs/0', match_fn=lambda rep, resources: '/kidslock/0' not in resources, entities=( - SwitchDesc(key='child_lock', field='x.com.samsung.da.kidsLock', - device_class='lock', - value_fn=lambda v: v != 'Ready', - write_fn=lambda p, rep, href=None: ( - ['kidslock', 'vs', '0'], - {'x.com.samsung.da.kidsLock': 'Enable' if p == 'On' else 'Ready'})), + # Read-only, not a SwitchDesc (issues #181/#183): the write side of + # this capability wrote 'Enable', a value no dump in the fixture + # corpus has ever reported back -- every one reports either 'Ready' + # or 'Run', so it was never a confirmed contract. #181's reporter + # confirmed this directly: writing the *correct* value ('Run') + # still 4.05s, and the SmartThings app itself has no control for + # it either -- the resource is genuinely read-only on this + # hardware, not just wrong-valued. binary_sensor's 'lock' device + # class is inverted from the switch reading below it used to be: + # On means open/unlocked, so value_fn flips to `v == 'Ready'`. + BinarySensorDesc(key='child_lock', field='x.com.samsung.da.kidsLock', + device_class='lock', + value_fn=lambda v: v == 'Ready'), ), ) diff --git a/custom_components/localthings/translations/en.json b/custom_components/localthings/translations/en.json index 5d718da..64b7809 100644 --- a/custom_components/localthings/translations/en.json +++ b/custom_components/localthings/translations/en.json @@ -16,6 +16,9 @@ "burner_pan_detected": { "name": "Burner {number} pan detected" }, + "child_lock": { + "name": "Child lock" + }, "cloud_connected": { "name": "Cloud connected" }, diff --git a/custom_components/localthings/translations/nl.json b/custom_components/localthings/translations/nl.json index 890ea12..b48539a 100644 --- a/custom_components/localthings/translations/nl.json +++ b/custom_components/localthings/translations/nl.json @@ -16,6 +16,9 @@ "burner_pan_detected": { "name": "Brander {number} pan gedetecteerd" }, + "child_lock": { + "name": "Kinderslot" + }, "cloud_connected": { "name": "Verbonden met cloud" }, diff --git a/tests/test_common_capabilities.py b/tests/test_common_capabilities.py index 37218cf..7b9741b 100644 --- a/tests/test_common_capabilities.py +++ b/tests/test_common_capabilities.py @@ -15,9 +15,13 @@ def _reg(): def test_kids_lock_vs_value_fn(): + """binary_sensor's 'lock' device class is inverted from a plain on/off + switch: On means open/unlocked (issues #181/#183 -- see + TestKidsLockFallback.test_vs_fallback_is_read_only for why this is a + binary_sensor at all).""" desc = common.KIDS_LOCK_VS_FALLBACK.entities[0] - assert desc.value_fn('Lock') is True - assert desc.value_fn('Ready') is False + assert desc.value_fn('Lock') is False + assert desc.value_fn('Ready') is True def test_common_caps_discover_on_dishwasher(dishwasher_resources): @@ -241,6 +245,16 @@ class TestKidsLockFallback: assert common.KIDS_LOCK_VS_FALLBACK.match_fn( {}, {'/kidslock/0': {}, '/kidslock/vs/0': {}}) is False + def test_vs_fallback_is_read_only(self): + """Issues #181/#183: writing this resource 4.05s on real hardware + even with the *correct* value ('Run'), and no dump in the fixture + corpus has ever reported the value this used to write ('Enable') + back -- every one reports 'Ready' or 'Run'. Never a confirmed write + contract, so it's a binary_sensor (no write_fn field at all), not + a switch.""" + desc = common.KIDS_LOCK_VS_FALLBACK.entities[0] + assert isinstance(desc, BinarySensorDesc) + class TestRemoteControlFallback: def test_generic_read(self): diff --git a/tests/test_range_ne6516a_capabilities.py b/tests/test_range_ne6516a_capabilities.py index ccf905c..c59c1cb 100644 --- a/tests/test_range_ne6516a_capabilities.py +++ b/tests/test_range_ne6516a_capabilities.py @@ -56,7 +56,10 @@ def test_energy_saving_and_cooktop_alert_present(): def test_child_lock_already_reads_correctly(): """issue #183 also reported child lock as unreadable -- but this dump's /kidslock/vs/0 ('Run') and /doors/vs/0's door lock field ('Lock') already - agree the door is locked, and the existing common.KIDS_LOCK_VS_FALLBACK - already reads that correctly with no code change needed.""" + agree the door is locked, and common.KIDS_LOCK_VS_FALLBACK already reads + that correctly with no further code change needed. Now a read-only + binary_sensor (issues #181/#183 -- the write side was never a confirmed + contract), whose 'lock' device class is inverted from a switch's plain + on/off: False means locked/closed, matching 'Run' here.""" state = _state() - assert state['child_lock'] is True + assert state['child_lock'] is False