From 669dd93e83d85b76e9f5669dfcf3ee7d081fd4eb Mon Sep 17 00:00:00 2001 From: Mattias Arrelid Date: Sat, 4 Jul 2026 16:27:54 +0200 Subject: [PATCH] Fix HomeKit select accessories not marking the active option as on (#175603) Co-authored-by: Claude Fable 5 --- .../components/homekit/type_switches.py | 2 +- .../components/homekit/test_type_switches.py | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index a0d9830de4f0..a9b2d45d6e87 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -556,6 +556,6 @@ class SelectSwitch(HomeAccessory): @override def async_update_state(self, new_state: State) -> None: """Update switch state after state changed.""" - current_option = cleanup_name_for_homekit(new_state.state) + current_option = new_state.state for option, char in self.select_chars.items(): char.set_value(option == current_option) diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 796caba2c0db..2bc060960df4 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -5,9 +5,11 @@ from datetime import timedelta from freezegun import freeze_time import pytest +from homeassistant.components.homekit.accessories import HomeDriver from homeassistant.components.homekit.const import ( ATTR_VALUE, CHAR_CONFIGURED_NAME, + CHAR_NAME, SERV_OUTLET, TYPE_FAUCET, TYPE_SHOWER, @@ -618,6 +620,57 @@ async def test_input_select_switch( assert acc.select_chars["option3"].value is False +@pytest.mark.parametrize( + "domain", + ["input_select", "select"], +) +async def test_select_switch_with_options_needing_name_cleanup( + hass: HomeAssistant, hk_driver: HomeDriver, events: list[Event], domain: str +) -> None: + """Test select options altered by HomeKit name cleanup still sync state.""" + entity_id = f"{domain}.test" + options = ["always_on", "always on"] + + hass.states.async_set(entity_id, "always_on", {ATTR_OPTIONS: options}) + await hass.async_block_till_done() + acc = SelectSwitch(hass, hk_driver, "SelectSwitch", entity_id, 2, None) + acc.run() + await hass.async_block_till_done() + + outlets = [serv for serv in acc.services if serv.display_name == SERV_OUTLET] + assert [serv.get_characteristic(CHAR_NAME).value for serv in outlets] == [ + "always on", + "always on", + ] + assert [ + serv.get_characteristic(CHAR_CONFIGURED_NAME).value for serv in outlets + ] == ["always on", "always on"] + + assert {option: char.value for option, char in acc.select_chars.items()} == { + "always_on": True, + "always on": False, + } + + hass.states.async_set(entity_id, "always on", {ATTR_OPTIONS: options}) + await hass.async_block_till_done() + assert {option: char.value for option, char in acc.select_chars.items()} == { + "always_on": False, + "always on": True, + } + + call_select_option = async_mock_service(hass, domain, SERVICE_SELECT_OPTION) + acc.select_chars["always_on"].client_update_value(True) + await hass.async_block_till_done() + + assert call_select_option + assert call_select_option[0].data == { + "entity_id": entity_id, + "option": "always_on", + } + assert len(events) == 1 + assert events[-1].data[ATTR_VALUE] is None + + @pytest.mark.parametrize( "domain", ["button", "input_button"],