async def identify(self): """ This call can be used to trigger the identification of a paired accessory. A successful call should cause the accessory to perform some specific action by which it can be distinguished from the others (blink a LED for example). It uses the identify characteristic as described on page 152 of the spec. :return True, if the identification was run, False otherwise """ await self._ensure_connected() if "accessories" not in self.pairing_data: await self.list_accessories_and_characteristics() # we are looking for a characteristic of the identify type identify_type = CharacteristicsTypes.get_uuid( CharacteristicsTypes.IDENTIFY) # search all accessories, all services and all characteristics for accessory in self.pairing_data["accessories"]: aid = accessory["aid"] for service in accessory["services"]: for characteristic in service["characteristics"]: iid = characteristic["iid"] c_type = CharacteristicsTypes.get_uuid( characteristic["type"]) if identify_type == c_type: # found the identify characteristic, so let's put a value there if not await self.put_characteristics([(aid, iid, True) ]): return True return False
async def list_accessories_and_characteristics(self): """ This retrieves a current set of accessories and characteristics behind this pairing. :return: the accessory data as described in the spec on page 73 and following :raises AccessoryNotFoundError: if the device can not be found via zeroconf """ await self._ensure_connected() response = await self.connection.get_json("/accessories") accessories = response["accessories"] for accessory in accessories: for service in accessory["services"]: service["type"] = service["type"].upper() try: service["type"] = ServicesTypes.get_uuid(service["type"]) except KeyError: pass for characteristic in service["characteristics"]: characteristic["type"] = characteristic["type"].upper() try: characteristic["type"] = CharacteristicsTypes.get_uuid( characteristic["type"]) except KeyError: pass self.pairing_data["accessories"] = accessories return accessories
def update_named_service(self, name: str, new_values): """ Finds a named service then sets characteristics by type. pairing.test.update_named_service("kitchen lamp", { CharacteristicTypes.ON: True }) Triggers events if enabled. """ if name not in self.services: raise RuntimeError(f"Fake error: service {name!r} not found") service = self.services[name] changed = [] for uuid, value in new_values.items(): uuid = CharacteristicsTypes.get_uuid(uuid) if uuid not in service: raise RuntimeError( f"Unexpected characteristic {uuid!r} applied to service {name!r}" ) char = service[uuid] char.set_value(value) changed.append((char.service.accessory.aid, char.iid)) self._send_events(changed)
def filter(self, char_types=None) -> Iterable[Characteristic]: matches = iter(self) if char_types: char_types = [CharacteristicsTypes.get_uuid(c) for c in char_types] matches = filter(lambda char: char.type in char_types, matches) return matches
def value(self, char_type, default_value=None): try: char_type = CharacteristicsTypes.get_uuid(char_type) except KeyError: pass if char_type not in self.characteristics_by_type: return default_value return self.characteristics_by_type[char_type].value
def __init__(self, pairing): self.pairing = pairing self.events_enabled = True self.characteristics = {} self.services = {} name_uuid = CharacteristicsTypes.get_uuid(CharacteristicsTypes.NAME) for accessory in self.pairing.accessories: for service in accessory.services: service_map = {} for char in service.characteristics: self.characteristics[(accessory.aid, char.iid)] = char service_map[char.type] = char if char.type == name_uuid: self.services[char.get_value()] = service_map
"camera-rtp-stream-management": "camera", } CHARACTERISTIC_PLATFORMS = { CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor", CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor", CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number", CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY: "sensor", CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY_2: "sensor", CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL: "number", CharacteristicsTypes.TEMPERATURE_CURRENT: "sensor", CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT: "sensor", CharacteristicsTypes.AIR_QUALITY: "sensor", CharacteristicsTypes.DENSITY_PM25: "sensor", CharacteristicsTypes.DENSITY_PM10: "sensor", CharacteristicsTypes.DENSITY_OZONE: "sensor", CharacteristicsTypes.DENSITY_NO2: "sensor", CharacteristicsTypes.DENSITY_SO2: "sensor", CharacteristicsTypes.DENSITY_VOC: "sensor", } # For legacy reasons, "built-in" characteristic types are in their short form # And vendor types don't have a short form # This means long and short forms get mixed up in this dict, and comparisons # don't work! # We call get_uuid on *every* type to normalise them to the long form # Eventually aiohomekit will use the long form exclusively amd this can be removed. for k, v in list(CHARACTERISTIC_PLATFORMS.items()): value = CHARACTERISTIC_PLATFORMS.pop(k) CHARACTERISTIC_PLATFORMS[CharacteristicsTypes.get_uuid(k)] = value
"smoke": "binary_sensor", "carbon-monoxide": "binary_sensor", "leak": "binary_sensor", "fan": "fan", "fanv2": "fan", "air-quality": "air_quality", "occupancy": "binary_sensor", "television": "media_player", "valve": "switch", "camera-rtp-stream-management": "camera", } CHARACTERISTIC_PLATFORMS = { CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor", CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor", CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number", CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY: "sensor", CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY_2: "sensor", CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL: "number", CharacteristicsTypes.get_uuid(CharacteristicsTypes.TEMPERATURE_CURRENT): "sensor", CharacteristicsTypes.get_uuid(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT): "sensor", }
HomeKitButtonEntityDescription( key=CharacteristicsTypes.IDENTIFY, name="Identify", entity_category=EntityCategory.DIAGNOSTIC, write_value=True, ), } # For legacy reasons, "built-in" characteristic types are in their short form # And vendor types don't have a short form # This means long and short forms get mixed up in this dict, and comparisons # don't work! # We call get_uuid on *every* type to normalise them to the long form # Eventually aiohomekit will use the long form exclusively amd this can be removed. for k, v in list(BUTTON_ENTITIES.items()): BUTTON_ENTITIES[CharacteristicsTypes.get_uuid(k)] = BUTTON_ENTITIES.pop(k) async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit buttons.""" hkid = config_entry.data["AccessoryPairingID"] conn = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_characteristic(char: Characteristic): if not (description := BUTTON_ENTITIES.get(char.type)): return False
key=CharacteristicsTypes.DENSITY_VOC, name="Volatile Organic Compound Density", device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ), } # For legacy reasons, "built-in" characteristic types are in their short form # And vendor types don't have a short form # This means long and short forms get mixed up in this dict, and comparisons # don't work! # We call get_uuid on *every* type to normalise them to the long form # Eventually aiohomekit will use the long form exclusively amd this can be removed. for k, v in list(SIMPLE_SENSOR.items()): SIMPLE_SENSOR[CharacteristicsTypes.get_uuid(k)] = SIMPLE_SENSOR.pop(k) class HomeKitHumiditySensor(HomeKitEntity, SensorEntity): """Representation of a Homekit humidity sensor.""" _attr_device_class = SensorDeviceClass.HUMIDITY _attr_native_unit_of_measurement = PERCENTAGE def get_characteristic_types(self): """Define the homekit characteristics the entity is tracking.""" return [CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT] @property def name(self): """Return the name of the device."""
SIMPLE_SENSOR = { CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: { "name": "Real Time Energy", "device_class": DEVICE_CLASS_POWER, "state_class": STATE_CLASS_MEASUREMENT, "unit": "watts", }, CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY: { "name": "Real Time Energy", "device_class": DEVICE_CLASS_POWER, "state_class": STATE_CLASS_MEASUREMENT, "unit": "watts", }, CharacteristicsTypes.get_uuid(CharacteristicsTypes.TEMPERATURE_CURRENT): { "name": "Current Temperature", "device_class": DEVICE_CLASS_TEMPERATURE, "state_class": STATE_CLASS_MEASUREMENT, "unit": TEMP_CELSIUS, # This sensor is only for temperature characteristics that are not part # of a temperature sensor service. "probe": lambda char: char.service.type != ServicesTypes.get_uuid(ServicesTypes.TEMPERATURE_SENSOR), }, } class HomeKitHumiditySensor(HomeKitEntity, SensorEntity): """Representation of a Homekit humidity sensor."""
def has(self, char_type) -> bool: try: char_type = CharacteristicsTypes.get_uuid(char_type) except KeyError: pass return char_type in self.characteristics_by_type
def __getitem__(self, key): try: key = CharacteristicsTypes.get_uuid(key) except KeyError: pass return self.characteristics_by_type[key]