From 671e838085bdeb253d7aca8fc55677a774d935b8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 19 Jul 2021 00:07:12 -1000 Subject: [PATCH] Execute scripts from HomeKit (#53106) --- .../components/homekit/type_switches.py | 17 +++++++---- .../components/homekit/test_type_switches.py | 30 +++++++++++++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index 8ea19897420..381110a4e79 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -55,6 +55,9 @@ VALVE_TYPE = { } +ACTIVATE_ONLY_SWITCH_DOMAINS = {"scene", "script"} + + @TYPES.register("Outlet") class Outlet(HomeAccessory): """Generate an Outlet accessory.""" @@ -98,7 +101,7 @@ class Switch(HomeAccessory): def __init__(self, *args): """Initialize a Switch accessory object.""" super().__init__(*args, category=CATEGORY_SWITCH) - self._domain = split_entity_id(self.entity_id)[0] + self._domain, self._object_id = split_entity_id(self.entity_id) state = self.hass.states.get(self.entity_id) self.activate_only = self.is_activate(self.hass.states.get(self.entity_id)) @@ -113,9 +116,7 @@ class Switch(HomeAccessory): def is_activate(self, state): """Check if entity is activate only.""" - if self._domain == "scene": - return True - return False + return self._domain in ACTIVATE_ONLY_SWITCH_DOMAINS def reset_switch(self, *args): """Reset switch to emulate activate click.""" @@ -129,8 +130,14 @@ class Switch(HomeAccessory): if self.activate_only and not value: _LOGGER.debug("%s: Ignoring turn_off call", self.entity_id) return + params = {ATTR_ENTITY_ID: self.entity_id} - service = SERVICE_TURN_ON if value else SERVICE_TURN_OFF + if self._domain == "script": + service = self._object_id + params = {} + else: + service = SERVICE_TURN_ON if value else SERVICE_TURN_OFF + self.async_call_service(self._domain, service, params) if self.activate_only: diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 2ce0acfc8bc..455f7a6141a 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -84,7 +84,6 @@ async def test_outlet_set_state(hass, hk_driver, events): ("automation.test", {}), ("input_boolean.test", {}), ("remote.test", {}), - ("script.test", {}), ("switch.test", {}), ], ) @@ -340,8 +339,9 @@ async def test_reset_switch(hass, hk_driver, events): assert len(events) == 1 -async def test_reset_switch_reload(hass, hk_driver, events): - """Test reset switch after script reload.""" +async def test_script_switch(hass, hk_driver, events): + """Test if script switch accessory is reset correctly.""" + domain = "script" entity_id = "script.test" hass.states.async_set(entity_id, None) @@ -350,8 +350,28 @@ async def test_reset_switch_reload(hass, hk_driver, events): await acc.run() await hass.async_block_till_done() - assert acc.activate_only is False + assert acc.activate_only is True + assert acc.char_on.value is False - hass.states.async_set(entity_id, None) + call_turn_on = async_mock_service(hass, domain, "test") + call_turn_off = async_mock_service(hass, domain, "turn_off") + + await hass.async_add_executor_job(acc.char_on.client_update_value, True) + await hass.async_block_till_done() + assert acc.char_on.value is True + assert call_turn_on + assert call_turn_on[0].data == {} + assert len(events) == 1 + assert events[-1].data[ATTR_VALUE] is None + + future = dt_util.utcnow() + timedelta(seconds=1) + async_fire_time_changed(hass, future) await hass.async_block_till_done() assert acc.char_on.value is False + assert len(events) == 1 + assert not call_turn_off + + await hass.async_add_executor_job(acc.char_on.client_update_value, False) + await hass.async_block_till_done() + assert acc.char_on.value is False + assert len(events) == 1