mirror of
https://github.com/home-assistant/core.git
synced 2026-04-29 02:13:44 +02:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e73063ed3 | |||
| e9796547c6 | |||
| 9c7b80090a | |||
| 19ddf478e2 | |||
| 5cdcbcd5fe | |||
| 803d4a9998 | |||
| 8ccc77eb3d | |||
| 5994dd558b | |||
| b548be35bc | |||
| 2cf1235b78 | |||
| 609fc9196f | |||
| b7396a736e | |||
| a64e56c8ad | |||
| 94160903a7 | |||
| f4948e8f48 | |||
| ec7302ef1b | |||
| 7b462e1b8e | |||
| 92bc93466e | |||
| 54dd556459 | |||
| 8553faf3c8 | |||
| 1631d10365 | |||
| 141f37504d | |||
| f97795fbb9 | |||
| ebf133ef80 | |||
| 886525112b | |||
| 9a15494e69 | |||
| 047012d167 | |||
| 8703e14cab | |||
| 5992361717 | |||
| 54748cec82 | |||
| c8d560946b | |||
| 07c60686b1 | |||
| 7795cc7fe8 | |||
| 172d587f84 | |||
| 7903f01f0c |
@@ -9,7 +9,7 @@
|
||||
"bleak==0.19.2",
|
||||
"bleak-retry-connector==2.10.1",
|
||||
"bluetooth-adapters==0.12.0",
|
||||
"bluetooth-auto-recovery==0.5.4",
|
||||
"bluetooth-auto-recovery==0.5.5",
|
||||
"bluetooth-data-tools==0.3.0",
|
||||
"dbus-fast==1.75.0"
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"domain": "cloud",
|
||||
"name": "Home Assistant Cloud",
|
||||
"documentation": "https://www.home-assistant.io/integrations/cloud",
|
||||
"requirements": ["hass-nabucasa==0.59.0"],
|
||||
"requirements": ["hass-nabucasa==0.61.0"],
|
||||
"dependencies": ["http", "webhook"],
|
||||
"after_dependencies": ["google_assistant", "alexa"],
|
||||
"codeowners": ["@home-assistant/cloud"],
|
||||
|
||||
@@ -30,7 +30,7 @@ def async_manage_legacy_subscription_issue(
|
||||
If the provider is "legacy" create an issue,
|
||||
in all other cases remove the issue.
|
||||
"""
|
||||
if subscription_info["provider"] == "legacy":
|
||||
if subscription_info.get("provider") == "legacy":
|
||||
ir.async_create_issue(
|
||||
hass=hass,
|
||||
domain=DOMAIN,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"domain": "frontend",
|
||||
"name": "Home Assistant Frontend",
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"requirements": ["home-assistant-frontend==20221206.0"],
|
||||
"requirements": ["home-assistant-frontend==20221208.0"],
|
||||
"dependencies": [
|
||||
"api",
|
||||
"auth",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"domain": "hikvision",
|
||||
"name": "Hikvision",
|
||||
"documentation": "https://www.home-assistant.io/integrations/hikvision",
|
||||
"requirements": ["pyhik==0.3.1"],
|
||||
"requirements": ["pyhik==0.3.2"],
|
||||
"codeowners": ["@mezz64"],
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyhik"]
|
||||
|
||||
@@ -236,6 +236,15 @@ class OptionsFlowHandler(BaseMultiPanFlow, config_entries.OptionsFlow):
|
||||
if not is_hassio(self.hass):
|
||||
return self.async_abort(reason="not_hassio")
|
||||
|
||||
return self.async_abort(
|
||||
reason="disabled_due_to_bug",
|
||||
description_placeholders={
|
||||
"url": "https://developers.home-assistant.io/blog/2022/12/08/multi-pan-rollback"
|
||||
},
|
||||
)
|
||||
|
||||
# pylint: disable=unreachable
|
||||
|
||||
return await self.async_step_on_supervisor()
|
||||
|
||||
async def async_step_on_supervisor(
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"addon_set_config_failed": "Failed to set Silicon Labs Multiprotocol configuration.",
|
||||
"addon_start_failed": "Failed to start the Silicon Labs Multiprotocol add-on.",
|
||||
"not_hassio": "The hardware options can only be configured on HassOS installations.",
|
||||
"zha_migration_failed": "The ZHA migration did not succeed."
|
||||
"zha_migration_failed": "The ZHA migration did not succeed.",
|
||||
"disabled_due_to_bug": "The hardware options are temporarily disabled while we fix a bug. [Learn more]({url})"
|
||||
},
|
||||
"progress": {
|
||||
"install_addon": "Please wait while the Silicon Labs Multiprotocol add-on installation finishes. This can take several minutes.",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"addon_install_failed": "Failed to install the Silicon Labs Multiprotocol add-on.",
|
||||
"addon_set_config_failed": "Failed to set Silicon Labs Multiprotocol configuration.",
|
||||
"addon_start_failed": "Failed to start the Silicon Labs Multiprotocol add-on.",
|
||||
"disabled_due_to_bug": "The hardware options are temporarily disabled while we fix a bug. [Learn more]({url})",
|
||||
"not_hassio": "The hardware options can only be configured on HassOS installations.",
|
||||
"zha_migration_failed": "The ZHA migration did not succeed."
|
||||
},
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
"addon_set_config_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::addon_set_config_failed%]",
|
||||
"addon_start_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::addon_start_failed%]",
|
||||
"not_hassio": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::not_hassio%]",
|
||||
"zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]"
|
||||
"zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]",
|
||||
"disabled_due_to_bug": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::disabled_due_to_bug%]"
|
||||
},
|
||||
"progress": {
|
||||
"install_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::install_addon%]",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"addon_install_failed": "Failed to install the Silicon Labs Multiprotocol add-on.",
|
||||
"addon_set_config_failed": "Failed to set Silicon Labs Multiprotocol configuration.",
|
||||
"addon_start_failed": "Failed to start the Silicon Labs Multiprotocol add-on.",
|
||||
"disabled_due_to_bug": "The hardware options are temporarily disabled while we fix a bug. [Learn more]({url})",
|
||||
"not_hassio": "The hardware options can only be configured on HassOS installations.",
|
||||
"zha_migration_failed": "The ZHA migration did not succeed."
|
||||
},
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
"addon_set_config_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::addon_set_config_failed%]",
|
||||
"addon_start_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::addon_start_failed%]",
|
||||
"not_hassio": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::not_hassio%]",
|
||||
"zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]"
|
||||
"zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]",
|
||||
"disabled_due_to_bug": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::disabled_due_to_bug%]"
|
||||
},
|
||||
"progress": {
|
||||
"install_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::install_addon%]",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"addon_install_failed": "Failed to install the Silicon Labs Multiprotocol add-on.",
|
||||
"addon_set_config_failed": "Failed to set Silicon Labs Multiprotocol configuration.",
|
||||
"addon_start_failed": "Failed to start the Silicon Labs Multiprotocol add-on.",
|
||||
"disabled_due_to_bug": "The hardware options are temporarily disabled while we fix a bug. [Learn more]({url})",
|
||||
"not_hassio": "The hardware options can only be configured on HassOS installations.",
|
||||
"zha_migration_failed": "The ZHA migration did not succeed."
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "IntelliFire",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/intellifire",
|
||||
"requirements": ["intellifire4py==2.2.1"],
|
||||
"requirements": ["intellifire4py==2.2.2"],
|
||||
"codeowners": ["@jeeftor"],
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["intellifire4py"],
|
||||
|
||||
@@ -11,6 +11,8 @@ from ical.calendar_stream import IcsCalendarStream
|
||||
from ical.event import Event
|
||||
from ical.store import EventStore
|
||||
from ical.types import Range, Recur
|
||||
from pydantic import ValidationError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.calendar import (
|
||||
EVENT_DESCRIPTION,
|
||||
@@ -102,14 +104,19 @@ class LocalCalendarEntity(CalendarEntity):
|
||||
|
||||
async def async_create_event(self, **kwargs: Any) -> None:
|
||||
"""Add a new event to calendar."""
|
||||
event = Event.parse_obj(
|
||||
{
|
||||
EVENT_SUMMARY: kwargs[EVENT_SUMMARY],
|
||||
EVENT_START: kwargs[EVENT_START],
|
||||
EVENT_END: kwargs[EVENT_END],
|
||||
EVENT_DESCRIPTION: kwargs.get(EVENT_DESCRIPTION),
|
||||
}
|
||||
)
|
||||
event_data = {
|
||||
EVENT_SUMMARY: kwargs[EVENT_SUMMARY],
|
||||
EVENT_START: kwargs[EVENT_START],
|
||||
EVENT_END: kwargs[EVENT_END],
|
||||
EVENT_DESCRIPTION: kwargs.get(EVENT_DESCRIPTION),
|
||||
}
|
||||
try:
|
||||
event = Event.parse_obj(event_data)
|
||||
except ValidationError as err:
|
||||
_LOGGER.debug(
|
||||
"Error parsing event input fields: %s (%s)", event_data, str(err)
|
||||
)
|
||||
raise vol.Invalid("Error parsing event input fields") from err
|
||||
if rrule := kwargs.get(EVENT_RRULE):
|
||||
event.rrule = Recur.from_rrule(rrule)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Local Calendar",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
|
||||
"requirements": ["ical==4.2.1"],
|
||||
"requirements": ["ical==4.2.2"],
|
||||
"codeowners": ["@allenporter"],
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["ical"]
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
"""Matter binary sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.common.models import device_types
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
BinarySensorEntity,
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .entity import MatterEntity, MatterEntityDescriptionBaseClass
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .adapter import MatterAdapter
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Matter binary sensor from Config Entry."""
|
||||
matter: MatterAdapter = hass.data[DOMAIN][config_entry.entry_id]
|
||||
matter.register_platform_handler(Platform.BINARY_SENSOR, async_add_entities)
|
||||
|
||||
|
||||
class MatterBinarySensor(MatterEntity, BinarySensorEntity):
|
||||
"""Representation of a Matter binary sensor."""
|
||||
|
||||
entity_description: MatterBinarySensorEntityDescription
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
self._attr_is_on = self._device_type_instance.get_cluster(
|
||||
clusters.BooleanState
|
||||
).stateValue
|
||||
|
||||
|
||||
class MatterOccupancySensor(MatterBinarySensor):
|
||||
"""Representation of a Matter occupancy sensor."""
|
||||
|
||||
_attr_device_class = BinarySensorDeviceClass.OCCUPANCY
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
occupancy = self._device_type_instance.get_cluster(
|
||||
clusters.OccupancySensing
|
||||
).occupancy
|
||||
# The first bit = if occupied
|
||||
self._attr_is_on = occupancy & 1 == 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class MatterBinarySensorEntityDescription(
|
||||
BinarySensorEntityDescription,
|
||||
MatterEntityDescriptionBaseClass,
|
||||
):
|
||||
"""Matter Binary Sensor entity description."""
|
||||
|
||||
|
||||
# You can't set default values on inherited data classes
|
||||
MatterSensorEntityDescriptionFactory = partial(
|
||||
MatterBinarySensorEntityDescription, entity_cls=MatterBinarySensor
|
||||
)
|
||||
|
||||
DEVICE_ENTITY: dict[
|
||||
type[device_types.DeviceType],
|
||||
MatterEntityDescriptionBaseClass | list[MatterEntityDescriptionBaseClass],
|
||||
] = {
|
||||
device_types.ContactSensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.ContactSensor,
|
||||
name="Contact",
|
||||
subscribe_attributes=(clusters.BooleanState.Attributes.StateValue,),
|
||||
device_class=BinarySensorDeviceClass.DOOR,
|
||||
),
|
||||
device_types.OccupancySensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.OccupancySensor,
|
||||
name="Occupancy",
|
||||
entity_cls=MatterOccupancySensor,
|
||||
subscribe_attributes=(clusters.OccupancySensing.Attributes.Occupancy,),
|
||||
),
|
||||
}
|
||||
@@ -5,7 +5,10 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from homeassistant.const import Platform
|
||||
|
||||
from .binary_sensor import DEVICE_ENTITY as BINARY_SENSOR_DEVICE_ENTITY
|
||||
from .light import DEVICE_ENTITY as LIGHT_DEVICE_ENTITY
|
||||
from .sensor import DEVICE_ENTITY as SENSOR_DEVICE_ENTITY
|
||||
from .switch import DEVICE_ENTITY as SWITCH_DEVICE_ENTITY
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from matter_server.common.models.device_types import DeviceType
|
||||
@@ -20,5 +23,8 @@ DEVICE_PLATFORM: dict[
|
||||
MatterEntityDescriptionBaseClass | list[MatterEntityDescriptionBaseClass],
|
||||
],
|
||||
] = {
|
||||
Platform.BINARY_SENSOR: BINARY_SENSOR_DEVICE_ENTITY,
|
||||
Platform.LIGHT: LIGHT_DEVICE_ENTITY,
|
||||
Platform.SENSOR: SENSOR_DEVICE_ENTITY,
|
||||
Platform.SWITCH: SWITCH_DEVICE_ENTITY,
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "Matter (BETA)",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/matter",
|
||||
"requirements": ["python-matter-server==1.0.6"],
|
||||
"requirements": ["python-matter-server==1.0.7"],
|
||||
"dependencies": ["websocket_api"],
|
||||
"codeowners": ["@MartinHjelmare", "@marcelveldt"],
|
||||
"iot_class": "local_push"
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
"""Matter sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from chip.clusters.Types import Nullable, NullValue
|
||||
from matter_server.common.models import device_types
|
||||
from matter_server.common.models.device_type_instance import MatterDeviceTypeInstance
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR,
|
||||
Platform,
|
||||
UnitOfPressure,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .entity import MatterEntity, MatterEntityDescriptionBaseClass
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .adapter import MatterAdapter
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Matter sensors from Config Entry."""
|
||||
matter: MatterAdapter = hass.data[DOMAIN][config_entry.entry_id]
|
||||
matter.register_platform_handler(Platform.SENSOR, async_add_entities)
|
||||
|
||||
|
||||
class MatterSensor(MatterEntity, SensorEntity):
|
||||
"""Representation of a Matter sensor."""
|
||||
|
||||
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||
entity_description: MatterSensorEntityDescription
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
measurement: Nullable | float | None
|
||||
measurement = _get_attribute_value(
|
||||
self._device_type_instance,
|
||||
# We always subscribe to a single value
|
||||
self.entity_description.subscribe_attributes[0],
|
||||
)
|
||||
|
||||
if measurement is NullValue or measurement is None:
|
||||
measurement = None
|
||||
else:
|
||||
measurement = self.entity_description.measurement_to_ha(measurement)
|
||||
|
||||
self._attr_native_value = measurement
|
||||
|
||||
|
||||
def _get_attribute_value(
|
||||
device_type_instance: MatterDeviceTypeInstance,
|
||||
attribute: clusters.ClusterAttributeDescriptor,
|
||||
) -> Any:
|
||||
"""Return the value of an attribute."""
|
||||
# Find the cluster for this attribute. We don't have a lookup table yet.
|
||||
cluster_cls: clusters.Cluster = next(
|
||||
cluster
|
||||
for cluster in device_type_instance.device_type.clusters
|
||||
if cluster.id == attribute.cluster_id
|
||||
)
|
||||
|
||||
# Find the attribute descriptor so we know the instance variable to fetch
|
||||
attribute_descriptor: clusters.ClusterObjectFieldDescriptor = next(
|
||||
descriptor
|
||||
for descriptor in cluster_cls.descriptor.Fields
|
||||
if descriptor.Tag == attribute.attribute_id
|
||||
)
|
||||
|
||||
cluster_data = device_type_instance.get_cluster(cluster_cls)
|
||||
return getattr(cluster_data, attribute_descriptor.Label)
|
||||
|
||||
|
||||
@dataclass
|
||||
class MatterSensorEntityDescriptionMixin:
|
||||
"""Required fields for sensor device mapping."""
|
||||
|
||||
measurement_to_ha: Callable[[float], float]
|
||||
|
||||
|
||||
@dataclass
|
||||
class MatterSensorEntityDescription(
|
||||
SensorEntityDescription,
|
||||
MatterEntityDescriptionBaseClass,
|
||||
MatterSensorEntityDescriptionMixin,
|
||||
):
|
||||
"""Matter Sensor entity description."""
|
||||
|
||||
|
||||
# You can't set default values on inherited data classes
|
||||
MatterSensorEntityDescriptionFactory = partial(
|
||||
MatterSensorEntityDescription, entity_cls=MatterSensor
|
||||
)
|
||||
|
||||
|
||||
DEVICE_ENTITY: dict[
|
||||
type[device_types.DeviceType],
|
||||
MatterEntityDescriptionBaseClass | list[MatterEntityDescriptionBaseClass],
|
||||
] = {
|
||||
device_types.TemperatureSensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.TemperatureSensor,
|
||||
name="Temperature",
|
||||
measurement_to_ha=lambda x: x / 100,
|
||||
subscribe_attributes=(
|
||||
clusters.TemperatureMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
),
|
||||
device_types.PressureSensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.PressureSensor,
|
||||
name="Pressure",
|
||||
measurement_to_ha=lambda x: x / 10,
|
||||
subscribe_attributes=(clusters.PressureMeasurement.Attributes.MeasuredValue,),
|
||||
native_unit_of_measurement=UnitOfPressure.KPA,
|
||||
device_class=SensorDeviceClass.PRESSURE,
|
||||
),
|
||||
device_types.FlowSensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.FlowSensor,
|
||||
name="Flow",
|
||||
measurement_to_ha=lambda x: x / 10,
|
||||
subscribe_attributes=(clusters.FlowMeasurement.Attributes.MeasuredValue,),
|
||||
native_unit_of_measurement=VOLUME_FLOW_RATE_CUBIC_METERS_PER_HOUR,
|
||||
),
|
||||
device_types.HumiditySensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.HumiditySensor,
|
||||
name="Humidity",
|
||||
measurement_to_ha=lambda x: x / 100,
|
||||
subscribe_attributes=(
|
||||
clusters.RelativeHumidityMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
device_class=SensorDeviceClass.HUMIDITY,
|
||||
),
|
||||
device_types.LightSensor: MatterSensorEntityDescriptionFactory(
|
||||
key=device_types.LightSensor,
|
||||
name="Light",
|
||||
measurement_to_ha=lambda x: round(pow(10, ((x - 1) / 10000)), 1),
|
||||
subscribe_attributes=(
|
||||
clusters.IlluminanceMeasurement.Attributes.MeasuredValue,
|
||||
),
|
||||
native_unit_of_measurement=LIGHT_LUX,
|
||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||
),
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Matter switches."""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.common.models import device_types
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
SwitchDeviceClass,
|
||||
SwitchEntity,
|
||||
SwitchEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .entity import MatterEntity, MatterEntityDescriptionBaseClass
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .adapter import MatterAdapter
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Matter switches from Config Entry."""
|
||||
matter: MatterAdapter = hass.data[DOMAIN][config_entry.entry_id]
|
||||
matter.register_platform_handler(Platform.SWITCH, async_add_entities)
|
||||
|
||||
|
||||
class MatterSwitch(MatterEntity, SwitchEntity):
|
||||
"""Representation of a Matter switch."""
|
||||
|
||||
entity_description: MatterSwitchEntityDescription
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn switch on."""
|
||||
await self.matter_client.send_device_command(
|
||||
node_id=self._device_type_instance.node.node_id,
|
||||
endpoint=self._device_type_instance.endpoint,
|
||||
command=clusters.OnOff.Commands.On(),
|
||||
)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn switch off."""
|
||||
await self.matter_client.send_device_command(
|
||||
node_id=self._device_type_instance.node.node_id,
|
||||
endpoint=self._device_type_instance.endpoint,
|
||||
command=clusters.OnOff.Commands.Off(),
|
||||
)
|
||||
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
self._attr_is_on = self._device_type_instance.get_cluster(clusters.OnOff).onOff
|
||||
|
||||
|
||||
@dataclass
|
||||
class MatterSwitchEntityDescription(
|
||||
SwitchEntityDescription,
|
||||
MatterEntityDescriptionBaseClass,
|
||||
):
|
||||
"""Matter Switch entity description."""
|
||||
|
||||
|
||||
# You can't set default values on inherited data classes
|
||||
MatterSwitchEntityDescriptionFactory = partial(
|
||||
MatterSwitchEntityDescription, entity_cls=MatterSwitch
|
||||
)
|
||||
|
||||
|
||||
DEVICE_ENTITY: dict[
|
||||
type[device_types.DeviceType],
|
||||
MatterEntityDescriptionBaseClass | list[MatterEntityDescriptionBaseClass],
|
||||
] = {
|
||||
device_types.OnOffPlugInUnit: MatterSwitchEntityDescriptionFactory(
|
||||
key=device_types.OnOffPlugInUnit,
|
||||
subscribe_attributes=(clusters.OnOff.Attributes.OnOff,),
|
||||
device_class=SwitchDeviceClass.OUTLET,
|
||||
),
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
"""Support for MQTT message handling."""
|
||||
# pylint: disable=deprecated-typing-alias
|
||||
# In Python 3.9.0 and 3.9.1 collections.abc.Callable
|
||||
# can't be used inside typing.Union or typing.Optional
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable, Coroutine, Iterable
|
||||
from collections.abc import Coroutine, Iterable
|
||||
from functools import lru_cache, partial, wraps
|
||||
import inspect
|
||||
from itertools import groupby
|
||||
@@ -10,7 +13,7 @@ import logging
|
||||
from operator import attrgetter
|
||||
import ssl
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Any, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, Callable, Union, cast
|
||||
import uuid
|
||||
|
||||
import attr
|
||||
|
||||
@@ -101,6 +101,8 @@ class PhilipsTVMediaPlayer(
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Handle being added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
|
||||
if (entry := self.registry_entry) and entry.device_id:
|
||||
self.async_on_remove(
|
||||
self._turn_on.async_register(
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/sensirion_ble",
|
||||
"bluetooth": [
|
||||
{
|
||||
"connectable": false,
|
||||
"manufacturer_id": 1749
|
||||
},
|
||||
{
|
||||
"connectable": false,
|
||||
"local_name": "MyCO2*"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ from homeassistant.components.climate import (
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant, State, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
@@ -24,6 +24,8 @@ from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
||||
|
||||
from .const import LOGGER, SHTRV_01_TEMPERATURE_SETTINGS
|
||||
from .coordinator import ShellyBlockCoordinator, get_entry_data
|
||||
@@ -108,7 +110,7 @@ class BlockSleepingClimate(
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE
|
||||
)
|
||||
_attr_target_temperature_step = SHTRV_01_TEMPERATURE_SETTINGS["step"]
|
||||
_attr_temperature_unit = TEMP_CELSIUS
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -126,7 +128,14 @@ class BlockSleepingClimate(
|
||||
self.last_state: State | None = None
|
||||
self.last_state_attributes: Mapping[str, Any]
|
||||
self._preset_modes: list[str] = []
|
||||
self._last_target_temp = 20.0
|
||||
if coordinator.hass.config.units is US_CUSTOMARY_SYSTEM:
|
||||
self._last_target_temp = TemperatureConverter.convert(
|
||||
SHTRV_01_TEMPERATURE_SETTINGS["default"],
|
||||
UnitOfTemperature.CELSIUS,
|
||||
UnitOfTemperature.FAHRENHEIT,
|
||||
)
|
||||
else:
|
||||
self._last_target_temp = SHTRV_01_TEMPERATURE_SETTINGS["default"]
|
||||
|
||||
if self.block is not None and self.device_block is not None:
|
||||
self._unique_id = f"{self.coordinator.mac}-{self.block.description}"
|
||||
@@ -157,14 +166,32 @@ class BlockSleepingClimate(
|
||||
"""Set target temperature."""
|
||||
if self.block is not None:
|
||||
return cast(float, self.block.targetTemp)
|
||||
return self.last_state_attributes.get("temperature")
|
||||
# The restored value can be in Fahrenheit so we have to convert it to Celsius
|
||||
# because we use this unit internally in integration.
|
||||
target_temp = self.last_state_attributes.get("temperature")
|
||||
if self.hass.config.units is US_CUSTOMARY_SYSTEM and target_temp:
|
||||
return TemperatureConverter.convert(
|
||||
cast(float, target_temp),
|
||||
UnitOfTemperature.FAHRENHEIT,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
)
|
||||
return target_temp
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> float | None:
|
||||
"""Return current temperature."""
|
||||
if self.block is not None:
|
||||
return cast(float, self.block.temp)
|
||||
return self.last_state_attributes.get("current_temperature")
|
||||
# The restored value can be in Fahrenheit so we have to convert it to Celsius
|
||||
# because we use this unit internally in integration.
|
||||
current_temp = self.last_state_attributes.get("current_temperature")
|
||||
if self.hass.config.units is US_CUSTOMARY_SYSTEM and current_temp:
|
||||
return TemperatureConverter.convert(
|
||||
cast(float, current_temp),
|
||||
UnitOfTemperature.FAHRENHEIT,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
)
|
||||
return current_temp
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
|
||||
@@ -147,6 +147,7 @@ SHTRV_01_TEMPERATURE_SETTINGS: Final = {
|
||||
"min": 4,
|
||||
"max": 31,
|
||||
"step": 0.5,
|
||||
"default": 20.0,
|
||||
}
|
||||
|
||||
# Kelvin value for colorTemp
|
||||
|
||||
@@ -564,7 +564,8 @@ class ShellyRpcCoordinator(DataUpdateCoordinator):
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
"""Shutdown the coordinator."""
|
||||
await async_stop_scanner(self.device)
|
||||
if self.device.connected:
|
||||
await async_stop_scanner(self.device)
|
||||
await self.device.shutdown()
|
||||
await self._async_disconnected()
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "SimpliSafe",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||
"requirements": ["simplisafe-python==2022.11.2"],
|
||||
"requirements": ["simplisafe-python==2022.12.0"],
|
||||
"codeowners": ["@bachya"],
|
||||
"iot_class": "cloud_polling",
|
||||
"dhcp": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"domain": "tibber",
|
||||
"name": "Tibber",
|
||||
"documentation": "https://www.home-assistant.io/integrations/tibber",
|
||||
"requirements": ["pyTibber==0.26.3"],
|
||||
"requirements": ["pyTibber==0.26.4"],
|
||||
"codeowners": ["@danielhiversen"],
|
||||
"quality_scale": "silver",
|
||||
"config_flow": true,
|
||||
|
||||
@@ -12,10 +12,7 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity
|
||||
|
||||
from .const import DOMAIN
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -33,23 +30,6 @@ async def async_migrate_data(
|
||||
await async_migrate_device_ids(hass, entry, protect)
|
||||
_LOGGER.debug("Completed Migrate: async_migrate_device_ids")
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
for entity in er.async_entries_for_config_entry(entity_registry, entry.entry_id):
|
||||
if (
|
||||
entity.domain == Platform.SENSOR
|
||||
and entity.disabled_by is None
|
||||
and "detected_object" in entity.unique_id
|
||||
):
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecate_smart_sensor",
|
||||
is_fixable=False,
|
||||
breaks_in_ha_version="2023.2.0",
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecate_smart_sensor",
|
||||
)
|
||||
|
||||
|
||||
async def async_get_bootstrap(protect: ProtectApiClient) -> Bootstrap:
|
||||
"""Get UniFi Protect bootstrap or raise appropriate HA error."""
|
||||
|
||||
@@ -75,10 +75,6 @@
|
||||
"ea_setup_failed": {
|
||||
"title": "Setup error using Early Access version",
|
||||
"description": "You are using v{version} of UniFi Protect which is an Early Access version. An unrecoverable error occurred while trying to load the integration. Please [downgrade to a stable version](https://www.home-assistant.io/integrations/unifiprotect#downgrading-unifi-protect) of UniFi Protect to continue using the integration.\n\nError: {error}"
|
||||
},
|
||||
"deprecate_smart_sensor": {
|
||||
"title": "Smart Detection Sensor Deprecated",
|
||||
"description": "The unified \"Detected Object\" sensor for smart detections is now deprecated. It has been replaced with individual smart detection binary sensors for each smart detection type. Please update any templates or automations accordingly."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,6 @@
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecate_smart_sensor": {
|
||||
"description": "The unified \"Detected Object\" sensor for smart detections is now deprecated. It has been replaced with individual smart detection binary sensors for each smart detection type. Please update any templates or automations accordingly.",
|
||||
"title": "Smart Detection Sensor Deprecated"
|
||||
},
|
||||
"ea_setup_failed": {
|
||||
"description": "You are using v{version} of UniFi Protect which is an Early Access version. An unrecoverable error occurred while trying to load the integration. Please [downgrade to a stable version](https://www.home-assistant.io/integrations/unifiprotect#downgrading-unifi-protect) of UniFi Protect to continue using the integration.\n\nError: {error}",
|
||||
"title": "Setup error using Early Access version"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "VeSync",
|
||||
"documentation": "https://www.home-assistant.io/integrations/vesync",
|
||||
"codeowners": ["@markperdue", "@webdjoe", "@thegardenmonkey"],
|
||||
"requirements": ["pyvesync==2.0.3"],
|
||||
"requirements": ["pyvesync==2.1.1"],
|
||||
"config_flow": true,
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["pyvesync"]
|
||||
|
||||
@@ -360,6 +360,8 @@ class OnOffChannel(ZigbeeChannel):
|
||||
)
|
||||
self.ZCL_INIT_ATTRS["backlight_mode"] = True
|
||||
self.ZCL_INIT_ATTRS["power_on_state"] = True
|
||||
if self.cluster.endpoint.model == "TS011F":
|
||||
self.ZCL_INIT_ATTRS["child_lock"] = True
|
||||
|
||||
@property
|
||||
def on_off(self) -> bool | None:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"bellows==0.34.5",
|
||||
"pyserial==3.5",
|
||||
"pyserial-asyncio==0.6",
|
||||
"zha-quirks==0.0.87",
|
||||
"zha-quirks==0.0.88",
|
||||
"zigpy-deconz==0.19.2",
|
||||
"zigpy==0.52.3",
|
||||
"zigpy-xbee==0.16.2",
|
||||
|
||||
@@ -457,3 +457,15 @@ class AqaraPetFeederChildLock(ZHASwitchConfigurationEntity, id_suffix="child_loc
|
||||
_zcl_attribute: str = "child_lock"
|
||||
_attr_name = "Child lock"
|
||||
_attr_icon: str = "mdi:account-lock"
|
||||
|
||||
|
||||
@CONFIG_DIAGNOSTIC_MATCH(
|
||||
channel_names=CHANNEL_ON_OFF,
|
||||
models={"TS011F"},
|
||||
)
|
||||
class TuyaChildLockSwitch(ZHASwitchConfigurationEntity, id_suffix="child_lock"):
|
||||
"""Representation of a child lock configuration entity."""
|
||||
|
||||
_zcl_attribute: str = "child_lock"
|
||||
_attr_name = "Child lock"
|
||||
_attr_icon: str = "mdi:account-lock"
|
||||
|
||||
@@ -230,6 +230,7 @@ class DriverEvents:
|
||||
async def setup(self, driver: Driver) -> None:
|
||||
"""Set up devices using the ready driver."""
|
||||
self.driver = driver
|
||||
controller = driver.controller
|
||||
|
||||
# If opt in preference hasn't been specified yet, we do nothing, otherwise
|
||||
# we apply the preference
|
||||
@@ -244,7 +245,7 @@ class DriverEvents:
|
||||
)
|
||||
known_devices = [
|
||||
self.dev_reg.async_get_device({get_device_id(driver, node)})
|
||||
for node in driver.controller.nodes.values()
|
||||
for node in controller.nodes.values()
|
||||
]
|
||||
|
||||
# Devices that are in the device registry that are not known by the controller can be removed
|
||||
@@ -252,17 +253,24 @@ class DriverEvents:
|
||||
if device not in known_devices:
|
||||
self.dev_reg.async_remove_device(device.id)
|
||||
|
||||
# run discovery on all ready nodes
|
||||
# run discovery on controller node
|
||||
c_node_id = controller.own_node_id
|
||||
controller_node = controller.nodes.get(c_node_id) if c_node_id else None
|
||||
if controller_node:
|
||||
await self.controller_events.async_on_node_added(controller_node)
|
||||
|
||||
# run discovery on all other ready nodes
|
||||
await asyncio.gather(
|
||||
*(
|
||||
self.controller_events.async_on_node_added(node)
|
||||
for node in driver.controller.nodes.values()
|
||||
for node in controller.nodes.values()
|
||||
if controller_node is None or node != controller_node
|
||||
)
|
||||
)
|
||||
|
||||
# listen for new nodes being added to the mesh
|
||||
self.config_entry.async_on_unload(
|
||||
driver.controller.on(
|
||||
controller.on(
|
||||
"node added",
|
||||
lambda event: self.hass.async_create_task(
|
||||
self.controller_events.async_on_node_added(event["node"])
|
||||
@@ -272,9 +280,7 @@ class DriverEvents:
|
||||
# listen for nodes being removed from the mesh
|
||||
# NOTE: This will not remove nodes that were removed when HA was not running
|
||||
self.config_entry.async_on_unload(
|
||||
driver.controller.on(
|
||||
"node removed", self.controller_events.async_on_node_removed
|
||||
)
|
||||
controller.on("node removed", self.controller_events.async_on_node_removed)
|
||||
)
|
||||
|
||||
async def async_setup_platform(self, platform: Platform) -> None:
|
||||
@@ -383,6 +389,16 @@ class ControllerEvents:
|
||||
device_id = get_device_id(driver, node)
|
||||
device_id_ext = get_device_id_ext(driver, node)
|
||||
device = self.dev_reg.async_get_device({device_id})
|
||||
via_device_id = None
|
||||
controller = driver.controller
|
||||
# Get the controller node device ID if this node is not the controller
|
||||
if (
|
||||
controller.own_node_id is not None
|
||||
and controller.own_node_id != node.node_id
|
||||
):
|
||||
via_device_id = get_device_id(
|
||||
driver, controller.nodes[controller.own_node_id]
|
||||
)
|
||||
|
||||
# Replace the device if it can be determined that this node is not the
|
||||
# same product as it was previously.
|
||||
@@ -408,6 +424,7 @@ class ControllerEvents:
|
||||
model=node.device_config.label,
|
||||
manufacturer=node.device_config.manufacturer,
|
||||
suggested_area=node.location if node.location else UNDEFINED,
|
||||
via_device=via_device_id,
|
||||
)
|
||||
|
||||
async_dispatcher_send(self.hass, EVENT_DEVICE_ADDED_TO_REGISTRY, device)
|
||||
|
||||
@@ -150,6 +150,9 @@ async def async_get_actions(
|
||||
|
||||
node = async_get_node_from_device_id(hass, device_id)
|
||||
|
||||
if node.client.driver and node.client.driver.controller.own_node_id == node.node_id:
|
||||
return actions
|
||||
|
||||
base_action = {
|
||||
CONF_DEVICE_ID: device_id,
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
|
||||
@@ -126,7 +126,7 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Z-Wave JS devices."""
|
||||
conditions = []
|
||||
conditions: list[dict] = []
|
||||
base_condition = {
|
||||
CONF_CONDITION: "device",
|
||||
CONF_DEVICE_ID: device_id,
|
||||
@@ -134,6 +134,9 @@ async def async_get_conditions(
|
||||
}
|
||||
node = async_get_node_from_device_id(hass, device_id)
|
||||
|
||||
if node.client.driver and node.client.driver.controller.own_node_id == node.node_id:
|
||||
return conditions
|
||||
|
||||
# Any value's value condition
|
||||
conditions.append({**base_condition, CONF_TYPE: VALUE_TYPE})
|
||||
|
||||
|
||||
@@ -248,9 +248,6 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, Any]]:
|
||||
"""List device triggers for Z-Wave JS devices."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
node = async_get_node_from_device_id(hass, device_id, dev_reg)
|
||||
|
||||
triggers: list[dict] = []
|
||||
base_trigger = {
|
||||
CONF_PLATFORM: "device",
|
||||
@@ -258,6 +255,12 @@ async def async_get_triggers(
|
||||
CONF_DOMAIN: DOMAIN,
|
||||
}
|
||||
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
node = async_get_node_from_device_id(hass, device_id, dev_reg)
|
||||
|
||||
if node.client.driver and node.client.driver.controller.own_node_id == node.node_id:
|
||||
return triggers
|
||||
|
||||
# We can add a node status trigger if the node status sensor is enabled
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
entity_id = async_get_node_status_sensor_entity_id(
|
||||
|
||||
@@ -8,7 +8,7 @@ from .backports.enum import StrEnum
|
||||
APPLICATION_NAME: Final = "HomeAssistant"
|
||||
MAJOR_VERSION: Final = 2022
|
||||
MINOR_VERSION: Final = 12
|
||||
PATCH_VERSION: Final = "0b6"
|
||||
PATCH_VERSION: Final = "1"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
||||
|
||||
@@ -273,10 +273,12 @@ BLUETOOTH: list[dict[str, bool | str | int | list[int]]] = [
|
||||
"local_name": "Ruuvi *",
|
||||
},
|
||||
{
|
||||
"connectable": False,
|
||||
"domain": "sensirion_ble",
|
||||
"manufacturer_id": 1749,
|
||||
},
|
||||
{
|
||||
"connectable": False,
|
||||
"domain": "sensirion_ble",
|
||||
"local_name": "MyCO2*",
|
||||
},
|
||||
|
||||
@@ -13,16 +13,16 @@ bcrypt==3.1.7
|
||||
bleak-retry-connector==2.10.1
|
||||
bleak==0.19.2
|
||||
bluetooth-adapters==0.12.0
|
||||
bluetooth-auto-recovery==0.5.4
|
||||
bluetooth-auto-recovery==0.5.5
|
||||
bluetooth-data-tools==0.3.0
|
||||
certifi>=2021.5.30
|
||||
ciso8601==2.2.0
|
||||
cryptography==38.0.3
|
||||
dbus-fast==1.75.0
|
||||
fnvhash==0.1.0
|
||||
hass-nabucasa==0.59.0
|
||||
hass-nabucasa==0.61.0
|
||||
home-assistant-bluetooth==1.8.1
|
||||
home-assistant-frontend==20221206.0
|
||||
home-assistant-frontend==20221208.0
|
||||
httpx==0.23.1
|
||||
ifaddr==0.1.7
|
||||
janus==1.0.0
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "homeassistant"
|
||||
version = "2022.12.0b6"
|
||||
version = "2022.12.1"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "Open-source home automation platform running on Python 3."
|
||||
readme = "README.rst"
|
||||
|
||||
+11
-11
@@ -450,7 +450,7 @@ bluemaestro-ble==0.2.0
|
||||
bluetooth-adapters==0.12.0
|
||||
|
||||
# homeassistant.components.bluetooth
|
||||
bluetooth-auto-recovery==0.5.4
|
||||
bluetooth-auto-recovery==0.5.5
|
||||
|
||||
# homeassistant.components.bluetooth
|
||||
# homeassistant.components.led_ble
|
||||
@@ -848,7 +848,7 @@ ha-philipsjs==2.9.0
|
||||
habitipy==0.2.0
|
||||
|
||||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.59.0
|
||||
hass-nabucasa==0.61.0
|
||||
|
||||
# homeassistant.components.splunk
|
||||
hass_splunk==0.1.1
|
||||
@@ -884,7 +884,7 @@ hole==0.7.0
|
||||
holidays==0.17.2
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20221206.0
|
||||
home-assistant-frontend==20221208.0
|
||||
|
||||
# homeassistant.components.home_connect
|
||||
homeconnect==0.7.2
|
||||
@@ -926,7 +926,7 @@ ibm-watson==5.2.2
|
||||
ibmiotf==0.3.4
|
||||
|
||||
# homeassistant.components.local_calendar
|
||||
ical==4.2.1
|
||||
ical==4.2.2
|
||||
|
||||
# homeassistant.components.ping
|
||||
icmplib==3.0
|
||||
@@ -956,7 +956,7 @@ inkbird-ble==0.5.5
|
||||
insteon-frontend-home-assistant==0.2.0
|
||||
|
||||
# homeassistant.components.intellifire
|
||||
intellifire4py==2.2.1
|
||||
intellifire4py==2.2.2
|
||||
|
||||
# homeassistant.components.iotawatt
|
||||
iotawattpy==0.1.0
|
||||
@@ -1432,7 +1432,7 @@ pyRFXtrx==0.30.0
|
||||
pySwitchmate==0.5.1
|
||||
|
||||
# homeassistant.components.tibber
|
||||
pyTibber==0.26.3
|
||||
pyTibber==0.26.4
|
||||
|
||||
# homeassistant.components.dlink
|
||||
pyW215==0.7.0
|
||||
@@ -1627,7 +1627,7 @@ pyhaversion==22.8.0
|
||||
pyheos==0.7.2
|
||||
|
||||
# homeassistant.components.hikvision
|
||||
pyhik==0.3.1
|
||||
pyhik==0.3.2
|
||||
|
||||
# homeassistant.components.hive
|
||||
pyhiveapi==0.5.14
|
||||
@@ -2030,7 +2030,7 @@ python-kasa==0.5.0
|
||||
# python-lirc==1.2.3
|
||||
|
||||
# homeassistant.components.matter
|
||||
python-matter-server==1.0.6
|
||||
python-matter-server==1.0.7
|
||||
|
||||
# homeassistant.components.xiaomi_miio
|
||||
python-miio==0.5.12
|
||||
@@ -2116,7 +2116,7 @@ pyvera==0.3.13
|
||||
pyversasense==0.0.6
|
||||
|
||||
# homeassistant.components.vesync
|
||||
pyvesync==2.0.3
|
||||
pyvesync==2.1.1
|
||||
|
||||
# homeassistant.components.vizio
|
||||
pyvizio==0.1.57
|
||||
@@ -2291,7 +2291,7 @@ simplehound==0.3
|
||||
simplepush==2.1.1
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==2022.11.2
|
||||
simplisafe-python==2022.12.0
|
||||
|
||||
# homeassistant.components.sisyphus
|
||||
sisyphus-control==3.1.2
|
||||
@@ -2639,7 +2639,7 @@ zengge==0.2
|
||||
zeroconf==0.39.4
|
||||
|
||||
# homeassistant.components.zha
|
||||
zha-quirks==0.0.87
|
||||
zha-quirks==0.0.88
|
||||
|
||||
# homeassistant.components.zhong_hong
|
||||
zhong_hong_hvac==1.0.9
|
||||
|
||||
+10
-10
@@ -364,7 +364,7 @@ bluemaestro-ble==0.2.0
|
||||
bluetooth-adapters==0.12.0
|
||||
|
||||
# homeassistant.components.bluetooth
|
||||
bluetooth-auto-recovery==0.5.4
|
||||
bluetooth-auto-recovery==0.5.5
|
||||
|
||||
# homeassistant.components.bluetooth
|
||||
# homeassistant.components.led_ble
|
||||
@@ -640,7 +640,7 @@ ha-philipsjs==2.9.0
|
||||
habitipy==0.2.0
|
||||
|
||||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.59.0
|
||||
hass-nabucasa==0.61.0
|
||||
|
||||
# homeassistant.components.tasmota
|
||||
hatasmota==0.6.1
|
||||
@@ -664,7 +664,7 @@ hole==0.7.0
|
||||
holidays==0.17.2
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20221206.0
|
||||
home-assistant-frontend==20221208.0
|
||||
|
||||
# homeassistant.components.home_connect
|
||||
homeconnect==0.7.2
|
||||
@@ -691,7 +691,7 @@ iaqualink==0.5.0
|
||||
ibeacon_ble==1.0.1
|
||||
|
||||
# homeassistant.components.local_calendar
|
||||
ical==4.2.1
|
||||
ical==4.2.2
|
||||
|
||||
# homeassistant.components.ping
|
||||
icmplib==3.0
|
||||
@@ -712,7 +712,7 @@ inkbird-ble==0.5.5
|
||||
insteon-frontend-home-assistant==0.2.0
|
||||
|
||||
# homeassistant.components.intellifire
|
||||
intellifire4py==2.2.1
|
||||
intellifire4py==2.2.2
|
||||
|
||||
# homeassistant.components.iotawatt
|
||||
iotawattpy==0.1.0
|
||||
@@ -1032,7 +1032,7 @@ pyMetno==0.9.0
|
||||
pyRFXtrx==0.30.0
|
||||
|
||||
# homeassistant.components.tibber
|
||||
pyTibber==0.26.3
|
||||
pyTibber==0.26.4
|
||||
|
||||
# homeassistant.components.nextbus
|
||||
py_nextbusnext==0.1.5
|
||||
@@ -1417,7 +1417,7 @@ python-juicenet==1.1.0
|
||||
python-kasa==0.5.0
|
||||
|
||||
# homeassistant.components.matter
|
||||
python-matter-server==1.0.6
|
||||
python-matter-server==1.0.7
|
||||
|
||||
# homeassistant.components.xiaomi_miio
|
||||
python-miio==0.5.12
|
||||
@@ -1473,7 +1473,7 @@ pyuptimerobot==22.2.0
|
||||
pyvera==0.3.13
|
||||
|
||||
# homeassistant.components.vesync
|
||||
pyvesync==2.0.3
|
||||
pyvesync==2.1.1
|
||||
|
||||
# homeassistant.components.vizio
|
||||
pyvizio==0.1.57
|
||||
@@ -1588,7 +1588,7 @@ simplehound==0.3
|
||||
simplepush==2.1.1
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==2022.11.2
|
||||
simplisafe-python==2022.12.0
|
||||
|
||||
# homeassistant.components.slack
|
||||
slackclient==2.5.0
|
||||
@@ -1840,7 +1840,7 @@ zamg==0.1.1
|
||||
zeroconf==0.39.4
|
||||
|
||||
# homeassistant.components.zha
|
||||
zha-quirks==0.0.87
|
||||
zha-quirks==0.0.88
|
||||
|
||||
# homeassistant.components.zha
|
||||
zigpy-deconz==0.19.2
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
PIP_CACHE=$1
|
||||
|
||||
# Number of existing dependency conflicts
|
||||
# Update if a PR resolve one!
|
||||
DEPENDENCY_CONFLICTS=3
|
||||
# Update if a PR resolves one!
|
||||
DEPENDENCY_CONFLICTS=4
|
||||
|
||||
PIP_CHECK=$(pip check --cache-dir=$PIP_CACHE)
|
||||
LINE_COUNT=$(echo "$PIP_CHECK" | wc -l)
|
||||
|
||||
@@ -70,7 +70,7 @@ async def test_legacy_subscription_delete_issue_if_no_longer_legacy(
|
||||
domain="cloud", issue_id="legacy_subscription"
|
||||
)
|
||||
|
||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {"provider": None})
|
||||
cloud_repairs.async_manage_legacy_subscription_issue(hass, {})
|
||||
assert not issue_registry.async_get_issue(
|
||||
domain="cloud", issue_id="legacy_subscription"
|
||||
)
|
||||
|
||||
@@ -20,6 +20,9 @@ from tests.common import MockConfigEntry, MockModule, mock_integration, mock_pla
|
||||
TEST_DOMAIN = "test"
|
||||
|
||||
|
||||
pytest.skip(reason="Temporarily disabled", allow_module_level=True)
|
||||
|
||||
|
||||
class TestConfigFlow(ConfigFlow, domain=TEST_DOMAIN):
|
||||
"""Handle a config flow for the silabs multiprotocol add-on."""
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import copy
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import homeassistant_sky_connect, usb
|
||||
from homeassistant.components.homeassistant_sky_connect.const import DOMAIN
|
||||
from homeassistant.components.zha.core.const import (
|
||||
@@ -150,6 +152,7 @@ async def test_config_flow_update_device(hass: HomeAssistant) -> None:
|
||||
assert len(mock_unload_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Temporarily disabled")
|
||||
async def test_option_flow_install_multi_pan_addon(
|
||||
hass: HomeAssistant,
|
||||
addon_store_info,
|
||||
@@ -240,6 +243,7 @@ def mock_detect_radio_type(radio_type=RadioType.ezsp, ret=True):
|
||||
return detect
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Temporarily disabled")
|
||||
@patch(
|
||||
"homeassistant.components.zha.radio_manager.ZhaRadioManager.detect_radio_type",
|
||||
mock_detect_radio_type(),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Test the Home Assistant Yellow config flow."""
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.homeassistant_yellow.const import DOMAIN
|
||||
from homeassistant.components.zha.core.const import DOMAIN as ZHA_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -59,6 +61,7 @@ async def test_config_flow_single_entry(hass: HomeAssistant) -> None:
|
||||
mock_setup_entry.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Temporarily disabled")
|
||||
async def test_option_flow_install_multi_pan_addon(
|
||||
hass: HomeAssistant,
|
||||
addon_store_info,
|
||||
@@ -127,6 +130,7 @@ async def test_option_flow_install_multi_pan_addon(
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Temporarily disabled")
|
||||
async def test_option_flow_install_multi_pan_addon_zha(
|
||||
hass: HomeAssistant,
|
||||
addon_store_info,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
@@ -541,5 +648,9 @@
|
||||
}
|
||||
},
|
||||
"endpoints": [0, 1],
|
||||
"root_device_type_instance": null,
|
||||
"aggregator_device_type_instance": null,
|
||||
"device_type_instances": [null],
|
||||
"node_devices": [null],
|
||||
"_type": "matter_server.common.models.node.MatterNode"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
@@ -404,7 +511,7 @@
|
||||
},
|
||||
"1/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
@@ -413,9 +520,9 @@
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/1029/0": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -424,9 +531,9 @@
|
||||
"attribute_name": "MeasuredValue",
|
||||
"value": 0
|
||||
},
|
||||
"0/1029/1": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -435,9 +542,9 @@
|
||||
"attribute_name": "MinMeasuredValue",
|
||||
"value": 0
|
||||
},
|
||||
"0/1029/2": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -446,9 +553,9 @@
|
||||
"attribute_name": "MaxMeasuredValue",
|
||||
"value": 10000
|
||||
},
|
||||
"0/1029/65532": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -457,9 +564,9 @@
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/1029/65533": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -468,9 +575,9 @@
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 3
|
||||
},
|
||||
"0/1029/65528": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -479,9 +586,9 @@
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/1029/65529": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
@@ -490,9 +597,9 @@
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/1029/65531": {
|
||||
"node_id": 3,
|
||||
"endpoint": 0,
|
||||
"1/1029/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 1,
|
||||
"cluster_id": 1029,
|
||||
"cluster_type": "chip.clusters.Objects.RelativeHumidityMeasurement",
|
||||
"cluster_name": "RelativeHumidityMeasurement",
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -4,6 +4,113 @@
|
||||
"last_interview": "2022-11-29T21:23:48.485057",
|
||||
"interview_version": 1,
|
||||
"attributes": {
|
||||
"0/29/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 0,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.DeviceTypeList",
|
||||
"attribute_name": "DeviceTypeList",
|
||||
"value": [
|
||||
{
|
||||
"type": 22,
|
||||
"revision": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"0/29/1": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 1,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ServerList",
|
||||
"attribute_name": "ServerList",
|
||||
"value": [
|
||||
4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62,
|
||||
63, 64, 65
|
||||
]
|
||||
},
|
||||
"0/29/2": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 2,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClientList",
|
||||
"attribute_name": "ClientList",
|
||||
"value": [41]
|
||||
},
|
||||
"0/29/3": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 3,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.PartsList",
|
||||
"attribute_name": "PartsList",
|
||||
"value": [1]
|
||||
},
|
||||
"0/29/65532": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65532,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.FeatureMap",
|
||||
"attribute_name": "FeatureMap",
|
||||
"value": 0
|
||||
},
|
||||
"0/29/65533": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65533,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.ClusterRevision",
|
||||
"attribute_name": "ClusterRevision",
|
||||
"value": 1
|
||||
},
|
||||
"0/29/65528": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65528,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.GeneratedCommandList",
|
||||
"attribute_name": "GeneratedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65529": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65529,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AcceptedCommandList",
|
||||
"attribute_name": "AcceptedCommandList",
|
||||
"value": []
|
||||
},
|
||||
"0/29/65531": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
"cluster_id": 29,
|
||||
"cluster_type": "chip.clusters.Objects.Descriptor",
|
||||
"cluster_name": "Descriptor",
|
||||
"attribute_id": 65531,
|
||||
"attribute_type": "chip.clusters.Objects.Descriptor.Attributes.AttributeList",
|
||||
"attribute_name": "AttributeList",
|
||||
"value": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
|
||||
},
|
||||
"0/40/0": {
|
||||
"node_id": 1,
|
||||
"endpoint": 0,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Test Matter binary sensors."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from matter_server.common.models.node import MatterNode
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import (
|
||||
set_node_attribute,
|
||||
setup_integration_with_node_fixture,
|
||||
trigger_subscription_callback,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="contact_sensor_node")
|
||||
async def contact_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a contact sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "contact-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
async def test_contact_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
contact_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test contact sensor."""
|
||||
state = hass.states.get("binary_sensor.mock_contact_sensor_contact")
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
set_node_attribute(contact_sensor_node, 1, 69, 0, False)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("binary_sensor.mock_contact_sensor_contact")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
@pytest.fixture(name="occupancy_sensor_node")
|
||||
async def occupancy_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a occupancy sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "occupancy-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
async def test_occupancy_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
occupancy_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test occupancy sensor."""
|
||||
state = hass.states.get("binary_sensor.mock_occupancy_sensor_occupancy")
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
set_node_attribute(occupancy_sensor_node, 1, 1030, 0, 0)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("binary_sensor.mock_occupancy_sensor_occupancy")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
@@ -0,0 +1,169 @@
|
||||
"""Test Matter sensors."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from matter_server.common.models.node import MatterNode
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import (
|
||||
set_node_attribute,
|
||||
setup_integration_with_node_fixture,
|
||||
trigger_subscription_callback,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="flow_sensor_node")
|
||||
async def flow_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a flow sensor node."""
|
||||
return await setup_integration_with_node_fixture(hass, "flow-sensor", matter_client)
|
||||
|
||||
|
||||
@pytest.fixture(name="humidity_sensor_node")
|
||||
async def humidity_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a humidity sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "humidity-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="light_sensor_node")
|
||||
async def light_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a light sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "light-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="pressure_sensor_node")
|
||||
async def pressure_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a pressure sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "pressure-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="temperature_sensor_node")
|
||||
async def temperature_sensor_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a temperature sensor node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "temperature-sensor", matter_client
|
||||
)
|
||||
|
||||
|
||||
async def test_sensor_null_value(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
flow_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test flow sensor."""
|
||||
state = hass.states.get("sensor.mock_flow_sensor_flow")
|
||||
assert state
|
||||
assert state.state == "0.0"
|
||||
|
||||
set_node_attribute(flow_sensor_node, 1, 1028, 0, None)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_flow_sensor_flow")
|
||||
assert state
|
||||
assert state.state == "unknown"
|
||||
|
||||
|
||||
async def test_flow_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
flow_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test flow sensor."""
|
||||
state = hass.states.get("sensor.mock_flow_sensor_flow")
|
||||
assert state
|
||||
assert state.state == "0.0"
|
||||
|
||||
set_node_attribute(flow_sensor_node, 1, 1028, 0, 20)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_flow_sensor_flow")
|
||||
assert state
|
||||
assert state.state == "2.0"
|
||||
|
||||
|
||||
async def test_humidity_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
humidity_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test humidity sensor."""
|
||||
state = hass.states.get("sensor.mock_humidity_sensor_humidity")
|
||||
assert state
|
||||
assert state.state == "0.0"
|
||||
|
||||
set_node_attribute(humidity_sensor_node, 1, 1029, 0, 4000)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_humidity_sensor_humidity")
|
||||
assert state
|
||||
assert state.state == "40.0"
|
||||
|
||||
|
||||
async def test_light_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
light_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test light sensor."""
|
||||
state = hass.states.get("sensor.mock_light_sensor_light")
|
||||
assert state
|
||||
assert state.state == "1.3"
|
||||
|
||||
set_node_attribute(light_sensor_node, 1, 1024, 0, 3000)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_light_sensor_light")
|
||||
assert state
|
||||
assert state.state == "2.0"
|
||||
|
||||
|
||||
async def test_pressure_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
pressure_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test pressure sensor."""
|
||||
state = hass.states.get("sensor.mock_pressure_sensor_pressure")
|
||||
assert state
|
||||
assert state.state == "0.0"
|
||||
|
||||
set_node_attribute(pressure_sensor_node, 1, 1027, 0, 1010)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_pressure_sensor_pressure")
|
||||
assert state
|
||||
assert state.state == "101.0"
|
||||
|
||||
|
||||
async def test_temperature_sensor(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
temperature_sensor_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test temperature sensor."""
|
||||
state = hass.states.get("sensor.mock_temperature_sensor_temperature")
|
||||
assert state
|
||||
assert state.state == "21.0"
|
||||
|
||||
set_node_attribute(temperature_sensor_node, 1, 1026, 0, 2500)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("sensor.mock_temperature_sensor_temperature")
|
||||
assert state
|
||||
assert state.state == "25.0"
|
||||
@@ -0,0 +1,85 @@
|
||||
"""Test Matter switches."""
|
||||
from unittest.mock import MagicMock, call
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from matter_server.common.models.node import MatterNode
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .common import (
|
||||
set_node_attribute,
|
||||
setup_integration_with_node_fixture,
|
||||
trigger_subscription_callback,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(name="switch_node")
|
||||
async def switch_node_fixture(
|
||||
hass: HomeAssistant, matter_client: MagicMock
|
||||
) -> MatterNode:
|
||||
"""Fixture for a switch node."""
|
||||
return await setup_integration_with_node_fixture(
|
||||
hass, "on-off-plugin-unit", matter_client
|
||||
)
|
||||
|
||||
|
||||
async def test_turn_on(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
switch_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test turning on a switch."""
|
||||
state = hass.states.get("switch.mock_onoff_plugin_unit")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch",
|
||||
"turn_on",
|
||||
{
|
||||
"entity_id": "switch.mock_onoff_plugin_unit",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=switch_node.node_id,
|
||||
endpoint=1,
|
||||
command=clusters.OnOff.Commands.On(),
|
||||
)
|
||||
|
||||
set_node_attribute(switch_node, 1, 6, 0, True)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("switch.mock_onoff_plugin_unit")
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
|
||||
async def test_turn_off(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
switch_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test turning off a switch."""
|
||||
state = hass.states.get("switch.mock_onoff_plugin_unit")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
"switch",
|
||||
"turn_off",
|
||||
{
|
||||
"entity_id": "switch.mock_onoff_plugin_unit",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=switch_node.node_id,
|
||||
endpoint=1,
|
||||
command=clusters.OnOff.Commands.Off(),
|
||||
)
|
||||
@@ -21,6 +21,7 @@ from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
|
||||
from homeassistant.core import State
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
||||
|
||||
from . import init_integration, register_device, register_entity
|
||||
|
||||
@@ -212,6 +213,53 @@ async def test_block_restored_climate(hass, mock_block_device, device_reg, monke
|
||||
assert hass.states.get(entity_id).state == HVACMode.OFF
|
||||
|
||||
|
||||
async def test_block_restored_climate_us_customery(
|
||||
hass, mock_block_device, device_reg, monkeypatch
|
||||
):
|
||||
"""Test block restored climate with US CUSTOMATY unit system."""
|
||||
hass.config.units = US_CUSTOMARY_SYSTEM
|
||||
monkeypatch.delattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "targetTemp")
|
||||
monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "valveError", 0)
|
||||
entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
|
||||
register_device(device_reg, entry)
|
||||
entity_id = register_entity(
|
||||
hass,
|
||||
CLIMATE_DOMAIN,
|
||||
"test_name",
|
||||
"sensor_0",
|
||||
entry,
|
||||
)
|
||||
attrs = {"current_temperature": 67, "temperature": 68}
|
||||
mock_restore_cache(hass, [State(entity_id, HVACMode.HEAT, attributes=attrs)])
|
||||
|
||||
monkeypatch.setattr(mock_block_device, "initialized", False)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(entity_id).state == HVACMode.HEAT
|
||||
assert hass.states.get(entity_id).attributes.get("temperature") == 68
|
||||
assert hass.states.get(entity_id).attributes.get("current_temperature") == 67
|
||||
|
||||
# Partial update, should not change state
|
||||
mock_block_device.mock_update()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(entity_id).state == HVACMode.HEAT
|
||||
assert hass.states.get(entity_id).attributes.get("temperature") == 68
|
||||
assert hass.states.get(entity_id).attributes.get("current_temperature") == 67
|
||||
|
||||
# Make device online
|
||||
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "targetTemp", 19.7)
|
||||
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 18.2)
|
||||
mock_block_device.mock_update()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get(entity_id).state == HVACMode.HEAT
|
||||
assert hass.states.get(entity_id).attributes.get("temperature") == 67
|
||||
assert hass.states.get(entity_id).attributes.get("current_temperature") == 65
|
||||
|
||||
|
||||
async def test_block_restored_climate_unavailable(
|
||||
hass, mock_block_device, device_reg, monkeypatch
|
||||
):
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
"""Test cases for the Shelly component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.shelly.const import DOMAIN
|
||||
from homeassistant.components.shelly.const import (
|
||||
CONF_BLE_SCANNER_MODE,
|
||||
DOMAIN,
|
||||
BLEScannerMode,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||
from homeassistant.const import STATE_ON, STATE_UNAVAILABLE
|
||||
from homeassistant.helpers import device_registry
|
||||
@@ -183,3 +187,27 @@ async def test_entry_unload_device_not_ready(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.NOT_LOADED
|
||||
|
||||
|
||||
async def test_entry_unload_not_connected(hass, mock_rpc_device, monkeypatch):
|
||||
"""Test entry unload when not connected."""
|
||||
with patch(
|
||||
"homeassistant.components.shelly.coordinator.async_stop_scanner"
|
||||
) as mock_stop_scanner:
|
||||
|
||||
entry = await init_integration(
|
||||
hass, 2, options={CONF_BLE_SCANNER_MODE: BLEScannerMode.ACTIVE}
|
||||
)
|
||||
entity_id = "switch.test_switch_0"
|
||||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
assert hass.states.get(entity_id).state is STATE_ON
|
||||
assert not mock_stop_scanner.call_count
|
||||
|
||||
monkeypatch.setattr(mock_rpc_device, "connected", False)
|
||||
|
||||
await hass.config_entries.async_reload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not mock_stop_scanner.call_count
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
@@ -6,7 +6,7 @@ from copy import copy
|
||||
from http import HTTPStatus
|
||||
from unittest.mock import Mock
|
||||
|
||||
from pyunifiprotect.data import Camera, Version
|
||||
from pyunifiprotect.data import Version
|
||||
|
||||
from homeassistant.components.repairs.issue_handler import (
|
||||
async_process_repairs_platforms,
|
||||
@@ -16,9 +16,7 @@ from homeassistant.components.repairs.websocket_api import (
|
||||
RepairsFlowResourceView,
|
||||
)
|
||||
from homeassistant.components.unifiprotect.const import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .utils import MockUFPFixture, init_entry
|
||||
|
||||
@@ -126,53 +124,3 @@ async def test_ea_warning_fix(
|
||||
data = await resp.json()
|
||||
|
||||
assert data["type"] == "create_entry"
|
||||
|
||||
|
||||
async def test_deprecate_smart_default(
|
||||
hass: HomeAssistant, ufp: MockUFPFixture, hass_ws_client, doorbell: Camera
|
||||
):
|
||||
"""Test Deprecate Sensor repair does not exist by default (new installs)."""
|
||||
|
||||
await init_entry(hass, ufp, [doorbell])
|
||||
|
||||
await async_process_repairs_platforms(hass)
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
||||
msg = await ws_client.receive_json()
|
||||
|
||||
assert msg["success"]
|
||||
issue = None
|
||||
for i in msg["result"]["issues"]:
|
||||
if i["issue_id"] == "deprecate_smart_sensor":
|
||||
issue = i
|
||||
assert issue is None
|
||||
|
||||
|
||||
async def test_deprecate_smart_active(
|
||||
hass: HomeAssistant, ufp: MockUFPFixture, hass_ws_client, doorbell: Camera
|
||||
):
|
||||
"""Test Deprecate Sensor repair exists for existing installs."""
|
||||
|
||||
registry = er.async_get(hass)
|
||||
registry.async_get_or_create(
|
||||
Platform.SENSOR,
|
||||
DOMAIN,
|
||||
f"{doorbell.mac}_detected_object",
|
||||
config_entry=ufp.entry,
|
||||
)
|
||||
|
||||
await init_entry(hass, ufp, [doorbell])
|
||||
|
||||
await async_process_repairs_platforms(hass)
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
|
||||
msg = await ws_client.receive_json()
|
||||
|
||||
assert msg["success"]
|
||||
issue = None
|
||||
for i in msg["result"]["issues"]:
|
||||
if i["issue_id"] == "deprecate_smart_sensor":
|
||||
issue = i
|
||||
assert issue is not None
|
||||
|
||||
@@ -583,7 +583,9 @@ def lock_home_connect_620_state_fixture():
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def mock_client_fixture(controller_state, version_state, log_config_state):
|
||||
def mock_client_fixture(
|
||||
controller_state, controller_node_state, version_state, log_config_state
|
||||
):
|
||||
"""Mock a client."""
|
||||
|
||||
with patch(
|
||||
@@ -608,6 +610,8 @@ def mock_client_fixture(controller_state, version_state, log_config_state):
|
||||
client.listen = AsyncMock(side_effect=listen)
|
||||
client.disconnect = AsyncMock(side_effect=disconnect)
|
||||
client.driver = Driver(client, controller_state, log_config_state)
|
||||
node = Node(client, copy.deepcopy(controller_node_state))
|
||||
client.driver.controller.nodes[node.node_id] = node
|
||||
|
||||
client.version = VersionInfo.from_message(version_state)
|
||||
client.ws_server_url = "ws://test:3000/zjs"
|
||||
@@ -615,14 +619,6 @@ def mock_client_fixture(controller_state, version_state, log_config_state):
|
||||
yield client
|
||||
|
||||
|
||||
@pytest.fixture(name="controller_node")
|
||||
def controller_node_fixture(client, controller_node_state):
|
||||
"""Mock a controller node."""
|
||||
node = Node(client, copy.deepcopy(controller_node_state))
|
||||
client.driver.controller.nodes[node.node_id] = node
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(name="multisensor_6")
|
||||
def multisensor_6_fixture(client, multisensor_6_state):
|
||||
"""Mock a multisensor 6 node."""
|
||||
|
||||
@@ -10,7 +10,6 @@ async def test_ping_entity(
|
||||
hass,
|
||||
client,
|
||||
climate_radio_thermostat_ct100_plus_different_endpoints,
|
||||
controller_node,
|
||||
integration,
|
||||
caplog,
|
||||
):
|
||||
|
||||
@@ -91,6 +91,16 @@ async def test_get_actions(
|
||||
for action in expected_actions:
|
||||
assert action in actions
|
||||
|
||||
# Test that we don't return actions for a controller node
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(driver, client.driver.controller.nodes[1])}
|
||||
)
|
||||
assert device
|
||||
assert (
|
||||
await async_get_device_automations(hass, DeviceAutomationType.ACTION, device.id)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
async def test_get_actions_meter(
|
||||
hass: HomeAssistant,
|
||||
@@ -408,9 +418,10 @@ async def test_get_action_capabilities(
|
||||
):
|
||||
"""Test we get the expected action capabilities."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, climate_radio_thermostat_ct100_plus)}
|
||||
)
|
||||
assert device
|
||||
|
||||
# Test refresh_value
|
||||
capabilities = await device_action.async_get_action_capabilities(
|
||||
|
||||
@@ -15,7 +15,10 @@ from homeassistant.components.device_automation.exceptions import (
|
||||
InvalidDeviceAutomationConfig,
|
||||
)
|
||||
from homeassistant.components.zwave_js import DOMAIN, device_condition
|
||||
from homeassistant.components.zwave_js.helpers import get_zwave_value_from_config
|
||||
from homeassistant.components.zwave_js.helpers import (
|
||||
get_device_id,
|
||||
get_zwave_value_from_config,
|
||||
)
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv, device_registry
|
||||
from homeassistant.setup import async_setup_component
|
||||
@@ -32,9 +35,10 @@ def calls(hass):
|
||||
async def test_get_conditions(hass, client, lock_schlage_be469, integration) -> None:
|
||||
"""Test we get the expected onditions from a zwave_js."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
config_value = list(lock_schlage_be469.get_configuration_values().values())[0]
|
||||
value_id = config_value.value_id
|
||||
name = config_value.property_name
|
||||
@@ -70,15 +74,28 @@ async def test_get_conditions(hass, client, lock_schlage_be469, integration) ->
|
||||
for condition in expected_conditions:
|
||||
assert condition in conditions
|
||||
|
||||
# Test that we don't return actions for a controller node
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, client.driver.controller.nodes[1])}
|
||||
)
|
||||
assert device
|
||||
assert (
|
||||
await async_get_device_automations(
|
||||
hass, DeviceAutomationType.CONDITION, device.id
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
async def test_node_status_state(
|
||||
hass, client, lock_schlage_be469, integration, calls
|
||||
) -> None:
|
||||
"""Test for node_status conditions."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -224,9 +241,10 @@ async def test_config_parameter_state(
|
||||
) -> None:
|
||||
"""Test for config_parameter conditions."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -333,9 +351,10 @@ async def test_value_state(
|
||||
) -> None:
|
||||
"""Test for value conditions."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -377,9 +396,10 @@ async def test_get_condition_capabilities_node_status(
|
||||
):
|
||||
"""Test we don't get capabilities from a node_status condition."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
capabilities = await device_condition.async_get_condition_capabilities(
|
||||
hass,
|
||||
@@ -413,9 +433,10 @@ async def test_get_condition_capabilities_value(
|
||||
):
|
||||
"""Test we get the expected capabilities from a value condition."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
capabilities = await device_condition.async_get_condition_capabilities(
|
||||
hass,
|
||||
@@ -462,9 +483,10 @@ async def test_get_condition_capabilities_config_parameter(
|
||||
"""Test we get the expected capabilities from a config_parameter condition."""
|
||||
node = climate_radio_thermostat_ct100_plus
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, climate_radio_thermostat_ct100_plus)}
|
||||
)
|
||||
assert device
|
||||
|
||||
# Test enumerated type param
|
||||
capabilities = await device_condition.async_get_condition_capabilities(
|
||||
@@ -541,9 +563,10 @@ async def test_get_condition_capabilities_config_parameter(
|
||||
async def test_failure_scenarios(hass, client, hank_binary_switch, integration):
|
||||
"""Test failure scenarios."""
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
device = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, integration.entry_id
|
||||
)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, hank_binary_switch)}
|
||||
)
|
||||
assert device
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await device_condition.async_condition_from_config(
|
||||
|
||||
@@ -15,13 +15,11 @@ from homeassistant.components.device_automation.exceptions import (
|
||||
from homeassistant.components.zwave_js import DOMAIN, device_trigger
|
||||
from homeassistant.components.zwave_js.helpers import (
|
||||
async_get_node_status_sensor_entity_id,
|
||||
get_device_id,
|
||||
)
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.device_registry import (
|
||||
async_entries_for_config_entry,
|
||||
async_get as async_get_dev_reg,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import async_get as async_get_dev_reg
|
||||
from homeassistant.helpers.entity_registry import async_get as async_get_ent_reg
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
@@ -38,12 +36,30 @@ def calls(hass):
|
||||
return async_mock_service(hass, "test", "automation")
|
||||
|
||||
|
||||
async def test_no_controller_triggers(hass, client, integration):
|
||||
"""Test that we do not get triggers for the controller."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, client.driver.controller.nodes[1])}
|
||||
)
|
||||
assert device
|
||||
assert (
|
||||
await async_get_device_automations(
|
||||
hass, DeviceAutomationType.TRIGGER, device.id
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
async def test_get_notification_notification_triggers(
|
||||
hass, client, lock_schlage_be469, integration
|
||||
):
|
||||
"""Test we get the expected triggers from a zwave_js device with the Notification CC."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -64,7 +80,10 @@ async def test_if_notification_notification_fires(
|
||||
"""Test for event.notification.notification trigger firing."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -157,7 +176,10 @@ async def test_get_trigger_capabilities_notification_notification(
|
||||
):
|
||||
"""Test we get the expected capabilities from a notification.notification trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -189,7 +211,10 @@ async def test_if_entry_control_notification_fires(
|
||||
"""Test for notification.entry_control trigger firing."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -281,7 +306,10 @@ async def test_get_trigger_capabilities_entry_control_notification(
|
||||
):
|
||||
"""Test we get the expected capabilities from a notification.entry_control trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -308,7 +336,10 @@ async def test_get_trigger_capabilities_entry_control_notification(
|
||||
async def test_get_node_status_triggers(hass, client, lock_schlage_be469, integration):
|
||||
"""Test we get the expected triggers from a device with node status sensor enabled."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
ent_reg = async_get_ent_reg(hass)
|
||||
entity_id = async_get_node_status_sensor_entity_id(
|
||||
hass, device.id, ent_reg, dev_reg
|
||||
@@ -337,7 +368,10 @@ async def test_if_node_status_change_fires(
|
||||
"""Test for node_status trigger firing."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
ent_reg = async_get_ent_reg(hass)
|
||||
entity_id = async_get_node_status_sensor_entity_id(
|
||||
hass, device.id, ent_reg, dev_reg
|
||||
@@ -412,7 +446,10 @@ async def test_get_trigger_capabilities_node_status(
|
||||
):
|
||||
"""Test we get the expected capabilities from a node_status trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
ent_reg = async_get_ent_reg(hass)
|
||||
entity_id = async_get_node_status_sensor_entity_id(
|
||||
hass, device.id, ent_reg, dev_reg
|
||||
@@ -467,7 +504,10 @@ async def test_get_basic_value_notification_triggers(
|
||||
):
|
||||
"""Test we get the expected triggers from a zwave_js device with the Basic CC."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, ge_in_wall_dimmer_switch)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -492,7 +532,10 @@ async def test_if_basic_value_notification_fires(
|
||||
"""Test for event.value_notification.basic trigger firing."""
|
||||
node: Node = ge_in_wall_dimmer_switch
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, ge_in_wall_dimmer_switch)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -600,7 +643,10 @@ async def test_get_trigger_capabilities_basic_value_notification(
|
||||
):
|
||||
"""Test we get the expected capabilities from a value_notification.basic trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, ge_in_wall_dimmer_switch)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -635,7 +681,10 @@ async def test_get_central_scene_value_notification_triggers(
|
||||
):
|
||||
"""Test we get the expected triggers from a zwave_js device with the Central Scene CC."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, wallmote_central_scene)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -660,7 +709,10 @@ async def test_if_central_scene_value_notification_fires(
|
||||
"""Test for event.value_notification.central_scene trigger firing."""
|
||||
node: Node = wallmote_central_scene
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, wallmote_central_scene)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -775,7 +827,10 @@ async def test_get_trigger_capabilities_central_scene_value_notification(
|
||||
):
|
||||
"""Test we get the expected capabilities from a value_notification.central_scene trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, wallmote_central_scene)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -809,7 +864,10 @@ async def test_get_scene_activation_value_notification_triggers(
|
||||
):
|
||||
"""Test we get the expected triggers from a zwave_js device with the SceneActivation CC."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, hank_binary_switch)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -834,7 +892,10 @@ async def test_if_scene_activation_value_notification_fires(
|
||||
"""Test for event.value_notification.scene_activation trigger firing."""
|
||||
node: Node = hank_binary_switch
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, hank_binary_switch)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -942,7 +1003,10 @@ async def test_get_trigger_capabilities_scene_activation_value_notification(
|
||||
):
|
||||
"""Test we get the expected capabilities from a value_notification.scene_activation trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, hank_binary_switch)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -977,7 +1041,10 @@ async def test_get_value_updated_value_triggers(
|
||||
):
|
||||
"""Test we get the zwave_js.value_updated.value trigger from a zwave_js device."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -997,7 +1064,10 @@ async def test_if_value_updated_value_fires(
|
||||
"""Test for zwave_js.value_updated.value trigger firing."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -1086,7 +1156,10 @@ async def test_value_updated_value_no_driver(
|
||||
"""Test zwave_js.value_updated.value trigger with missing driver."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
driver = client.driver
|
||||
client.driver = None
|
||||
|
||||
@@ -1153,7 +1226,10 @@ async def test_get_trigger_capabilities_value_updated_value(
|
||||
):
|
||||
"""Test we get the expected capabilities from a zwave_js.value_updated.value trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -1201,7 +1277,10 @@ async def test_get_value_updated_config_parameter_triggers(
|
||||
):
|
||||
"""Test we get the zwave_js.value_updated.config_parameter trigger from a zwave_js device."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
expected_trigger = {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
@@ -1226,7 +1305,10 @@ async def test_if_value_updated_config_parameter_fires(
|
||||
"""Test for zwave_js.value_updated.config_parameter trigger firing."""
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@@ -1293,7 +1375,10 @@ async def test_get_trigger_capabilities_value_updated_config_parameter_range(
|
||||
):
|
||||
"""Test we get the expected capabilities from a range zwave_js.value_updated.config_parameter trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -1335,7 +1420,10 @@ async def test_get_trigger_capabilities_value_updated_config_parameter_enumerate
|
||||
):
|
||||
"""Test we get the expected capabilities from an enumerated zwave_js.value_updated.config_parameter trigger."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
capabilities = await device_trigger.async_get_trigger_capabilities(
|
||||
hass,
|
||||
{
|
||||
@@ -1386,7 +1474,10 @@ async def test_failure_scenarios(hass, client, hank_binary_switch, integration):
|
||||
)
|
||||
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, hank_binary_switch)}
|
||||
)
|
||||
assert device
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await device_trigger.async_attach_trigger(
|
||||
|
||||
@@ -199,7 +199,7 @@ async def test_on_node_added_not_ready(
|
||||
device_id = f"{client.driver.controller.home_id}-{zp3111_not_ready_state['nodeId']}"
|
||||
|
||||
assert len(hass.states.async_all()) == 0
|
||||
assert not dev_reg.devices
|
||||
assert len(dev_reg.devices) == 1
|
||||
|
||||
node_state = deepcopy(zp3111_not_ready_state)
|
||||
node_state["isSecure"] = False
|
||||
@@ -911,12 +911,12 @@ async def test_removed_device(
|
||||
driver = client.driver
|
||||
assert driver
|
||||
# Verify how many nodes are available
|
||||
assert len(driver.controller.nodes) == 2
|
||||
assert len(driver.controller.nodes) == 3
|
||||
|
||||
# Make sure there are the same number of devices
|
||||
dev_reg = dr.async_get(hass)
|
||||
device_entries = dr.async_entries_for_config_entry(dev_reg, integration.entry_id)
|
||||
assert len(device_entries) == 2
|
||||
assert len(device_entries) == 3
|
||||
|
||||
# Check how many entities there are
|
||||
ent_reg = er.async_get(hass)
|
||||
@@ -931,7 +931,7 @@ async def test_removed_device(
|
||||
# Assert that the node and all of it's entities were removed from the device and
|
||||
# entity registry
|
||||
device_entries = dr.async_entries_for_config_entry(dev_reg, integration.entry_id)
|
||||
assert len(device_entries) == 1
|
||||
assert len(device_entries) == 2
|
||||
entity_entries = er.async_entries_for_config_entry(ent_reg, integration.entry_id)
|
||||
assert len(entity_entries) == 18
|
||||
assert dev_reg.async_get_device({get_device_id(driver, old_node)}) is None
|
||||
|
||||
@@ -156,9 +156,7 @@ async def test_config_parameter_sensor(hass, lock_id_lock_as_id150, integration)
|
||||
assert entity_entry.disabled
|
||||
|
||||
|
||||
async def test_node_status_sensor(
|
||||
hass, client, controller_node, lock_id_lock_as_id150, integration
|
||||
):
|
||||
async def test_node_status_sensor(hass, client, lock_id_lock_as_id150, integration):
|
||||
"""Test node status sensor is created and gets updated on node state changes."""
|
||||
NODE_STATUS_ENTITY = "sensor.z_wave_module_for_id_lock_150_and_101_node_status"
|
||||
node = lock_id_lock_as_id150
|
||||
|
||||
@@ -34,10 +34,7 @@ from homeassistant.components.zwave_js.helpers import get_device_id
|
||||
from homeassistant.const import ATTR_AREA_ID, ATTR_DEVICE_ID, ATTR_ENTITY_ID
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.area_registry import async_get as async_get_area_reg
|
||||
from homeassistant.helpers.device_registry import (
|
||||
async_entries_for_config_entry,
|
||||
async_get as async_get_dev_reg,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import async_get as async_get_dev_reg
|
||||
from homeassistant.helpers.entity_registry import async_get as async_get_ent_reg
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
@@ -408,7 +405,8 @@ async def test_set_config_parameter_gather(
|
||||
async def test_bulk_set_config_parameters(hass, client, multisensor_6, integration):
|
||||
"""Test the bulk_set_partial_config_parameters service."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device({get_device_id(client.driver, multisensor_6)})
|
||||
assert device
|
||||
# Test setting config parameter by property and property_key
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
@@ -736,7 +734,10 @@ async def test_refresh_value(
|
||||
async def test_set_value(hass, client, climate_danfoss_lc_13, integration):
|
||||
"""Test set_value service."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, climate_danfoss_lc_13)}
|
||||
)
|
||||
assert device
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
||||
@@ -9,15 +9,13 @@ from zwave_js_server.model.node import Node
|
||||
|
||||
from homeassistant.components import automation
|
||||
from homeassistant.components.zwave_js import DOMAIN
|
||||
from homeassistant.components.zwave_js.helpers import get_device_id
|
||||
from homeassistant.components.zwave_js.trigger import async_validate_trigger_config
|
||||
from homeassistant.components.zwave_js.triggers.trigger_helpers import (
|
||||
async_bypass_dynamic_config_validation,
|
||||
)
|
||||
from homeassistant.const import SERVICE_RELOAD
|
||||
from homeassistant.helpers.device_registry import (
|
||||
async_entries_for_config_entry,
|
||||
async_get as async_get_dev_reg,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import async_get as async_get_dev_reg
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .common import SCHLAGE_BE469_LOCK_ENTITY
|
||||
@@ -30,7 +28,10 @@ async def test_zwave_js_value_updated(hass, client, lock_schlage_be469, integrat
|
||||
trigger_type = f"{DOMAIN}.value_updated"
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
no_value_filter = async_capture_events(hass, "no_value_filter")
|
||||
single_from_value_filter = async_capture_events(hass, "single_from_value_filter")
|
||||
@@ -449,7 +450,10 @@ async def test_zwave_js_event(hass, client, lock_schlage_be469, integration):
|
||||
trigger_type = f"{DOMAIN}.event"
|
||||
node: Node = lock_schlage_be469
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
node_no_event_data_filter = async_capture_events(hass, "node_no_event_data_filter")
|
||||
node_event_data_filter = async_capture_events(hass, "node_event_data_filter")
|
||||
@@ -992,7 +996,10 @@ async def test_zwave_js_trigger_config_entry_unloaded(
|
||||
):
|
||||
"""Test zwave_js triggers bypass dynamic validation when needed."""
|
||||
dev_reg = async_get_dev_reg(hass)
|
||||
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
|
||||
device = dev_reg.async_get_device(
|
||||
{get_device_id(client.driver, lock_schlage_be469)}
|
||||
)
|
||||
assert device
|
||||
|
||||
# Test bypass check is False
|
||||
assert not async_bypass_dynamic_config_validation(
|
||||
|
||||
@@ -72,7 +72,6 @@ async def test_update_entity_states(
|
||||
hass,
|
||||
client,
|
||||
climate_radio_thermostat_ct100_plus_different_endpoints,
|
||||
controller_node,
|
||||
integration,
|
||||
caplog,
|
||||
hass_ws_client,
|
||||
|
||||
Reference in New Issue
Block a user