mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Cache homekit_controller supported features (#106702)
This commit is contained in:
parent
f2514c0bde
commit
bc26377c16
@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any, Final
|
||||
from typing import TYPE_CHECKING, Any, Final
|
||||
|
||||
from aiohomekit.model.characteristics import (
|
||||
ActivationStateValues,
|
||||
@ -48,6 +48,12 @@ from . import KNOWN_DEVICES
|
||||
from .connection import HKDevice
|
||||
from .entity import HomeKitEntity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from functools import cached_property
|
||||
else:
|
||||
from homeassistant.backports.functools import cached_property
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# Map of Homekit operation modes to hass modes
|
||||
@ -134,6 +140,12 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(("supported_features", "fan_modes"))
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
@ -146,7 +158,7 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||
"""Return the current temperature."""
|
||||
return self.service.value(CharacteristicsTypes.TEMPERATURE_CURRENT)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def fan_modes(self) -> list[str] | None:
|
||||
"""Return the available fan modes."""
|
||||
if self.service.has(CharacteristicsTypes.FAN_STATE_TARGET):
|
||||
@ -165,7 +177,7 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||
{CharacteristicsTypes.FAN_STATE_TARGET: int(fan_mode == FAN_AUTO)}
|
||||
)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_features(self) -> ClimateEntityFeature:
|
||||
"""Return the list of supported features."""
|
||||
features = ClimateEntityFeature(0)
|
||||
@ -179,6 +191,12 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||
class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
"""Representation of a Homekit climate device."""
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(("hvac_modes", "swing_modes"))
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return super().get_characteristic_types() + [
|
||||
@ -197,7 +215,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
rotation_speed.maxValue or 100
|
||||
)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def fan_modes(self) -> list[str]:
|
||||
"""Return the available fan modes."""
|
||||
return [FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
|
||||
@ -388,7 +406,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
value = self.service.value(CharacteristicsTypes.TARGET_HEATER_COOLER_STATE)
|
||||
return TARGET_HEATER_COOLER_STATE_HOMEKIT_TO_HASS[value]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def hvac_modes(self) -> list[HVACMode]:
|
||||
"""Return the list of available hvac operation modes."""
|
||||
valid_values = clamp_enum_to_char(
|
||||
@ -410,7 +428,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
value = self.service.value(CharacteristicsTypes.SWING_MODE)
|
||||
return SWING_MODE_HOMEKIT_TO_HASS[value]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def swing_modes(self) -> list[str]:
|
||||
"""Return the list of available swing modes.
|
||||
|
||||
@ -428,7 +446,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
{CharacteristicsTypes.SWING_MODE: SWING_MODE_HASS_TO_HOMEKIT[swing_mode]}
|
||||
)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_features(self) -> ClimateEntityFeature:
|
||||
"""Return the list of supported features."""
|
||||
features = super().supported_features
|
||||
@ -451,6 +469,12 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||
class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
"""Representation of a Homekit climate device."""
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(("hvac_modes",))
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return super().get_characteristic_types() + [
|
||||
@ -483,7 +507,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
if (
|
||||
(mode == HVACMode.HEAT_COOL)
|
||||
and (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||
)
|
||||
and heat_temp
|
||||
and cool_temp
|
||||
@ -524,9 +548,8 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT, HVACMode.COOL}) or (
|
||||
(MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL})
|
||||
and not (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
)
|
||||
and ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||
not in self.supported_features
|
||||
):
|
||||
return self.service.value(CharacteristicsTypes.TEMPERATURE_TARGET)
|
||||
return None
|
||||
@ -536,7 +559,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
"""Return the highbound target temperature we try to reach."""
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||
):
|
||||
return self.service.value(
|
||||
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
||||
@ -548,7 +571,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
"""Return the lowbound target temperature we try to reach."""
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||
):
|
||||
return self.service.value(
|
||||
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
||||
@ -560,7 +583,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
"""Return the minimum target temp."""
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||
):
|
||||
min_temp = self.service[
|
||||
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
||||
@ -582,7 +605,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
"""Return the maximum target temp."""
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||
):
|
||||
max_temp = self.service[
|
||||
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
||||
@ -656,7 +679,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||
return MODE_HOMEKIT_TO_HASS[value]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def hvac_modes(self) -> list[HVACMode]:
|
||||
"""Return the list of available hvac operation modes."""
|
||||
valid_values = clamp_enum_to_char(
|
||||
@ -665,7 +688,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||
)
|
||||
return [MODE_HOMEKIT_TO_HASS[mode] for mode in valid_values]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_features(self) -> ClimateEntityFeature:
|
||||
"""Return the list of supported features."""
|
||||
features = super().supported_features
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for Homekit covers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||
from aiohomekit.model.services import Service, ServicesTypes
|
||||
@ -28,6 +28,12 @@ from . import KNOWN_DEVICES
|
||||
from .connection import HKDevice
|
||||
from .entity import HomeKitEntity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from functools import cached_property
|
||||
else:
|
||||
from homeassistant.backports.functools import cached_property
|
||||
|
||||
|
||||
STATE_STOPPED = "stopped"
|
||||
|
||||
CURRENT_GARAGE_STATE_MAP = {
|
||||
@ -128,6 +134,12 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverEntity):
|
||||
class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
||||
"""Representation of a HomeKit Window or Window Covering."""
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(("supported_features",))
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
@ -142,7 +154,7 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
||||
CharacteristicsTypes.OBSTRUCTION_DETECTED,
|
||||
]
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_features(self) -> CoverEntityFeature:
|
||||
"""Flag supported features."""
|
||||
features = (
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Homekit Controller entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
from typing import Any
|
||||
|
||||
from aiohomekit.model.characteristics import (
|
||||
@ -74,6 +75,16 @@ class HomeKitEntity(Entity):
|
||||
if not self._async_remove_entity_if_accessory_or_service_disappeared():
|
||||
self._async_reconfigure()
|
||||
|
||||
@callback
|
||||
def _async_clear_property_cache(self, properties: tuple[str, ...]) -> None:
|
||||
"""Clear the cache of properties."""
|
||||
for prop in properties:
|
||||
# suppress is slower than try-except-pass, but
|
||||
# we do not expect to have many properties to clear
|
||||
# or this to be called often.
|
||||
with contextlib.suppress(AttributeError):
|
||||
delattr(self, prop)
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure the entity."""
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for Homekit fans."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||
from aiohomekit.model.services import Service, ServicesTypes
|
||||
@ -25,6 +25,12 @@ from . import KNOWN_DEVICES
|
||||
from .connection import HKDevice
|
||||
from .entity import HomeKitEntity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from functools import cached_property
|
||||
else:
|
||||
from homeassistant.backports.functools import cached_property
|
||||
|
||||
|
||||
# 0 is clockwise, 1 is counter-clockwise. The match to forward and reverse is so that
|
||||
# its consistent with homeassistant.components.homekit.
|
||||
DIRECTION_TO_HK = {
|
||||
@ -41,6 +47,20 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||
# that controls whether the fan is on or off.
|
||||
on_characteristic: str
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(
|
||||
(
|
||||
"_speed_range",
|
||||
"_min_speed",
|
||||
"_max_speed",
|
||||
"speed_count",
|
||||
"supported_features",
|
||||
)
|
||||
)
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
@ -55,19 +75,19 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||
"""Return true if device is on."""
|
||||
return self.service.value(self.on_characteristic) == 1
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def _speed_range(self) -> tuple[int, int]:
|
||||
"""Return the speed range."""
|
||||
return (self._min_speed, self._max_speed)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def _min_speed(self) -> int:
|
||||
"""Return the minimum speed."""
|
||||
return (
|
||||
round(self.service[CharacteristicsTypes.ROTATION_SPEED].minValue or 0) + 1
|
||||
)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def _max_speed(self) -> int:
|
||||
"""Return the minimum speed."""
|
||||
return round(self.service[CharacteristicsTypes.ROTATION_SPEED].maxValue or 100)
|
||||
@ -94,7 +114,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||
oscillating = self.service.value(CharacteristicsTypes.SWING_MODE)
|
||||
return oscillating == 1
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_features(self) -> FanEntityFeature:
|
||||
"""Flag supported features."""
|
||||
features = FanEntityFeature(0)
|
||||
@ -110,7 +130,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||
|
||||
return features
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def speed_count(self) -> int:
|
||||
"""Speed count for the fan."""
|
||||
return round(
|
||||
@ -157,7 +177,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||
|
||||
if (
|
||||
percentage is not None
|
||||
and self.supported_features & FanEntityFeature.SET_SPEED
|
||||
and FanEntityFeature.SET_SPEED in self.supported_features
|
||||
):
|
||||
characteristics[CharacteristicsTypes.ROTATION_SPEED] = round(
|
||||
percentage_to_ranged_value(self._speed_range, percentage)
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for HomeKit Controller humidifier."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||
from aiohomekit.model.services import Service, ServicesTypes
|
||||
@ -25,6 +25,12 @@ from . import KNOWN_DEVICES
|
||||
from .connection import HKDevice
|
||||
from .entity import HomeKitEntity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from functools import cached_property
|
||||
else:
|
||||
from homeassistant.backports.functools import cached_property
|
||||
|
||||
|
||||
HK_MODE_TO_HA = {
|
||||
0: "off",
|
||||
1: MODE_AUTO,
|
||||
@ -39,46 +45,25 @@ HA_MODE_TO_HK = {
|
||||
}
|
||||
|
||||
|
||||
class HomeKitHumidifier(HomeKitEntity, HumidifierEntity):
|
||||
class HomeKitBaseHumidifier(HomeKitEntity, HumidifierEntity):
|
||||
"""Representation of a HomeKit Controller Humidifier."""
|
||||
|
||||
_attr_device_class = HumidifierDeviceClass.HUMIDIFIER
|
||||
_attr_supported_features = HumidifierEntityFeature.MODES
|
||||
_attr_available_modes = [MODE_NORMAL, MODE_AUTO]
|
||||
_humidity_char = CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD
|
||||
_on_mode_value = 1
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
CharacteristicsTypes.ACTIVE,
|
||||
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD,
|
||||
]
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(("max_humidity", "min_humidity"))
|
||||
super()._async_reconfigure()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self.service.value(CharacteristicsTypes.ACTIVE)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve on."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve off."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False})
|
||||
|
||||
@property
|
||||
def target_humidity(self) -> int | None:
|
||||
"""Return the humidity we try to reach."""
|
||||
return self.service.value(
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD
|
||||
)
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> int | None:
|
||||
"""Return the current humidity."""
|
||||
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||
|
||||
@property
|
||||
def mode(self) -> str | None:
|
||||
"""Return the current mode, e.g., home, auto, baby.
|
||||
@ -91,23 +76,36 @@ class HomeKitHumidifier(HomeKitEntity, HumidifierEntity):
|
||||
return MODE_AUTO if mode == 1 else MODE_NORMAL
|
||||
|
||||
@property
|
||||
def available_modes(self) -> list[str] | None:
|
||||
"""Return a list of available modes.
|
||||
def current_humidity(self) -> int | None:
|
||||
"""Return the current humidity."""
|
||||
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||
|
||||
Requires HumidifierEntityFeature.MODES.
|
||||
"""
|
||||
available_modes = [
|
||||
MODE_NORMAL,
|
||||
MODE_AUTO,
|
||||
]
|
||||
@property
|
||||
def target_humidity(self) -> int | None:
|
||||
"""Return the humidity we try to reach."""
|
||||
return self.service.value(self._humidity_char)
|
||||
|
||||
return available_modes
|
||||
@cached_property
|
||||
def min_humidity(self) -> int:
|
||||
"""Return the minimum humidity."""
|
||||
return int(self.service[self._humidity_char].minValue or DEFAULT_MIN_HUMIDITY)
|
||||
|
||||
@cached_property
|
||||
def max_humidity(self) -> int:
|
||||
"""Return the maximum humidity."""
|
||||
return int(self.service[self._humidity_char].maxValue or DEFAULT_MAX_HUMIDITY)
|
||||
|
||||
async def async_set_humidity(self, humidity: int) -> None:
|
||||
"""Set new target humidity."""
|
||||
await self.async_put_characteristics(
|
||||
{CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD: humidity}
|
||||
)
|
||||
await self.async_put_characteristics({self._humidity_char: humidity})
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve on."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve off."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False})
|
||||
|
||||
async def async_set_mode(self, mode: str) -> None:
|
||||
"""Set new mode."""
|
||||
@ -121,37 +119,33 @@ class HomeKitHumidifier(HomeKitEntity, HumidifierEntity):
|
||||
else:
|
||||
await self.async_put_characteristics(
|
||||
{
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 1,
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: self._on_mode_value,
|
||||
CharacteristicsTypes.ACTIVE: True,
|
||||
}
|
||||
)
|
||||
|
||||
@property
|
||||
def min_humidity(self) -> int:
|
||||
"""Return the minimum humidity."""
|
||||
return int(
|
||||
self.service[
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD
|
||||
].minValue
|
||||
or DEFAULT_MIN_HUMIDITY
|
||||
)
|
||||
|
||||
@property
|
||||
def max_humidity(self) -> int:
|
||||
"""Return the maximum humidity."""
|
||||
return int(
|
||||
self.service[
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD
|
||||
].maxValue
|
||||
or DEFAULT_MAX_HUMIDITY
|
||||
)
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
CharacteristicsTypes.ACTIVE,
|
||||
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD,
|
||||
]
|
||||
|
||||
|
||||
class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity):
|
||||
class HomeKitHumidifier(HomeKitBaseHumidifier):
|
||||
"""Representation of a HomeKit Controller Humidifier."""
|
||||
|
||||
_attr_device_class = HumidifierDeviceClass.HUMIDIFIER
|
||||
|
||||
|
||||
class HomeKitDehumidifier(HomeKitBaseHumidifier):
|
||||
"""Representation of a HomeKit Controller Humidifier."""
|
||||
|
||||
_attr_device_class = HumidifierDeviceClass.DEHUMIDIFIER
|
||||
_attr_supported_features = HumidifierEntityFeature.MODES
|
||||
_humidity_char = CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD
|
||||
_on_mode_value = 2
|
||||
|
||||
def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None:
|
||||
"""Initialise the dehumidifier."""
|
||||
@ -160,106 +154,10 @@ class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity):
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
CharacteristicsTypes.ACTIVE,
|
||||
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD,
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD,
|
||||
]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self.service.value(CharacteristicsTypes.ACTIVE)
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve on."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True})
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the specified valve off."""
|
||||
await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False})
|
||||
|
||||
@property
|
||||
def target_humidity(self) -> int | None:
|
||||
"""Return the humidity we try to reach."""
|
||||
return self.service.value(
|
||||
return super().get_characteristic_types() + [
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD
|
||||
)
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> int | None:
|
||||
"""Return the current humidity."""
|
||||
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||
|
||||
@property
|
||||
def mode(self) -> str | None:
|
||||
"""Return the current mode, e.g., home, auto, baby.
|
||||
|
||||
Requires HumidifierEntityFeature.MODES.
|
||||
"""
|
||||
mode = self.service.value(
|
||||
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE
|
||||
)
|
||||
return MODE_AUTO if mode == 1 else MODE_NORMAL
|
||||
|
||||
@property
|
||||
def available_modes(self) -> list[str] | None:
|
||||
"""Return a list of available modes.
|
||||
|
||||
Requires HumidifierEntityFeature.MODES.
|
||||
"""
|
||||
available_modes = [
|
||||
MODE_NORMAL,
|
||||
MODE_AUTO,
|
||||
]
|
||||
|
||||
return available_modes
|
||||
|
||||
async def async_set_humidity(self, humidity: int) -> None:
|
||||
"""Set new target humidity."""
|
||||
await self.async_put_characteristics(
|
||||
{CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD: humidity}
|
||||
)
|
||||
|
||||
async def async_set_mode(self, mode: str) -> None:
|
||||
"""Set new mode."""
|
||||
if mode == MODE_AUTO:
|
||||
await self.async_put_characteristics(
|
||||
{
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 0,
|
||||
CharacteristicsTypes.ACTIVE: True,
|
||||
}
|
||||
)
|
||||
else:
|
||||
await self.async_put_characteristics(
|
||||
{
|
||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 2,
|
||||
CharacteristicsTypes.ACTIVE: True,
|
||||
}
|
||||
)
|
||||
|
||||
@property
|
||||
def min_humidity(self) -> int:
|
||||
"""Return the minimum humidity."""
|
||||
return int(
|
||||
self.service[
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD
|
||||
].minValue
|
||||
or DEFAULT_MIN_HUMIDITY
|
||||
)
|
||||
|
||||
@property
|
||||
def max_humidity(self) -> int:
|
||||
"""Return the maximum humidity."""
|
||||
return int(
|
||||
self.service[
|
||||
CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD
|
||||
].maxValue
|
||||
or DEFAULT_MAX_HUMIDITY
|
||||
)
|
||||
|
||||
@property
|
||||
def old_unique_id(self) -> str:
|
||||
"""Return the old ID of this device."""
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Support for Homekit lights."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||
from aiohomekit.model.services import Service, ServicesTypes
|
||||
@ -22,6 +22,11 @@ from . import KNOWN_DEVICES
|
||||
from .connection import HKDevice
|
||||
from .entity import HomeKitEntity
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from functools import cached_property
|
||||
else:
|
||||
from homeassistant.backports.functools import cached_property
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@ -50,6 +55,14 @@ async def async_setup_entry(
|
||||
class HomeKitLight(HomeKitEntity, LightEntity):
|
||||
"""Representation of a Homekit light."""
|
||||
|
||||
@callback
|
||||
def _async_reconfigure(self) -> None:
|
||||
"""Reconfigure entity."""
|
||||
self._async_clear_property_cache(
|
||||
("supported_features", "min_mireds", "max_mireds", "supported_color_modes")
|
||||
)
|
||||
super()._async_reconfigure()
|
||||
|
||||
def get_characteristic_types(self) -> list[str]:
|
||||
"""Define the homekit characteristics the entity cares about."""
|
||||
return [
|
||||
@ -78,13 +91,13 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
||||
self.service.value(CharacteristicsTypes.SATURATION),
|
||||
)
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def min_mireds(self) -> int:
|
||||
"""Return minimum supported color temperature."""
|
||||
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
|
||||
return int(min_value) if min_value else super().min_mireds
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def max_mireds(self) -> int:
|
||||
"""Return the maximum color temperature."""
|
||||
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
|
||||
@ -113,7 +126,7 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
||||
|
||||
return ColorMode.ONOFF
|
||||
|
||||
@property
|
||||
@cached_property
|
||||
def supported_color_modes(self) -> set[ColorMode]:
|
||||
"""Flag supported color modes."""
|
||||
color_modes: set[ColorMode] = set()
|
||||
|
@ -0,0 +1,323 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 878448248,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Inc."
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Shade"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Kitchen Window"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "cover.kitchen_window"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "3.6.2"
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 10,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 11,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 12,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 13,
|
||||
"type": "8C",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 14,
|
||||
"type": "6D",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 15,
|
||||
"type": "7C",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 16,
|
||||
"type": "72",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 123016423,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 155,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 156,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Inc."
|
||||
},
|
||||
{
|
||||
"iid": 157,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Shade"
|
||||
},
|
||||
{
|
||||
"iid": 158,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Family Room North"
|
||||
},
|
||||
{
|
||||
"iid": 159,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "cover.family_door_north"
|
||||
},
|
||||
{
|
||||
"iid": 160,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "3.6.2"
|
||||
},
|
||||
{
|
||||
"iid": 161,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 162,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 163,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 164,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 165,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 166,
|
||||
"type": "8C",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 167,
|
||||
"type": "6D",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 98
|
||||
},
|
||||
{
|
||||
"iid": 168,
|
||||
"type": "7C",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 98
|
||||
},
|
||||
{
|
||||
"iid": 169,
|
||||
"type": "72",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,229 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 1233851541,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 163,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 164,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Lookin"
|
||||
},
|
||||
{
|
||||
"iid": 165,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Climate Control"
|
||||
},
|
||||
{
|
||||
"iid": 166,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "89 Living Room"
|
||||
},
|
||||
{
|
||||
"iid": 167,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "climate.89_living_room"
|
||||
},
|
||||
{
|
||||
"iid": 168,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
],
|
||||
"primary": false
|
||||
},
|
||||
{
|
||||
"iid": 169,
|
||||
"type": "BC",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 170,
|
||||
"type": "B2",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 171,
|
||||
"type": "B1",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2, 3],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 172,
|
||||
"type": "11",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "celsius",
|
||||
"minStep": 0.1,
|
||||
"maxValue": 1000,
|
||||
"minValue": -273.1,
|
||||
"value": 22.8
|
||||
},
|
||||
{
|
||||
"iid": 173,
|
||||
"type": "35",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"unit": "celsius",
|
||||
"minStep": 0.1,
|
||||
"maxValue": 30.0,
|
||||
"minValue": 16.0,
|
||||
"value": 20.0
|
||||
},
|
||||
{
|
||||
"iid": 174,
|
||||
"type": "36",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 180,
|
||||
"type": "10",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 60
|
||||
}
|
||||
],
|
||||
"primary": true,
|
||||
"linked": [175]
|
||||
},
|
||||
{
|
||||
"iid": 175,
|
||||
"type": "B7",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 176,
|
||||
"type": "B0",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 177,
|
||||
"type": "29",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"description": "Fan Mode",
|
||||
"unit": "percentage",
|
||||
"minStep": 33.333333333333336,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 33.33333333333334
|
||||
},
|
||||
{
|
||||
"iid": 178,
|
||||
"type": "BF",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"description": "Fan Auto",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 179,
|
||||
"type": "B6",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"description": "Swing Mode",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,183 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 3982136094,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 597,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 598,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "FirstAlert"
|
||||
},
|
||||
{
|
||||
"iid": 599,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1039102"
|
||||
},
|
||||
{
|
||||
"iid": 600,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Laundry Smoke ED78"
|
||||
},
|
||||
{
|
||||
"iid": 601,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "light.laundry_smoke_ed78"
|
||||
},
|
||||
{
|
||||
"iid": 602,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.4.84"
|
||||
},
|
||||
{
|
||||
"iid": 603,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "9.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 604,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 605,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 606,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 607,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 608,
|
||||
"type": "43",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 609,
|
||||
"type": "25",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"iid": 610,
|
||||
"type": "8",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "int",
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,330 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 878448248,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Inc."
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Shade"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Kitchen Window"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "cover.kitchen_window"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "3.6.2"
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 10,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 11,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 12,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 13,
|
||||
"type": "8C",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 14,
|
||||
"type": "6D",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 15,
|
||||
"type": "7C",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 16,
|
||||
"type": "72",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 123016423,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 155,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 156,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Inc."
|
||||
},
|
||||
{
|
||||
"iid": 157,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "RYSE Shade"
|
||||
},
|
||||
{
|
||||
"iid": 158,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Family Room North"
|
||||
},
|
||||
{
|
||||
"iid": 159,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "cover.family_door_north"
|
||||
},
|
||||
{
|
||||
"iid": 160,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "3.6.2"
|
||||
},
|
||||
{
|
||||
"iid": 161,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 162,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 163,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 164,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 165,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 166,
|
||||
"type": "8C",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 167,
|
||||
"type": "6D",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 98
|
||||
},
|
||||
{
|
||||
"iid": 168,
|
||||
"type": "7C",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"maxValue": 100,
|
||||
"value": 98
|
||||
},
|
||||
{
|
||||
"iid": 169,
|
||||
"type": "72",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 170,
|
||||
"type": "6F",
|
||||
"perms": ["pw", "pr", "ev"],
|
||||
"format": "bool",
|
||||
"value": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,237 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 1233851541,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 163,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 164,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Lookin"
|
||||
},
|
||||
{
|
||||
"iid": 165,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Climate Control"
|
||||
},
|
||||
{
|
||||
"iid": 166,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "89 Living Room"
|
||||
},
|
||||
{
|
||||
"iid": 167,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "climate.89_living_room"
|
||||
},
|
||||
{
|
||||
"iid": 168,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
],
|
||||
"primary": false
|
||||
},
|
||||
{
|
||||
"iid": 169,
|
||||
"type": "BC",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 170,
|
||||
"type": "B2",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 171,
|
||||
"type": "B1",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2, 3],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 172,
|
||||
"type": "11",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "celsius",
|
||||
"minStep": 0.1,
|
||||
"maxValue": 1000,
|
||||
"minValue": -273.1,
|
||||
"value": 22.8
|
||||
},
|
||||
{
|
||||
"iid": 173,
|
||||
"type": "35",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"unit": "celsius",
|
||||
"minStep": 0.1,
|
||||
"maxValue": 30.0,
|
||||
"minValue": 16.0,
|
||||
"value": 20.0
|
||||
},
|
||||
{
|
||||
"iid": 174,
|
||||
"type": "36",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 180,
|
||||
"type": "10",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 60
|
||||
},
|
||||
{
|
||||
"iid": 290,
|
||||
"type": "B6",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"primary": true,
|
||||
"linked": [175]
|
||||
},
|
||||
{
|
||||
"iid": 175,
|
||||
"type": "B7",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 176,
|
||||
"type": "B0",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 177,
|
||||
"type": "29",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"description": "Fan Mode",
|
||||
"unit": "percentage",
|
||||
"minStep": 33.333333333333336,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 33.33333333333334
|
||||
},
|
||||
{
|
||||
"iid": 178,
|
||||
"type": "BF",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"description": "Fan Auto",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 179,
|
||||
"type": "B6",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"description": "Swing Mode",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,173 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 293334836,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "switchbot"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "WoHumi"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Humidifier 182A"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "humidifier.humidifier_182a"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "BD",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "10",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 10,
|
||||
"type": "B3",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 11,
|
||||
"type": "B4",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"maxValue": 1,
|
||||
"minValue": 1,
|
||||
"valid-values": [1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 12,
|
||||
"type": "B0",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 13,
|
||||
"type": "CA",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 45
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,173 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 293334836,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "switchbot"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "WoHumi"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Humidifier 182A"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "humidifier.humidifier_182a"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "BD",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "10",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 10,
|
||||
"type": "B3",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 11,
|
||||
"type": "B4",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"maxValue": 1,
|
||||
"minValue": 1,
|
||||
"valid-values": [1],
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"iid": 12,
|
||||
"type": "B0",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 13,
|
||||
"type": "CA",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"unit": "percentage",
|
||||
"minStep": 1,
|
||||
"maxValue": 80,
|
||||
"minValue": 20,
|
||||
"value": 45
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,205 @@
|
||||
[
|
||||
{
|
||||
"aid": 1,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 2,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 3,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Home Assistant"
|
||||
},
|
||||
{
|
||||
"iid": 4,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Bridge"
|
||||
},
|
||||
{
|
||||
"iid": 5,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "HASS Bridge S6"
|
||||
},
|
||||
{
|
||||
"iid": 6,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "homekit.bridge"
|
||||
},
|
||||
{
|
||||
"iid": 7,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "2024.2.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 8,
|
||||
"type": "A2",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 9,
|
||||
"type": "37",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "string",
|
||||
"value": "01.01.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aid": 3982136094,
|
||||
"services": [
|
||||
{
|
||||
"iid": 1,
|
||||
"type": "3E",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 597,
|
||||
"type": "14",
|
||||
"perms": ["pw"],
|
||||
"format": "bool"
|
||||
},
|
||||
{
|
||||
"iid": 598,
|
||||
"type": "20",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "FirstAlert"
|
||||
},
|
||||
{
|
||||
"iid": 599,
|
||||
"type": "21",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1039102"
|
||||
},
|
||||
{
|
||||
"iid": 600,
|
||||
"type": "23",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "Laundry Smoke ED78"
|
||||
},
|
||||
{
|
||||
"iid": 601,
|
||||
"type": "30",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "light.laundry_smoke_ed78"
|
||||
},
|
||||
{
|
||||
"iid": 602,
|
||||
"type": "52",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "1.4.84"
|
||||
},
|
||||
{
|
||||
"iid": 603,
|
||||
"type": "53",
|
||||
"perms": ["pr"],
|
||||
"format": "string",
|
||||
"value": "9.0.0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 604,
|
||||
"type": "96",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 605,
|
||||
"type": "68",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 606,
|
||||
"type": "8F",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1, 2],
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"iid": 607,
|
||||
"type": "79",
|
||||
"perms": ["pr", "ev"],
|
||||
"format": "uint8",
|
||||
"valid-values": [0, 1],
|
||||
"value": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"iid": 608,
|
||||
"type": "43",
|
||||
"characteristics": [
|
||||
{
|
||||
"iid": 609,
|
||||
"type": "25",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "bool",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"iid": 610,
|
||||
"type": "8",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "int",
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"iid": 611,
|
||||
"type": "13",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"maxValue": 360,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "arcdegrees",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"iid": 612,
|
||||
"type": "2F",
|
||||
"perms": ["pr", "pw", "ev"],
|
||||
"format": "float",
|
||||
"maxValue": 100,
|
||||
"minStep": 1,
|
||||
"minValue": 0,
|
||||
"unit": "percentage",
|
||||
"value": 75
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,54 @@
|
||||
"""Test for a Home Assistant bridge that changes cover features at runtime."""
|
||||
|
||||
|
||||
from homeassistant.components.cover import CoverEntityFeature
|
||||
from homeassistant.const import ATTR_SUPPORTED_FEATURES
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..common import (
|
||||
device_config_changed,
|
||||
setup_accessories_from_file,
|
||||
setup_test_accessories,
|
||||
)
|
||||
|
||||
|
||||
async def test_cover_add_feature_at_runtime(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test that new features can be added at runtime."""
|
||||
|
||||
# Set up a basic cover that does not support position
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_cover.json"
|
||||
)
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
cover = entity_registry.async_get("cover.family_room_north")
|
||||
assert cover.unique_id == "00:00:00:00:00:00_123016423_166"
|
||||
|
||||
cover_state = hass.states.get("cover.family_room_north")
|
||||
assert (
|
||||
cover_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is CoverEntityFeature.OPEN
|
||||
| CoverEntityFeature.STOP
|
||||
| CoverEntityFeature.CLOSE
|
||||
| CoverEntityFeature.SET_POSITION
|
||||
)
|
||||
|
||||
cover = entity_registry.async_get("cover.family_room_north")
|
||||
assert cover.unique_id == "00:00:00:00:00:00_123016423_166"
|
||||
|
||||
# Now change the config to remove stop
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_basic_cover.json"
|
||||
)
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
cover_state = hass.states.get("cover.family_room_north")
|
||||
assert (
|
||||
cover_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is CoverEntityFeature.OPEN
|
||||
| CoverEntityFeature.CLOSE
|
||||
| CoverEntityFeature.SET_POSITION
|
||||
)
|
@ -0,0 +1,48 @@
|
||||
"""Test for a Home Assistant bridge that changes climate features at runtime."""
|
||||
|
||||
|
||||
from homeassistant.components.climate import ATTR_SWING_MODES, ClimateEntityFeature
|
||||
from homeassistant.const import ATTR_SUPPORTED_FEATURES
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..common import (
|
||||
device_config_changed,
|
||||
setup_accessories_from_file,
|
||||
setup_test_accessories,
|
||||
)
|
||||
|
||||
|
||||
async def test_cover_add_feature_at_runtime(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test that new features can be added at runtime."""
|
||||
|
||||
# Set up a basic heater cooler that does not support swing mode
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_basic_heater_cooler.json"
|
||||
)
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
climate = entity_registry.async_get("climate.89_living_room")
|
||||
assert climate.unique_id == "00:00:00:00:00:00_1233851541_169"
|
||||
|
||||
climate_state = hass.states.get("climate.89_living_room")
|
||||
assert climate_state.attributes[ATTR_SUPPORTED_FEATURES] is ClimateEntityFeature(0)
|
||||
assert ATTR_SWING_MODES not in climate_state.attributes
|
||||
|
||||
climate = entity_registry.async_get("climate.89_living_room")
|
||||
assert climate.unique_id == "00:00:00:00:00:00_1233851541_169"
|
||||
|
||||
# Now change the config to add swing mode
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_heater_cooler.json"
|
||||
)
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
climate_state = hass.states.get("climate.89_living_room")
|
||||
assert (
|
||||
climate_state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
is ClimateEntityFeature.SWING_MODE
|
||||
)
|
||||
assert climate_state.attributes[ATTR_SWING_MODES] == ["off", "vertical"]
|
@ -0,0 +1,44 @@
|
||||
"""Test for a Home Assistant bridge that changes humidifier min/max at runtime."""
|
||||
|
||||
|
||||
from homeassistant.components.humidifier import ATTR_MAX_HUMIDITY, ATTR_MIN_HUMIDITY
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..common import (
|
||||
device_config_changed,
|
||||
setup_accessories_from_file,
|
||||
setup_test_accessories,
|
||||
)
|
||||
|
||||
|
||||
async def test_humidifier_change_range_at_runtime(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test that min max can be changed at runtime."""
|
||||
|
||||
# Set up a basic humidifier
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_humidifier.json"
|
||||
)
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
humidifier = entity_registry.async_get("humidifier.humidifier_182a")
|
||||
assert humidifier.unique_id == "00:00:00:00:00:00_293334836_8"
|
||||
|
||||
humidifier_state = hass.states.get("humidifier.humidifier_182a")
|
||||
assert humidifier_state.attributes[ATTR_MIN_HUMIDITY] == 0
|
||||
assert humidifier_state.attributes[ATTR_MAX_HUMIDITY] == 100
|
||||
|
||||
cover = entity_registry.async_get("humidifier.humidifier_182a")
|
||||
assert cover.unique_id == "00:00:00:00:00:00_293334836_8"
|
||||
|
||||
# Now change min/max values
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_humidifier_new_range.json"
|
||||
)
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
humidifier_state = hass.states.get("humidifier.humidifier_182a")
|
||||
assert humidifier_state.attributes[ATTR_MIN_HUMIDITY] == 20
|
||||
assert humidifier_state.attributes[ATTR_MAX_HUMIDITY] == 80
|
@ -0,0 +1,42 @@
|
||||
"""Test for a Home Assistant bridge that changes light features at runtime."""
|
||||
|
||||
|
||||
from homeassistant.components.light import ATTR_SUPPORTED_COLOR_MODES, ColorMode
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ..common import (
|
||||
device_config_changed,
|
||||
setup_accessories_from_file,
|
||||
setup_test_accessories,
|
||||
)
|
||||
|
||||
|
||||
async def test_light_add_feature_at_runtime(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test that new features can be added at runtime."""
|
||||
|
||||
# Set up a basic light that does not support color
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_basic_light.json"
|
||||
)
|
||||
await setup_test_accessories(hass, accessories)
|
||||
|
||||
light = entity_registry.async_get("light.laundry_smoke_ed78")
|
||||
assert light.unique_id == "00:00:00:00:00:00_3982136094_608"
|
||||
|
||||
light_state = hass.states.get("light.laundry_smoke_ed78")
|
||||
assert light_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.BRIGHTNESS]
|
||||
|
||||
light = entity_registry.async_get("light.laundry_smoke_ed78")
|
||||
assert light.unique_id == "00:00:00:00:00:00_3982136094_608"
|
||||
|
||||
# Now add hue and saturation
|
||||
accessories = await setup_accessories_from_file(
|
||||
hass, "home_assistant_bridge_light.json"
|
||||
)
|
||||
await device_config_changed(hass, accessories)
|
||||
|
||||
light_state = hass.states.get("light.laundry_smoke_ed78")
|
||||
assert light_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.HS]
|
Loading…
x
Reference in New Issue
Block a user