Keep Tuya channel entities on the main device (#183734)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
epenet
2026-09-30 14:55:14 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 09508aa089
commit a854a04e28
12 changed files with 6577 additions and 7222 deletions
+2 -32
View File
@@ -1,13 +1,12 @@
"""Tuya Home Assistant Base Device Model."""
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, override
from tuya_device_handlers.device_wrapper import DeviceWrapper
from tuya_sharing import CustomerDevice, Manager
from homeassistant.helpers.device_registry import ChildDeviceInfo, DeviceInfo
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity, EntityDescription
@@ -18,31 +17,6 @@ from .const import DOMAIN, LOGGER, TUYA_HA_SIGNAL_UPDATE_ENTITY
class TuyaEntityDescription(EntityDescription):
"""Describes a Tuya entity."""
channel_index: int | None = None
channel_condition: Callable[[CustomerDevice], bool] | None = None
def get_child_device_info(
device: CustomerDevice,
parent_device_id: str,
description: TuyaEntityDescription,
) -> ChildDeviceInfo | None:
"""Get the device info for a single channel of a Tuya device.
Returns None for entities belonging to the device itself, and for devices
that do not expose more than one channel.
"""
if (channel_index := description.channel_index) is None:
return None
if description.channel_condition and not description.channel_condition(device):
return None
return ChildDeviceInfo(
identifiers={(DOMAIN, f"{device.id}_channel_{channel_index}")},
parent_device_id=parent_device_id,
translation_key="channel",
translation_placeholders={"index": str(channel_index)},
)
class TuyaEntity(Entity):
"""Tuya base device."""
@@ -55,13 +29,9 @@ class TuyaEntity(Entity):
device: CustomerDevice,
device_manager: Manager,
description: TuyaEntityDescription,
*,
device_info: ChildDeviceInfo | None = None,
) -> None:
"""Init TuyaEntity."""
self._attr_device_info = device_info or DeviceInfo(
identifiers={(DOMAIN, device.id)}
)
self._attr_device_info = DeviceInfo(identifiers={(DOMAIN, device.id)})
# Legacy format, kept as migrating existing unique IDs is not worth the risk
self._attr_unique_id = f"tuya.{device.id}{description.key}" # pylint: disable=home-assistant-entity-unique-id-redundant-domain
self.entity_description = description
+5 -24
View File
@@ -17,21 +17,18 @@ from homeassistant.components.number import (
)
from homeassistant.const import EntityCategory, UnitOfRatio, UnitOfTime
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import ChildDeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import (
DEVICE_CLASS_UNITS,
DOMAIN,
LOGGER,
TUYA_DISCOVERY_NEW,
DeviceCategory,
DPCode,
)
from .coordinator import TuyaConfigEntry
from .entity import TuyaEntity, TuyaEntityDescription, get_child_device_info
from .entity import TuyaEntity, TuyaEntityDescription
from .util import get_device_temp_unit_convert
@@ -275,13 +272,10 @@ NUMBERS: dict[DeviceCategory, tuple[TuyaNumberEntityDescription, ...]] = {
*(
TuyaNumberEntityDescription(
key=DPCode(f"countdown_{channel}"),
translation_key="irrigation_duration",
translation_key="indexed_irrigation_duration",
translation_placeholders={"index": str(channel)},
device_class=NumberDeviceClass.DURATION,
entity_category=EntityCategory.CONFIG,
channel_index=channel,
channel_condition=lambda device: (
DPCode.COUNTDOWN_2 in device.status_range
),
)
for channel in range(1, 9)
),
@@ -499,19 +493,8 @@ async def async_setup_entry(
for device_id in device_ids:
device = manager.device_map[device_id]
if descriptions := NUMBERS.get(device.category):
parent_device_id = dr.async_get_device_id_by_identifier(
hass, (DOMAIN, device.id), config_entry_id=entry.entry_id
)
entities.extend(
TuyaNumberEntity(
device,
manager,
description,
definition,
device_info=get_child_device_info(
device, parent_device_id, description
),
)
TuyaNumberEntity(device, manager, description, definition)
for description in descriptions
if (definition := get_default_definition(device, description.key))
)
@@ -534,11 +517,9 @@ class TuyaNumberEntity(TuyaEntity, NumberEntity):
device_manager: Manager,
description: TuyaNumberEntityDescription,
definition: NumberDefinition,
*,
device_info: ChildDeviceInfo | None = None,
) -> None:
"""Initialize a Tuya number entity."""
super().__init__(device, device_manager, description, device_info=device_info)
super().__init__(device, device_manager, description)
self._dpcode_wrapper = definition.number_wrapper
self._attr_native_max_value = definition.number_wrapper.max_value
+15 -38
View File
@@ -53,22 +53,19 @@ from homeassistant.const import (
UnitOfTime,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import ChildDeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from .const import (
DEVICE_CLASS_UNITS,
DOMAIN,
LOGGER,
TUYA_DISCOVERY_NEW,
DeviceCategory,
DPCode,
)
from .coordinator import TuyaConfigEntry
from .entity import TuyaEntity, TuyaEntityDescription, get_child_device_info
from .entity import TuyaEntity, TuyaEntityDescription
from .util import get_device_temp_unit_convert
@@ -146,11 +143,6 @@ def _electricity_data(dpcode: DPCode) -> tuple[TuyaSensorEntityDescription, ...]
)
def _has_multiple_phase_channels(device: CustomerDevice) -> bool:
"""Return if the device reports more than one indexed phase channel."""
return DPCode.PHASE_S2 in device.status_range
def _indexed_electricity_data(
dpcode: DPCode, index: int
) -> tuple[TuyaSensorEntityDescription, ...]:
@@ -159,56 +151,56 @@ def _indexed_electricity_data(
TuyaSensorEntityDescription(
key=f"{dpcode}electriccurrent",
dpcode=dpcode,
translation_key="indexed_current",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.CURRENT,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityCurrentHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
TuyaSensorEntityDescription(
key=f"{dpcode}power",
dpcode=dpcode,
translation_key="indexed_power",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityPowerHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
TuyaSensorEntityDescription(
key=f"{dpcode}voltage",
dpcode=dpcode,
translation_key="indexed_voltage",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityVoltageHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
TuyaSensorEntityDescription(
key=f"{dpcode}reactivepower",
dpcode=dpcode,
translation_key="indexed_reactive_power",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.REACTIVE_POWER,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityReactivePowerHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
TuyaSensorEntityDescription(
key=f"{dpcode}apparentpower",
dpcode=dpcode,
translation_key="indexed_apparent_power",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.APPARENT_POWER,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityApparentPowerHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
TuyaSensorEntityDescription(
key=f"{dpcode}powerfactor",
dpcode=dpcode,
translation_key="indexed_power_factor",
translation_placeholders={"index": str(index)},
device_class=SensorDeviceClass.POWER_FACTOR,
state_class=SensorStateClass.MEASUREMENT,
wrapper_class=(ElectricityPowerFactorHexStringWrapper,),
channel_index=index,
channel_condition=_has_multiple_phase_channels,
),
)
@@ -1919,21 +1911,8 @@ async def async_setup_entry(
for device_id in device_ids:
device = manager.device_map[device_id]
if descriptions := SENSORS.get(device.category):
parent_device_id = dr.async_get_device_id_by_identifier(
hass,
(DOMAIN, device.id),
config_entry_id=entry.entry_id,
)
entities.extend(
TuyaSensorEntity(
device,
manager,
description,
definition,
device_info=get_child_device_info(
device, parent_device_id, description
),
)
TuyaSensorEntity(device, manager, description, definition)
for description in descriptions
if (
definition := get_default_definition(
@@ -1964,11 +1943,9 @@ class TuyaSensorEntity(TuyaEntity, SensorEntity):
device_manager: Manager,
description: TuyaSensorEntityDescription,
definition: SensorDefinition,
*,
device_info: ChildDeviceInfo | None = None,
) -> None:
"""Init Tuya sensor."""
super().__init__(device, device_manager, description, device_info=device_info)
super().__init__(device, device_manager, description)
self._dpcode_wrapper = definition.sensor_wrapper
if description.suggested_unit_of_measurement is None:
+15 -5
View File
@@ -29,11 +29,6 @@
}
}
},
"device": {
"channel": {
"name": "Channel {index}"
}
},
"entity": {
"binary_sensor": {
"bag_full": {
@@ -229,6 +224,9 @@
"indexed_cook_temperature": {
"name": "Cooking temperature {index}"
},
"indexed_irrigation_duration": {
"name": "Irrigation duration {index}"
},
"indexed_maximum_brightness": {
"name": "Maximum brightness {index}"
},
@@ -796,6 +794,9 @@
"illuminance": {
"name": "[%key:component::sensor::entity_component::illuminance::name%]"
},
"indexed_apparent_power": {
"name": "Apparent power channel {index}"
},
"indexed_current": {
"name": "Current channel {index}"
},
@@ -818,6 +819,12 @@
"indexed_power": {
"name": "Power channel {index}"
},
"indexed_power_factor": {
"name": "Power factor channel {index}"
},
"indexed_reactive_power": {
"name": "Reactive power channel {index}"
},
"indexed_temperature_external": {
"name": "Probe temperature channel {index}"
},
@@ -1279,6 +1286,9 @@
}
},
"valve": {
"indexed_valve": {
"name": "Valve {index}"
},
"valve": {
"name": "Valve"
}
+6 -22
View File
@@ -16,14 +16,12 @@ from homeassistant.components.valve import (
ValveEntityFeature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import ChildDeviceInfo
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
from .coordinator import TuyaConfigEntry
from .entity import TuyaEntity, TuyaEntityDescription, get_child_device_info
from .entity import TuyaEntity, TuyaEntityDescription
@dataclass(frozen=True)
@@ -41,10 +39,9 @@ VALVES: dict[DeviceCategory, tuple[TuyaValveEntityDescription, ...]] = {
*(
TuyaValveEntityDescription(
key=DPCode(f"switch_{channel}"),
translation_key="valve",
translation_key="indexed_valve",
translation_placeholders={"index": str(channel)},
device_class=ValveDeviceClass.WATER,
channel_index=channel,
channel_condition=lambda device: DPCode.SWITCH_2 in device.status_range,
)
for channel in range(1, 9)
),
@@ -67,19 +64,8 @@ async def async_setup_entry(
for device_id in device_ids:
device = manager.device_map[device_id]
if descriptions := VALVES.get(device.category):
parent_device_id = dr.async_get_device_id_by_identifier(
hass, (DOMAIN, device.id), config_entry_id=entry.entry_id
)
entities.extend(
TuyaValveEntity(
device,
manager,
description,
definition,
device_info=get_child_device_info(
device, parent_device_id, description
),
)
TuyaValveEntity(device, manager, description, definition)
for description in descriptions
if (definition := get_default_definition(device, description.key))
)
@@ -104,11 +90,9 @@ class TuyaValveEntity(TuyaEntity, ValveEntity):
device_manager: Manager,
description: TuyaValveEntityDescription,
definition: ValveDefinition,
*,
device_info: ChildDeviceInfo | None = None,
) -> None:
"""Init TuyaValveEntity."""
super().__init__(device, device_manager, description, device_info=device_info)
super().__init__(device, device_manager, description)
self._dpcode_wrapper = definition.control_wrapper
@property
@@ -2819,166 +2819,6 @@
'via_device_id': None,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_1]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_1',
),
}),
'labels': set({
}),
'name': 'Channel 1',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_2]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_2',
),
}),
'labels': set({
}),
'name': 'Channel 2',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_3]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_3',
),
}),
'labels': set({
}),
'name': 'Channel 3',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_4]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_4',
),
}),
'labels': set({
}),
'name': 'Channel 4',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_5]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_5',
),
}),
'labels': set({
}),
'name': 'Channel 5',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_6]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_6',
),
}),
'labels': set({
}),
'name': 'Channel 6',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_7]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_7',
),
}),
'labels': set({
}),
'name': 'Channel 7',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cijerqyssiwrf7deqzkfs_channel_8]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'cijerqyssiwrf7deqzkfs_channel_8',
),
}),
'labels': set({
}),
'name': 'Channel 8',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[cju47ovcbeuapei2zc]
DeviceRegistryEntrySnapshot({
'area_id': None,
@@ -9009,406 +8849,6 @@
'via_device_id': None,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_10]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_10',
),
}),
'labels': set({
}),
'name': 'Channel 10',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_11]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_11',
),
}),
'labels': set({
}),
'name': 'Channel 11',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_12]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_12',
),
}),
'labels': set({
}),
'name': 'Channel 12',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_13]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_13',
),
}),
'labels': set({
}),
'name': 'Channel 13',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_14]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_14',
),
}),
'labels': set({
}),
'name': 'Channel 14',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_15]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_15',
),
}),
'labels': set({
}),
'name': 'Channel 15',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_16]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_16',
),
}),
'labels': set({
}),
'name': 'Channel 16',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_17]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_17',
),
}),
'labels': set({
}),
'name': 'Channel 17',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_18]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_18',
),
}),
'labels': set({
}),
'name': 'Channel 18',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_19]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_19',
),
}),
'labels': set({
}),
'name': 'Channel 19',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_1]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_1',
),
}),
'labels': set({
}),
'name': 'Channel 1',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_20]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_20',
),
}),
'labels': set({
}),
'name': 'Channel 20',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_2]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_2',
),
}),
'labels': set({
}),
'name': 'Channel 2',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_3]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_3',
),
}),
'labels': set({
}),
'name': 'Channel 3',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_4]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_4',
),
}),
'labels': set({
}),
'name': 'Channel 4',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_5]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_5',
),
}),
'labels': set({
}),
'name': 'Channel 5',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_6]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_6',
),
}),
'labels': set({
}),
'name': 'Channel 6',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_7]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_7',
),
}),
'labels': set({
}),
'name': 'Channel 7',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_8]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_8',
),
}),
'labels': set({
}),
'name': 'Channel 8',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[wrr5fva8vgffwlxqbdnz_channel_9]
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'disabled_by': None,
'id': <ANY>,
'identifiers': set({
tuple(
'tuya',
'wrr5fva8vgffwlxqbdnz_channel_9',
),
}),
'labels': set({
}),
'name': 'Channel 9',
'name_by_user': None,
'parent_device_id': <ANY>,
})
# ---
# name: test_device_registry[x4nogasbi8ggpb3lcd]
DeviceRegistryEntrySnapshot({
'area_id': None,
@@ -1573,7 +1573,7 @@
'state': '28.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_1_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1592,7 +1592,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_1_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1600,26 +1600,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 1',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 1',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_1',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_1_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 1 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 1',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1627,14 +1627,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_1_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_2_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1653,7 +1653,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_2_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1661,26 +1661,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 2',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 2',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_2',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_2_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 2 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 2',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1688,14 +1688,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_2_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_3_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1714,7 +1714,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_3_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1722,26 +1722,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 3',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 3',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_3',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_3_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 3 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 3',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1749,14 +1749,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_3_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '3.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_4_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_4-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1775,7 +1775,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_4_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_4',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1783,26 +1783,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 4',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 4',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_4',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_4_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 4 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 4',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1810,14 +1810,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_4_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_4',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_5_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_5-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1836,7 +1836,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_5_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_5',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1844,26 +1844,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 5',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 5',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_5',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_5_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_5-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 5 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 5',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1871,14 +1871,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_5_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_5',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_6_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_6-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1897,7 +1897,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_6_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_6',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1905,26 +1905,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 6',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 6',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_6',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_6_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_6-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 6 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 6',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1932,14 +1932,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_6_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_6',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '3.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_7_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_7-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -1958,7 +1958,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_7_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_7',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -1966,26 +1966,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 7',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 7',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_7',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_7_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_7-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 7 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 7',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -1993,14 +1993,14 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_7_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_7',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.0',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_8_irrigation_duration-entry]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_8-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -2019,7 +2019,7 @@
'disabled_by': None,
'domain': 'number',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'number.jie_hashui_fa_channel_8_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_8',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -2027,26 +2027,26 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Irrigation duration',
'object_id_base': 'Irrigation duration 8',
'options': dict({
}),
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Irrigation duration',
'original_name': 'Irrigation duration 8',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'irrigation_duration',
'translation_key': 'indexed_irrigation_duration',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_8',
'unit_of_measurement': 'min',
})
# ---
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_channel_8_irrigation_duration-state]
# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_8-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 8 Irrigation duration',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Irrigation duration 8',
<NumberEntityCapabilityAttribute.MAX: 'max'>: 1439.0,
<NumberEntityCapabilityAttribute.MIN: 'min'>: 1.0,
<NumberEntityCapabilityAttribute.MODE: 'mode'>: <NumberMode.AUTO: 'auto'>,
@@ -2054,7 +2054,7 @@
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: 'min',
}),
'context': <ANY>,
'entity_id': 'number.jie_hashui_fa_channel_8_irrigation_duration',
'entity_id': 'number.jie_hashui_fa_irrigation_duration_8',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
File diff suppressed because it is too large Load Diff
+64 -64
View File
@@ -105,7 +105,7 @@
'state': 'closed',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_1_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -119,7 +119,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_1_valve',
'entity_id': 'valve.jie_hashui_fa_valve_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -127,38 +127,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 1',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 1',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_1',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_1_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 1 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 1',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: False,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_1_valve',
'entity_id': 'valve.jie_hashui_fa_valve_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_2_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -172,7 +172,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_2_valve',
'entity_id': 'valve.jie_hashui_fa_valve_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -180,38 +180,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 2',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 2',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_2',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_2_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 2 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 2',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: True,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_2_valve',
'entity_id': 'valve.jie_hashui_fa_valve_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_3_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_3-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -225,7 +225,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_3_valve',
'entity_id': 'valve.jie_hashui_fa_valve_3',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -233,38 +233,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 3',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 3',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_3',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_3_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_3-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 3 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 3',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: False,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_3_valve',
'entity_id': 'valve.jie_hashui_fa_valve_3',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_4_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_4-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -278,7 +278,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_4_valve',
'entity_id': 'valve.jie_hashui_fa_valve_4',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -286,38 +286,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 4',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 4',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_4',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_4_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_4-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 4 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 4',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: True,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_4_valve',
'entity_id': 'valve.jie_hashui_fa_valve_4',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_5_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_5-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -331,7 +331,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_5_valve',
'entity_id': 'valve.jie_hashui_fa_valve_5',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -339,38 +339,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 5',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 5',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_5',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_5_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_5-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 5 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 5',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: False,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_5_valve',
'entity_id': 'valve.jie_hashui_fa_valve_5',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_6_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_6-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -384,7 +384,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_6_valve',
'entity_id': 'valve.jie_hashui_fa_valve_6',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -392,38 +392,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 6',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 6',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_6',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_6_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_6-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 6 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 6',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: True,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_6_valve',
'entity_id': 'valve.jie_hashui_fa_valve_6',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_7_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_7-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -437,7 +437,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_7_valve',
'entity_id': 'valve.jie_hashui_fa_valve_7',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -445,38 +445,38 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 7',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 7',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_7',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_7_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_7-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 7 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 7',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: False,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_7_valve',
'entity_id': 'valve.jie_hashui_fa_valve_7',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_8_valve-entry]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_8-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
@@ -490,7 +490,7 @@
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.jie_hashui_fa_channel_8_valve',
'entity_id': 'valve.jie_hashui_fa_valve_8',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
@@ -498,31 +498,31 @@
'labels': set({
}),
'name': None,
'object_id_base': 'Valve',
'object_id_base': 'Valve 8',
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': 'Valve',
'original_name': 'Valve 8',
'platform': 'tuya',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': 'valve',
'translation_key': 'indexed_valve',
'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_8',
'unit_of_measurement': None,
})
# ---
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_channel_8_valve-state]
# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_8-state]
StateSnapshot({
'attributes': ReadOnlyDict({
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'water',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Channel 8 Valve',
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: '接HA水阀 Valve 8',
<ValveEntityStateAttribute.IS_CLOSED: 'is_closed'>: True,
<EntityStateAttribute.SUPPORTED_FEATURES: 'supported_features'>: <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.jie_hashui_fa_channel_8_valve',
'entity_id': 'valve.jie_hashui_fa_valve_8',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
-7
View File
@@ -135,13 +135,6 @@ async def test_device_registry(
name=list(device_registry_entry.identifiers)[0][1]
)
for child_device_entry in dr.async_child_entries_for_config_entry(
device_registry, mock_config_entry.entry_id
):
assert child_device_entry == snapshot(
name=list(child_device_entry.identifiers)[0][1]
)
@pytest.mark.parametrize(
("mock_device_code", "platforms", "manufacturer", "model", "model_id", "quirks"),
+2 -2
View File
@@ -50,7 +50,7 @@ async def test_platform_setup_and_discovery(
@pytest.mark.parametrize(
("mock_device_code", "expected_children", "expected_parent_phase_entities"),
[
pytest.param("zndb_qxlwffgv8avf5rrw", 20, 0, id="multi_channel"),
pytest.param("zndb_qxlwffgv8avf5rrw", 0, 120, id="multi_channel"),
pytest.param("zndb_uqzhc4bx5zqwpg2m", 0, 6, id="single_channel"),
],
)
@@ -64,7 +64,7 @@ async def test_indexed_phase_child_devices(
expected_children: int,
expected_parent_phase_entities: int,
) -> None:
"""Test indexed phase sensors only move to child devices for multi-channel meters."""
"""Test indexed phase sensors stay on the main device."""
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
parent = device_registry.async_get_device_by_identifier(
+4 -4
View File
@@ -53,7 +53,7 @@ async def test_single_channel_device_has_no_child_devices(
assert not dr.async_child_entries_for_config_entry(
device_registry, mock_config_entry.entry_id
)
entity_entry = entity_registry.async_get("valve.jie_hashui_fa_valve")
entity_entry = entity_registry.async_get("valve.jie_hashui_fa_valve_1")
assert entity_entry
device_entry = device_registry.async_get_device_by_identifier(
(DOMAIN, mock_device.id), mock_config_entry.entry_id
@@ -116,7 +116,7 @@ async def test_selective_state_update(
mock_device,
notification_helper,
freezer,
entity_id="valve.jie_hashui_fa_channel_1_valve",
entity_id="valve.jie_hashui_fa_valve_1",
dpcode="switch_1",
initial_state="open",
updates=updates,
@@ -151,7 +151,7 @@ async def test_action(
expected_commands: list[dict[str, Any]],
) -> None:
"""Test valve action."""
entity_id = "valve.jie_hashui_fa_channel_1_valve"
entity_id = "valve.jie_hashui_fa_valve_1"
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
state = hass.states.get(entity_id)
@@ -191,7 +191,7 @@ async def test_state(
expected_state: str,
) -> None:
"""Test valve state."""
entity_id = "valve.jie_hashui_fa_channel_1_valve"
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)