mirror of
https://github.com/home-assistant/core.git
synced 2025-04-26 18:27:51 +00:00
Add HomeKit Reset Accessory (#25158)
* added the ability to reset homekit accessories * added tests for homekit reset accessory * minor fixes
This commit is contained in:
parent
cca50a8339
commit
c2f4f06005
@ -8,11 +8,11 @@ import voluptuous as vol
|
||||
from homeassistant.components import cover
|
||||
from homeassistant.components.media_player import DEVICE_CLASS_TV
|
||||
from homeassistant.const import (
|
||||
ATTR_DEVICE_CLASS, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONF_IP_ADDRESS, CONF_NAME, CONF_PORT, CONF_TYPE, DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE,
|
||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT)
|
||||
ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES,
|
||||
ATTR_UNIT_OF_MEASUREMENT, CONF_IP_ADDRESS, CONF_NAME, CONF_PORT,
|
||||
CONF_TYPE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE,
|
||||
DEVICE_CLASS_TEMPERATURE, EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
|
||||
from homeassistant.util import get_local_ip
|
||||
@ -22,8 +22,10 @@ from .const import (
|
||||
BRIDGE_NAME, CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FEATURE_LIST,
|
||||
CONF_FILTER, CONF_SAFE_MODE, DEFAULT_AUTO_START, DEFAULT_PORT,
|
||||
DEFAULT_SAFE_MODE, DEVICE_CLASS_CO, DEVICE_CLASS_CO2, DEVICE_CLASS_PM25,
|
||||
DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START, TYPE_FAUCET, TYPE_OUTLET,
|
||||
TYPE_SHOWER, TYPE_SPRINKLER, TYPE_SWITCH, TYPE_VALVE)
|
||||
DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START,
|
||||
SERVICE_HOMEKIT_RESET_ACCESSORY, TYPE_FAUCET, TYPE_OUTLET, TYPE_SHOWER,
|
||||
TYPE_SPRINKLER, TYPE_SWITCH, TYPE_VALVE)
|
||||
|
||||
from .util import (
|
||||
show_setup_message, validate_entity_config, validate_media_player_features)
|
||||
|
||||
@ -60,6 +62,10 @@ CONFIG_SCHEMA = vol.Schema({
|
||||
})
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
RESET_ACCESSORY_SERVICE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids
|
||||
})
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the HomeKit component."""
|
||||
@ -78,6 +84,21 @@ async def async_setup(hass, config):
|
||||
entity_config, safe_mode)
|
||||
await hass.async_add_executor_job(homekit.setup)
|
||||
|
||||
def handle_homekit_reset_accessory(service):
|
||||
"""Handle start HomeKit service call."""
|
||||
if homekit.status != STATUS_RUNNING:
|
||||
_LOGGER.warning(
|
||||
'HomeKit is not running. Either it is waiting to be '
|
||||
'started or has been stopped.')
|
||||
return
|
||||
|
||||
entity_ids = service.data.get('entity_id')
|
||||
homekit.reset_accessories(entity_ids)
|
||||
|
||||
hass.services.async_register(DOMAIN, SERVICE_HOMEKIT_RESET_ACCESSORY,
|
||||
handle_homekit_reset_accessory,
|
||||
schema=RESET_ACCESSORY_SERVICE_SCHEMA)
|
||||
|
||||
if auto_start:
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, homekit.start)
|
||||
return True
|
||||
@ -229,6 +250,23 @@ class HomeKit():
|
||||
_LOGGER.debug('Safe_mode selected')
|
||||
self.driver.safe_mode = True
|
||||
|
||||
def reset_accessories(self, entity_ids):
|
||||
"""Reset the accessory to load the latest configuration."""
|
||||
removed = []
|
||||
for entity_id in entity_ids:
|
||||
aid = generate_aid(entity_id)
|
||||
if aid not in self.bridge.accessories:
|
||||
_LOGGER.warning('Could not reset accessory. entity_id '
|
||||
'not found %s', entity_id)
|
||||
continue
|
||||
acc = self.remove_bridge_accessory(aid)
|
||||
removed.append(acc)
|
||||
self.driver.config_changed()
|
||||
|
||||
for acc in removed:
|
||||
self.bridge.add_accessory(acc)
|
||||
self.driver.config_changed()
|
||||
|
||||
def add_bridge_accessory(self, state):
|
||||
"""Try adding accessory to bridge if configured beforehand."""
|
||||
if not state or not self._filter(state.entity_id):
|
||||
@ -239,6 +277,13 @@ class HomeKit():
|
||||
if acc is not None:
|
||||
self.bridge.add_accessory(acc)
|
||||
|
||||
def remove_bridge_accessory(self, aid):
|
||||
"""Try adding accessory to bridge if configured beforehand."""
|
||||
acc = None
|
||||
if aid in self.bridge.accessories:
|
||||
acc = self.bridge.accessories.pop(aid)
|
||||
return acc
|
||||
|
||||
def start(self, *args):
|
||||
"""Start the accessory driver."""
|
||||
if self.status != STATUS_READY:
|
||||
|
@ -36,6 +36,7 @@ EVENT_HOMEKIT_CHANGED = 'homekit_state_change'
|
||||
|
||||
# #### HomeKit Component Services ####
|
||||
SERVICE_HOMEKIT_START = 'start'
|
||||
SERVICE_HOMEKIT_RESET_ACCESSORY = 'reset_accessory'
|
||||
|
||||
# #### String Constants ####
|
||||
BRIDGE_MODEL = 'Bridge'
|
||||
|
@ -4,21 +4,24 @@ from unittest.mock import patch, ANY, Mock
|
||||
import pytest
|
||||
|
||||
from homeassistant import setup
|
||||
|
||||
from homeassistant.components.homekit import (
|
||||
generate_aid, HomeKit, MAX_DEVICES, STATUS_READY,
|
||||
STATUS_RUNNING, STATUS_STOPPED, STATUS_WAIT)
|
||||
from homeassistant.components.homekit.accessories import HomeBridge
|
||||
from homeassistant.components.homekit.const import (
|
||||
CONF_AUTO_START, CONF_SAFE_MODE, BRIDGE_NAME, DEFAULT_PORT,
|
||||
DEFAULT_SAFE_MODE, DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START)
|
||||
DEFAULT_SAFE_MODE, DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START,
|
||||
SERVICE_HOMEKIT_RESET_ACCESSORY)
|
||||
from homeassistant.const import (
|
||||
CONF_NAME, CONF_IP_ADDRESS, CONF_PORT,
|
||||
ATTR_ENTITY_ID, CONF_NAME, CONF_IP_ADDRESS, CONF_PORT,
|
||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
||||
from homeassistant.core import State
|
||||
from homeassistant.helpers.entityfilter import generate_filter
|
||||
|
||||
from tests.components.homekit.common import patch_debounce
|
||||
|
||||
|
||||
IP_ADDRESS = '127.0.0.1'
|
||||
PATH_HOMEKIT = 'homeassistant.components.homekit'
|
||||
|
||||
@ -164,6 +167,19 @@ async def test_homekit_add_accessory():
|
||||
mock_bridge.add_accessory.assert_called_with('acc')
|
||||
|
||||
|
||||
async def test_homekit_remove_accessory():
|
||||
"""Remove accessory from bridge."""
|
||||
homekit = HomeKit('hass', None, None, None, lambda entity_id: True, {},
|
||||
None)
|
||||
homekit.driver = 'driver'
|
||||
homekit.bridge = mock_bridge = Mock()
|
||||
mock_bridge.accessories = {'light.demo': 'acc'}
|
||||
|
||||
acc = homekit.remove_bridge_accessory('light.demo')
|
||||
assert acc == 'acc'
|
||||
assert len(mock_bridge.accessories) == 0
|
||||
|
||||
|
||||
async def test_homekit_entity_filter(hass):
|
||||
"""Test the entity filter."""
|
||||
entity_filter = generate_filter(['cover'], ['demo.test'], [], [])
|
||||
@ -235,6 +251,36 @@ async def test_homekit_stop(hass):
|
||||
assert homekit.driver.stop.called is True
|
||||
|
||||
|
||||
async def test_homekit_reset_accessories(hass):
|
||||
"""Test adding too many accessories to HomeKit."""
|
||||
entity_id = 'light.demo'
|
||||
homekit = HomeKit(hass, None, None, None, {}, {entity_id: {}}, None)
|
||||
homekit.bridge = Mock()
|
||||
|
||||
with patch(PATH_HOMEKIT + '.HomeKit', return_value=homekit), \
|
||||
patch(PATH_HOMEKIT + '.HomeKit.setup'), \
|
||||
patch('pyhap.accessory.Bridge.add_accessory') as \
|
||||
mock_add_accessory, \
|
||||
patch('pyhap.accessory_driver.AccessoryDriver.config_changed') as \
|
||||
hk_driver_config_changed:
|
||||
|
||||
assert await setup.async_setup_component(
|
||||
hass, DOMAIN, {DOMAIN: {}})
|
||||
|
||||
aid = generate_aid(entity_id)
|
||||
homekit.bridge.accessories = {aid: 'acc'}
|
||||
homekit.status = STATUS_RUNNING
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN, SERVICE_HOMEKIT_RESET_ACCESSORY,
|
||||
{ATTR_ENTITY_ID: entity_id}, blocking=True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert 2 == hk_driver_config_changed.call_count
|
||||
assert mock_add_accessory.called
|
||||
homekit.status = STATUS_READY
|
||||
|
||||
|
||||
async def test_homekit_too_many_accessories(hass, hk_driver):
|
||||
"""Test adding too many accessories to HomeKit."""
|
||||
homekit = HomeKit(hass, None, None, None, None, None, None)
|
||||
|
Loading…
x
Reference in New Issue
Block a user