From c4b72f63763146294cc4148b8e1e068384fa1d77 Mon Sep 17 00:00:00 2001 From: Mick Vleeshouwer Date: Sat, 16 May 2026 15:25:06 +0000 Subject: [PATCH] Fix `is_closed` state for SlidingDiscreteGateWithPedestrianPosition in Overkiz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SlidingDiscreteGateWithPedestrianPosition widget reports core:OpenClosedPedestrianState instead of core:OpenClosedState. Without a dedicated override, it falls through to the UIClass.GATE default which looks for core:OpenClosedState—a state this device does not have—resulting in is_closed always being None. Fixes #170259 --- homeassistant/components/overkiz/cover.py | 11 ++ .../setup/cloud_somfy_tahoma_v2_europe.json | 122 ++++++++++++++++++ .../overkiz/snapshots/test_button.ambr | 51 ++++++++ .../overkiz/snapshots/test_cover.ambr | 53 ++++++++ tests/components/overkiz/test_cover.py | 11 ++ 5 files changed, 248 insertions(+) diff --git a/homeassistant/components/overkiz/cover.py b/homeassistant/components/overkiz/cover.py index a464c1a5b0d366..3005d7c0aff9fc 100644 --- a/homeassistant/components/overkiz/cover.py +++ b/homeassistant/components/overkiz/cover.py @@ -185,6 +185,17 @@ class OverkizCoverDescription(CoverEntityDescription): is_closed_state=OverkizState.CORE_OPEN_CLOSED_PEDESTRIAN, stop_command=OverkizCommand.STOP, ), + # Needs override since SlidingDiscreteGateWithPedestrianPosition reports + # core:OpenClosedPedestrianState instead of core:OpenClosedState + # uiClass is Gate + OverkizCoverDescription( + key=UIWidget.SLIDING_DISCRETE_GATE_WITH_PEDESTRIAN_POSITION, + device_class=CoverDeviceClass.GATE, + open_command=OverkizCommand.OPEN, + close_command=OverkizCommand.CLOSE, + is_closed_state=OverkizState.CORE_OPEN_CLOSED_PEDESTRIAN, + stop_command=OverkizCommand.STOP, + ), # Needs override to support this Generic device (rts:GenericRTSComponent) # uiClass is Generic (not mapped to cover as this is a Generic device class) OverkizCoverDescription( diff --git a/tests/components/overkiz/fixtures/setup/cloud_somfy_tahoma_v2_europe.json b/tests/components/overkiz/fixtures/setup/cloud_somfy_tahoma_v2_europe.json index d69c75e548ff1c..a8b4aaf4349c30 100644 --- a/tests/components/overkiz/fixtures/setup/cloud_somfy_tahoma_v2_europe.json +++ b/tests/components/overkiz/fixtures/setup/cloud_somfy_tahoma_v2_europe.json @@ -7441,6 +7441,128 @@ "oid": "6ba9b1de-8037-41d7-9150-21f7d5f49a3f", "uiClass": "Gate" }, + { + "creationTime": 1654894302000, + "lastUpdateTime": 1654894302000, + "label": "Sliding Gate", + "deviceURL": "io://1234-1234-6233/16730051", + "shortcut": false, + "controllableName": "io:SlidingDiscreteGateOpenerIOComponent", + "definition": { + "commands": [ + { + "commandName": "close", + "nparams": 0 + }, + { + "commandName": "identify", + "nparams": 0 + }, + { + "commandName": "open", + "nparams": 0 + }, + { + "commandName": "refreshPedestrianPosition", + "nparams": 0 + }, + { + "commandName": "setPedestrianPosition", + "nparams": 0 + }, + { + "commandName": "stop", + "nparams": 0 + } + ], + "states": [ + { + "type": "DiscreteState", + "values": ["good", "low", "normal", "verylow"], + "qualifiedName": "core:DiscreteRSSILevelState" + }, + { + "type": "DataState", + "qualifiedName": "core:NameState" + }, + { + "type": "DiscreteState", + "values": ["closed", "open", "pedestrian", "unknown"], + "qualifiedName": "core:OpenClosedPedestrianState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:PedestrianPositionState" + }, + { + "type": "ContinuousState", + "qualifiedName": "core:RSSILevelState" + }, + { + "type": "DiscreteState", + "values": ["available", "unavailable"], + "qualifiedName": "core:StatusState" + } + ], + "dataProperties": [], + "widgetName": "SlidingDiscreteGateWithPedestrianPosition", + "uiProfiles": ["OpenCloseGateOpener", "OpenClose"], + "uiClass": "Gate", + "qualifiedName": "io:SlidingDiscreteGateOpenerIOComponent", + "type": "ACTUATOR" + }, + "states": [ + { + "name": "core:NameState", + "type": 3, + "value": "Sliding Gate" + }, + { + "name": "core:StatusState", + "type": 3, + "value": "available" + }, + { + "name": "core:DiscreteRSSILevelState", + "type": 3, + "value": "normal" + }, + { + "name": "core:RSSILevelState", + "type": 2, + "value": 50.0 + }, + { + "name": "core:OpenClosedPedestrianState", + "type": 3, + "value": "closed" + }, + { + "name": "core:PedestrianPositionState", + "type": 1, + "value": 50 + } + ], + "attributes": [ + { + "name": "core:Manufacturer", + "type": 3, + "value": "Somfy" + }, + { + "name": "core:FirmwareRevision", + "type": 3, + "value": "5107456G05" + } + ], + "available": true, + "enabled": true, + "placeOID": "bcbb34ef-2241-43a1-9c5b-523aa0563ec3", + "widget": "SlidingDiscreteGateWithPedestrianPosition", + "type": 1, + "oid": "c1e2f3a4-b5d6-7890-abcd-ef1234567890", + "uiClass": "Gate" + }, { "creationTime": 1521964729000, "lastUpdateTime": 1521964729000, diff --git a/tests/components/overkiz/snapshots/test_button.ambr b/tests/components/overkiz/snapshots/test_button.ambr index d01827f1bbb877..e331b720fed308 100644 --- a/tests/components/overkiz/snapshots/test_button.ambr +++ b/tests/components/overkiz/snapshots/test_button.ambr @@ -4462,6 +4462,57 @@ 'state': 'unknown', }) # --- +# name: test_button_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][button.sliding_gate_start_identify-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.sliding_gate_start_identify', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Start identify', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': 'mdi:human-greeting-variant', + 'original_name': 'Start identify', + 'platform': 'overkiz', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'io://1234-1234-6233/16730051-identify', + 'unit_of_measurement': None, + }) +# --- +# name: test_button_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][button.sliding_gate_start_identify-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Sliding Gate Start identify', + 'icon': 'mdi:human-greeting-variant', + }), + 'context': , + 'entity_id': 'button.sliding_gate_start_identify', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_button_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][button.start_identify-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/overkiz/snapshots/test_cover.ambr b/tests/components/overkiz/snapshots/test_cover.ambr index b1aaf0ea9a3bee..0fd3e7c3cc6eae 100644 --- a/tests/components/overkiz/snapshots/test_cover.ambr +++ b/tests/components/overkiz/snapshots/test_cover.ambr @@ -1993,6 +1993,59 @@ 'state': 'closed', }) # --- +# name: test_cover_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][cover.sliding_gate-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.sliding_gate', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'overkiz', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': 'io://1234-1234-6233/16730051', + 'unit_of_measurement': None, + }) +# --- +# name: test_cover_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][cover.sliding_gate-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'gate', + 'friendly_name': 'Sliding Gate', + 'is_closed': True, + 'supported_features': , + }), + 'context': , + 'entity_id': 'cover.sliding_gate', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'closed', + }) +# --- # name: test_cover_entities_snapshot[cloud_somfy_tahoma_v2_europe.json][cover.studio_shutter-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/overkiz/test_cover.py b/tests/components/overkiz/test_cover.py index 4e158a53b46c0b..61ee583008701d 100644 --- a/tests/components/overkiz/test_cover.py +++ b/tests/components/overkiz/test_cover.py @@ -124,6 +124,11 @@ "io://1234-1234-6233/7433515", "cover.partial_garage_door", ) +SLIDING_DISCRETE_GATE = FixtureDevice( + "setup/cloud_somfy_tahoma_v2_europe.json", + "io://1234-1234-6233/16730051", + "cover.sliding_gate", +) DYNAMIC_GATE = FixtureDevice( "setup/cloud_somfy_tahoma_v2_europe.json", "ogp://1234-1234-6233/10410217", @@ -177,6 +182,7 @@ async def test_cover_entities_snapshot( (DYNAMIC_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING), (DYNAMIC_GARAGE_DOOR_OGP, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING), (DYNAMIC_GATE, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING), + (SLIDING_DISCRETE_GATE, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING), (PARTIAL_GARAGE_DOOR, SERVICE_OPEN_COVER, "open", None, CoverState.OPENING), ( UP_DOWN_BIOCLIMATIC_PERGOLA, @@ -199,6 +205,7 @@ async def test_cover_entities_snapshot( CoverState.CLOSING, ), (DYNAMIC_GATE, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING), + (SLIDING_DISCRETE_GATE, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING), (PARTIAL_GARAGE_DOOR, SERVICE_CLOSE_COVER, "close", None, CoverState.CLOSING), ( UP_DOWN_BIOCLIMATIC_PERGOLA, @@ -221,6 +228,7 @@ async def test_cover_entities_snapshot( (DYNAMIC_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED), (DYNAMIC_GARAGE_DOOR_OGP, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED), (DYNAMIC_GATE, SERVICE_STOP_COVER, "stop", None, CoverState.OPEN), + (SLIDING_DISCRETE_GATE, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED), (PARTIAL_GARAGE_DOOR, SERVICE_STOP_COVER, "stop", None, CoverState.CLOSED), ( UP_DOWN_BIOCLIMATIC_PERGOLA, @@ -281,6 +289,7 @@ async def test_cover_entities_snapshot( "open-dynamic-garage-door", "open-dynamic-garage-door-ogp", "open-dynamic-gate", + "open-sliding-discrete-gate", "open-partial-garage-door", "open-up-down-bioclimatic-pergola", "open-tilt-only-venetian-blind", @@ -291,6 +300,7 @@ async def test_cover_entities_snapshot( "close-dynamic-garage-door", "close-dynamic-garage-door-ogp", "close-dynamic-gate", + "close-sliding-discrete-gate", "close-partial-garage-door", "close-up-down-bioclimatic-pergola", "close-tilt-only-venetian-blind", @@ -301,6 +311,7 @@ async def test_cover_entities_snapshot( "stop-dynamic-garage-door", "stop-dynamic-garage-door-ogp", "stop-dynamic-gate", + "stop-sliding-discrete-gate", "stop-partial-garage-door", "stop-up-down-bioclimatic-pergola", "stop-tilt-only-venetian-blind",