Compare commits

..

35 Commits

Author SHA1 Message Date
Franck Nijhof 4e73063ed3 2022.12.1 (#83592) 2022-12-09 08:29:14 +01:00
Paulus Schoutsen e9796547c6 Make mypy happy (#83605) 2022-12-08 23:21:45 -05:00
Paulus Schoutsen 9c7b80090a Disable multi-pan (#83603)
* Disable multi-pan

* One more test skip
2022-12-08 22:44:16 -05:00
J. Nick Koston 19ddf478e2 Bump bluetooth-auto-recovery to 0.5.5 (#83597)
changelog: https://github.com/Bluetooth-Devices/bluetooth-auto-recovery/compare/v0.5.4...v0.5.5

fixes #78036
2022-12-08 21:44:15 -05:00
Jeef 5cdcbcd5fe Bump intellifire4py to 2.2.2 (#83589) 2022-12-08 21:43:54 -05:00
Franck Nijhof 803d4a9998 Bump pip_check conflicts +1 (#83536)
* Bump pip_check conflicts +1

* Update script/pip_check

Co-authored-by: Philip Allgaier <mail@spacegaier.de>

Co-authored-by: Philip Allgaier <mail@spacegaier.de>
2022-12-08 21:39:30 -05:00
Paulus Schoutsen 8ccc77eb3d Bumped version to 2022.12.1 2022-12-08 16:45:23 -05:00
Allen Porter 5994dd558b Improve local calendar input validation error handling (#83563) 2022-12-08 16:45:16 -05:00
Bram Kragten b548be35bc Update frontend to 20221208.0 (#83551) 2022-12-08 16:45:16 -05:00
Marc Mueller 2cf1235b78 Fix issue with Callable, Union, and Python 3.9 [mqtt] (#83547) 2022-12-08 16:45:15 -05:00
Allen Porter 609fc9196f Bump ical to 4.2.2 (#83520)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2022-12-08 16:45:14 -05:00
mezz64 b7396a736e Bump pyhik to 0.3.2 (#83517)
Increase pyHik version to fix videoloss error
2022-12-08 16:45:13 -05:00
Marcel van der Veldt a64e56c8ad Bump python-matter-server to 1.0.7 (#83507) 2022-12-08 16:45:12 -05:00
Aaron Bach 94160903a7 Bump simplisafe-python to 2022.12.0 (#83497) 2022-12-08 16:45:12 -05:00
Joakim Plate f4948e8f48 Make sure super async_added_to_hass is called (#83493)
Make sure super added to hass is called
2022-12-08 16:45:11 -05:00
Christian Kündig ec7302ef1b Set connectable as false for sensirion_ble (#83481)
This is a passive ble integration. Not setting it as false means it won't match properly when using through a passive remote scanner.
2022-12-08 16:45:10 -05:00
Franck Nijhof 7b462e1b8e 2022.12.0 (#83482) 2022-12-07 20:26:50 +01:00
puddly 92bc93466e Fix missing Shelly UnitOfTemperature import (#83483) 2022-12-07 18:45:16 +01:00
Franck Nijhof 54dd556459 Bumped version to 2022.12.0 2022-12-07 17:49:50 +01:00
Bram Kragten 8553faf3c8 Update frontend to 20221207.0 (#83479) 2022-12-07 17:49:22 +01:00
TheJulianJES 1631d10365 Cleanup ZHA initialization for TS011F child_lock (#83478) 2022-12-07 17:49:19 +01:00
Joakim Sørensen 141f37504d When an account exist without a subscription "provider" will not exist (#83472) 2022-12-07 17:49:16 +01:00
David F. Mulcahey f97795fbb9 Bump the ZHA quirks lib to 0.0.88 (#83468) 2022-12-07 17:49:12 +01:00
Joakim Sørensen ebf133ef80 Bump hass-nabucasa from 0.59.0 to 0.61.0 (#83466) 2022-12-07 17:49:08 +01:00
Franck Nijhof 886525112b Remove doubtful repairs issue from UniFi Protect (#83463) 2022-12-07 17:49:05 +01:00
Maciej Bieniek 9a15494e69 Fix restored temperature values in Shelly climate platform (#83428)
* Set last_target_temp value according the unit system

* Convert restored temperature values

* Add test

* Improve comments

* Move _last_target_temp value to constants
2022-12-07 17:49:01 +01:00
mbo18 047012d167 Add Child lock support to Tuya devices (#83233)
* Add Child lock support to Tuya devices

* flake/black

* Add attribute to general.py

* apply only to TS011F

* also update general.py
2022-12-07 17:48:56 +01:00
Paulus Schoutsen 8703e14cab Bumped version to 2022.12.0b7 2022-12-06 22:58:47 -05:00
J. Nick Koston 5992361717 Do not try to stop the shelly ble scanner if not connected (#83424)
Co-authored-by: Shay Levy <levyshay1@gmail.com>
2022-12-06 22:58:42 -05:00
Daniel Hjelseth Høyer 54748cec82 Update tibber lib to 0.26.4, improve logging (#83418) 2022-12-06 22:58:41 -05:00
Raman Gupta c8d560946b Add via_device support to zwave_js (#83219)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2022-12-06 22:58:40 -05:00
Martin Hjelmare 07c60686b1 Add matter switch platform (#83149) 2022-12-06 22:58:40 -05:00
Martin Hjelmare 7795cc7fe8 Add matter sensor platform (#83147) 2022-12-06 22:58:39 -05:00
Guido Pio Mariotti 172d587f84 Update pyvesync to 2.1.1 (#83146)
Update pyvesync to 2.1.1 to close #70420
2022-12-06 22:58:38 -05:00
Martin Hjelmare 7903f01f0c Add matter binary sensor platform (#83144) 2022-12-06 22:58:37 -05:00
74 changed files with 2040 additions and 269 deletions
@@ -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"
],
+1 -1
View File
@@ -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"],
+1 -1
View File
@@ -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"
+167
View File
@@ -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,
),
}
+88
View File
@@ -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,
),
}
+5 -2
View File
@@ -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*"
}
],
+32 -5
View File
@@ -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:
+1
View File
@@ -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:
+1 -1
View File
@@ -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",
+12
View File
@@ -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"
+24 -7
View File
@@ -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(
+1 -1
View File
@@ -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)
+2
View File
@@ -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*",
},
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+1 -1
View File
@@ -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"
+169
View File
@@ -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"
+85
View File
@@ -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(),
)
+48
View File
@@ -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
):
+30 -2
View File
@@ -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
+1 -53
View File
@@ -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
+5 -9
View File
@@ -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."""
-1
View File
@@ -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(
+121 -30
View File
@@ -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(
+4 -4
View File
@@ -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
+1 -3
View File
@@ -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
+7 -6
View File
@@ -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,
+14 -7
View File
@@ -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(
-1
View File
@@ -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,