From 3e9376c418ec0280355543b8184403d6cfe4dc08 Mon Sep 17 00:00:00 2001 From: koreth Date: Sun, 24 Feb 2019 04:56:52 -0800 Subject: [PATCH] Handle capitalized HomeKit property names (#21382) The Velux ACTIVE gateway uses `C#` rather than `c#` as the name of the property that holds the count of accessories. Apple's HomeKit docs suggest that properties should be case-insensitive, so update the code to not assume the property names are lower case. --- .../components/homekit_controller/__init__.py | 14 +++++++++++--- tests/components/homekit_controller/common.py | 13 ++++++++----- tests/components/homekit_controller/test_cover.py | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index ffeb9d625be..eb748a3d883 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -343,9 +343,17 @@ def setup(hass, config): # model, id host = discovery_info['host'] port = discovery_info['port'] - model = discovery_info['properties']['md'] - hkid = discovery_info['properties']['id'] - config_num = int(discovery_info['properties']['c#']) + + # Fold property keys to lower case, making them effectively + # case-insensitive. Some HomeKit devices capitalize them. + properties = { + key.lower(): value + for (key, value) in discovery_info['properties'].items() + } + + model = properties['md'] + hkid = properties['id'] + config_num = int(properties['c#']) if model in HOMEKIT_IGNORE: return diff --git a/tests/components/homekit_controller/common.py b/tests/components/homekit_controller/common.py index d3c1f9ab07b..d543cf51749 100644 --- a/tests/components/homekit_controller/common.py +++ b/tests/components/homekit_controller/common.py @@ -134,8 +134,11 @@ class FakeService(AbstractService): return char -async def setup_test_component(hass, services): - """Load a fake homekit accessory based on a homekit accessory model.""" +async def setup_test_component(hass, services, capitalize=False): + """Load a fake homekit accessory based on a homekit accessory model. + + If capitalize is True, property names will be in upper case. + """ domain = None for service in services: service_name = ServicesTypes.get_short(service.type) @@ -162,9 +165,9 @@ async def setup_test_component(hass, services): 'host': '127.0.0.1', 'port': 8080, 'properties': { - 'md': 'TestDevice', - 'id': '00:00:00:00:00:00', - 'c#': 1, + ('MD' if capitalize else 'md'): 'TestDevice', + ('ID' if capitalize else 'id'): '00:00:00:00:00:00', + ('C#' if capitalize else 'c#'): 1, } } diff --git a/tests/components/homekit_controller/test_cover.py b/tests/components/homekit_controller/test_cover.py index 062ecc54041..62fce4325c7 100644 --- a/tests/components/homekit_controller/test_cover.py +++ b/tests/components/homekit_controller/test_cover.py @@ -70,6 +70,20 @@ def create_window_covering_service_with_v_tilt(): return service +async def test_accept_capitalized_property_names(hass, utcnow): + """Test that we can handle a device with capitalized property names.""" + window_cover = create_window_covering_service() + helper = await setup_test_component(hass, [window_cover], capitalize=True) + + # The specific interaction we do here doesn't matter; we just need + # to do *something* to ensure that discovery properly dealt with the + # capitalized property names. + await hass.services.async_call('cover', 'open_cover', { + 'entity_id': helper.entity_id, + }, blocking=True) + assert helper.characteristics[POSITION_TARGET].value == 100 + + async def test_change_window_cover_state(hass, utcnow): """Test that we can turn a HomeKit alarm on and off again.""" window_cover = create_window_covering_service()