Add homekit_controller occupancy sensor (#32188)

This commit is contained in:
Jc2k 2020-02-25 22:01:03 +00:00 committed by GitHub
parent dd13e99967
commit 4a89fba6f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 327 additions and 0 deletions

View file

@ -5,6 +5,7 @@ from aiohomekit.model.characteristics import CharacteristicsTypes
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OCCUPANCY,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_SMOKE,
BinarySensorDevice,
@ -94,10 +95,37 @@ class HomeKitSmokeSensor(HomeKitEntity, BinarySensorDevice):
return self._state == 1
class HomeKitOccupancySensor(HomeKitEntity, BinarySensorDevice):
"""Representation of a Homekit smoke sensor."""
def __init__(self, *args):
"""Initialise the entity."""
super().__init__(*args)
self._state = None
@property
def device_class(self) -> str:
"""Return the class of this sensor."""
return DEVICE_CLASS_OCCUPANCY
def get_characteristic_types(self):
"""Define the homekit characteristics the entity is tracking."""
return [CharacteristicsTypes.OCCUPANCY_DETECTED]
def _update_occupancy_detected(self, value):
self._state = value
@property
def is_on(self):
"""Return true if smoke is currently detected."""
return self._state == 1
ENTITY_TYPES = {
"motion": HomeKitMotionSensor,
"contact": HomeKitContactSensor,
"smoke": HomeKitSmokeSensor,
"occupancy": HomeKitOccupancySensor,
}

View file

@ -30,4 +30,5 @@ HOMEKIT_ACCESSORY_DISPATCH = {
"fan": "fan",
"fanv2": "fan",
"air-quality": "air_quality",
"occupancy": "binary_sensor",
}

View file

@ -0,0 +1,37 @@
"""
Regression tests for Ecobee occupancy.
https://github.com/home-assistant/home-assistant/issues/31827
"""
from tests.components.homekit_controller.common import (
Helper,
setup_accessories_from_file,
setup_test_accessories,
)
async def test_ecobee_occupancy_setup(hass):
"""Test that an Ecbobee occupancy sensor be correctly setup in HA."""
accessories = await setup_accessories_from_file(hass, "ecobee_occupancy.json")
config_entry, pairing = await setup_test_accessories(hass, accessories)
entity_registry = await hass.helpers.entity_registry.async_get_registry()
sensor = entity_registry.async_get("binary_sensor.master_fan")
assert sensor.unique_id == "homekit-111111111111-56"
sensor_helper = Helper(
hass, "binary_sensor.master_fan", pairing, accessories[0], config_entry
)
sensor_state = await sensor_helper.poll_and_get_state()
assert sensor_state.attributes["friendly_name"] == "Master Fan"
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get(sensor.device_id)
assert device.manufacturer == "ecobee Inc."
assert device.name == "Master Fan"
assert device.model == "ecobee Switch+"
assert device.sw_version == "4.5.130201"
assert device.via_device_id is None

View file

@ -4,6 +4,7 @@ from aiohomekit.model.services import ServicesTypes
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OCCUPANCY,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_SMOKE,
)
@ -13,6 +14,7 @@ from tests.components.homekit_controller.common import setup_test_component
MOTION_DETECTED = ("motion", "motion-detected")
CONTACT_STATE = ("contact", "contact-state")
SMOKE_DETECTED = ("smoke", "smoke-detected")
OCCUPANCY_DETECTED = ("occupancy", "occupancy-detected")
def create_motion_sensor_service(accessory):
@ -82,3 +84,26 @@ async def test_smoke_sensor_read_state(hass, utcnow):
assert state.state == "on"
assert state.attributes["device_class"] == DEVICE_CLASS_SMOKE
def create_occupancy_sensor_service(accessory):
"""Define occupancy characteristics."""
service = accessory.add_service(ServicesTypes.OCCUPANCY_SENSOR)
cur_state = service.add_char(CharacteristicsTypes.OCCUPANCY_DETECTED)
cur_state.value = 0
async def test_occupancy_sensor_read_state(hass, utcnow):
"""Test that we can read the state of a HomeKit occupancy sensor accessory."""
helper = await setup_test_component(hass, create_occupancy_sensor_service)
helper.characteristics[OCCUPANCY_DETECTED].value = False
state = await helper.poll_and_get_state()
assert state.state == "off"
helper.characteristics[OCCUPANCY_DETECTED].value = True
state = await helper.poll_and_get_state()
assert state.state == "on"
assert state.attributes["device_class"] == DEVICE_CLASS_OCCUPANCY

View file

@ -0,0 +1,236 @@
[
{
"aid": 1,
"services": [
{
"characteristics": [
{
"format": "string",
"iid": 2,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
},
{
"format": "string",
"iid": 3,
"perms": [
"pr"
],
"type": "00000020-0000-1000-8000-0026BB765291",
"value": "ecobee Inc."
},
{
"format": "string",
"iid": 4,
"perms": [
"pr"
],
"type": "00000030-0000-1000-8000-0026BB765291",
"value": "111111111111"
},
{
"format": "string",
"iid": 5,
"perms": [
"pr"
],
"type": "00000021-0000-1000-8000-0026BB765291",
"value": "ecobee Switch+"
},
{
"format": "bool",
"iid": 6,
"perms": [
"pw"
],
"type": "00000014-0000-1000-8000-0026BB765291"
},
{
"format": "string",
"iid": 8,
"perms": [
"pr"
],
"type": "00000052-0000-1000-8000-0026BB765291",
"value": "4.5.130201"
},
{
"format": "uint32",
"iid": 9,
"perms": [
"pr",
"ev"
],
"type": "000000A6-0000-1000-8000-0026BB765291",
"value": 0
}
],
"iid": 1,
"stype": "accessory-information",
"type": "0000003E-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "string",
"iid": 31,
"maxLen": 64,
"perms": [
"pr"
],
"type": "00000037-0000-1000-8000-0026BB765291",
"value": "1.1.0"
}
],
"iid": 30,
"stype": "service",
"type": "000000A2-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "bool",
"iid": 17,
"perms": [
"pr",
"pw",
"ev"
],
"type": "00000025-0000-1000-8000-0026BB765291",
"value": false
},
{
"format": "string",
"iid": 18,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
}
],
"iid": 16,
"primary": true,
"stype": "switch",
"type": "00000049-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "float",
"iid": 20,
"maxValue": 100000,
"minValue": 0,
"perms": [
"pr",
"ev"
],
"type": "0000006B-0000-1000-8000-0026BB765291",
"unit": "lux",
"value": 0
},
{
"format": "string",
"iid": 21,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
}
],
"iid": 27,
"stype": "light",
"type": "00000084-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "bool",
"iid": 66,
"perms": [
"pr",
"ev"
],
"type": "00000022-0000-1000-8000-0026BB765291",
"value": false
},
{
"format": "string",
"iid": 28,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
}
],
"iid": 56,
"stype": "motion",
"type": "00000085-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "uint8",
"iid": 65,
"maxValue": 1,
"minStep": 1,
"minValue": 0,
"perms": [
"pr",
"ev"
],
"type": "00000071-0000-1000-8000-0026BB765291",
"value": 0
},
{
"format": "string",
"iid": 29,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
}
],
"iid": 57,
"stype": "occupancy",
"type": "00000086-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"format": "float",
"iid": 19,
"maxValue": 100,
"minStep": 0.1,
"minValue": 0,
"perms": [
"pr",
"ev"
],
"type": "00000011-0000-1000-8000-0026BB765291",
"unit": "celsius",
"value": 25.6
},
{
"format": "string",
"iid": 22,
"perms": [
"pr"
],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Master Fan"
}
],
"iid": 55,
"stype": "temperature",
"type": "0000008A-0000-1000-8000-0026BB765291"
}
]
}
]