mirror of
https://github.com/home-assistant/core.git
synced 2026-10-07 06:50:41 -04:00
Add Tuya indexed phase sensors as child devices (#182161)
Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
epenet
Claude Opus 5.5
parent
e1b51fdd01
commit
bb82a71866
@@ -816,6 +816,26 @@ class DPCode(StrEnum):
|
||||
PHASE_A = "phase_a"
|
||||
PHASE_B = "phase_b"
|
||||
PHASE_C = "phase_c"
|
||||
PHASE_S1 = "phase_s1"
|
||||
PHASE_S2 = "phase_s2"
|
||||
PHASE_S3 = "phase_s3"
|
||||
PHASE_S4 = "phase_s4"
|
||||
PHASE_S5 = "phase_s5"
|
||||
PHASE_S6 = "phase_s6"
|
||||
PHASE_S7 = "phase_s7"
|
||||
PHASE_S8 = "phase_s8"
|
||||
PHASE_S9 = "phase_s9"
|
||||
PHASE_S10 = "phase_s10"
|
||||
PHASE_S11 = "phase_s11"
|
||||
PHASE_S12 = "phase_s12"
|
||||
PHASE_S13 = "phase_s13"
|
||||
PHASE_S14 = "phase_s14"
|
||||
PHASE_S15 = "phase_s15"
|
||||
PHASE_S16 = "phase_s16"
|
||||
PHASE_S17 = "phase_s17"
|
||||
PHASE_S18 = "phase_s18"
|
||||
PHASE_S19 = "phase_s19"
|
||||
PHASE_S20 = "phase_s20"
|
||||
PH_CURRENT = "ph_current"
|
||||
PIR = "pir" # Motion sensor
|
||||
PM1 = "pm1"
|
||||
|
||||
@@ -13,16 +13,22 @@ from tuya_device_handlers.device_wrapper.common import (
|
||||
)
|
||||
from tuya_device_handlers.device_wrapper.sensor import (
|
||||
DeltaIntegerWrapper,
|
||||
ElectricityApparentPowerHexStringWrapper,
|
||||
ElectricityApparentPowerJsonWrapper,
|
||||
ElectricityApparentPowerRawWrapper,
|
||||
ElectricityCurrentHexStringWrapper,
|
||||
ElectricityCurrentJsonWrapper,
|
||||
ElectricityCurrentRawWrapper,
|
||||
ElectricityPowerFactorHexStringWrapper,
|
||||
ElectricityPowerFactorJsonWrapper,
|
||||
ElectricityPowerFactorRawWrapper,
|
||||
ElectricityPowerHexStringWrapper,
|
||||
ElectricityPowerJsonWrapper,
|
||||
ElectricityPowerRawWrapper,
|
||||
ElectricityReactivePowerHexStringWrapper,
|
||||
ElectricityReactivePowerJsonWrapper,
|
||||
ElectricityReactivePowerRawWrapper,
|
||||
ElectricityVoltageHexStringWrapper,
|
||||
ElectricityVoltageJsonWrapper,
|
||||
ElectricityVoltageRawWrapper,
|
||||
WindDirectionEnumWrapper,
|
||||
@@ -47,19 +53,22 @@ 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
|
||||
from .entity import TuyaEntity, TuyaEntityDescription, get_child_device_info
|
||||
from .util import get_device_temp_unit_convert
|
||||
|
||||
|
||||
@@ -137,6 +146,73 @@ 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, ...]:
|
||||
"""Build sensors extracted from an indexed hex-string electricity DPCode."""
|
||||
return (
|
||||
TuyaSensorEntityDescription(
|
||||
key=f"{dpcode}electriccurrent",
|
||||
dpcode=dpcode,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
device_class=SensorDeviceClass.POWER_FACTOR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
wrapper_class=(ElectricityPowerFactorHexStringWrapper,),
|
||||
channel_index=index,
|
||||
channel_condition=_has_multiple_phase_channels,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# Commonly used battery sensors, that are reused in the sensors down below.
|
||||
BATTERY_SENSORS: tuple[TuyaSensorEntityDescription, ...] = (
|
||||
TuyaSensorEntityDescription(
|
||||
@@ -1705,6 +1781,13 @@ SENSORS: dict[DeviceCategory, tuple[TuyaSensorEntityDescription, ...]] = {
|
||||
*_electricity_data(DPCode.PHASE_A),
|
||||
*_electricity_data(DPCode.PHASE_B),
|
||||
*_electricity_data(DPCode.PHASE_C),
|
||||
*(
|
||||
description
|
||||
for index in range(1, 21)
|
||||
for description in _indexed_electricity_data(
|
||||
DPCode(f"phase_s{index}"), index
|
||||
)
|
||||
),
|
||||
),
|
||||
DeviceCategory.ZNJDQ: (
|
||||
TuyaSensorEntityDescription(
|
||||
@@ -1836,8 +1919,21 @@ 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)
|
||||
TuyaSensorEntity(
|
||||
device,
|
||||
manager,
|
||||
description,
|
||||
definition,
|
||||
device_info=get_child_device_info(
|
||||
device, parent_device_id, description
|
||||
),
|
||||
)
|
||||
for description in descriptions
|
||||
if (
|
||||
definition := get_default_definition(
|
||||
@@ -1868,9 +1964,11 @@ 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)
|
||||
super().__init__(device, device_manager, description, device_info=device_info)
|
||||
self._dpcode_wrapper = definition.sensor_wrapper
|
||||
|
||||
if description.suggested_unit_of_measurement is None:
|
||||
|
||||
@@ -9009,6 +9009,406 @@
|
||||
'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,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,10 @@ from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.sensor import SensorStateClass
|
||||
from homeassistant.components.tuya.const import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er, json
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er, json
|
||||
from homeassistant.util import json as json_util
|
||||
from homeassistant.util.unit_system import (
|
||||
METRIC_SYSTEM,
|
||||
@@ -46,6 +47,43 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("mock_device_code", "expected_children", "expected_parent_phase_entities"),
|
||||
[
|
||||
pytest.param("zndb_qxlwffgv8avf5rrw", 20, 0, id="multi_channel"),
|
||||
pytest.param("zndb_uqzhc4bx5zqwpg2m", 0, 6, id="single_channel"),
|
||||
],
|
||||
)
|
||||
async def test_indexed_phase_child_devices(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
expected_children: int,
|
||||
expected_parent_phase_entities: int,
|
||||
) -> None:
|
||||
"""Test indexed phase sensors only move to child devices for multi-channel meters."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
parent = device_registry.async_get_device_by_identifier(
|
||||
(DOMAIN, mock_device.id), mock_config_entry.entry_id
|
||||
)
|
||||
assert parent is not None
|
||||
assert (
|
||||
len(dr.async_entries_for_parent_device(device_registry, parent.id))
|
||||
== expected_children
|
||||
)
|
||||
assert (
|
||||
sum(
|
||||
"phase_s" in entry.unique_id
|
||||
for entry in er.async_entries_for_device(entity_registry, parent.id)
|
||||
)
|
||||
== expected_parent_phase_entities
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mcs_8yhypbo7"],
|
||||
|
||||
Reference in New Issue
Block a user