Add vacuum support to homekit (#34386)
parent
d144228272
commit
f0d553514d
|
@ -5,7 +5,7 @@ import logging
|
|||
import voluptuous as vol
|
||||
from zeroconf import InterfaceChoice
|
||||
|
||||
from homeassistant.components import cover
|
||||
from homeassistant.components import cover, vacuum
|
||||
from homeassistant.components.cover import DEVICE_CLASS_GARAGE, DEVICE_CLASS_GATE
|
||||
from homeassistant.components.media_player import DEVICE_CLASS_TV
|
||||
from homeassistant.const import (
|
||||
|
@ -268,6 +268,13 @@ def get_accessory(hass, driver, state, aid, config):
|
|||
switch_type = config.get(CONF_TYPE, TYPE_SWITCH)
|
||||
a_type = SWITCH_TYPES[switch_type]
|
||||
|
||||
elif state.domain == "vacuum":
|
||||
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||
if features & (vacuum.SUPPORT_START | vacuum.SUPPORT_RETURN_HOME):
|
||||
a_type = "DockVacuum"
|
||||
else:
|
||||
a_type = "Switch"
|
||||
|
||||
elif state.domain in ("automation", "input_boolean", "remote", "scene", "script"):
|
||||
a_type = "Switch"
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@ from pyhap.const import (
|
|||
|
||||
from homeassistant.components.script import ATTR_CAN_CANCEL
|
||||
from homeassistant.components.switch import DOMAIN
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_RETURN_TO_BASE,
|
||||
SERVICE_START,
|
||||
STATE_CLEANING,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
CONF_TYPE,
|
||||
|
@ -146,6 +152,25 @@ class Switch(HomeAccessory):
|
|||
self.char_on.set_value(current_state)
|
||||
|
||||
|
||||
@TYPES.register("DockVacuum")
|
||||
class DockVacuum(Switch):
|
||||
"""Generate a Switch accessory."""
|
||||
|
||||
def set_state(self, value):
|
||||
"""Move switch state to value if call came from HomeKit."""
|
||||
_LOGGER.debug("%s: Set switch state to %s", self.entity_id, value)
|
||||
params = {ATTR_ENTITY_ID: self.entity_id}
|
||||
service = SERVICE_START if value else SERVICE_RETURN_TO_BASE
|
||||
self.call_service(VACUUM_DOMAIN, service, params)
|
||||
|
||||
def update_state(self, new_state):
|
||||
"""Update switch state after state changed."""
|
||||
current_state = new_state.state in (STATE_CLEANING, STATE_ON)
|
||||
if self.char_on.value is not current_state:
|
||||
_LOGGER.debug("%s: Set current state to %s", self.entity_id, current_state)
|
||||
self.char_on.set_value(current_state)
|
||||
|
||||
|
||||
@TYPES.register("Valve")
|
||||
class Valve(HomeAccessory):
|
||||
"""Generate a Valve accessory."""
|
||||
|
|
|
@ -10,8 +10,20 @@ from homeassistant.components.homekit.const import (
|
|||
TYPE_SPRINKLER,
|
||||
TYPE_VALVE,
|
||||
)
|
||||
from homeassistant.components.homekit.type_switches import Outlet, Switch, Valve
|
||||
from homeassistant.components.homekit.type_switches import (
|
||||
DockVacuum,
|
||||
Outlet,
|
||||
Switch,
|
||||
Valve,
|
||||
)
|
||||
from homeassistant.components.script import ATTR_CAN_CANCEL
|
||||
from homeassistant.components.vacuum import (
|
||||
DOMAIN as VACUUM_DOMAIN,
|
||||
SERVICE_RETURN_TO_BASE,
|
||||
SERVICE_START,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_TYPE, STATE_OFF, STATE_ON
|
||||
from homeassistant.core import split_entity_id
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
@ -182,6 +194,52 @@ async def test_valve_set_state(hass, hk_driver, events):
|
|||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
async def test_vacuum_set_state(hass, hk_driver, events):
|
||||
"""Test if Vacuum accessory and HA are updated accordingly."""
|
||||
entity_id = "vacuum.roomba"
|
||||
|
||||
hass.states.async_set(entity_id, None)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
acc = DockVacuum(hass, hk_driver, "DockVacuum", entity_id, 2, None)
|
||||
await acc.run_handler()
|
||||
await hass.async_block_till_done()
|
||||
assert acc.aid == 2
|
||||
assert acc.category == 8 # Switch
|
||||
|
||||
assert acc.char_on.value == 0
|
||||
|
||||
hass.states.async_set(entity_id, STATE_CLEANING)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_on.value == 1
|
||||
|
||||
hass.states.async_set(entity_id, STATE_DOCKED)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_on.value == 0
|
||||
|
||||
# Set from HomeKit
|
||||
call_start = async_mock_service(hass, VACUUM_DOMAIN, SERVICE_START)
|
||||
call_return_to_base = async_mock_service(
|
||||
hass, VACUUM_DOMAIN, SERVICE_RETURN_TO_BASE
|
||||
)
|
||||
|
||||
await hass.async_add_executor_job(acc.char_on.client_update_value, 1)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_on.value == 1
|
||||
assert call_start
|
||||
assert call_start[0].data[ATTR_ENTITY_ID] == entity_id
|
||||
assert len(events) == 1
|
||||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
await hass.async_add_executor_job(acc.char_on.client_update_value, 0)
|
||||
await hass.async_block_till_done()
|
||||
assert acc.char_on.value == 0
|
||||
assert call_return_to_base
|
||||
assert call_return_to_base[0].data[ATTR_ENTITY_ID] == entity_id
|
||||
assert len(events) == 2
|
||||
assert events[-1].data[ATTR_VALUE] is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"entity_id, attrs",
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue