Add homekit_controller occupancy sensor (#32188)
This commit is contained in:
parent
dd13e99967
commit
4a89fba6f9
5 changed files with 327 additions and 0 deletions
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,4 +30,5 @@ HOMEKIT_ACCESSORY_DISPATCH = {
|
|||
"fan": "fan",
|
||||
"fanv2": "fan",
|
||||
"air-quality": "air_quality",
|
||||
"occupancy": "binary_sensor",
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
236
tests/fixtures/homekit_controller/ecobee_occupancy.json
vendored
Normal file
236
tests/fixtures/homekit_controller/ecobee_occupancy.json
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Loading…
Add table
Add a link
Reference in a new issue