Add button support to HomeKit (#60165)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
f510534c58
commit
766c889e70
6 changed files with 59 additions and 2 deletions
|
@ -195,7 +195,14 @@ def get_accessory(hass, driver, state, aid, config): # noqa: C901
|
||||||
elif state.domain == "remote" and features & SUPPORT_ACTIVITY:
|
elif state.domain == "remote" and features & SUPPORT_ACTIVITY:
|
||||||
a_type = "ActivityRemote"
|
a_type = "ActivityRemote"
|
||||||
|
|
||||||
elif state.domain in ("automation", "input_boolean", "remote", "scene", "script"):
|
elif state.domain in (
|
||||||
|
"automation",
|
||||||
|
"button",
|
||||||
|
"input_boolean",
|
||||||
|
"remote",
|
||||||
|
"scene",
|
||||||
|
"script",
|
||||||
|
):
|
||||||
a_type = "Switch"
|
a_type = "Switch"
|
||||||
|
|
||||||
elif state.domain in ("input_select", "select"):
|
elif state.domain in ("input_select", "select"):
|
||||||
|
|
|
@ -76,6 +76,7 @@ SUPPORTED_DOMAINS = [
|
||||||
"alarm_control_panel",
|
"alarm_control_panel",
|
||||||
"automation",
|
"automation",
|
||||||
"binary_sensor",
|
"binary_sensor",
|
||||||
|
"button",
|
||||||
CAMERA_DOMAIN,
|
CAMERA_DOMAIN,
|
||||||
"climate",
|
"climate",
|
||||||
"cover",
|
"cover",
|
||||||
|
|
|
@ -12,6 +12,7 @@ from pyhap.const import (
|
||||||
CATEGORY_SWITCH,
|
CATEGORY_SWITCH,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from homeassistant.components import button
|
||||||
from homeassistant.components.input_select import ATTR_OPTIONS, SERVICE_SELECT_OPTION
|
from homeassistant.components.input_select import ATTR_OPTIONS, SERVICE_SELECT_OPTION
|
||||||
from homeassistant.components.switch import DOMAIN
|
from homeassistant.components.switch import DOMAIN
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (
|
||||||
|
@ -69,7 +70,7 @@ VALVE_TYPE: dict[str, ValveInfo] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ACTIVATE_ONLY_SWITCH_DOMAINS = {"scene", "script"}
|
ACTIVATE_ONLY_SWITCH_DOMAINS = {"button", "scene", "script"}
|
||||||
|
|
||||||
ACTIVATE_ONLY_RESET_SECONDS = 10
|
ACTIVATE_ONLY_RESET_SECONDS = 10
|
||||||
|
|
||||||
|
@ -149,6 +150,8 @@ class Switch(HomeAccessory):
|
||||||
if self._domain == "script":
|
if self._domain == "script":
|
||||||
service = self._object_id
|
service = self._object_id
|
||||||
params = {}
|
params = {}
|
||||||
|
elif self._domain == button.DOMAIN:
|
||||||
|
service = button.SERVICE_PRESS
|
||||||
else:
|
else:
|
||||||
service = SERVICE_TURN_ON if value else SERVICE_TURN_OFF
|
service = SERVICE_TURN_ON if value else SERVICE_TURN_OFF
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ ALLOWED_USED_COMPONENTS = {
|
||||||
"alert",
|
"alert",
|
||||||
"automation",
|
"automation",
|
||||||
"conversation",
|
"conversation",
|
||||||
|
"button",
|
||||||
"device_automation",
|
"device_automation",
|
||||||
"frontend",
|
"frontend",
|
||||||
"group",
|
"group",
|
||||||
|
|
|
@ -30,6 +30,7 @@ from homeassistant.const import (
|
||||||
DEVICE_CLASS_CO2,
|
DEVICE_CLASS_CO2,
|
||||||
LIGHT_LUX,
|
LIGHT_LUX,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
)
|
)
|
||||||
|
@ -270,6 +271,7 @@ def test_type_sensors(type_name, entity_id, state, attrs):
|
||||||
[
|
[
|
||||||
("Outlet", "switch.test", "on", {}, {CONF_TYPE: TYPE_OUTLET}),
|
("Outlet", "switch.test", "on", {}, {CONF_TYPE: TYPE_OUTLET}),
|
||||||
("Switch", "automation.test", "on", {}, {}),
|
("Switch", "automation.test", "on", {}, {}),
|
||||||
|
("Switch", "button.test", STATE_UNKNOWN, {}, {}),
|
||||||
("Switch", "input_boolean.test", "on", {}, {}),
|
("Switch", "input_boolean.test", "on", {}, {}),
|
||||||
("Switch", "remote.test", "on", {}, {}),
|
("Switch", "remote.test", "on", {}, {}),
|
||||||
("Switch", "scene.test", "on", {}, {}),
|
("Switch", "scene.test", "on", {}, {}),
|
||||||
|
|
|
@ -449,3 +449,46 @@ async def test_input_select_switch(hass, hk_driver, events, domain):
|
||||||
assert acc.select_chars["option1"].value is False
|
assert acc.select_chars["option1"].value is False
|
||||||
assert acc.select_chars["option2"].value is False
|
assert acc.select_chars["option2"].value is False
|
||||||
assert acc.select_chars["option3"].value is False
|
assert acc.select_chars["option3"].value is False
|
||||||
|
|
||||||
|
|
||||||
|
async def test_button_switch(hass, hk_driver, events):
|
||||||
|
"""Test switch accessory from a button entity."""
|
||||||
|
domain = "button"
|
||||||
|
entity_id = "button.test"
|
||||||
|
|
||||||
|
hass.states.async_set(entity_id, None)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = Switch(hass, hk_driver, "Switch", entity_id, 2, None)
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert acc.activate_only is True
|
||||||
|
assert acc.char_on.value is False
|
||||||
|
|
||||||
|
call_press = async_mock_service(hass, domain, "press")
|
||||||
|
|
||||||
|
acc.char_on.client_update_value(True)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_on.value is True
|
||||||
|
assert len(call_press) == 1
|
||||||
|
assert call_press[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
|
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 True
|
||||||
|
|
||||||
|
future = dt_util.utcnow() + timedelta(seconds=10)
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_on.value is False
|
||||||
|
|
||||||
|
assert len(events) == 1
|
||||||
|
assert len(call_press) == 1
|
||||||
|
|
||||||
|
acc.char_on.client_update_value(False)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_on.value is False
|
||||||
|
assert len(events) == 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue