Cache homekit_controller supported features (#106702)
This commit is contained in:
parent
f2514c0bde
commit
bc26377c16
19 changed files with 4588 additions and 192 deletions
|
@ -2,7 +2,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Final
|
from typing import TYPE_CHECKING, Any, Final
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import (
|
from aiohomekit.model.characteristics import (
|
||||||
ActivationStateValues,
|
ActivationStateValues,
|
||||||
|
@ -48,6 +48,12 @@ from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
from .entity import HomeKitEntity
|
from .entity import HomeKitEntity
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from functools import cached_property
|
||||||
|
else:
|
||||||
|
from homeassistant.backports.functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Map of Homekit operation modes to hass modes
|
# Map of Homekit operation modes to hass modes
|
||||||
|
@ -134,6 +140,12 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||||
|
|
||||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
_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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -146,7 +158,7 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
return self.service.value(CharacteristicsTypes.TEMPERATURE_CURRENT)
|
return self.service.value(CharacteristicsTypes.TEMPERATURE_CURRENT)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def fan_modes(self) -> list[str] | None:
|
def fan_modes(self) -> list[str] | None:
|
||||||
"""Return the available fan modes."""
|
"""Return the available fan modes."""
|
||||||
if self.service.has(CharacteristicsTypes.FAN_STATE_TARGET):
|
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)}
|
{CharacteristicsTypes.FAN_STATE_TARGET: int(fan_mode == FAN_AUTO)}
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_features(self) -> ClimateEntityFeature:
|
def supported_features(self) -> ClimateEntityFeature:
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
features = ClimateEntityFeature(0)
|
features = ClimateEntityFeature(0)
|
||||||
|
@ -179,6 +191,12 @@ class HomeKitBaseClimateEntity(HomeKitEntity, ClimateEntity):
|
||||||
class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||||
"""Representation of a Homekit climate device."""
|
"""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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return super().get_characteristic_types() + [
|
return super().get_characteristic_types() + [
|
||||||
|
@ -197,7 +215,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||||
rotation_speed.maxValue or 100
|
rotation_speed.maxValue or 100
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def fan_modes(self) -> list[str]:
|
def fan_modes(self) -> list[str]:
|
||||||
"""Return the available fan modes."""
|
"""Return the available fan modes."""
|
||||||
return [FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
|
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)
|
value = self.service.value(CharacteristicsTypes.TARGET_HEATER_COOLER_STATE)
|
||||||
return TARGET_HEATER_COOLER_STATE_HOMEKIT_TO_HASS[value]
|
return TARGET_HEATER_COOLER_STATE_HOMEKIT_TO_HASS[value]
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def hvac_modes(self) -> list[HVACMode]:
|
def hvac_modes(self) -> list[HVACMode]:
|
||||||
"""Return the list of available hvac operation modes."""
|
"""Return the list of available hvac operation modes."""
|
||||||
valid_values = clamp_enum_to_char(
|
valid_values = clamp_enum_to_char(
|
||||||
|
@ -410,7 +428,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||||
value = self.service.value(CharacteristicsTypes.SWING_MODE)
|
value = self.service.value(CharacteristicsTypes.SWING_MODE)
|
||||||
return SWING_MODE_HOMEKIT_TO_HASS[value]
|
return SWING_MODE_HOMEKIT_TO_HASS[value]
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def swing_modes(self) -> list[str]:
|
def swing_modes(self) -> list[str]:
|
||||||
"""Return the list of available swing modes.
|
"""Return the list of available swing modes.
|
||||||
|
|
||||||
|
@ -428,7 +446,7 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||||
{CharacteristicsTypes.SWING_MODE: SWING_MODE_HASS_TO_HOMEKIT[swing_mode]}
|
{CharacteristicsTypes.SWING_MODE: SWING_MODE_HASS_TO_HOMEKIT[swing_mode]}
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_features(self) -> ClimateEntityFeature:
|
def supported_features(self) -> ClimateEntityFeature:
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
features = super().supported_features
|
features = super().supported_features
|
||||||
|
@ -451,6 +469,12 @@ class HomeKitHeaterCoolerEntity(HomeKitBaseClimateEntity):
|
||||||
class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
"""Representation of a Homekit climate device."""
|
"""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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return super().get_characteristic_types() + [
|
return super().get_characteristic_types() + [
|
||||||
|
@ -483,7 +507,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
if (
|
if (
|
||||||
(mode == HVACMode.HEAT_COOL)
|
(mode == HVACMode.HEAT_COOL)
|
||||||
and (
|
and (
|
||||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE in self.supported_features
|
||||||
)
|
)
|
||||||
and heat_temp
|
and heat_temp
|
||||||
and cool_temp
|
and cool_temp
|
||||||
|
@ -524,9 +548,8 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT, HVACMode.COOL}) or (
|
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT, HVACMode.COOL}) or (
|
||||||
(MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL})
|
(MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL})
|
||||||
and not (
|
and ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
|
||||||
ClimateEntityFeature.TARGET_TEMPERATURE_RANGE & self.supported_features
|
not in self.supported_features
|
||||||
)
|
|
||||||
):
|
):
|
||||||
return self.service.value(CharacteristicsTypes.TEMPERATURE_TARGET)
|
return self.service.value(CharacteristicsTypes.TEMPERATURE_TARGET)
|
||||||
return None
|
return None
|
||||||
|
@ -536,7 +559,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
"""Return the highbound target temperature we try to reach."""
|
"""Return the highbound target temperature we try to reach."""
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
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(
|
return self.service.value(
|
||||||
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
||||||
|
@ -548,7 +571,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
"""Return the lowbound target temperature we try to reach."""
|
"""Return the lowbound target temperature we try to reach."""
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
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(
|
return self.service.value(
|
||||||
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
||||||
|
@ -560,7 +583,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
"""Return the minimum target temp."""
|
"""Return the minimum target temp."""
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
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[
|
min_temp = self.service[
|
||||||
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
CharacteristicsTypes.TEMPERATURE_HEATING_THRESHOLD
|
||||||
|
@ -582,7 +605,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
"""Return the maximum target temp."""
|
"""Return the maximum target temp."""
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
if (MODE_HOMEKIT_TO_HASS.get(value) in {HVACMode.HEAT_COOL}) and (
|
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[
|
max_temp = self.service[
|
||||||
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
CharacteristicsTypes.TEMPERATURE_COOLING_THRESHOLD
|
||||||
|
@ -656,7 +679,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
return MODE_HOMEKIT_TO_HASS[value]
|
return MODE_HOMEKIT_TO_HASS[value]
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def hvac_modes(self) -> list[HVACMode]:
|
def hvac_modes(self) -> list[HVACMode]:
|
||||||
"""Return the list of available hvac operation modes."""
|
"""Return the list of available hvac operation modes."""
|
||||||
valid_values = clamp_enum_to_char(
|
valid_values = clamp_enum_to_char(
|
||||||
|
@ -665,7 +688,7 @@ class HomeKitClimateEntity(HomeKitBaseClimateEntity):
|
||||||
)
|
)
|
||||||
return [MODE_HOMEKIT_TO_HASS[mode] for mode in valid_values]
|
return [MODE_HOMEKIT_TO_HASS[mode] for mode in valid_values]
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_features(self) -> ClimateEntityFeature:
|
def supported_features(self) -> ClimateEntityFeature:
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
features = super().supported_features
|
features = super().supported_features
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Support for Homekit covers."""
|
"""Support for Homekit covers."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
@ -28,6 +28,12 @@ from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
from .entity import HomeKitEntity
|
from .entity import HomeKitEntity
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from functools import cached_property
|
||||||
|
else:
|
||||||
|
from homeassistant.backports.functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
STATE_STOPPED = "stopped"
|
STATE_STOPPED = "stopped"
|
||||||
|
|
||||||
CURRENT_GARAGE_STATE_MAP = {
|
CURRENT_GARAGE_STATE_MAP = {
|
||||||
|
@ -128,6 +134,12 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverEntity):
|
||||||
class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
||||||
"""Representation of a HomeKit Window or Window Covering."""
|
"""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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -142,7 +154,7 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity):
|
||||||
CharacteristicsTypes.OBSTRUCTION_DETECTED,
|
CharacteristicsTypes.OBSTRUCTION_DETECTED,
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_features(self) -> CoverEntityFeature:
|
def supported_features(self) -> CoverEntityFeature:
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
features = (
|
features = (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Homekit Controller entities."""
|
"""Homekit Controller entities."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import contextlib
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import (
|
from aiohomekit.model.characteristics import (
|
||||||
|
@ -74,6 +75,16 @@ class HomeKitEntity(Entity):
|
||||||
if not self._async_remove_entity_if_accessory_or_service_disappeared():
|
if not self._async_remove_entity_if_accessory_or_service_disappeared():
|
||||||
self._async_reconfigure()
|
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
|
@callback
|
||||||
def _async_reconfigure(self) -> None:
|
def _async_reconfigure(self) -> None:
|
||||||
"""Reconfigure the entity."""
|
"""Reconfigure the entity."""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Support for Homekit fans."""
|
"""Support for Homekit fans."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
@ -25,6 +25,12 @@ from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
from .entity import HomeKitEntity
|
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
|
# 0 is clockwise, 1 is counter-clockwise. The match to forward and reverse is so that
|
||||||
# its consistent with homeassistant.components.homekit.
|
# its consistent with homeassistant.components.homekit.
|
||||||
DIRECTION_TO_HK = {
|
DIRECTION_TO_HK = {
|
||||||
|
@ -41,6 +47,20 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
# that controls whether the fan is on or off.
|
# that controls whether the fan is on or off.
|
||||||
on_characteristic: str
|
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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -55,19 +75,19 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self.service.value(self.on_characteristic) == 1
|
return self.service.value(self.on_characteristic) == 1
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def _speed_range(self) -> tuple[int, int]:
|
def _speed_range(self) -> tuple[int, int]:
|
||||||
"""Return the speed range."""
|
"""Return the speed range."""
|
||||||
return (self._min_speed, self._max_speed)
|
return (self._min_speed, self._max_speed)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def _min_speed(self) -> int:
|
def _min_speed(self) -> int:
|
||||||
"""Return the minimum speed."""
|
"""Return the minimum speed."""
|
||||||
return (
|
return (
|
||||||
round(self.service[CharacteristicsTypes.ROTATION_SPEED].minValue or 0) + 1
|
round(self.service[CharacteristicsTypes.ROTATION_SPEED].minValue or 0) + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def _max_speed(self) -> int:
|
def _max_speed(self) -> int:
|
||||||
"""Return the minimum speed."""
|
"""Return the minimum speed."""
|
||||||
return round(self.service[CharacteristicsTypes.ROTATION_SPEED].maxValue or 100)
|
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)
|
oscillating = self.service.value(CharacteristicsTypes.SWING_MODE)
|
||||||
return oscillating == 1
|
return oscillating == 1
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_features(self) -> FanEntityFeature:
|
def supported_features(self) -> FanEntityFeature:
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
features = FanEntityFeature(0)
|
features = FanEntityFeature(0)
|
||||||
|
@ -110,7 +130,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
|
|
||||||
return features
|
return features
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def speed_count(self) -> int:
|
def speed_count(self) -> int:
|
||||||
"""Speed count for the fan."""
|
"""Speed count for the fan."""
|
||||||
return round(
|
return round(
|
||||||
|
@ -157,7 +177,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
percentage is not None
|
percentage is not None
|
||||||
and self.supported_features & FanEntityFeature.SET_SPEED
|
and FanEntityFeature.SET_SPEED in self.supported_features
|
||||||
):
|
):
|
||||||
characteristics[CharacteristicsTypes.ROTATION_SPEED] = round(
|
characteristics[CharacteristicsTypes.ROTATION_SPEED] = round(
|
||||||
percentage_to_ranged_value(self._speed_range, percentage)
|
percentage_to_ranged_value(self._speed_range, percentage)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Support for HomeKit Controller humidifier."""
|
"""Support for HomeKit Controller humidifier."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
@ -25,6 +25,12 @@ from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
from .entity import HomeKitEntity
|
from .entity import HomeKitEntity
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from functools import cached_property
|
||||||
|
else:
|
||||||
|
from homeassistant.backports.functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
HK_MODE_TO_HA = {
|
HK_MODE_TO_HA = {
|
||||||
0: "off",
|
0: "off",
|
||||||
1: MODE_AUTO,
|
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."""
|
"""Representation of a HomeKit Controller Humidifier."""
|
||||||
|
|
||||||
_attr_device_class = HumidifierDeviceClass.HUMIDIFIER
|
|
||||||
_attr_supported_features = HumidifierEntityFeature.MODES
|
_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]:
|
@callback
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
def _async_reconfigure(self) -> None:
|
||||||
return [
|
"""Reconfigure entity."""
|
||||||
CharacteristicsTypes.ACTIVE,
|
self._async_clear_property_cache(("max_humidity", "min_humidity"))
|
||||||
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
super()._async_reconfigure()
|
||||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
|
||||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD,
|
|
||||||
]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self.service.value(CharacteristicsTypes.ACTIVE)
|
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
|
@property
|
||||||
def mode(self) -> str | None:
|
def mode(self) -> str | None:
|
||||||
"""Return the current mode, e.g., home, auto, baby.
|
"""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
|
return MODE_AUTO if mode == 1 else MODE_NORMAL
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available_modes(self) -> list[str] | None:
|
def current_humidity(self) -> int | None:
|
||||||
"""Return a list of available modes.
|
"""Return the current humidity."""
|
||||||
|
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||||
|
|
||||||
Requires HumidifierEntityFeature.MODES.
|
@property
|
||||||
"""
|
def target_humidity(self) -> int | None:
|
||||||
available_modes = [
|
"""Return the humidity we try to reach."""
|
||||||
MODE_NORMAL,
|
return self.service.value(self._humidity_char)
|
||||||
MODE_AUTO,
|
|
||||||
]
|
|
||||||
|
|
||||||
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:
|
async def async_set_humidity(self, humidity: int) -> None:
|
||||||
"""Set new target humidity."""
|
"""Set new target humidity."""
|
||||||
await self.async_put_characteristics(
|
await self.async_put_characteristics({self._humidity_char: humidity})
|
||||||
{CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD: 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:
|
async def async_set_mode(self, mode: str) -> None:
|
||||||
"""Set new mode."""
|
"""Set new mode."""
|
||||||
|
@ -121,37 +119,33 @@ class HomeKitHumidifier(HomeKitEntity, HumidifierEntity):
|
||||||
else:
|
else:
|
||||||
await self.async_put_characteristics(
|
await self.async_put_characteristics(
|
||||||
{
|
{
|
||||||
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: 1,
|
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE: self._on_mode_value,
|
||||||
CharacteristicsTypes.ACTIVE: True,
|
CharacteristicsTypes.ACTIVE: True,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
def get_characteristic_types(self) -> list[str]:
|
||||||
def min_humidity(self) -> int:
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
"""Return the minimum humidity."""
|
return [
|
||||||
return int(
|
CharacteristicsTypes.ACTIVE,
|
||||||
self.service[
|
CharacteristicsTypes.CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||||
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD
|
CharacteristicsTypes.TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE,
|
||||||
].minValue
|
CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD,
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
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."""
|
"""Representation of a HomeKit Controller Humidifier."""
|
||||||
|
|
||||||
_attr_device_class = HumidifierDeviceClass.DEHUMIDIFIER
|
_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:
|
def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None:
|
||||||
"""Initialise the dehumidifier."""
|
"""Initialise the dehumidifier."""
|
||||||
|
@ -160,106 +154,10 @@ class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity):
|
||||||
|
|
||||||
def get_characteristic_types(self) -> list[str]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return super().get_characteristic_types() + [
|
||||||
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(
|
|
||||||
CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD
|
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
|
@property
|
||||||
def old_unique_id(self) -> str:
|
def old_unique_id(self) -> str:
|
||||||
"""Return the old ID of this device."""
|
"""Return the old ID of this device."""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Support for Homekit lights."""
|
"""Support for Homekit lights."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
@ -22,6 +22,11 @@ from . import KNOWN_DEVICES
|
||||||
from .connection import HKDevice
|
from .connection import HKDevice
|
||||||
from .entity import HomeKitEntity
|
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(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -50,6 +55,14 @@ async def async_setup_entry(
|
||||||
class HomeKitLight(HomeKitEntity, LightEntity):
|
class HomeKitLight(HomeKitEntity, LightEntity):
|
||||||
"""Representation of a Homekit light."""
|
"""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]:
|
def get_characteristic_types(self) -> list[str]:
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -78,13 +91,13 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
||||||
self.service.value(CharacteristicsTypes.SATURATION),
|
self.service.value(CharacteristicsTypes.SATURATION),
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def min_mireds(self) -> int:
|
def min_mireds(self) -> int:
|
||||||
"""Return minimum supported color temperature."""
|
"""Return minimum supported color temperature."""
|
||||||
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
|
min_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].minValue
|
||||||
return int(min_value) if min_value else super().min_mireds
|
return int(min_value) if min_value else super().min_mireds
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def max_mireds(self) -> int:
|
def max_mireds(self) -> int:
|
||||||
"""Return the maximum color temperature."""
|
"""Return the maximum color temperature."""
|
||||||
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
|
max_value = self.service[CharacteristicsTypes.COLOR_TEMPERATURE].maxValue
|
||||||
|
@ -113,7 +126,7 @@ class HomeKitLight(HomeKitEntity, LightEntity):
|
||||||
|
|
||||||
return ColorMode.ONOFF
|
return ColorMode.ONOFF
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def supported_color_modes(self) -> set[ColorMode]:
|
def supported_color_modes(self) -> set[ColorMode]:
|
||||||
"""Flag supported color modes."""
|
"""Flag supported color modes."""
|
||||||
color_modes: set[ColorMode] = set()
|
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…
Add table
Add a link
Reference in a new issue