mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 16:17:20 +00:00
Add safe_mode HomeKit (#18356)
* Use: 'safe_mode: True' in case of pairing issues
This commit is contained in:
parent
b7b8296c73
commit
ed7aea006a
@ -22,7 +22,8 @@ from homeassistant.util import get_local_ip
|
|||||||
from homeassistant.util.decorator import Registry
|
from homeassistant.util.decorator import Registry
|
||||||
from .const import (
|
from .const import (
|
||||||
BRIDGE_NAME, CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FEATURE_LIST,
|
BRIDGE_NAME, CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FEATURE_LIST,
|
||||||
CONF_FILTER, DEFAULT_AUTO_START, DEFAULT_PORT, DEVICE_CLASS_CO,
|
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,
|
DEVICE_CLASS_CO2, DEVICE_CLASS_PM25, DOMAIN, HOMEKIT_FILE,
|
||||||
SERVICE_HOMEKIT_START, TYPE_FAUCET, TYPE_OUTLET, TYPE_SHOWER,
|
SERVICE_HOMEKIT_START, TYPE_FAUCET, TYPE_OUTLET, TYPE_SHOWER,
|
||||||
TYPE_SPRINKLER, TYPE_SWITCH, TYPE_VALVE)
|
TYPE_SPRINKLER, TYPE_SWITCH, TYPE_VALVE)
|
||||||
@ -58,6 +59,7 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
vol.Optional(CONF_IP_ADDRESS):
|
vol.Optional(CONF_IP_ADDRESS):
|
||||||
vol.All(ipaddress.ip_address, cv.string),
|
vol.All(ipaddress.ip_address, cv.string),
|
||||||
vol.Optional(CONF_AUTO_START, default=DEFAULT_AUTO_START): cv.boolean,
|
vol.Optional(CONF_AUTO_START, default=DEFAULT_AUTO_START): cv.boolean,
|
||||||
|
vol.Optional(CONF_SAFE_MODE, default=DEFAULT_SAFE_MODE): cv.boolean,
|
||||||
vol.Optional(CONF_FILTER, default={}): FILTER_SCHEMA,
|
vol.Optional(CONF_FILTER, default={}): FILTER_SCHEMA,
|
||||||
vol.Optional(CONF_ENTITY_CONFIG, default={}): validate_entity_config,
|
vol.Optional(CONF_ENTITY_CONFIG, default={}): validate_entity_config,
|
||||||
})
|
})
|
||||||
@ -73,11 +75,12 @@ async def async_setup(hass, config):
|
|||||||
port = conf[CONF_PORT]
|
port = conf[CONF_PORT]
|
||||||
ip_address = conf.get(CONF_IP_ADDRESS)
|
ip_address = conf.get(CONF_IP_ADDRESS)
|
||||||
auto_start = conf[CONF_AUTO_START]
|
auto_start = conf[CONF_AUTO_START]
|
||||||
|
safe_mode = conf[CONF_SAFE_MODE]
|
||||||
entity_filter = conf[CONF_FILTER]
|
entity_filter = conf[CONF_FILTER]
|
||||||
entity_config = conf[CONF_ENTITY_CONFIG]
|
entity_config = conf[CONF_ENTITY_CONFIG]
|
||||||
|
|
||||||
homekit = HomeKit(hass, name, port, ip_address, entity_filter,
|
homekit = HomeKit(hass, name, port, ip_address, entity_filter,
|
||||||
entity_config)
|
entity_config, safe_mode)
|
||||||
await hass.async_add_executor_job(homekit.setup)
|
await hass.async_add_executor_job(homekit.setup)
|
||||||
|
|
||||||
if auto_start:
|
if auto_start:
|
||||||
@ -196,7 +199,7 @@ class HomeKit():
|
|||||||
"""Class to handle all actions between HomeKit and Home Assistant."""
|
"""Class to handle all actions between HomeKit and Home Assistant."""
|
||||||
|
|
||||||
def __init__(self, hass, name, port, ip_address, entity_filter,
|
def __init__(self, hass, name, port, ip_address, entity_filter,
|
||||||
entity_config):
|
entity_config, safe_mode):
|
||||||
"""Initialize a HomeKit object."""
|
"""Initialize a HomeKit object."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -204,6 +207,7 @@ class HomeKit():
|
|||||||
self._ip_address = ip_address
|
self._ip_address = ip_address
|
||||||
self._filter = entity_filter
|
self._filter = entity_filter
|
||||||
self._config = entity_config
|
self._config = entity_config
|
||||||
|
self._safe_mode = safe_mode
|
||||||
self.status = STATUS_READY
|
self.status = STATUS_READY
|
||||||
|
|
||||||
self.bridge = None
|
self.bridge = None
|
||||||
@ -221,6 +225,9 @@ class HomeKit():
|
|||||||
self.driver = HomeDriver(self.hass, address=ip_addr,
|
self.driver = HomeDriver(self.hass, address=ip_addr,
|
||||||
port=self._port, persist_file=path)
|
port=self._port, persist_file=path)
|
||||||
self.bridge = HomeBridge(self.hass, self.driver, self._name)
|
self.bridge = HomeBridge(self.hass, self.driver, self._name)
|
||||||
|
if self._safe_mode:
|
||||||
|
_LOGGER.debug('Safe_mode selected')
|
||||||
|
self.driver.safe_mode = True
|
||||||
|
|
||||||
def add_bridge_accessory(self, state):
|
def add_bridge_accessory(self, state):
|
||||||
"""Try adding accessory to bridge if configured beforehand."""
|
"""Try adding accessory to bridge if configured beforehand."""
|
||||||
|
@ -15,10 +15,12 @@ CONF_ENTITY_CONFIG = 'entity_config'
|
|||||||
CONF_FEATURE = 'feature'
|
CONF_FEATURE = 'feature'
|
||||||
CONF_FEATURE_LIST = 'feature_list'
|
CONF_FEATURE_LIST = 'feature_list'
|
||||||
CONF_FILTER = 'filter'
|
CONF_FILTER = 'filter'
|
||||||
|
CONF_SAFE_MODE = 'safe_mode'
|
||||||
|
|
||||||
# #### Config Defaults ####
|
# #### Config Defaults ####
|
||||||
DEFAULT_AUTO_START = True
|
DEFAULT_AUTO_START = True
|
||||||
DEFAULT_PORT = 51827
|
DEFAULT_PORT = 51827
|
||||||
|
DEFAULT_SAFE_MODE = False
|
||||||
|
|
||||||
# #### Features ####
|
# #### Features ####
|
||||||
FEATURE_ON_OFF = 'on_off'
|
FEATURE_ON_OFF = 'on_off'
|
||||||
|
@ -9,8 +9,8 @@ from homeassistant.components.homekit import (
|
|||||||
STATUS_RUNNING, STATUS_STOPPED, STATUS_WAIT)
|
STATUS_RUNNING, STATUS_STOPPED, STATUS_WAIT)
|
||||||
from homeassistant.components.homekit.accessories import HomeBridge
|
from homeassistant.components.homekit.accessories import HomeBridge
|
||||||
from homeassistant.components.homekit.const import (
|
from homeassistant.components.homekit.const import (
|
||||||
CONF_AUTO_START, BRIDGE_NAME, DEFAULT_PORT, DOMAIN, HOMEKIT_FILE,
|
CONF_AUTO_START, CONF_SAFE_MODE, BRIDGE_NAME, DEFAULT_PORT,
|
||||||
SERVICE_HOMEKIT_START)
|
DEFAULT_SAFE_MODE, DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_NAME, CONF_IP_ADDRESS, CONF_PORT,
|
CONF_NAME, CONF_IP_ADDRESS, CONF_PORT,
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
||||||
@ -49,7 +49,7 @@ async def test_setup_min(hass):
|
|||||||
hass, DOMAIN, {DOMAIN: {}})
|
hass, DOMAIN, {DOMAIN: {}})
|
||||||
|
|
||||||
mock_homekit.assert_any_call(hass, BRIDGE_NAME, DEFAULT_PORT, None, ANY,
|
mock_homekit.assert_any_call(hass, BRIDGE_NAME, DEFAULT_PORT, None, ANY,
|
||||||
{})
|
{}, DEFAULT_SAFE_MODE)
|
||||||
assert mock_homekit().setup.called is True
|
assert mock_homekit().setup.called is True
|
||||||
|
|
||||||
# Test auto start enabled
|
# Test auto start enabled
|
||||||
@ -63,7 +63,8 @@ async def test_setup_min(hass):
|
|||||||
async def test_setup_auto_start_disabled(hass):
|
async def test_setup_auto_start_disabled(hass):
|
||||||
"""Test async_setup with auto start disabled and test service calls."""
|
"""Test async_setup with auto start disabled and test service calls."""
|
||||||
config = {DOMAIN: {CONF_AUTO_START: False, CONF_NAME: 'Test Name',
|
config = {DOMAIN: {CONF_AUTO_START: False, CONF_NAME: 'Test Name',
|
||||||
CONF_PORT: 11111, CONF_IP_ADDRESS: '172.0.0.0'}}
|
CONF_PORT: 11111, CONF_IP_ADDRESS: '172.0.0.0',
|
||||||
|
CONF_SAFE_MODE: DEFAULT_SAFE_MODE}}
|
||||||
|
|
||||||
with patch(PATH_HOMEKIT + '.HomeKit') as mock_homekit:
|
with patch(PATH_HOMEKIT + '.HomeKit') as mock_homekit:
|
||||||
mock_homekit.return_value = homekit = Mock()
|
mock_homekit.return_value = homekit = Mock()
|
||||||
@ -71,7 +72,7 @@ async def test_setup_auto_start_disabled(hass):
|
|||||||
hass, DOMAIN, config)
|
hass, DOMAIN, config)
|
||||||
|
|
||||||
mock_homekit.assert_any_call(hass, 'Test Name', 11111, '172.0.0.0', ANY,
|
mock_homekit.assert_any_call(hass, 'Test Name', 11111, '172.0.0.0', ANY,
|
||||||
{})
|
{}, DEFAULT_SAFE_MODE)
|
||||||
assert mock_homekit().setup.called is True
|
assert mock_homekit().setup.called is True
|
||||||
|
|
||||||
# Test auto_start disabled
|
# Test auto_start disabled
|
||||||
@ -99,7 +100,8 @@ async def test_setup_auto_start_disabled(hass):
|
|||||||
|
|
||||||
async def test_homekit_setup(hass, hk_driver):
|
async def test_homekit_setup(hass, hk_driver):
|
||||||
"""Test setup of bridge and driver."""
|
"""Test setup of bridge and driver."""
|
||||||
homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, None, {}, {})
|
homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, None, {}, {},
|
||||||
|
DEFAULT_SAFE_MODE)
|
||||||
|
|
||||||
with patch(PATH_HOMEKIT + '.accessories.HomeDriver',
|
with patch(PATH_HOMEKIT + '.accessories.HomeDriver',
|
||||||
return_value=hk_driver) as mock_driver, \
|
return_value=hk_driver) as mock_driver, \
|
||||||
@ -111,6 +113,7 @@ async def test_homekit_setup(hass, hk_driver):
|
|||||||
assert isinstance(homekit.bridge, HomeBridge)
|
assert isinstance(homekit.bridge, HomeBridge)
|
||||||
mock_driver.assert_called_with(
|
mock_driver.assert_called_with(
|
||||||
hass, address=IP_ADDRESS, port=DEFAULT_PORT, persist_file=path)
|
hass, address=IP_ADDRESS, port=DEFAULT_PORT, persist_file=path)
|
||||||
|
assert homekit.driver.safe_mode is False
|
||||||
|
|
||||||
# Test if stop listener is setup
|
# Test if stop listener is setup
|
||||||
assert hass.bus.async_listeners().get(EVENT_HOMEASSISTANT_STOP) == 1
|
assert hass.bus.async_listeners().get(EVENT_HOMEASSISTANT_STOP) == 1
|
||||||
@ -118,7 +121,8 @@ async def test_homekit_setup(hass, hk_driver):
|
|||||||
|
|
||||||
async def test_homekit_setup_ip_address(hass, hk_driver):
|
async def test_homekit_setup_ip_address(hass, hk_driver):
|
||||||
"""Test setup with given IP address."""
|
"""Test setup with given IP address."""
|
||||||
homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, '172.0.0.0', {}, {})
|
homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, '172.0.0.0', {}, {},
|
||||||
|
None)
|
||||||
|
|
||||||
with patch(PATH_HOMEKIT + '.accessories.HomeDriver',
|
with patch(PATH_HOMEKIT + '.accessories.HomeDriver',
|
||||||
return_value=hk_driver) as mock_driver:
|
return_value=hk_driver) as mock_driver:
|
||||||
@ -127,9 +131,20 @@ async def test_homekit_setup_ip_address(hass, hk_driver):
|
|||||||
hass, address='172.0.0.0', port=DEFAULT_PORT, persist_file=ANY)
|
hass, address='172.0.0.0', port=DEFAULT_PORT, persist_file=ANY)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_homekit_setup_safe_mode(hass, hk_driver):
|
||||||
|
"""Test if safe_mode flag is set."""
|
||||||
|
homekit = HomeKit(hass, BRIDGE_NAME, DEFAULT_PORT, None, {}, {}, True)
|
||||||
|
|
||||||
|
with patch(PATH_HOMEKIT + '.accessories.HomeDriver',
|
||||||
|
return_value=hk_driver):
|
||||||
|
await hass.async_add_job(homekit.setup)
|
||||||
|
assert homekit.driver.safe_mode is True
|
||||||
|
|
||||||
|
|
||||||
async def test_homekit_add_accessory():
|
async def test_homekit_add_accessory():
|
||||||
"""Add accessory if config exists and get_acc returns an accessory."""
|
"""Add accessory if config exists and get_acc returns an accessory."""
|
||||||
homekit = HomeKit('hass', None, None, None, lambda entity_id: True, {})
|
homekit = HomeKit('hass', None, None, None, lambda entity_id: True, {},
|
||||||
|
None)
|
||||||
homekit.driver = 'driver'
|
homekit.driver = 'driver'
|
||||||
homekit.bridge = mock_bridge = Mock()
|
homekit.bridge = mock_bridge = Mock()
|
||||||
|
|
||||||
@ -152,7 +167,7 @@ async def test_homekit_add_accessory():
|
|||||||
async def test_homekit_entity_filter(hass):
|
async def test_homekit_entity_filter(hass):
|
||||||
"""Test the entity filter."""
|
"""Test the entity filter."""
|
||||||
entity_filter = generate_filter(['cover'], ['demo.test'], [], [])
|
entity_filter = generate_filter(['cover'], ['demo.test'], [], [])
|
||||||
homekit = HomeKit(hass, None, None, None, entity_filter, {})
|
homekit = HomeKit(hass, None, None, None, entity_filter, {}, None)
|
||||||
|
|
||||||
with patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc:
|
with patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc:
|
||||||
mock_get_acc.return_value = None
|
mock_get_acc.return_value = None
|
||||||
@ -172,7 +187,7 @@ async def test_homekit_entity_filter(hass):
|
|||||||
async def test_homekit_start(hass, hk_driver, debounce_patcher):
|
async def test_homekit_start(hass, hk_driver, debounce_patcher):
|
||||||
"""Test HomeKit start method."""
|
"""Test HomeKit start method."""
|
||||||
pin = b'123-45-678'
|
pin = b'123-45-678'
|
||||||
homekit = HomeKit(hass, None, None, None, {}, {'cover.demo': {}})
|
homekit = HomeKit(hass, None, None, None, {}, {'cover.demo': {}}, None)
|
||||||
homekit.bridge = Mock()
|
homekit.bridge = Mock()
|
||||||
homekit.bridge.accessories = []
|
homekit.bridge.accessories = []
|
||||||
homekit.driver = hk_driver
|
homekit.driver = hk_driver
|
||||||
@ -203,7 +218,7 @@ async def test_homekit_start(hass, hk_driver, debounce_patcher):
|
|||||||
|
|
||||||
async def test_homekit_stop(hass):
|
async def test_homekit_stop(hass):
|
||||||
"""Test HomeKit stop method."""
|
"""Test HomeKit stop method."""
|
||||||
homekit = HomeKit(hass, None, None, None, None, None)
|
homekit = HomeKit(hass, None, None, None, None, None, None)
|
||||||
homekit.driver = Mock()
|
homekit.driver = Mock()
|
||||||
|
|
||||||
assert homekit.status == STATUS_READY
|
assert homekit.status == STATUS_READY
|
||||||
@ -222,7 +237,7 @@ async def test_homekit_stop(hass):
|
|||||||
|
|
||||||
async def test_homekit_too_many_accessories(hass, hk_driver):
|
async def test_homekit_too_many_accessories(hass, hk_driver):
|
||||||
"""Test adding too many accessories to HomeKit."""
|
"""Test adding too many accessories to HomeKit."""
|
||||||
homekit = HomeKit(hass, None, None, None, None, None)
|
homekit = HomeKit(hass, None, None, None, None, None, None)
|
||||||
homekit.bridge = Mock()
|
homekit.bridge = Mock()
|
||||||
homekit.bridge.accessories = range(MAX_DEVICES + 1)
|
homekit.bridge.accessories = range(MAX_DEVICES + 1)
|
||||||
homekit.driver = hk_driver
|
homekit.driver = hk_driver
|
||||||
|
Loading…
x
Reference in New Issue
Block a user