From e6be327f2b114a896ebc0e835bf5b31c4f42aab6 Mon Sep 17 00:00:00 2001 From: louwii17 Date: Wed, 9 Sep 2026 00:38:34 -0700 Subject: [PATCH] Add configurable HomeKit types for valve entities (#177407) --- .../components/homekit/type_switches.py | 19 ++++++++-- homeassistant/components/homekit/util.py | 4 +++ .../components/homekit/test_type_switches.py | 35 ++++++++++++++++++- tests/components/homekit/test_util.py | 8 ++--- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index ab852d7c29ed..58e42b03fc48 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -505,13 +505,28 @@ class ValveSwitch(ValveBase): class Valve(ValveBase): """Generate a Valve accessory from a HomeAssistant valve.""" - def __init__(self, *args: Any) -> None: + def __init__( + self, + hass: HomeAssistant, + driver: HomeDriver, + name: str, + entity_id: str, + aid: int, + config: dict[str, Any], + *args: Any, + ) -> None: """Initialize a Valve accessory object.""" super().__init__( - TYPE_VALVE, + config.get(CONF_TYPE, TYPE_VALVE), VALVE_OPEN_STATES, SERVICE_OPEN_VALVE, SERVICE_CLOSE_VALVE, + hass, + driver, + name, + entity_id, + aid, + config, *args, ) diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 9eafda8b0ae3..aa2cb347ce07 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -304,6 +304,10 @@ SENSOR_SCHEMA = BASIC_INFO_SCHEMA.extend( VALVE_SCHEMA = BASIC_INFO_SCHEMA.extend( { + vol.Optional(CONF_TYPE): vol.All( + cv.string, + vol.In((TYPE_FAUCET, TYPE_SHOWER, TYPE_SPRINKLER, TYPE_VALVE)), + ), vol.Optional(CONF_LINKED_VALVE_DURATION): cv.entity_domain(INPUT_NUMBER_DOMAIN), vol.Optional(CONF_LINKED_VALVE_END_TIME): cv.entity_domain(SENSOR_DOMAIN), } diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 2bc060960df4..66cb16e80d1e 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -244,7 +244,7 @@ async def test_valve_set_state( hass.states.async_set(entity_id, None) await hass.async_block_till_done() - acc = Valve(hass, hk_driver, "Valve", entity_id, 5, {CONF_TYPE: TYPE_VALVE}) + acc = Valve(hass, hk_driver, "Valve", entity_id, 5, {}) acc.run() await hass.async_block_till_done() @@ -286,6 +286,39 @@ async def test_valve_set_state( assert events[-1].data[ATTR_VALUE] is None +@pytest.mark.parametrize( + ("valve_type", "category", "homekit_valve_type"), + [ + pytest.param(TYPE_FAUCET, 29, 3, id="faucet"), + pytest.param(TYPE_SHOWER, 30, 2, id="shower"), + pytest.param(TYPE_SPRINKLER, 28, 1, id="sprinkler"), + pytest.param(TYPE_VALVE, 29, 0, id="generic"), + ], +) +async def test_valve_type( + hass: HomeAssistant, + hk_driver: HomeDriver, + valve_type: str, + category: int, + homekit_valve_type: int, +) -> None: + """Test native valve HomeKit type configuration.""" + entity_id = f"valve.{valve_type}" + hass.states.async_set(entity_id, STATE_CLOSED) + + acc = Valve( + hass, + hk_driver, + "Valve", + entity_id, + 5, + {CONF_TYPE: valve_type}, + ) + + assert acc.category == category + assert acc.char_valve_type.value == homekit_valve_type + + async def test_vacuum_set_state_with_returnhome_and_start_support( hass: HomeAssistant, hk_driver, events: list[Event] ) -> None: diff --git a/tests/components/homekit/test_util.py b/tests/components/homekit/test_util.py index 05d09b89848a..04e125806348 100644 --- a/tests/components/homekit/test_util.py +++ b/tests/components/homekit/test_util.py @@ -151,11 +151,7 @@ def test_validate_entity_config() -> None: CONF_LINKED_VALVE_DURATION: "number.valve_duration", } }, - { - "valve.test": { - CONF_TYPE: "sprinkler", # Extra keys not allowed - } - }, + {"valve.test": {CONF_TYPE: "invalid_type"}}, ] for conf in configs: @@ -291,11 +287,13 @@ def test_validate_entity_config() -> None: } } config = { + CONF_TYPE: TYPE_SPRINKLER, CONF_LINKED_VALVE_DURATION: "input_number.valve_duration", CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time", } assert vec({"valve.demo": config}) == { "valve.demo": { + CONF_TYPE: TYPE_SPRINKLER, CONF_LINKED_VALVE_DURATION: "input_number.valve_duration", CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time", CONF_LOW_BATTERY_THRESHOLD: DEFAULT_LOW_BATTERY_THRESHOLD,