mirror of
https://github.com/home-assistant/core.git
synced 2025-11-07 18:09:31 +00:00
Compare commits
13 Commits
add-includ
...
window_cov
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29fbfff138 | ||
|
|
fd60b738c9 | ||
|
|
fe94f978b2 | ||
|
|
3aea41c722 | ||
|
|
750123cc1f | ||
|
|
99b6362b59 | ||
|
|
e1fa5a11cb | ||
|
|
a265ecfade | ||
|
|
d52749c71a | ||
|
|
5eb5b93c0e | ||
|
|
7c6a39ec91 | ||
|
|
57c3a5c349 | ||
|
|
07c4c58ce4 |
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from collections.abc import Mapping
|
||||
from functools import partial
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from devolo_home_control_api.exceptions.gateway import GatewayOfflineError
|
||||
@@ -22,6 +23,8 @@ from .const import DOMAIN, PLATFORMS
|
||||
|
||||
type DevoloHomeControlConfigEntry = ConfigEntry[list[HomeControl]]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: DevoloHomeControlConfigEntry
|
||||
@@ -44,26 +47,29 @@ async def async_setup_entry(
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, shutdown)
|
||||
)
|
||||
|
||||
try:
|
||||
zeroconf_instance = await zeroconf.async_get_instance(hass)
|
||||
entry.runtime_data = []
|
||||
for gateway_id in gateway_ids:
|
||||
zeroconf_instance = await zeroconf.async_get_instance(hass)
|
||||
entry.runtime_data = []
|
||||
offline_gateways = 0
|
||||
for gateway_id in gateway_ids:
|
||||
try:
|
||||
entry.runtime_data.append(
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
HomeControl,
|
||||
gateway_id=str(gateway_id),
|
||||
gateway_id=gateway_id,
|
||||
mydevolo_instance=mydevolo,
|
||||
zeroconf_instance=zeroconf_instance,
|
||||
)
|
||||
)
|
||||
)
|
||||
except GatewayOfflineError as err:
|
||||
except GatewayOfflineError:
|
||||
offline_gateways += 1
|
||||
_LOGGER.info("Central unit %s cannot be reached locally", gateway_id)
|
||||
if len(gateway_ids) == offline_gateways:
|
||||
raise ConfigEntryNotReady(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="connection_failed",
|
||||
translation_placeholders={"gateway_id": gateway_id},
|
||||
) from err
|
||||
)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/devolo_home_control",
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["devolo_home_control_api"],
|
||||
"loggers": ["HomeControl", "Mydevolo", "MprmRest", "MprmWebsocket", "Mprm"],
|
||||
"requirements": ["devolo-home-control-api==0.19.0"],
|
||||
"zeroconf": ["_dvl-deviceapi._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
"exceptions": {
|
||||
"connection_failed": {
|
||||
"message": "Failed to connect to devolo Home Control central unit {gateway_id}."
|
||||
"message": "Failed to connect to any devolo Home Control central unit."
|
||||
},
|
||||
"invalid_auth": {
|
||||
"message": "Authentication failed. Please re-authenticate with your mydevolo account."
|
||||
|
||||
@@ -108,6 +108,7 @@ _DEFAULT_BIND = ["0.0.0.0", "::"] if _HAS_IPV6 else ["0.0.0.0"]
|
||||
|
||||
HTTP_SCHEMA: Final = vol.All(
|
||||
cv.deprecated(CONF_BASE_URL),
|
||||
cv.deprecated(CONF_SERVER_HOST), # Deprecated in HA Core 2025.12
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_SERVER_HOST): vol.All(
|
||||
@@ -208,14 +209,21 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
if conf is None:
|
||||
conf = cast(ConfData, HTTP_SCHEMA({}))
|
||||
|
||||
if CONF_SERVER_HOST in conf and is_hassio(hass):
|
||||
if CONF_SERVER_HOST in conf:
|
||||
if is_hassio(hass):
|
||||
issue_id = "server_host_deprecated_hassio"
|
||||
severity = ir.IssueSeverity.ERROR
|
||||
else:
|
||||
issue_id = "server_host_deprecated"
|
||||
severity = ir.IssueSeverity.WARNING
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"server_host_may_break_hassio",
|
||||
issue_id,
|
||||
breaks_in_ha_version="2026.6.0",
|
||||
is_fixable=False,
|
||||
severity=ir.IssueSeverity.ERROR,
|
||||
translation_key="server_host_may_break_hassio",
|
||||
severity=severity,
|
||||
translation_key=issue_id,
|
||||
)
|
||||
|
||||
server_host = conf.get(CONF_SERVER_HOST, _DEFAULT_BIND)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"issues": {
|
||||
"server_host_may_break_hassio": {
|
||||
"description": "The `server_host` configuration option in the HTTP integration is prone to break the communication between Home Assistant Core and Supervisor, and will be removed in a future release.\n\nIf you are using this option to bind Home Assistant to specific network interfaces, please remove it from your configuration. Home Assistant will automatically bind to all available interfaces by default.\n\nIf you have specific networking requirements, consider using firewall rules or other network configuration to control access to Home Assistant.",
|
||||
"server_host_deprecated": {
|
||||
"description": "The `server_host` configuration option in the HTTP integration is deprecated and will be removed.\n\nIf you are using this option to bind Home Assistant to specific network interfaces, please remove it from your configuration. Home Assistant will automatically bind to all available interfaces by default.\n\nIf you have specific networking requirements, consider using firewall rules or other network configuration to control access to Home Assistant.",
|
||||
"title": "The `server_host` HTTP configuration option is deprecated"
|
||||
},
|
||||
"server_host_deprecated_hassio": {
|
||||
"description": "The deprecated `server_host` configuration option in the HTTP integration is prone to break the communication between Home Assistant Core and Supervisor, and will be removed.\n\nIf you are using this option to bind Home Assistant to specific network interfaces, please remove it from your configuration. Home Assistant will automatically bind to all available interfaces by default.\n\nIf you have specific networking requirements, consider using firewall rules or other network configuration to control access to Home Assistant.",
|
||||
"title": "The `server_host` HTTP configuration may break Home Assistant Core - Supervisor communication"
|
||||
},
|
||||
"ssl_configured_without_configured_urls": {
|
||||
|
||||
@@ -486,4 +486,19 @@ DISCOVERY_SCHEMAS = [
|
||||
required_attributes=(clusters.RefrigeratorAlarm.Attributes.State,),
|
||||
allow_multi=True,
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.BINARY_SENSOR,
|
||||
entity_description=MatterBinarySensorEntityDescription(
|
||||
key="WindowCoveringConfigStatus",
|
||||
translation_key="window_covering_config_status",
|
||||
device_class=BinarySensorDeviceClass.RUNNING,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
# ConfigStatus is a bitmap – return True when the 'Operational' bit(s) is set
|
||||
device_to_ha=lambda x: bool(
|
||||
x & clusters.WindowCovering.Bitmaps.ConfigStatus.kOperational
|
||||
),
|
||||
),
|
||||
entity_class=MatterBinarySensor,
|
||||
required_attributes=(clusters.WindowCovering.Attributes.ConfigStatus,),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -103,6 +103,9 @@
|
||||
},
|
||||
"water_leak": {
|
||||
"name": "Water leak"
|
||||
},
|
||||
"window_covering_config_status": {
|
||||
"name": "Config status"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
|
||||
@@ -295,10 +295,6 @@ def async_setup_entry_rest(
|
||||
class BlockEntityDescription(EntityDescription):
|
||||
"""Class to describe a BLOCK entity."""
|
||||
|
||||
# BlockEntity does not support UNDEFINED or None,
|
||||
# restrict the type to str.
|
||||
name: str = ""
|
||||
|
||||
unit_fn: Callable[[dict], str] | None = None
|
||||
value: Callable[[Any], Any] = lambda val: val
|
||||
available: Callable[[Block], bool] | None = None
|
||||
@@ -311,10 +307,6 @@ class BlockEntityDescription(EntityDescription):
|
||||
class RpcEntityDescription(EntityDescription):
|
||||
"""Class to describe a RPC entity."""
|
||||
|
||||
# BlockEntity does not support UNDEFINED or None,
|
||||
# restrict the type to str.
|
||||
name: str = ""
|
||||
|
||||
sub_key: str | None = None
|
||||
|
||||
value: Callable[[Any, Any], Any] | None = None
|
||||
@@ -332,10 +324,6 @@ class RpcEntityDescription(EntityDescription):
|
||||
class RestEntityDescription(EntityDescription):
|
||||
"""Class to describe a REST entity."""
|
||||
|
||||
# BlockEntity does not support UNDEFINED or None,
|
||||
# restrict the type to str.
|
||||
name: str = ""
|
||||
|
||||
value: Callable[[dict, Any], Any] | None = None
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
"detected_objects": {
|
||||
"default": "mdi:account-group"
|
||||
},
|
||||
"detected_objects_with_channel_name": {
|
||||
"default": "mdi:account-group"
|
||||
},
|
||||
"gas_concentration": {
|
||||
"default": "mdi:gauge"
|
||||
},
|
||||
@@ -38,9 +41,21 @@
|
||||
"lamp_life": {
|
||||
"default": "mdi:progress-wrench"
|
||||
},
|
||||
"left_slot_level": {
|
||||
"default": "mdi:bottle-tonic-outline"
|
||||
},
|
||||
"left_slot_vial": {
|
||||
"default": "mdi:scent"
|
||||
},
|
||||
"operation": {
|
||||
"default": "mdi:cog-transfer"
|
||||
},
|
||||
"right_slot_level": {
|
||||
"default": "mdi:bottle-tonic-outline"
|
||||
},
|
||||
"right_slot_vial": {
|
||||
"default": "mdi:scent"
|
||||
},
|
||||
"self_test": {
|
||||
"default": "mdi:progress-wrench"
|
||||
},
|
||||
@@ -52,12 +67,6 @@
|
||||
},
|
||||
"valve_status": {
|
||||
"default": "mdi:valve"
|
||||
},
|
||||
"vial_level": {
|
||||
"default": "mdi:bottle-tonic-outline"
|
||||
},
|
||||
"vial_name": {
|
||||
"default": "mdi:scent"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -163,7 +163,29 @@
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"adc": {
|
||||
"name": "ADC"
|
||||
},
|
||||
"analog": {
|
||||
"name": "Analog"
|
||||
},
|
||||
"analog_value": {
|
||||
"name": "Analog value"
|
||||
},
|
||||
"analog_value_with_channel_name": {
|
||||
"name": "{channel_name} analog value"
|
||||
},
|
||||
"analog_with_channel_name": {
|
||||
"name": "{channel_name} analog"
|
||||
},
|
||||
"apparent_power_with_channel_name": {
|
||||
"name": "{channel_name} apparent power"
|
||||
},
|
||||
"average_temperature": {
|
||||
"name": "Average temperature"
|
||||
},
|
||||
"charger_state": {
|
||||
"name": "Charger state",
|
||||
"state": {
|
||||
"charger_charging": "[%key:common::state::charging%]",
|
||||
"charger_end": "Charge completed",
|
||||
@@ -175,10 +197,43 @@
|
||||
"charger_wait": "Charging paused by vehicle"
|
||||
}
|
||||
},
|
||||
"current_with_channel_name": {
|
||||
"name": "{channel_name} current"
|
||||
},
|
||||
"detected_objects": {
|
||||
"name": "Detected objects",
|
||||
"unit_of_measurement": "objects"
|
||||
},
|
||||
"detected_objects_with_channel_name": {
|
||||
"name": "{channel_name} detected objects",
|
||||
"unit_of_measurement": "objects"
|
||||
},
|
||||
"device_temperature": {
|
||||
"name": "Device temperature"
|
||||
},
|
||||
"energy_consumed": {
|
||||
"name": "Energy consumed"
|
||||
},
|
||||
"energy_consumed_with_channel_name": {
|
||||
"name": "{channel_name} energy consumed"
|
||||
},
|
||||
"energy_returned": {
|
||||
"name": "Energy returned"
|
||||
},
|
||||
"energy_returned_with_channel_name": {
|
||||
"name": "{channel_name} energy returned"
|
||||
},
|
||||
"energy_with_channel_name": {
|
||||
"name": "{channel_name} energy"
|
||||
},
|
||||
"frequency_with_channel_name": {
|
||||
"name": "{channel_name} frequency"
|
||||
},
|
||||
"gas_concentration": {
|
||||
"name": "Gas concentration"
|
||||
},
|
||||
"gas_detected": {
|
||||
"name": "Gas detected",
|
||||
"state": {
|
||||
"heavy": "Heavy",
|
||||
"mild": "Mild",
|
||||
@@ -196,21 +251,81 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"humidity_with_channel_name": {
|
||||
"name": "{channel_name} humidity"
|
||||
},
|
||||
"illuminance_level": {
|
||||
"name": "Illuminance level",
|
||||
"state": {
|
||||
"bright": "Bright",
|
||||
"dark": "Dark",
|
||||
"twilight": "Twilight"
|
||||
}
|
||||
},
|
||||
"lamp_life": {
|
||||
"name": "Lamp life"
|
||||
},
|
||||
"last_restart": {
|
||||
"name": "Last restart"
|
||||
},
|
||||
"left_slot_level": {
|
||||
"name": "Left slot level"
|
||||
},
|
||||
"left_slot_vial": {
|
||||
"name": "Left slot vial"
|
||||
},
|
||||
"neutral_current": {
|
||||
"name": "Neutral current"
|
||||
},
|
||||
"operation": {
|
||||
"name": "Operation",
|
||||
"state": {
|
||||
"fault": "[%key:common::state::fault%]",
|
||||
"normal": "[%key:common::state::normal%]",
|
||||
"warmup": "Warm-up"
|
||||
}
|
||||
},
|
||||
"power_factor_with_channel_name": {
|
||||
"name": "{channel_name} power factor"
|
||||
},
|
||||
"power_with_channel_name": {
|
||||
"name": "{channel_name} power"
|
||||
},
|
||||
"pulse_counter": {
|
||||
"name": "Pulse counter"
|
||||
},
|
||||
"pulse_counter_frequency": {
|
||||
"name": "Pulse counter frequency"
|
||||
},
|
||||
"pulse_counter_frequency_value": {
|
||||
"name": "Pulse counter frequency value"
|
||||
},
|
||||
"pulse_counter_frequency_value_with_channel_name": {
|
||||
"name": "{channel_name} pulse counter frequency value"
|
||||
},
|
||||
"pulse_counter_frequency_with_channel_name": {
|
||||
"name": "{channel_name} pulse counter frequency"
|
||||
},
|
||||
"pulse_counter_value": {
|
||||
"name": "Pulse counter value"
|
||||
},
|
||||
"pulse_counter_value_with_channel_name": {
|
||||
"name": "{channel_name} Pulse counter value"
|
||||
},
|
||||
"pulse_counter_with_channel_name": {
|
||||
"name": "{channel_name} pulse counter"
|
||||
},
|
||||
"rainfall_last_24h": {
|
||||
"name": "Rainfall last 24h"
|
||||
},
|
||||
"right_slot_level": {
|
||||
"name": "Right slot level"
|
||||
},
|
||||
"right_slot_vial": {
|
||||
"name": "Right slot vial"
|
||||
},
|
||||
"self_test": {
|
||||
"name": "Self test",
|
||||
"state": {
|
||||
"completed": "Completed",
|
||||
"not_completed": "Not completed",
|
||||
@@ -228,7 +343,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"session_duration": {
|
||||
"name": "Session duration"
|
||||
},
|
||||
"session_energy": {
|
||||
"name": "Session energy"
|
||||
},
|
||||
"temperature_with_channel_name": {
|
||||
"name": "{channel_name} temperature"
|
||||
},
|
||||
"tilt": {
|
||||
"name": "Tilt"
|
||||
},
|
||||
"valve_position": {
|
||||
"name": "Valve position"
|
||||
},
|
||||
"valve_status": {
|
||||
"name": "Valve status",
|
||||
"state": {
|
||||
"checking": "Checking",
|
||||
"closed": "[%key:common::state::closed%]",
|
||||
@@ -237,6 +368,30 @@
|
||||
"opened": "Opened",
|
||||
"opening": "[%key:common::state::opening%]"
|
||||
}
|
||||
},
|
||||
"voltage_with_channel_name": {
|
||||
"name": "{channel_name} voltage"
|
||||
},
|
||||
"voltage_with_phase_name": {
|
||||
"name": "Phase {phase_name} voltage"
|
||||
},
|
||||
"voltmeter": {
|
||||
"name": "Voltmeter"
|
||||
},
|
||||
"voltmeter_value": {
|
||||
"name": "Voltmeter value"
|
||||
},
|
||||
"water_consumption": {
|
||||
"name": "Water consumption"
|
||||
},
|
||||
"water_flow_rate": {
|
||||
"name": "Water flow rate"
|
||||
},
|
||||
"water_pressure": {
|
||||
"name": "Water pressure"
|
||||
},
|
||||
"water_temperature": {
|
||||
"name": "Water temperature"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -49,6 +49,7 @@ from homeassistant.helpers.device_registry import (
|
||||
DeviceInfo,
|
||||
)
|
||||
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
||||
from homeassistant.helpers.typing import UNDEFINED, UndefinedType
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from .const import (
|
||||
@@ -119,12 +120,12 @@ def get_number_of_channels(device: BlockDevice, block: Block) -> int:
|
||||
def get_block_entity_name(
|
||||
device: BlockDevice,
|
||||
block: Block | None,
|
||||
description: str | None = None,
|
||||
description: str | UndefinedType | None = None,
|
||||
) -> str | None:
|
||||
"""Naming for block based switch and sensors."""
|
||||
channel_name = get_block_channel_name(device, block)
|
||||
|
||||
if description:
|
||||
if description is not UNDEFINED and description:
|
||||
return f"{channel_name} {description.lower()}" if channel_name else description
|
||||
|
||||
return channel_name
|
||||
@@ -442,12 +443,15 @@ def get_rpc_sub_device_name(
|
||||
|
||||
|
||||
def get_rpc_entity_name(
|
||||
device: RpcDevice, key: str, name: str | None = None, role: str | None = None
|
||||
device: RpcDevice,
|
||||
key: str,
|
||||
name: str | UndefinedType | None = None,
|
||||
role: str | None = None,
|
||||
) -> str | None:
|
||||
"""Naming for RPC based switch and sensors."""
|
||||
channel_name = get_rpc_channel_name(device, key)
|
||||
|
||||
if name:
|
||||
if name is not UNDEFINED and name:
|
||||
if role and role != ROLE_GENERIC:
|
||||
return name
|
||||
return f"{channel_name} {name.lower()}" if channel_name else name
|
||||
|
||||
@@ -6,7 +6,7 @@ import base64
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
import struct
|
||||
from typing import Literal, Self, overload
|
||||
from typing import Any, Literal, Self, overload
|
||||
|
||||
from tuya_sharing import CustomerDevice
|
||||
|
||||
@@ -14,6 +14,76 @@ from .const import DPCode, DPType
|
||||
from .util import remap_value
|
||||
|
||||
|
||||
@dataclass
|
||||
class DPCodeWrapper:
|
||||
"""Base DPCode wrapper.
|
||||
|
||||
Used as a common interface for referring to a DPCode, and
|
||||
access read conversion routines.
|
||||
"""
|
||||
|
||||
dpcode: str
|
||||
|
||||
def _read_device_status_raw(self, device: CustomerDevice) -> Any | None:
|
||||
"""Read the raw device status for the DPCode.
|
||||
|
||||
Private helper method for `read_device_status`.
|
||||
"""
|
||||
return device.status.get(self.dpcode)
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> Any | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
raise NotImplementedError("read_device_value must be implemented")
|
||||
|
||||
|
||||
@dataclass
|
||||
class DPCodeBooleanWrapper(DPCodeWrapper):
|
||||
"""Simple wrapper for boolean values.
|
||||
|
||||
Supports True/False only.
|
||||
"""
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> bool | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (raw_value := self._read_device_status_raw(device)) in (True, False):
|
||||
return raw_value
|
||||
return None
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class DPCodeEnumWrapper(DPCodeWrapper):
|
||||
"""Simple wrapper for EnumTypeData values."""
|
||||
|
||||
enum_type_information: EnumTypeData
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> str | None:
|
||||
"""Read the device value for the dpcode.
|
||||
|
||||
Values outside of the list defined by the Enum type information will
|
||||
return None.
|
||||
"""
|
||||
if (
|
||||
raw_value := self._read_device_status_raw(device)
|
||||
) in self.enum_type_information.range:
|
||||
return raw_value
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def find_dpcode(
|
||||
cls,
|
||||
device: CustomerDevice,
|
||||
dpcodes: str | DPCode | tuple[DPCode, ...],
|
||||
*,
|
||||
prefer_function: bool = False,
|
||||
) -> Self | None:
|
||||
"""Find and return a DPCodeEnumWrapper for the given DP codes."""
|
||||
if enum_type := find_dpcode(
|
||||
device, dpcodes, dptype=DPType.ENUM, prefer_function=prefer_function
|
||||
):
|
||||
return cls(dpcode=enum_type.dpcode, enum_type_information=enum_type)
|
||||
return None
|
||||
|
||||
|
||||
@overload
|
||||
def find_dpcode(
|
||||
device: CustomerDevice,
|
||||
|
||||
@@ -11,9 +11,9 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode, DPType
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
|
||||
from .entity import TuyaEntity
|
||||
from .models import find_dpcode
|
||||
from .models import DPCodeEnumWrapper
|
||||
|
||||
# All descriptions can be found here. Mostly the Enum data types in the
|
||||
# default instructions set of each category end up being a select.
|
||||
@@ -360,9 +360,15 @@ async def async_setup_entry(
|
||||
device = manager.device_map[device_id]
|
||||
if descriptions := SELECTS.get(device.category):
|
||||
entities.extend(
|
||||
TuyaSelectEntity(device, manager, description)
|
||||
TuyaSelectEntity(
|
||||
device, manager, description, dpcode_wrapper=dpcode_wrapper
|
||||
)
|
||||
for description in descriptions
|
||||
if description.key in device.status
|
||||
if (
|
||||
dpcode_wrapper := DPCodeEnumWrapper.find_dpcode(
|
||||
device, description.key, prefer_function=True
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
@@ -382,35 +388,20 @@ class TuyaSelectEntity(TuyaEntity, SelectEntity):
|
||||
device: CustomerDevice,
|
||||
device_manager: Manager,
|
||||
description: SelectEntityDescription,
|
||||
dpcode_wrapper: DPCodeEnumWrapper,
|
||||
) -> None:
|
||||
"""Init Tuya sensor."""
|
||||
super().__init__(device, device_manager)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
||||
|
||||
self._attr_options: list[str] = []
|
||||
if enum_type := find_dpcode(
|
||||
self.device, description.key, dptype=DPType.ENUM, prefer_function=True
|
||||
):
|
||||
self._attr_options = enum_type.range
|
||||
self._dpcode_wrapper = dpcode_wrapper
|
||||
self._attr_options = dpcode_wrapper.enum_type_information.range
|
||||
|
||||
@property
|
||||
def current_option(self) -> str | None:
|
||||
"""Return the selected entity option to represent the entity state."""
|
||||
# Raw value
|
||||
value = self.device.status.get(self.entity_description.key)
|
||||
if value is None or value not in self._attr_options:
|
||||
return None
|
||||
|
||||
return value
|
||||
return self._dpcode_wrapper.read_device_status(self.device)
|
||||
|
||||
def select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
self._send_command(
|
||||
[
|
||||
{
|
||||
"code": self.entity_description.key,
|
||||
"value": option,
|
||||
}
|
||||
]
|
||||
)
|
||||
self._send_command([{"code": self._dpcode_wrapper.dpcode, "value": option}])
|
||||
|
||||
@@ -27,6 +27,7 @@ from homeassistant.helpers.issue_registry import (
|
||||
from . import TuyaConfigEntry
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
|
||||
from .entity import TuyaEntity
|
||||
from .models import DPCodeBooleanWrapper
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
@@ -938,7 +939,12 @@ async def async_setup_entry(
|
||||
device = manager.device_map[device_id]
|
||||
if descriptions := SWITCHES.get(device.category):
|
||||
entities.extend(
|
||||
TuyaSwitchEntity(device, manager, description)
|
||||
TuyaSwitchEntity(
|
||||
device,
|
||||
manager,
|
||||
description,
|
||||
DPCodeBooleanWrapper(description.key),
|
||||
)
|
||||
for description in descriptions
|
||||
if description.key in device.status
|
||||
and _check_deprecation(
|
||||
@@ -1015,21 +1021,23 @@ class TuyaSwitchEntity(TuyaEntity, SwitchEntity):
|
||||
device: CustomerDevice,
|
||||
device_manager: Manager,
|
||||
description: SwitchEntityDescription,
|
||||
dpcode_wrapper: DPCodeBooleanWrapper,
|
||||
) -> None:
|
||||
"""Init TuyaHaSwitch."""
|
||||
super().__init__(device, device_manager)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
||||
self._dpcode_wrapper = dpcode_wrapper
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if switch is on."""
|
||||
return self.device.status.get(self.entity_description.key, False)
|
||||
return self._dpcode_wrapper.read_device_status(self.device)
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
self._send_command([{"code": self.entity_description.key, "value": True}])
|
||||
self._send_command([{"code": self._dpcode_wrapper.dpcode, "value": True}])
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch off."""
|
||||
self._send_command([{"code": self.entity_description.key, "value": False}])
|
||||
self._send_command([{"code": self._dpcode_wrapper.dpcode, "value": False}])
|
||||
|
||||
@@ -17,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
|
||||
from .entity import TuyaEntity
|
||||
from .models import DPCodeBooleanWrapper
|
||||
|
||||
VALVES: dict[DeviceCategory, tuple[ValveEntityDescription, ...]] = {
|
||||
DeviceCategory.SFKZQ: (
|
||||
@@ -93,7 +94,12 @@ async def async_setup_entry(
|
||||
device = manager.device_map[device_id]
|
||||
if descriptions := VALVES.get(device.category):
|
||||
entities.extend(
|
||||
TuyaValveEntity(device, manager, description)
|
||||
TuyaValveEntity(
|
||||
device,
|
||||
manager,
|
||||
description,
|
||||
DPCodeBooleanWrapper(description.key),
|
||||
)
|
||||
for description in descriptions
|
||||
if description.key in device.status
|
||||
)
|
||||
@@ -117,25 +123,29 @@ class TuyaValveEntity(TuyaEntity, ValveEntity):
|
||||
device: CustomerDevice,
|
||||
device_manager: Manager,
|
||||
description: ValveEntityDescription,
|
||||
dpcode_wrapper: DPCodeBooleanWrapper,
|
||||
) -> None:
|
||||
"""Init TuyaValveEntity."""
|
||||
super().__init__(device, device_manager)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
||||
self._dpcode_wrapper = dpcode_wrapper
|
||||
|
||||
@property
|
||||
def is_closed(self) -> bool:
|
||||
def is_closed(self) -> bool | None:
|
||||
"""Return if the valve is closed."""
|
||||
return not self.device.status.get(self.entity_description.key, False)
|
||||
if (is_open := self._dpcode_wrapper.read_device_status(self.device)) is None:
|
||||
return None
|
||||
return not is_open
|
||||
|
||||
async def async_open_valve(self) -> None:
|
||||
"""Open the valve."""
|
||||
await self.hass.async_add_executor_job(
|
||||
self._send_command, [{"code": self.entity_description.key, "value": True}]
|
||||
self._send_command, [{"code": self._dpcode_wrapper.dpcode, "value": True}]
|
||||
)
|
||||
|
||||
async def async_close_valve(self) -> None:
|
||||
"""Close the valve."""
|
||||
await self.hass.async_add_executor_job(
|
||||
self._send_command, [{"code": self.entity_description.key, "value": False}]
|
||||
self._send_command, [{"code": self._dpcode_wrapper.dpcode, "value": False}]
|
||||
)
|
||||
|
||||
@@ -41,8 +41,11 @@ from homeassistant.helpers import (
|
||||
template,
|
||||
)
|
||||
from homeassistant.helpers.condition import (
|
||||
async_from_config as async_condition_from_config,
|
||||
async_get_all_descriptions as async_get_all_condition_descriptions,
|
||||
async_subscribe_platform_events as async_subscribe_condition_platform_events,
|
||||
async_validate_condition_config,
|
||||
async_validate_conditions_config,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
@@ -66,7 +69,9 @@ from homeassistant.helpers.service import (
|
||||
)
|
||||
from homeassistant.helpers.trigger import (
|
||||
async_get_all_descriptions as async_get_all_trigger_descriptions,
|
||||
async_initialize_triggers,
|
||||
async_subscribe_platform_events as async_subscribe_trigger_platform_events,
|
||||
async_validate_trigger_config,
|
||||
)
|
||||
from homeassistant.loader import (
|
||||
IntegrationNotFound,
|
||||
@@ -885,10 +890,7 @@ async def handle_subscribe_trigger(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Handle subscribe trigger command."""
|
||||
# Circular dep
|
||||
from homeassistant.helpers import trigger # noqa: PLC0415
|
||||
|
||||
trigger_config = await trigger.async_validate_trigger_config(hass, msg["trigger"])
|
||||
trigger_config = await async_validate_trigger_config(hass, msg["trigger"])
|
||||
|
||||
@callback
|
||||
def forward_triggers(
|
||||
@@ -905,7 +907,7 @@ async def handle_subscribe_trigger(
|
||||
)
|
||||
|
||||
connection.subscriptions[msg["id"]] = (
|
||||
await trigger.async_initialize_triggers(
|
||||
await async_initialize_triggers(
|
||||
hass,
|
||||
trigger_config,
|
||||
forward_triggers,
|
||||
@@ -935,13 +937,10 @@ async def handle_test_condition(
|
||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||
) -> None:
|
||||
"""Handle test condition command."""
|
||||
# Circular dep
|
||||
from homeassistant.helpers import condition # noqa: PLC0415
|
||||
|
||||
# Do static + dynamic validation of the condition
|
||||
config = await condition.async_validate_condition_config(hass, msg["condition"])
|
||||
config = await async_validate_condition_config(hass, msg["condition"])
|
||||
# Test the condition
|
||||
check_condition = await condition.async_from_config(hass, config)
|
||||
check_condition = await async_condition_from_config(hass, config)
|
||||
connection.send_result(
|
||||
msg["id"], {"result": check_condition(hass, msg.get("variables"))}
|
||||
)
|
||||
@@ -1028,16 +1027,16 @@ async def handle_validate_config(
|
||||
) -> None:
|
||||
"""Handle validate config command."""
|
||||
# Circular dep
|
||||
from homeassistant.helpers import condition, script, trigger # noqa: PLC0415
|
||||
from homeassistant.helpers import script # noqa: PLC0415
|
||||
|
||||
result = {}
|
||||
|
||||
for key, schema, validator in (
|
||||
("triggers", cv.TRIGGER_SCHEMA, trigger.async_validate_trigger_config),
|
||||
("triggers", cv.TRIGGER_SCHEMA, async_validate_trigger_config),
|
||||
(
|
||||
"conditions",
|
||||
cv.CONDITIONS_SCHEMA,
|
||||
condition.async_validate_conditions_config,
|
||||
async_validate_conditions_config,
|
||||
),
|
||||
("actions", cv.SCRIPT_SCHEMA, script.async_validate_actions_config),
|
||||
):
|
||||
|
||||
@@ -25,7 +25,6 @@ from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_ENTITY_PICTURE,
|
||||
ATTR_FRIENDLY_NAME,
|
||||
ATTR_ICON,
|
||||
@@ -527,9 +526,6 @@ class Entity(
|
||||
__capabilities_updated_at_reported: bool = False
|
||||
__remove_future: asyncio.Future[None] | None = None
|
||||
|
||||
# Remember we keep track of included entities
|
||||
__init_track_included_entities: bool = False
|
||||
|
||||
# Entity Properties
|
||||
_attr_assumed_state: bool = False
|
||||
_attr_attribution: str | None = None
|
||||
@@ -545,8 +541,6 @@ class Entity(
|
||||
_attr_extra_state_attributes: dict[str, Any]
|
||||
_attr_force_update: bool
|
||||
_attr_icon: str | None
|
||||
_attr_included_entities: list[str]
|
||||
_attr_included_unique_ids: list[str]
|
||||
_attr_name: str | None
|
||||
_attr_should_poll: bool = True
|
||||
_attr_state: StateType = STATE_UNKNOWN
|
||||
@@ -1093,8 +1087,6 @@ class Entity(
|
||||
available = self.available # only call self.available once per update cycle
|
||||
state = self._stringify_state(available)
|
||||
if available:
|
||||
if self._included_entities:
|
||||
attr[ATTR_ENTITY_ID] = self._included_entities.copy()
|
||||
if state_attributes := self.state_attributes:
|
||||
attr |= state_attributes
|
||||
if extra_state_attributes := self.extra_state_attributes:
|
||||
@@ -1386,7 +1378,6 @@ class Entity(
|
||||
"""Finish adding an entity to a platform."""
|
||||
await self.async_internal_added_to_hass()
|
||||
await self.async_added_to_hass()
|
||||
self.async_set_included_entities()
|
||||
self._platform_state = EntityPlatformState.ADDED
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -1644,67 +1635,6 @@ class Entity(
|
||||
self.hass, integration_domain=platform_name, module=type(self).__module__
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_set_included_entities(self) -> None:
|
||||
"""Set the list of included entities identified by their unique IDs.
|
||||
|
||||
Integrations need to when the list of included entities changes.
|
||||
"""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
assert self.entity_id is not None
|
||||
|
||||
def _update_group_entity_ids() -> None:
|
||||
self._attr_included_entities = []
|
||||
for included_id in self.included_unique_ids:
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
self.platform.domain, self.platform.platform_name, included_id
|
||||
):
|
||||
self._attr_included_entities.append(entity_id)
|
||||
|
||||
async def _handle_entity_registry_updated(event: Event[Any]) -> None:
|
||||
"""Handle registry create or update event."""
|
||||
if (
|
||||
event.data["action"] in {"create", "update"}
|
||||
and (entry := entity_registry.async_get(event.data["entity_id"]))
|
||||
and entry.unique_id in self.included_unique_ids
|
||||
) or (
|
||||
event.data["action"] == "remove"
|
||||
and self._included_entities is not None
|
||||
and event.data["entity_id"] in self._included_entities
|
||||
):
|
||||
_update_group_entity_ids()
|
||||
self.async_write_ha_state()
|
||||
|
||||
if not self.__init_track_included_entities:
|
||||
self.async_on_remove(
|
||||
self.hass.bus.async_listen(
|
||||
er.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
_handle_entity_registry_updated,
|
||||
)
|
||||
)
|
||||
self.__init_track_included_entities = True
|
||||
_update_group_entity_ids()
|
||||
|
||||
@property
|
||||
def included_unique_ids(self) -> list[str]:
|
||||
"""Return the list of unique IDs if the entity represents a group.
|
||||
|
||||
The corresponding entities will be shown as members in the UI.
|
||||
"""
|
||||
if hasattr(self, "_attr_included_unique_ids"):
|
||||
return self._attr_included_unique_ids
|
||||
return []
|
||||
|
||||
@property
|
||||
def _included_entities(self) -> list[str] | None:
|
||||
"""Return a list of entity IDs if the entity represents a group.
|
||||
|
||||
Included entities will be shown as members in the UI.
|
||||
"""
|
||||
if hasattr(self, "_attr_included_entities"):
|
||||
return self._attr_included_entities
|
||||
return None
|
||||
|
||||
|
||||
class ToggleEntityDescription(EntityDescription, frozen_or_thawed=True):
|
||||
"""A class that describes toggle entities."""
|
||||
|
||||
@@ -47,7 +47,19 @@ async def test_setup_entry_maintenance(
|
||||
|
||||
|
||||
async def test_setup_gateway_offline(hass: HomeAssistant) -> None:
|
||||
"""Test setup entry fails on gateway offline."""
|
||||
"""Test setup entry with one gateway online and one gateway offline."""
|
||||
entry = configure_integration(hass)
|
||||
test_gateway = HomeControlMock()
|
||||
with patch(
|
||||
"homeassistant.components.devolo_home_control.HomeControl",
|
||||
side_effect=[test_gateway, GatewayOfflineError],
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
|
||||
|
||||
async def test_setup_all_gateways_offline(hass: HomeAssistant) -> None:
|
||||
"""Test setup entry fails on all gateways offline."""
|
||||
entry = configure_integration(hass)
|
||||
with patch(
|
||||
"homeassistant.components.devolo_home_control.HomeControl",
|
||||
|
||||
@@ -683,19 +683,27 @@ async def test_ssl_issue_urls_configured(
|
||||
"hassio",
|
||||
"http_config",
|
||||
"expected_serverhost",
|
||||
"expected_warning_count",
|
||||
"expected_issues",
|
||||
),
|
||||
[
|
||||
(False, {}, ["0.0.0.0", "::"], set()),
|
||||
(False, {"server_host": "0.0.0.0"}, ["0.0.0.0"], set()),
|
||||
(True, {}, ["0.0.0.0", "::"], set()),
|
||||
(False, {}, ["0.0.0.0", "::"], 0, set()),
|
||||
(
|
||||
False,
|
||||
{"server_host": "0.0.0.0"},
|
||||
["0.0.0.0"],
|
||||
1,
|
||||
{("http", "server_host_deprecated")},
|
||||
),
|
||||
(True, {}, ["0.0.0.0", "::"], 0, set()),
|
||||
(
|
||||
True,
|
||||
{"server_host": "0.0.0.0"},
|
||||
[
|
||||
"0.0.0.0",
|
||||
],
|
||||
{("http", "server_host_may_break_hassio")},
|
||||
1,
|
||||
{("http", "server_host_deprecated_hassio")},
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -705,7 +713,9 @@ async def test_server_host(
|
||||
issue_registry: ir.IssueRegistry,
|
||||
http_config: dict,
|
||||
expected_serverhost: list,
|
||||
expected_warning_count: int,
|
||||
expected_issues: set[tuple[str, str]],
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test server_host behavior."""
|
||||
mock_server = Mock()
|
||||
@@ -733,4 +743,11 @@ async def test_server_host(
|
||||
reuse_port=None,
|
||||
)
|
||||
|
||||
assert (
|
||||
caplog.text.count(
|
||||
"The 'server_host' option is deprecated, please remove it from your configuration"
|
||||
)
|
||||
== expected_warning_count
|
||||
)
|
||||
|
||||
assert set(issue_registry.issues) == expected_issues
|
||||
|
||||
@@ -94,6 +94,7 @@ async def integration_fixture(
|
||||
"eve_energy_20ecn4101",
|
||||
"eve_energy_plug",
|
||||
"eve_energy_plug_patched",
|
||||
"eve_shutter",
|
||||
"eve_thermo",
|
||||
"eve_weather_sensor",
|
||||
"extended_color_light",
|
||||
|
||||
617
tests/components/matter/fixtures/nodes/eve_shutter.json
Normal file
617
tests/components/matter/fixtures/nodes/eve_shutter.json
Normal file
@@ -0,0 +1,617 @@
|
||||
{
|
||||
"node_id": 148,
|
||||
"date_commissioned": "2025-11-07T16:57:31.360667",
|
||||
"last_interview": "2025-11-07T16:57:31.360690",
|
||||
"interview_version": 6,
|
||||
"available": true,
|
||||
"is_bridge": false,
|
||||
"attributes": {
|
||||
"0/29/0": [
|
||||
{
|
||||
"0": 18,
|
||||
"1": 1
|
||||
},
|
||||
{
|
||||
"0": 22,
|
||||
"1": 3
|
||||
}
|
||||
],
|
||||
"0/29/1": [29, 31, 40, 42, 48, 49, 50, 51, 52, 53, 56, 60, 62, 63],
|
||||
"0/29/2": [41],
|
||||
"0/29/3": [1],
|
||||
"0/29/65532": 0,
|
||||
"0/29/65533": 2,
|
||||
"0/29/65528": [],
|
||||
"0/29/65529": [],
|
||||
"0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/31/0": [
|
||||
{
|
||||
"1": 5,
|
||||
"2": 2,
|
||||
"3": [112233],
|
||||
"4": null,
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/31/1": [],
|
||||
"0/31/2": 10,
|
||||
"0/31/3": 3,
|
||||
"0/31/4": 5,
|
||||
"0/31/65532": 1,
|
||||
"0/31/65533": 2,
|
||||
"0/31/65528": [],
|
||||
"0/31/65529": [],
|
||||
"0/31/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/40/0": 18,
|
||||
"0/40/1": "Eve Systems",
|
||||
"0/40/2": 4874,
|
||||
"0/40/3": "Eve Shutter Switch 20ECI1701",
|
||||
"0/40/4": 96,
|
||||
"0/40/5": "",
|
||||
"0/40/6": "**REDACTED**",
|
||||
"0/40/7": 1,
|
||||
"0/40/8": "1.1",
|
||||
"0/40/9": 10203,
|
||||
"0/40/10": "3.6.1",
|
||||
"0/40/15": "**********",
|
||||
"0/40/18": "**********",
|
||||
"0/40/19": {
|
||||
"0": 3,
|
||||
"1": 3
|
||||
},
|
||||
"0/40/21": 17039616,
|
||||
"0/40/22": 1,
|
||||
"0/40/65532": 0,
|
||||
"0/40/65533": 4,
|
||||
"0/40/65528": [],
|
||||
"0/40/65529": [],
|
||||
"0/40/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 18, 19, 21, 22, 65528, 65529, 65531,
|
||||
65532, 65533
|
||||
],
|
||||
"0/42/0": [],
|
||||
"0/42/1": true,
|
||||
"0/42/2": 1,
|
||||
"0/42/3": null,
|
||||
"0/42/65532": 0,
|
||||
"0/42/65533": 1,
|
||||
"0/42/65528": [],
|
||||
"0/42/65529": [0],
|
||||
"0/42/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/48/0": 0,
|
||||
"0/48/1": {
|
||||
"0": 60,
|
||||
"1": 900
|
||||
},
|
||||
"0/48/2": 0,
|
||||
"0/48/3": 0,
|
||||
"0/48/4": true,
|
||||
"0/48/65532": 0,
|
||||
"0/48/65533": 2,
|
||||
"0/48/65528": [1, 3, 5],
|
||||
"0/48/65529": [0, 2, 4],
|
||||
"0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/49/0": 1,
|
||||
"0/49/1": [
|
||||
{
|
||||
"0": "p0jbsOzJRNw=",
|
||||
"1": true
|
||||
}
|
||||
],
|
||||
"0/49/2": 10,
|
||||
"0/49/3": 20,
|
||||
"0/49/4": true,
|
||||
"0/49/5": 0,
|
||||
"0/49/6": "p0jbsOzJRNw=",
|
||||
"0/49/7": null,
|
||||
"0/49/9": 10,
|
||||
"0/49/10": 5,
|
||||
"0/49/65532": 2,
|
||||
"0/49/65533": 2,
|
||||
"0/49/65528": [1, 5, 7],
|
||||
"0/49/65529": [0, 3, 4, 6, 8],
|
||||
"0/49/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"0/50/65532": 0,
|
||||
"0/50/65533": 1,
|
||||
"0/50/65528": [1],
|
||||
"0/50/65529": [0],
|
||||
"0/50/65531": [65528, 65529, 65531, 65532, 65533],
|
||||
"0/51/0": [
|
||||
{
|
||||
"0": "ieee802154",
|
||||
"1": true,
|
||||
"2": null,
|
||||
"3": null,
|
||||
"4": "Wi5/8pP0edY=",
|
||||
"5": [],
|
||||
"6": [],
|
||||
"7": 4
|
||||
}
|
||||
],
|
||||
"0/51/1": 1,
|
||||
"0/51/2": 213,
|
||||
"0/51/3": 0,
|
||||
"0/51/5": [],
|
||||
"0/51/6": [],
|
||||
"0/51/7": [],
|
||||
"0/51/8": false,
|
||||
"0/51/65532": 0,
|
||||
"0/51/65533": 2,
|
||||
"0/51/65528": [2],
|
||||
"0/51/65529": [0, 1],
|
||||
"0/51/65531": [0, 1, 2, 3, 5, 6, 7, 8, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/52/1": 10104,
|
||||
"0/52/2": 2008,
|
||||
"0/52/65532": 0,
|
||||
"0/52/65533": 1,
|
||||
"0/52/65528": [],
|
||||
"0/52/65529": [],
|
||||
"0/52/65531": [1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/53/0": 25,
|
||||
"0/53/1": 5,
|
||||
"0/53/2": "MyHome",
|
||||
"0/53/3": 4660,
|
||||
"0/53/4": 12054125955590472924,
|
||||
"0/53/5": "QP0ADbgAoAAA",
|
||||
"0/53/6": 0,
|
||||
"0/53/7": [
|
||||
{
|
||||
"0": 12864791528929066571,
|
||||
"1": 28,
|
||||
"2": 11264,
|
||||
"3": 411672,
|
||||
"4": 11555,
|
||||
"5": 3,
|
||||
"6": -53,
|
||||
"7": -53,
|
||||
"8": 44,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 13438285129078731668,
|
||||
"1": 16,
|
||||
"2": 18432,
|
||||
"3": 50641,
|
||||
"4": 10901,
|
||||
"5": 1,
|
||||
"6": -89,
|
||||
"7": -89,
|
||||
"8": 0,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 8265194500311707858,
|
||||
"1": 51,
|
||||
"2": 24576,
|
||||
"3": 75011,
|
||||
"4": 10782,
|
||||
"5": 2,
|
||||
"6": -84,
|
||||
"7": -84,
|
||||
"8": 0,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 14318601490803184919,
|
||||
"1": 16,
|
||||
"2": 27648,
|
||||
"3": 310236,
|
||||
"4": 10937,
|
||||
"5": 3,
|
||||
"6": -50,
|
||||
"7": -50,
|
||||
"8": 20,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 2202349555917590819,
|
||||
"1": 22,
|
||||
"2": 45056,
|
||||
"3": 86183,
|
||||
"4": 25554,
|
||||
"5": 3,
|
||||
"6": -78,
|
||||
"7": -85,
|
||||
"8": 3,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 4206032556233211940,
|
||||
"1": 63,
|
||||
"2": 53248,
|
||||
"3": 80879,
|
||||
"4": 10668,
|
||||
"5": 3,
|
||||
"6": -78,
|
||||
"7": -77,
|
||||
"8": 3,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 7085268071783685380,
|
||||
"1": 15,
|
||||
"2": 54272,
|
||||
"3": 4269,
|
||||
"4": 3159,
|
||||
"5": 3,
|
||||
"6": -76,
|
||||
"7": -74,
|
||||
"8": 0,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
},
|
||||
{
|
||||
"0": 10848996971365580420,
|
||||
"1": 17,
|
||||
"2": 60416,
|
||||
"3": 318410,
|
||||
"4": 10506,
|
||||
"5": 3,
|
||||
"6": -61,
|
||||
"7": -62,
|
||||
"8": 43,
|
||||
"9": 0,
|
||||
"10": true,
|
||||
"11": true,
|
||||
"12": true,
|
||||
"13": false
|
||||
}
|
||||
],
|
||||
"0/53/8": [
|
||||
{
|
||||
"0": 12864791528929066571,
|
||||
"1": 11264,
|
||||
"2": 11,
|
||||
"3": 27,
|
||||
"4": 1,
|
||||
"5": 3,
|
||||
"6": 3,
|
||||
"7": 28,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 13438285129078731668,
|
||||
"1": 18432,
|
||||
"2": 18,
|
||||
"3": 53,
|
||||
"4": 1,
|
||||
"5": 1,
|
||||
"6": 2,
|
||||
"7": 16,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 8265194500311707858,
|
||||
"1": 24576,
|
||||
"2": 24,
|
||||
"3": 52,
|
||||
"4": 1,
|
||||
"5": 2,
|
||||
"6": 3,
|
||||
"7": 51,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 14318601490803184919,
|
||||
"1": 27648,
|
||||
"2": 27,
|
||||
"3": 11,
|
||||
"4": 1,
|
||||
"5": 3,
|
||||
"6": 3,
|
||||
"7": 16,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 6498271992183290326,
|
||||
"1": 40960,
|
||||
"2": 40,
|
||||
"3": 63,
|
||||
"4": 0,
|
||||
"5": 0,
|
||||
"6": 0,
|
||||
"7": 0,
|
||||
"8": true,
|
||||
"9": false
|
||||
},
|
||||
{
|
||||
"0": 2202349555917590819,
|
||||
"1": 45056,
|
||||
"2": 44,
|
||||
"3": 27,
|
||||
"4": 1,
|
||||
"5": 3,
|
||||
"6": 2,
|
||||
"7": 22,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 4206032556233211940,
|
||||
"1": 53248,
|
||||
"2": 52,
|
||||
"3": 59,
|
||||
"4": 1,
|
||||
"5": 3,
|
||||
"6": 3,
|
||||
"7": 63,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 7085268071783685380,
|
||||
"1": 54272,
|
||||
"2": 53,
|
||||
"3": 27,
|
||||
"4": 2,
|
||||
"5": 3,
|
||||
"6": 3,
|
||||
"7": 15,
|
||||
"8": true,
|
||||
"9": true
|
||||
},
|
||||
{
|
||||
"0": 10848996971365580420,
|
||||
"1": 60416,
|
||||
"2": 59,
|
||||
"3": 11,
|
||||
"4": 1,
|
||||
"5": 3,
|
||||
"6": 3,
|
||||
"7": 17,
|
||||
"8": true,
|
||||
"9": true
|
||||
}
|
||||
],
|
||||
"0/53/9": 1938283056,
|
||||
"0/53/10": 68,
|
||||
"0/53/11": 65,
|
||||
"0/53/12": 8,
|
||||
"0/53/13": 27,
|
||||
"0/53/14": 1,
|
||||
"0/53/15": 1,
|
||||
"0/53/16": 1,
|
||||
"0/53/17": 0,
|
||||
"0/53/18": 1,
|
||||
"0/53/19": 1,
|
||||
"0/53/20": 0,
|
||||
"0/53/21": 0,
|
||||
"0/53/22": 759,
|
||||
"0/53/23": 737,
|
||||
"0/53/24": 22,
|
||||
"0/53/25": 737,
|
||||
"0/53/26": 737,
|
||||
"0/53/27": 22,
|
||||
"0/53/28": 759,
|
||||
"0/53/29": 0,
|
||||
"0/53/30": 0,
|
||||
"0/53/31": 0,
|
||||
"0/53/32": 0,
|
||||
"0/53/33": 529,
|
||||
"0/53/34": 0,
|
||||
"0/53/35": 0,
|
||||
"0/53/36": 0,
|
||||
"0/53/37": 0,
|
||||
"0/53/38": 0,
|
||||
"0/53/39": 3405,
|
||||
"0/53/40": 275,
|
||||
"0/53/41": 126,
|
||||
"0/53/42": 392,
|
||||
"0/53/43": 0,
|
||||
"0/53/44": 0,
|
||||
"0/53/45": 0,
|
||||
"0/53/46": 0,
|
||||
"0/53/47": 0,
|
||||
"0/53/48": 2796,
|
||||
"0/53/49": 9,
|
||||
"0/53/50": 18,
|
||||
"0/53/51": 10,
|
||||
"0/53/52": 0,
|
||||
"0/53/53": 0,
|
||||
"0/53/54": 70,
|
||||
"0/53/55": 110,
|
||||
"0/53/59": {
|
||||
"0": 672,
|
||||
"1": 143
|
||||
},
|
||||
"0/53/60": "AB//4A==",
|
||||
"0/53/61": {
|
||||
"0": true,
|
||||
"1": false,
|
||||
"2": true,
|
||||
"3": true,
|
||||
"4": true,
|
||||
"5": true,
|
||||
"6": false,
|
||||
"7": true,
|
||||
"8": true,
|
||||
"9": true,
|
||||
"10": true,
|
||||
"11": true
|
||||
},
|
||||
"0/53/62": [],
|
||||
"0/53/65532": 15,
|
||||
"0/53/65533": 3,
|
||||
"0/53/65528": [],
|
||||
"0/53/65529": [0],
|
||||
"0/53/65531": [
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 59,
|
||||
60, 61, 62, 65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"0/56/0": 815849852639528,
|
||||
"0/56/1": 2,
|
||||
"0/56/2": 2,
|
||||
"0/56/3": null,
|
||||
"0/56/5": [
|
||||
{
|
||||
"0": 3600,
|
||||
"1": 0,
|
||||
"2": "Europe/Paris"
|
||||
}
|
||||
],
|
||||
"0/56/6": [
|
||||
{
|
||||
"0": 0,
|
||||
"1": 0,
|
||||
"2": 828061200000000
|
||||
},
|
||||
{
|
||||
"0": 3600,
|
||||
"1": 828061200000000,
|
||||
"2": 846205200000000
|
||||
}
|
||||
],
|
||||
"0/56/7": 815853452640810,
|
||||
"0/56/8": 2,
|
||||
"0/56/10": 2,
|
||||
"0/56/11": 2,
|
||||
"0/56/65532": 9,
|
||||
"0/56/65533": 2,
|
||||
"0/56/65528": [3],
|
||||
"0/56/65529": [0, 1, 2, 4],
|
||||
"0/56/65531": [
|
||||
0, 1, 2, 3, 5, 6, 7, 8, 10, 11, 65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"0/60/0": 0,
|
||||
"0/60/1": null,
|
||||
"0/60/2": null,
|
||||
"0/60/65532": 1,
|
||||
"0/60/65533": 1,
|
||||
"0/60/65528": [],
|
||||
"0/60/65529": [0, 1, 2],
|
||||
"0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/62/0": [
|
||||
{
|
||||
"1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRlBgkBwEkCAEwCUEEQ2q1XJVV19WnxHHSfOUdx9bDmdDqjNtb9YgZA2j76IaZCChToVK6aKvw+YxIPL3mgzVfD08t2wHpcNjyBIAYFjcKNQEoARgkAgE2AwQCBAEYMAQUXObIaHWU7+qbdq7roNf1TweBIfMwBRS5+zzv8ZPGnI9mC3wH9vq10JnwlhgwC0BByE+Cvdi+klStM4F55ptZC4sE7IRIzqFHEUa2CZY2k7uTFPj9Yo1YzWgpnNJlAc0vnGXdN9E7B6yttZk4tSkZGA==",
|
||||
"2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEE/DujEcdTsX19xbxX+KuKKWiMaA5D9u99P/pVxIOmscd2BA2PadEMNnjvtPOpf+WE2Zxar4rby1IfAClGUUuQrTcKNQEpARgkAmAwBBS5+zzv8ZPGnI9mC3wH9vq10JnwljAFFPT6p93JKGcb7g+rTWnA6evF2EdGGDALQGkPpvsbkAFEbfPN6H3Kf23R0zzmW/gpAA3kgaL6wKB2Ofm+Tmylw22qM536Kj8mOMwaV0EL1dCCGcuxF98aL6gY",
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/62/1": [
|
||||
{
|
||||
"1": "BBmX+KwLR5HGlVNbvlC+dO8Jv9fPthHiTfGpUzi2JJADX5az6GxBAFn02QKHwLcZHyh+lh9faf6rf38/nPYF7/M=",
|
||||
"2": 4939,
|
||||
"3": 2,
|
||||
"4": 148,
|
||||
"5": "ha-freebox",
|
||||
"254": 3
|
||||
}
|
||||
],
|
||||
"0/62/2": 5,
|
||||
"0/62/3": 3,
|
||||
"0/62/4": [
|
||||
"FTABAQAkAgE3AyYUyakYCSYVj6gLsxgmBBHhoDAkBQA3BiYUyakYCSYVj6gLsxgkBwEkCAEwCUEEgYwxrTB+tyiEGfrRwjlXTG34MiQtJXbg5Qqd0ohdRW7MfwYY7vZiX/0h9hI8MqUralFaVPcnghAP0MSJm1YrqTcKNQEpARgkAmAwBBS3BS9aJzt+p6i28Nj+trB2Uu+vdzAFFLcFL1onO36nqLbw2P62sHZS7693GDALQKhZq5zQ3AYFGQVcWu+OD8c4yQyTpkGu09UkZu0SXSjWU0Onq7U6RnfhEnsCTZeNC3TB25octZQPnoe4yQyMhOMY",
|
||||
"FTABAQAkAgE3AycUQhmZbaIbYjokFQIYJgRWZLcqJAUANwYnFEIZmW2iG2I6JBUCGCQHASQIATAJQQT2AlKGW/kOMjqayzeO0md523/fuhrhGEUU91uQpTiKo0I7wcPpKnmrwfQNPX6g0kEQl+VGaXa3e22lzfu5Tzp0Nwo1ASkBGCQCYDAEFOOMk13ScMKuT2hlaydi1yEJnhTqMAUU44yTXdJwwq5PaGVrJ2LXIQmeFOoYMAtAv2jJd1qd5miXbYesH1XrJ+vgyY0hzGuZ78N6Jw4Cb1oN1sLSpA+PNM0u7+hsEqcSvvn2eSV8EaRR+hg5YQjHDxg=",
|
||||
"FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEGZf4rAtHkcaVU1u+UL507wm/18+2EeJN8alTOLYkkANflrPobEEAWfTZAofAtxkfKH6WH19p/qt/fz+c9gXv8zcKNQEpARgkAmAwBBT0+qfdyShnG+4Pq01pwOnrxdhHRjAFFPT6p93JKGcb7g+rTWnA6evF2EdGGDALQPVrsFnfFplsQGV5m5EUua+rmo9hAr+OP1bvaifdLqiEIn3uXLTLoKmVUkPImRL2Fb+xcMEAqR2p7RM6ZlFCR20Y"
|
||||
],
|
||||
"0/62/5": 3,
|
||||
"0/62/65532": 0,
|
||||
"0/62/65533": 1,
|
||||
"0/62/65528": [1, 3, 5, 8],
|
||||
"0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11],
|
||||
"0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533],
|
||||
"0/63/0": [],
|
||||
"0/63/1": [],
|
||||
"0/63/2": 4,
|
||||
"0/63/3": 3,
|
||||
"0/63/65532": 0,
|
||||
"0/63/65533": 2,
|
||||
"0/63/65528": [2, 5],
|
||||
"0/63/65529": [0, 1, 3, 4],
|
||||
"0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/3/0": 0,
|
||||
"1/3/1": 2,
|
||||
"1/3/65532": 0,
|
||||
"1/3/65533": 5,
|
||||
"1/3/65528": [],
|
||||
"1/3/65529": [0],
|
||||
"1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/4/0": 128,
|
||||
"1/4/65532": 1,
|
||||
"1/4/65533": 4,
|
||||
"1/4/65528": [0, 1, 2, 3],
|
||||
"1/4/65529": [0, 1, 2, 3, 4, 5],
|
||||
"1/4/65531": [0, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/29/0": [
|
||||
{
|
||||
"0": 514,
|
||||
"1": 3
|
||||
}
|
||||
],
|
||||
"1/29/1": [3, 4, 29, 258, 319486977],
|
||||
"1/29/2": [],
|
||||
"1/29/3": [],
|
||||
"1/29/65532": 0,
|
||||
"1/29/65533": 2,
|
||||
"1/29/65528": [],
|
||||
"1/29/65529": [],
|
||||
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/258/0": 0,
|
||||
"1/258/7": 9,
|
||||
"1/258/10": 0,
|
||||
"1/258/11": 0,
|
||||
"1/258/13": 0,
|
||||
"1/258/14": 0,
|
||||
"1/258/23": 0,
|
||||
"1/258/26": 0,
|
||||
"1/258/65532": 5,
|
||||
"1/258/65533": 5,
|
||||
"1/258/65528": [],
|
||||
"1/258/65529": [0, 1, 2, 5],
|
||||
"1/258/65531": [
|
||||
0, 7, 10, 11, 13, 14, 23, 26, 65528, 65529, 65531, 65532, 65533
|
||||
],
|
||||
"1/319486977/319422464": "AAJgAAsCAAADAuEnBAxCSzM2TjJBMDEyMDWcAQD/BAECAKD5AQEdAQj/BCUCvg7wAcPxAf/vHwEAAAD//7mFDWkAAAAAzzAOaQAAAAAAZAAAAAAAAAD6AQDzFQHDAP8KFAAAAAEAAAAAAAAAAAAAAF0EAAAAAP4JEagIAABuCwAARQUFAAAAAEZUBW0jLA8AAEIGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASQYFDAgQgAFEEQUMAAUDPAAAAOEpPkKHWiu/RxEFAiTUJG4lRyZ4AAAAPAAAAEgGBQAAAAAASgYFAAAAAAD/CyIJEAAAAAAAAAAA",
|
||||
"1/319486977/319422466": "2AAAAM0AAABxXL4uBiUBKQEaARcBGAEZAQMAABAAAAAAAgAAAAEAAA==",
|
||||
"1/319486977/319422467": "",
|
||||
"1/319486977/319422479": false,
|
||||
"1/319486977/319422480": false,
|
||||
"1/319486977/319422481": false,
|
||||
"1/319486977/319422482": 40960,
|
||||
"1/319486977/65532": 0,
|
||||
"1/319486977/65533": 1,
|
||||
"1/319486977/65528": [],
|
||||
"1/319486977/65529": [],
|
||||
"1/319486977/65531": [
|
||||
65528, 65529, 65531, 319422464, 319422465, 319422466, 319422467,
|
||||
319422468, 319422469, 319422479, 319422480, 319422481, 319422482, 65532,
|
||||
65533
|
||||
]
|
||||
},
|
||||
"attribute_subscriptions": []
|
||||
}
|
||||
@@ -342,6 +342,55 @@
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000094-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[eve_shutter][binary_sensor.eve_shutter_switch_20eci1701_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Eve Shutter Switch 20ECI1701 Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.eve_shutter_switch_20eci1701_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[heiman_motion_sensor_m1][binary_sensor.smart_motion_sensor_occupancy-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@@ -1516,3 +1565,297 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.mock_full_window_covering_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_full][binary_sensor.mock_full_window_covering_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Mock Full Window Covering Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.mock_full_window_covering_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.mock_lift_window_covering_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_lift][binary_sensor.mock_lift_window_covering_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Mock Lift Window Covering Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.mock_lift_window_covering_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.longan_link_wncv_da01_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000001-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_pa_lift][binary_sensor.longan_link_wncv_da01_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Longan link WNCV DA01 Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.longan_link_wncv_da01_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Mock PA Tilt Window Covering Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.mock_pa_tilt_window_covering_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.mock_tilt_window_covering_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-0000000000000032-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[window_covering_tilt][binary_sensor.mock_tilt_window_covering_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Mock Tilt Window Covering Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.mock_tilt_window_covering_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_config_status-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_config_status',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.RUNNING: 'running'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Config status',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'window_covering_config_status',
|
||||
'unique_id': '00000000000004D2-000000000000007A-MatterNodeDevice-1-WindowCoveringConfigStatus-258-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_binary_sensors[zemismart_mt25b][binary_sensor.zemismart_mt25b_roller_motor_config_status-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'running',
|
||||
'friendly_name': 'Zemismart MT25B Roller Motor Config status',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.zemismart_mt25b_roller_motor_config_status',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -373,3 +373,24 @@ async def test_thermostat_occupancy(
|
||||
state = hass.states.get("binary_sensor.longan_link_hvac_occupancy")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("node_fixture", ["eve_shutter"])
|
||||
async def test_shutter(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
matter_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test shutter ConfigStatus."""
|
||||
# Eve Shutter default state (ConfigStatus = 9)
|
||||
state = hass.states.get("binary_sensor.eve_shutter_switch_20eci1701_config_status")
|
||||
assert state
|
||||
assert state.state == "on"
|
||||
|
||||
# Eve Shutter ConfigStatus Operational bit not set
|
||||
set_node_attribute(matter_node, 1, 258, 7, 8)
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
|
||||
state = hass.states.get("binary_sensor.eve_shutter_switch_20eci1701_config_status")
|
||||
assert state
|
||||
assert state.state == "off"
|
||||
|
||||
@@ -292,7 +292,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -343,7 +343,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_level',
|
||||
'translation_key': 'left_slot_level',
|
||||
'unique_id': '123456789ABC-cury:0-cury_left_level',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
@@ -393,7 +393,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_name',
|
||||
'translation_key': 'left_slot_vial',
|
||||
'unique_id': '123456789ABC-cury:0-cury_left_vial',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -443,7 +443,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_level',
|
||||
'translation_key': 'right_slot_level',
|
||||
'unique_id': '123456789ABC-cury:0-cury_right_level',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
@@ -493,7 +493,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_name',
|
||||
'translation_key': 'right_slot_vial',
|
||||
'unique_id': '123456789ABC-cury:0-cury_right_vial',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -1126,7 +1126,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -1183,7 +1183,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_with_channel_name',
|
||||
'unique_id': '123456789ABC-cct:0-energy_cct',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -1239,7 +1239,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'power_with_channel_name',
|
||||
'unique_id': '123456789ABC-cct:0-power_cct',
|
||||
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
|
||||
})
|
||||
@@ -2576,7 +2576,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:1-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -2635,7 +2635,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:1-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -2977,7 +2977,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:3-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -3036,7 +3036,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:3-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -3255,7 +3255,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -3480,7 +3480,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:0-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -3539,7 +3539,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:0-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -3881,7 +3881,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:2-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -3940,7 +3940,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:2-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -4779,7 +4779,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -4830,7 +4830,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'detected_objects',
|
||||
'translation_key': 'detected_objects_with_channel_name',
|
||||
'unique_id': '123456789ABC-presencezone:201-presencezone_num_objects',
|
||||
'unit_of_measurement': 'objects',
|
||||
})
|
||||
@@ -4882,7 +4882,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'detected_objects',
|
||||
'translation_key': 'detected_objects_with_channel_name',
|
||||
'unique_id': '123456789ABC-presencezone:202-presencezone_num_objects',
|
||||
'unit_of_measurement': 'objects',
|
||||
})
|
||||
@@ -4934,7 +4934,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'detected_objects',
|
||||
'translation_key': 'detected_objects_with_channel_name',
|
||||
'unique_id': '123456789ABC-presencezone:200-presencezone_num_objects',
|
||||
'unit_of_measurement': 'objects',
|
||||
})
|
||||
@@ -5750,7 +5750,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -6740,7 +6740,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -7769,7 +7769,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -7994,7 +7994,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:0-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -8053,7 +8053,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:0-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -8451,7 +8451,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed',
|
||||
'unique_id': '123456789ABC-switch:1-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -8510,7 +8510,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-switch:1-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -9329,7 +9329,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-emdata:0-total_act_ret',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -9380,7 +9380,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'last_restart',
|
||||
'unique_id': '123456789ABC-sys-uptime',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -9434,7 +9434,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'neutral_current',
|
||||
'unique_id': '123456789ABC-em:0-n_current',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
})
|
||||
@@ -9664,7 +9664,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-emdata:0-a_total_act_ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -10114,7 +10114,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-emdata:0-b_total_act_ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -10564,7 +10564,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned',
|
||||
'unique_id': '123456789ABC-emdata:0-c_total_act_ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_level',
|
||||
'translation_key': 'left_slot_level',
|
||||
'unique_id': '123456789ABC-cury:0-cury_left_level',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
@@ -239,7 +239,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_name',
|
||||
'translation_key': 'left_slot_vial',
|
||||
'unique_id': '123456789ABC-cury:0-cury_left_vial',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -289,7 +289,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_level',
|
||||
'translation_key': 'right_slot_level',
|
||||
'unique_id': '123456789ABC-cury:0-cury_right_level',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
@@ -339,7 +339,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'vial_name',
|
||||
'translation_key': 'right_slot_vial',
|
||||
'unique_id': '123456789ABC-cury:0-cury_right_vial',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@@ -460,7 +460,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'session_duration',
|
||||
'unique_id': '123456789ABC-number:202-number_time_charge',
|
||||
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
|
||||
})
|
||||
@@ -515,7 +515,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'session_energy',
|
||||
'unique_id': '123456789ABC-number:201-number_energy_charge',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -574,7 +574,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_with_channel_name',
|
||||
'unique_id': '123456789ABC-switch:0-energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -633,7 +633,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_consumed_with_channel_name',
|
||||
'unique_id': '123456789ABC-switch:0-consumed_energy_switch',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -692,7 +692,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'energy_returned_with_channel_name',
|
||||
'unique_id': '123456789ABC-switch:0-ret_energy',
|
||||
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
|
||||
})
|
||||
@@ -741,12 +741,12 @@
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Average Temperature',
|
||||
'original_name': 'Average temperature',
|
||||
'platform': 'shelly',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'average_temperature',
|
||||
'unique_id': '123456789ABC-number:200-number_average_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
@@ -755,7 +755,7 @@
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': 'Test name Average Temperature',
|
||||
'friendly_name': 'Test name Average temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
@@ -799,7 +799,7 @@
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'translation_key': 'rainfall_last_24h',
|
||||
'unique_id': '123456789ABC-number:201-number_last_precipitation',
|
||||
'unit_of_measurement': <UnitOfPrecipitationDepth.MILLIMETERS: 'mm'>,
|
||||
})
|
||||
|
||||
@@ -2928,7 +2928,7 @@
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'countdown',
|
||||
'unique_id': 'tuya.owozxdzgbibizu4sjkcountdown_set',
|
||||
'unique_id': 'tuya.owozxdzgbibizu4sjkcountdown',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
@@ -2953,6 +2953,71 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.ion1000pro_countdown_2-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.ion1000pro_countdown_2',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Countdown',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'countdown',
|
||||
'unique_id': 'tuya.owozxdzgbibizu4sjkcountdown_set',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.ion1000pro_countdown_2-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'ION1000PRO Countdown',
|
||||
'options': list([
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.ion1000pro_countdown_2',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.jardin_fraises_power_on_behavior-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@@ -4088,6 +4153,65 @@
|
||||
'state': 'power_on',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.seating_side_6_ch_smart_switch_power_on_behavior-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'select.seating_side_6_ch_smart_switch_power_on_behavior',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Power on behavior',
|
||||
'platform': 'tuya',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'relay_status',
|
||||
'unique_id': 'tuya.kxxrbv93k2vvkconqdtrelay_status',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.seating_side_6_ch_smart_switch_power_on_behavior-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Seating side 6-ch Smart Switch Power on behavior',
|
||||
'options': list([
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.seating_side_6_ch_smart_switch_power_on_behavior',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[select.security_light_indicator_light_mode-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.components.switch import (
|
||||
DOMAIN as SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.components.tuya import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
|
||||
@@ -83,3 +88,95 @@ async def test_sfkzq_deprecated_switch(
|
||||
)
|
||||
is not None
|
||||
) is expected_issue
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SWITCH])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cz_PGEkBctAbtzKOZng"],
|
||||
)
|
||||
async def test_turn_on(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
) -> None:
|
||||
"""Test turning on a switch."""
|
||||
entity_id = "switch.din_socket"
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None, f"{entity_id} does not exist"
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
mock_manager.send_commands.assert_called_once_with(
|
||||
mock_device.id, [{"code": "switch", "value": True}]
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SWITCH])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cz_PGEkBctAbtzKOZng"],
|
||||
)
|
||||
async def test_turn_off(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
) -> None:
|
||||
"""Test turning off a switch."""
|
||||
entity_id = "switch.din_socket"
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None, f"{entity_id} does not exist"
|
||||
await hass.services.async_call(
|
||||
SWITCH_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{
|
||||
ATTR_ENTITY_ID: entity_id,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
mock_manager.send_commands.assert_called_once_with(
|
||||
mock_device.id, [{"code": "switch", "value": False}]
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SWITCH])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cz_PGEkBctAbtzKOZng"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("initial_status", "expected_state"),
|
||||
[
|
||||
(True, "on"),
|
||||
(False, "off"),
|
||||
(None, STATE_UNKNOWN),
|
||||
("some string", STATE_UNKNOWN),
|
||||
],
|
||||
)
|
||||
async def test_state(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
initial_status: Any,
|
||||
expected_state: str,
|
||||
) -> None:
|
||||
"""Test switch state."""
|
||||
entity_id = "switch.din_socket"
|
||||
mock_device.status["switch"] = initial_status
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None, f"{entity_id} does not exist"
|
||||
assert state.state == expected_state
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
@@ -13,7 +14,7 @@ from homeassistant.components.valve import (
|
||||
SERVICE_CLOSE_VALVE,
|
||||
SERVICE_OPEN_VALVE,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
@@ -95,3 +96,35 @@ async def test_close_valve(
|
||||
mock_manager.send_commands.assert_called_once_with(
|
||||
mock_device.id, [{"code": "switch_1", "value": False}]
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.VALVE])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["sfkzq_ed7frwissyqrejic"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("initial_status", "expected_state"),
|
||||
[
|
||||
(True, "open"),
|
||||
(False, "closed"),
|
||||
(None, STATE_UNKNOWN),
|
||||
("some string", STATE_UNKNOWN),
|
||||
],
|
||||
)
|
||||
async def test_state(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
initial_status: Any,
|
||||
expected_state: str,
|
||||
) -> None:
|
||||
"""Test valve state."""
|
||||
entity_id = "valve.jie_hashui_fa_valve_1"
|
||||
mock_device.status["switch_1"] = initial_status
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None, f"{entity_id} does not exist"
|
||||
assert state.state == expected_state
|
||||
|
||||
@@ -6,7 +6,7 @@ import dataclasses
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import threading
|
||||
from typing import Any, final
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
@@ -20,7 +20,6 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_FRIENDLY_NAME,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
@@ -1879,7 +1878,6 @@ async def test_change_entity_id(
|
||||
self.remove_calls = []
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
await super().async_added_to_hass()
|
||||
self.added_calls.append(None)
|
||||
self.async_on_remove(lambda: result.append(1))
|
||||
|
||||
@@ -2898,107 +2896,3 @@ async def test_platform_state_write_from_init_unique_id(
|
||||
# The early attempt to write is interpreted as a unique ID collision
|
||||
assert "Platform test_platform does not generate unique IDs." in caplog.text
|
||||
assert "Entity id already exists - ignoring: test.test" not in caplog.text
|
||||
|
||||
|
||||
async def test_included_entities(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test included entities are exposed via the entity_id attribute."""
|
||||
|
||||
entity_registry.async_get_or_create(
|
||||
domain="hello",
|
||||
platform="test",
|
||||
unique_id="very_unique_oceans",
|
||||
suggested_object_id="oceans",
|
||||
)
|
||||
entity_registry.async_get_or_create(
|
||||
domain="hello",
|
||||
platform="test",
|
||||
unique_id="very_unique_continents",
|
||||
suggested_object_id="continents",
|
||||
)
|
||||
entity_registry.async_get_or_create(
|
||||
domain="hello",
|
||||
platform="test",
|
||||
unique_id="very_unique_moon",
|
||||
suggested_object_id="moon",
|
||||
)
|
||||
|
||||
class MockHelloBaseClass(entity.Entity):
|
||||
"""Domain base entity platform domain Hello."""
|
||||
|
||||
@final
|
||||
@property
|
||||
def state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes."""
|
||||
return {"extra": "beer"}
|
||||
|
||||
class MockHelloIncludedEntitiesClass(MockHelloBaseClass, entity.Entity):
|
||||
"""Mock hello grouped entity class for a test integration."""
|
||||
|
||||
platform = MockEntityPlatform(hass, domain="hello", platform_name="test")
|
||||
mock_entity = MockHelloIncludedEntitiesClass()
|
||||
mock_entity.hass = hass
|
||||
mock_entity.entity_id = "hello.universe"
|
||||
mock_entity.unique_id = "very_unique_universe"
|
||||
mock_entity._attr_included_unique_ids = [
|
||||
"very_unique_continents",
|
||||
"very_unique_oceans",
|
||||
]
|
||||
|
||||
await platform.async_add_entities([mock_entity])
|
||||
|
||||
# Initiate mock grouped entity for hello domain
|
||||
mock_entity.async_schedule_update_ha_state(True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.continents", "hello.oceans"]
|
||||
|
||||
# Add an entity to the group of included entities
|
||||
mock_entity._attr_included_unique_ids = [
|
||||
"very_unique_continents",
|
||||
"very_unique_moon",
|
||||
"very_unique_oceans",
|
||||
]
|
||||
mock_entity.async_set_included_entities()
|
||||
|
||||
mock_entity.async_schedule_update_ha_state(True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get("extra") == "beer"
|
||||
assert state.attributes.get(ATTR_ENTITY_ID) == [
|
||||
"hello.continents",
|
||||
"hello.moon",
|
||||
"hello.oceans",
|
||||
]
|
||||
|
||||
# Remove an entity from the group of included entities
|
||||
mock_entity._attr_included_unique_ids = ["very_unique_moon", "very_unique_oceans"]
|
||||
mock_entity.async_set_included_entities()
|
||||
|
||||
mock_entity.async_schedule_update_ha_state(True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.moon", "hello.oceans"]
|
||||
|
||||
# Rename an included entity via the registry entity
|
||||
entity_registry.async_update_entity(
|
||||
entity_id="hello.moon", new_entity_id="hello.moon_light"
|
||||
)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.moon_light", "hello.oceans"]
|
||||
|
||||
# Remove an included entity from the registry entity
|
||||
entity_registry.async_remove(entity_id="hello.oceans")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.moon_light"]
|
||||
|
||||
Reference in New Issue
Block a user