core/homeassistant/components/homekit_controller/event.py

160 lines
5.3 KiB
Python

"""Support for Homekit motion sensors."""
from __future__ import annotations
from aiohomekit.model.characteristics import CharacteristicsTypes
from aiohomekit.model.characteristics.const import InputEventValues
from aiohomekit.model.services import Service, ServicesTypes
from aiohomekit.utils import clamp_enum_to_char
from homeassistant.components.event import (
EventDeviceClass,
EventEntity,
EventEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import KNOWN_DEVICES
from .connection import HKDevice
from .entity import BaseCharacteristicEntity
INPUT_EVENT_VALUES = {
InputEventValues.SINGLE_PRESS: "single_press",
InputEventValues.DOUBLE_PRESS: "double_press",
InputEventValues.LONG_PRESS: "long_press",
}
class HomeKitEventEntity(BaseCharacteristicEntity, EventEntity):
"""Representation of a Homekit event entity."""
_attr_should_poll = False
def __init__(
self,
connection: HKDevice,
service: Service,
entity_description: EventEntityDescription,
) -> None:
"""Initialise a generic HomeKit event entity."""
super().__init__(
connection,
{
"aid": service.accessory.aid,
"iid": service.iid,
},
service.characteristics_by_type[CharacteristicsTypes.INPUT_EVENT],
)
self.entity_description = entity_description
# An INPUT_EVENT may support single_press, long_press and double_press. All are optional. So we have to
# clamp InputEventValues for this exact device
self._attr_event_types = [
INPUT_EVENT_VALUES[v]
for v in clamp_enum_to_char(InputEventValues, self._char)
]
def get_characteristic_types(self) -> list[str]:
"""Define the homekit characteristics the entity cares about."""
return [CharacteristicsTypes.INPUT_EVENT]
async def async_added_to_hass(self) -> None:
"""Entity added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self._accessory.async_subscribe(
{(self._aid, self._char.iid)},
self._handle_event,
)
)
@callback
def _handle_event(self) -> None:
if self._char.value is None:
# For IP backed devices the characteristic is marked as
# pollable, but always returns None when polled
# Make sure we don't explode if we see that edge case.
return
self._trigger_event(INPUT_EVENT_VALUES[self._char.value])
self.async_write_ha_state()
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Homekit event."""
hkid: str = config_entry.data["AccessoryPairingID"]
conn: HKDevice = hass.data[KNOWN_DEVICES][hkid]
@callback
def async_add_service(service: Service) -> bool:
entities = []
if service.type == ServicesTypes.DOORBELL:
entities.append(
HomeKitEventEntity(
conn,
service,
EventEntityDescription(
key=f"{service.accessory.aid}_{service.iid}",
device_class=EventDeviceClass.DOORBELL,
translation_key="doorbell",
),
)
)
elif service.type == ServicesTypes.SERVICE_LABEL:
switches = list(
service.accessory.services.filter(
service_type=ServicesTypes.STATELESS_PROGRAMMABLE_SWITCH,
child_service=service,
order_by=[CharacteristicsTypes.SERVICE_LABEL_INDEX],
)
)
# The Apple docs say that if we number the buttons ourselves
# We do it in service label index order. `switches` is already in
# that order.
entities.extend(
HomeKitEventEntity(
conn,
switch,
EventEntityDescription(
key=f"{service.accessory.aid}_{service.iid}",
device_class=EventDeviceClass.BUTTON,
translation_key="button",
),
)
for switch in switches
)
elif service.type == ServicesTypes.STATELESS_PROGRAMMABLE_SWITCH:
# A stateless switch that has a SERVICE_LABEL_INDEX is part of a group
# And is handled separately
if not service.has(CharacteristicsTypes.SERVICE_LABEL_INDEX):
entities.append(
HomeKitEventEntity(
conn,
service,
EventEntityDescription(
key=f"{service.accessory.aid}_{service.iid}",
device_class=EventDeviceClass.BUTTON,
translation_key="button",
),
)
)
if entities:
async_add_entities(entities)
return True
return False
conn.add_listener(async_add_service)