Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
    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)
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
    "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
Beispiel #8
0
    "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",
}
Beispiel #9
0
    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
Beispiel #10
0
        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."""
Beispiel #11
0

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."""
Beispiel #12
0
 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
Beispiel #13
0
 def __getitem__(self, key):
     try:
         key = CharacteristicsTypes.get_uuid(key)
     except KeyError:
         pass
     return self.characteristics_by_type[key]