From e22802a4d47b28e0a3c570698ff9fb932a59d50f Mon Sep 17 00:00:00 2001 From: Jc2k Date: Tue, 29 Jan 2019 04:30:56 +0000 Subject: [PATCH] Add support for HomeKit motion sensor devices (#20555) --- .../components/homekit_controller/__init__.py | 3 +- .../homekit_controller/binary_sensor.py | 55 +++++++++++++++++++ .../homekit_controller/test_binary_sensor.py | 29 ++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/homekit_controller/binary_sensor.py create mode 100644 tests/components/homekit_controller/test_binary_sensor.py diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index b5577119178..72b7a502aa2 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -28,7 +28,8 @@ HOMEKIT_ACCESSORY_DISPATCH = { 'garage-door-opener': 'cover', 'window': 'cover', 'window-covering': 'cover', - 'lock-mechanism': 'lock' + 'lock-mechanism': 'lock', + 'motion': 'binary_sensor', } HOMEKIT_IGNORE = [ diff --git a/homeassistant/components/homekit_controller/binary_sensor.py b/homeassistant/components/homekit_controller/binary_sensor.py new file mode 100644 index 00000000000..8fe6248c65e --- /dev/null +++ b/homeassistant/components/homekit_controller/binary_sensor.py @@ -0,0 +1,55 @@ +""" +Support for Homekit motion sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.homekit_controller/ +""" +import logging + +from homeassistant.components.homekit_controller import (HomeKitEntity, + KNOWN_ACCESSORIES) +from homeassistant.components.binary_sensor import BinarySensorDevice + +DEPENDENCIES = ['homekit_controller'] + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up Homekit motion sensor support.""" + if discovery_info is not None: + accessory = hass.data[KNOWN_ACCESSORIES][discovery_info['serial']] + add_entities([HomeKitMotionSensor(accessory, discovery_info)], True) + + +class HomeKitMotionSensor(HomeKitEntity, BinarySensorDevice): + """Representation of a Homekit sensor.""" + + def __init__(self, *args): + """Initialise the entity.""" + super().__init__(*args) + self._on = False + + def get_characteristic_types(self): + """Define the homekit characteristics the entity is tracking.""" + # pylint: disable=import-error + from homekit.model.characteristics import CharacteristicsTypes + + return [ + CharacteristicsTypes.MOTION_DETECTED, + ] + + def _update_motion_detected(self, value): + self._on = value + + @property + def device_class(self): + """Define this binary_sensor as a motion sensor.""" + return 'motion' + + @property + def is_on(self): + """Has motion been detected.""" + if not self.available: + return False + return self._on diff --git a/tests/components/homekit_controller/test_binary_sensor.py b/tests/components/homekit_controller/test_binary_sensor.py new file mode 100644 index 00000000000..bfcd51b55fb --- /dev/null +++ b/tests/components/homekit_controller/test_binary_sensor.py @@ -0,0 +1,29 @@ +"""Basic checks for HomeKitLock.""" +from tests.components.homekit_controller.common import ( + FakeService, setup_test_component) + +MOTION_DETECTED = ('motion', 'motion-detected') + + +def create_sensor_motion_service(): + """Define motion characteristics as per page 225 of HAP spec.""" + service = FakeService('public.hap.service.sensor.motion') + + cur_state = service.add_characteristic('motion-detected') + cur_state.value = 0 + + return service + + +async def test_sensor_read_state(hass, utcnow): + """Test that we can read the state of a HomeKit motion sensor accessory.""" + sensor = create_sensor_motion_service() + helper = await setup_test_component(hass, [sensor]) + + helper.characteristics[MOTION_DETECTED].value = False + state = await helper.poll_and_get_state() + assert state.state == 'off' + + helper.characteristics[MOTION_DETECTED].value = True + state = await helper.poll_and_get_state() + assert state.state == 'on'