mirror of
https://github.com/home-assistant/core.git
synced 2026-02-07 15:46:19 +01:00
Compare commits
2 Commits
LocalTempe
...
epenet-202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e118e4d7e4 | ||
|
|
c2508d506f |
@@ -5,6 +5,12 @@ from __future__ import annotations
|
||||
from base64 import b64decode
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeRawWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import EnumTypeInformation
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.alarm_control_panel import (
|
||||
@@ -20,8 +26,6 @@ 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 DeviceWrapper, DPCodeEnumWrapper, DPCodeRawWrapper
|
||||
from .type_information import EnumTypeInformation
|
||||
|
||||
ALARM: dict[DeviceCategory, tuple[AlarmControlPanelEntityDescription, ...]] = {
|
||||
DeviceCategory.MAL: (
|
||||
@@ -39,7 +43,7 @@ class _AlarmChangedByWrapper(DPCodeRawWrapper):
|
||||
Decode base64 to utf-16be string, but only if alarm has been triggered.
|
||||
"""
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> str | None:
|
||||
def read_device_status(self, device: CustomerDevice) -> str | None: # type: ignore[override]
|
||||
"""Read the device status."""
|
||||
if (
|
||||
device.status.get(DPCode.MASTER_STATE) != "alarm"
|
||||
|
||||
@@ -4,6 +4,12 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.binary_sensor import DPCodeBitmapBitWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeWrapper,
|
||||
)
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
@@ -19,12 +25,6 @@ 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 (
|
||||
DeviceWrapper,
|
||||
DPCodeBitmapBitWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeWrapper,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeBooleanWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
@@ -13,7 +15,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper
|
||||
|
||||
BUTTONS: dict[DeviceCategory, tuple[ButtonEntityDescription, ...]] = {
|
||||
DeviceCategory.HXD: (
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeBooleanWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components import ffmpeg
|
||||
@@ -13,7 +15,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper
|
||||
|
||||
CAMERAS: tuple[DeviceCategory, ...] = (
|
||||
DeviceCategory.DGHSXJ,
|
||||
|
||||
@@ -6,6 +6,13 @@ import collections
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Self
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import EnumTypeInformation
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
@@ -33,13 +40,6 @@ from .const import (
|
||||
DPCode,
|
||||
)
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DeviceWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from .type_information import EnumTypeInformation
|
||||
|
||||
TUYA_HVAC_TO_HA = {
|
||||
"auto": HVACMode.HEAT_COOL,
|
||||
@@ -176,8 +176,10 @@ class _HvacModeWrapper(DPCodeEnumWrapper):
|
||||
return None
|
||||
return TUYA_HVAC_TO_HA[raw]
|
||||
|
||||
def _convert_value_to_raw_value(
|
||||
self, device: CustomerDevice, value: HVACMode
|
||||
def _convert_value_to_raw_value( # type: ignore[override]
|
||||
self,
|
||||
device: CustomerDevice,
|
||||
value: HVACMode,
|
||||
) -> Any:
|
||||
"""Convert value to raw value."""
|
||||
return next(
|
||||
|
||||
@@ -82,18 +82,6 @@ class WorkMode(StrEnum):
|
||||
WHITE = "white"
|
||||
|
||||
|
||||
class DPType(StrEnum):
|
||||
"""Data point types."""
|
||||
|
||||
BITMAP = "Bitmap"
|
||||
BOOLEAN = "Boolean"
|
||||
ENUM = "Enum"
|
||||
INTEGER = "Integer"
|
||||
JSON = "Json"
|
||||
RAW = "Raw"
|
||||
STRING = "String"
|
||||
|
||||
|
||||
class DeviceCategory(StrEnum):
|
||||
"""Tuya device categories.
|
||||
|
||||
|
||||
@@ -5,6 +5,17 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import (
|
||||
EnumTypeInformation,
|
||||
IntegerTypeInformation,
|
||||
)
|
||||
from tuya_device_handlers.utils import RemapHelper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
@@ -22,14 +33,6 @@ 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 (
|
||||
DeviceWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from .type_information import EnumTypeInformation, IntegerTypeInformation
|
||||
from .util import RemapHelper
|
||||
|
||||
|
||||
class _DPCodePercentageMappingWrapper(DPCodeIntegerWrapper):
|
||||
@@ -84,7 +87,7 @@ class _InstructionBooleanWrapper(DPCodeBooleanWrapper):
|
||||
options = ["open", "close"]
|
||||
_ACTION_MAPPINGS = {"open": True, "close": False}
|
||||
|
||||
def _convert_value_to_raw_value(self, device: CustomerDevice, value: str) -> bool:
|
||||
def _convert_value_to_raw_value(self, device: CustomerDevice, value: str) -> bool: # type: ignore[override]
|
||||
return self._ACTION_MAPPINGS[value]
|
||||
|
||||
|
||||
@@ -130,7 +133,7 @@ class _IsClosedEnumWrapper(DPCodeEnumWrapper):
|
||||
"fully_open": False,
|
||||
}
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> bool | None:
|
||||
def read_device_status(self, device: CustomerDevice) -> bool | None: # type: ignore[override]
|
||||
if (value := super().read_device_status(device)) is None:
|
||||
return None
|
||||
return self._MAPPINGS.get(value)
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper import DEVICE_WARNINGS
|
||||
from tuya_sharing import CustomerDevice
|
||||
|
||||
from homeassistant.components.diagnostics import REDACTED
|
||||
@@ -14,7 +15,6 @@ from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import TuyaConfigEntry
|
||||
from .const import DOMAIN, DPCode
|
||||
from .type_information import DEVICE_WARNINGS
|
||||
|
||||
_REDACTED_DPCODES = {
|
||||
DPCode.ALARM_MESSAGE,
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper import DeviceWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
@@ -11,7 +12,6 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from .const import DOMAIN, LOGGER, TUYA_HA_SIGNAL_UPDATE_ENTITY
|
||||
from .models import DeviceWrapper
|
||||
|
||||
|
||||
class TuyaEntity(Entity):
|
||||
|
||||
@@ -6,6 +6,13 @@ from base64 import b64decode
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeRawWrapper,
|
||||
DPCodeStringWrapper,
|
||||
DPCodeTypeInformationWrapper,
|
||||
)
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.event import (
|
||||
@@ -20,19 +27,14 @@ 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 (
|
||||
DeviceWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeRawWrapper,
|
||||
DPCodeStringWrapper,
|
||||
DPCodeTypeInformationWrapper,
|
||||
)
|
||||
|
||||
|
||||
class _EventEnumWrapper(DPCodeEnumWrapper):
|
||||
"""Wrapper for event enum DP codes."""
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> tuple[str, None] | None:
|
||||
def read_device_status( # type: ignore[override]
|
||||
self, device: CustomerDevice
|
||||
) -> tuple[str, None] | None:
|
||||
"""Return the event details."""
|
||||
if (raw_value := super().read_device_status(device)) is None:
|
||||
return None
|
||||
@@ -67,7 +69,7 @@ class _DoorbellPicWrapper(DPCodeRawWrapper):
|
||||
super().__init__(dpcode, type_information)
|
||||
self.options = ["triggered"]
|
||||
|
||||
def read_device_status(
|
||||
def read_device_status( # type: ignore[override]
|
||||
self, device: CustomerDevice
|
||||
) -> tuple[str, dict[str, Any]] | None:
|
||||
"""Return the event attributes for the doorbell picture."""
|
||||
|
||||
@@ -4,6 +4,14 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import IntegerTypeInformation
|
||||
from tuya_device_handlers.utils import RemapHelper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
@@ -23,14 +31,7 @@ from homeassistant.util.percentage import (
|
||||
from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DeviceWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from .type_information import IntegerTypeInformation
|
||||
from .util import RemapHelper, get_dpcode
|
||||
from .util import get_dpcode
|
||||
|
||||
_DIRECTION_DPCODES = (DPCode.FAN_DIRECTION,)
|
||||
_MODE_DPCODES = (DPCode.FAN_MODE, DPCode.MODE)
|
||||
@@ -82,7 +83,7 @@ def _has_a_valid_dpcode(device: CustomerDevice) -> bool:
|
||||
class _FanSpeedEnumWrapper(DPCodeEnumWrapper):
|
||||
"""Wrapper for fan speed DP code (from an enum)."""
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> int | None:
|
||||
def read_device_status(self, device: CustomerDevice) -> int | None: # type: ignore[override]
|
||||
"""Get the current speed as a percentage."""
|
||||
if (value := super().read_device_status(device)) is None:
|
||||
return None
|
||||
|
||||
@@ -5,6 +5,12 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.humidifier import (
|
||||
@@ -20,12 +26,6 @@ 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 (
|
||||
DeviceWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
)
|
||||
from .util import ActionDPCodeNotFoundError, get_dpcode
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,15 @@ from enum import StrEnum
|
||||
import json
|
||||
from typing import Any, cast
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
DPCodeJsonWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import IntegerTypeInformation
|
||||
from tuya_device_handlers.utils import RemapHelper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.light import (
|
||||
@@ -30,15 +39,6 @@ from homeassistant.util.json import json_loads_object
|
||||
from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode, WorkMode
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DeviceWrapper,
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
DPCodeJsonWrapper,
|
||||
)
|
||||
from .type_information import IntegerTypeInformation
|
||||
from .util import RemapHelper
|
||||
|
||||
|
||||
class _BrightnessWrapper(DPCodeIntegerWrapper):
|
||||
@@ -174,7 +174,7 @@ class _ColorDataWrapper(DPCodeJsonWrapper):
|
||||
s_type = DEFAULT_S_TYPE
|
||||
v_type = DEFAULT_V_TYPE
|
||||
|
||||
def read_device_status(
|
||||
def read_device_status( # type: ignore[override]
|
||||
self, device: CustomerDevice
|
||||
) -> tuple[float, float, float] | None:
|
||||
"""Return a tuple (H, S, V) from this color data."""
|
||||
|
||||
@@ -43,5 +43,8 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["tuya_sharing"],
|
||||
"requirements": ["tuya-device-sharing-sdk==0.2.8"]
|
||||
"requirements": [
|
||||
"tuya-device-handlers==0.0.10",
|
||||
"tuya-device-sharing-sdk==0.2.8"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,320 +0,0 @@
|
||||
"""Tuya Home Assistant Base Device Model."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any, Self
|
||||
|
||||
from tuya_sharing import CustomerDevice
|
||||
|
||||
from homeassistant.components.sensor import SensorStateClass
|
||||
|
||||
from .type_information import (
|
||||
BitmapTypeInformation,
|
||||
BooleanTypeInformation,
|
||||
EnumTypeInformation,
|
||||
IntegerTypeInformation,
|
||||
JsonTypeInformation,
|
||||
RawTypeInformation,
|
||||
StringTypeInformation,
|
||||
TypeInformation,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeviceWrapper[T]:
|
||||
"""Base device wrapper."""
|
||||
|
||||
native_unit: str | None = None
|
||||
suggested_unit: str | None = None
|
||||
state_class: SensorStateClass | None = None
|
||||
|
||||
max_value: float
|
||||
min_value: float
|
||||
value_step: float
|
||||
|
||||
options: list[str]
|
||||
|
||||
def initialize(self, device: CustomerDevice) -> None:
|
||||
"""Initialize the wrapper with device data.
|
||||
|
||||
Called when the entity is added to Home Assistant.
|
||||
Override in subclasses to perform initialization logic.
|
||||
"""
|
||||
|
||||
def skip_update(
|
||||
self,
|
||||
device: CustomerDevice,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict[str, int] | None,
|
||||
) -> bool:
|
||||
"""Determine if the wrapper should skip an update.
|
||||
|
||||
The default is to always skip, unless overridden in subclasses.
|
||||
"""
|
||||
return True
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> T | None:
|
||||
"""Read device status and convert to a Home Assistant value."""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_update_commands(
|
||||
self, device: CustomerDevice, value: T
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Generate update commands for a Home Assistant action."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class DPCodeWrapper(DeviceWrapper):
|
||||
"""Base device wrapper for a single DPCode.
|
||||
|
||||
Used as a common interface for referring to a DPCode, and
|
||||
access read conversion routines.
|
||||
"""
|
||||
|
||||
def __init__(self, dpcode: str) -> None:
|
||||
"""Init DPCodeWrapper."""
|
||||
self.dpcode = dpcode
|
||||
|
||||
def skip_update(
|
||||
self,
|
||||
device: CustomerDevice,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict[str, int] | None,
|
||||
) -> bool:
|
||||
"""Determine if the wrapper should skip an update.
|
||||
|
||||
By default, skip if updated_status_properties is given and
|
||||
does not include this dpcode.
|
||||
"""
|
||||
return (
|
||||
updated_status_properties is None
|
||||
or self.dpcode not in updated_status_properties
|
||||
)
|
||||
|
||||
def _convert_value_to_raw_value(self, device: CustomerDevice, value: Any) -> Any:
|
||||
"""Convert a Home Assistant value back to a raw device value.
|
||||
|
||||
This is called by `get_update_commands` to prepare the value for sending
|
||||
back to the device, and should be implemented in concrete classes if needed.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_update_commands(
|
||||
self, device: CustomerDevice, value: Any
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Get the update commands for the dpcode.
|
||||
|
||||
The Home Assistant value is converted back to a raw device value.
|
||||
"""
|
||||
return [
|
||||
{
|
||||
"code": self.dpcode,
|
||||
"value": self._convert_value_to_raw_value(device, value),
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
class DPCodeTypeInformationWrapper[T: TypeInformation](DPCodeWrapper):
|
||||
"""Base DPCode wrapper with Type Information."""
|
||||
|
||||
_DPTYPE: type[T]
|
||||
type_information: T
|
||||
|
||||
def __init__(self, dpcode: str, type_information: T) -> None:
|
||||
"""Init DPCodeWrapper."""
|
||||
super().__init__(dpcode)
|
||||
self.type_information = type_information
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> Any | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
return self.type_information.process_raw_value(
|
||||
device.status.get(self.dpcode), device
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def find_dpcode(
|
||||
cls,
|
||||
device: CustomerDevice,
|
||||
dpcodes: str | tuple[str, ...] | None,
|
||||
*,
|
||||
prefer_function: bool = False,
|
||||
) -> Self | None:
|
||||
"""Find and return a DPCodeTypeInformationWrapper for the given DP codes."""
|
||||
if type_information := cls._DPTYPE.find_dpcode(
|
||||
device, dpcodes, prefer_function=prefer_function
|
||||
):
|
||||
return cls(
|
||||
dpcode=type_information.dpcode, type_information=type_information
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
class DPCodeBooleanWrapper(DPCodeTypeInformationWrapper[BooleanTypeInformation]):
|
||||
"""Simple wrapper for boolean values.
|
||||
|
||||
Supports True/False only.
|
||||
"""
|
||||
|
||||
_DPTYPE = BooleanTypeInformation
|
||||
|
||||
def _convert_value_to_raw_value(
|
||||
self, device: CustomerDevice, value: Any
|
||||
) -> Any | None:
|
||||
"""Convert a Home Assistant value back to a raw device value."""
|
||||
if value in (True, False):
|
||||
return value
|
||||
# Currently only called with boolean values
|
||||
# Safety net in case of future changes
|
||||
raise ValueError(f"Invalid boolean value `{value}`")
|
||||
|
||||
|
||||
class DPCodeJsonWrapper(DPCodeTypeInformationWrapper[JsonTypeInformation]):
|
||||
"""Wrapper to extract information from a JSON value."""
|
||||
|
||||
_DPTYPE = JsonTypeInformation
|
||||
|
||||
|
||||
class DPCodeEnumWrapper(DPCodeTypeInformationWrapper[EnumTypeInformation]):
|
||||
"""Simple wrapper for EnumTypeInformation values."""
|
||||
|
||||
_DPTYPE = EnumTypeInformation
|
||||
|
||||
def __init__(self, dpcode: str, type_information: EnumTypeInformation) -> None:
|
||||
"""Init DPCodeEnumWrapper."""
|
||||
super().__init__(dpcode, type_information)
|
||||
self.options = type_information.range
|
||||
|
||||
def _convert_value_to_raw_value(self, device: CustomerDevice, value: Any) -> Any:
|
||||
"""Convert a Home Assistant value back to a raw device value."""
|
||||
if value in self.type_information.range:
|
||||
return value
|
||||
# Guarded by select option validation
|
||||
# Safety net in case of future changes
|
||||
raise ValueError(
|
||||
f"Enum value `{value}` out of range: {self.type_information.range}"
|
||||
)
|
||||
|
||||
|
||||
class DPCodeIntegerWrapper(DPCodeTypeInformationWrapper[IntegerTypeInformation]):
|
||||
"""Simple wrapper for IntegerTypeInformation values."""
|
||||
|
||||
_DPTYPE = IntegerTypeInformation
|
||||
|
||||
def __init__(self, dpcode: str, type_information: IntegerTypeInformation) -> None:
|
||||
"""Init DPCodeIntegerWrapper."""
|
||||
super().__init__(dpcode, type_information)
|
||||
self.native_unit = type_information.unit
|
||||
self.min_value = self.type_information.scale_value(type_information.min)
|
||||
self.max_value = self.type_information.scale_value(type_information.max)
|
||||
self.value_step = self.type_information.scale_value(type_information.step)
|
||||
|
||||
def _convert_value_to_raw_value(self, device: CustomerDevice, value: Any) -> Any:
|
||||
"""Convert a Home Assistant value back to a raw device value."""
|
||||
new_value = round(value * (10**self.type_information.scale))
|
||||
if self.type_information.min <= new_value <= self.type_information.max:
|
||||
return new_value
|
||||
# Guarded by number validation
|
||||
# Safety net in case of future changes
|
||||
raise ValueError(
|
||||
f"Value `{new_value}` (converted from `{value}`) out of range:"
|
||||
f" ({self.type_information.min}-{self.type_information.max})"
|
||||
)
|
||||
|
||||
|
||||
class DPCodeDeltaIntegerWrapper(DPCodeIntegerWrapper):
|
||||
"""Wrapper for integer values with delta report accumulation.
|
||||
|
||||
This wrapper handles sensors that report incremental (delta) values
|
||||
instead of cumulative totals. It accumulates the delta values locally
|
||||
to provide a running total.
|
||||
"""
|
||||
|
||||
_accumulated_value: float = 0
|
||||
_last_dp_timestamp: int | None = None
|
||||
|
||||
def __init__(self, dpcode: str, type_information: IntegerTypeInformation) -> None:
|
||||
"""Init DPCodeDeltaIntegerWrapper."""
|
||||
super().__init__(dpcode, type_information)
|
||||
# Delta reports use TOTAL_INCREASING state class
|
||||
self.state_class = SensorStateClass.TOTAL_INCREASING
|
||||
|
||||
def skip_update(
|
||||
self,
|
||||
device: CustomerDevice,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict[str, int] | None,
|
||||
) -> bool:
|
||||
"""Override skip_update to process delta updates.
|
||||
|
||||
Processes delta accumulation before determining if update should be skipped.
|
||||
"""
|
||||
if (
|
||||
super().skip_update(device, updated_status_properties, dp_timestamps)
|
||||
or dp_timestamps is None
|
||||
or (current_timestamp := dp_timestamps.get(self.dpcode)) is None
|
||||
or current_timestamp == self._last_dp_timestamp
|
||||
or (raw_value := super().read_device_status(device)) is None
|
||||
):
|
||||
return True
|
||||
|
||||
delta = float(raw_value)
|
||||
self._accumulated_value += delta
|
||||
_LOGGER.debug(
|
||||
"Delta update for %s: +%s, total: %s",
|
||||
self.dpcode,
|
||||
delta,
|
||||
self._accumulated_value,
|
||||
)
|
||||
|
||||
self._last_dp_timestamp = current_timestamp
|
||||
return False
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read device status, returning accumulated value for delta reports."""
|
||||
return self._accumulated_value
|
||||
|
||||
|
||||
class DPCodeRawWrapper(DPCodeTypeInformationWrapper[RawTypeInformation]):
|
||||
"""Wrapper to extract information from a RAW/binary value."""
|
||||
|
||||
_DPTYPE = RawTypeInformation
|
||||
|
||||
|
||||
class DPCodeStringWrapper(DPCodeTypeInformationWrapper[StringTypeInformation]):
|
||||
"""Wrapper to extract information from a STRING value."""
|
||||
|
||||
_DPTYPE = StringTypeInformation
|
||||
|
||||
|
||||
class DPCodeBitmapBitWrapper(DPCodeWrapper):
|
||||
"""Simple wrapper for a specific bit in bitmap values."""
|
||||
|
||||
def __init__(self, dpcode: str, mask: int) -> None:
|
||||
"""Init DPCodeBitmapWrapper."""
|
||||
super().__init__(dpcode)
|
||||
self._mask = mask
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> bool | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (raw_value := device.status.get(self.dpcode)) is None:
|
||||
return None
|
||||
return (raw_value & (1 << self._mask)) != 0
|
||||
|
||||
@classmethod
|
||||
def find_dpcode(
|
||||
cls,
|
||||
device: CustomerDevice,
|
||||
dpcodes: str | tuple[str, ...],
|
||||
*,
|
||||
bitmap_key: str,
|
||||
) -> Self | None:
|
||||
"""Find and return a DPCodeBitmapBitWrapper for the given DP codes."""
|
||||
if (
|
||||
type_information := BitmapTypeInformation.find_dpcode(device, dpcodes)
|
||||
) and bitmap_key in type_information.label:
|
||||
return cls(
|
||||
type_information.dpcode, type_information.label.index(bitmap_key)
|
||||
)
|
||||
return None
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeIntegerWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.number import (
|
||||
@@ -25,7 +27,6 @@ from .const import (
|
||||
DPCode,
|
||||
)
|
||||
from .entity import TuyaEntity
|
||||
from .models import DeviceWrapper, DPCodeIntegerWrapper
|
||||
|
||||
NUMBERS: dict[DeviceCategory, tuple[NumberEntityDescription, ...]] = {
|
||||
DeviceCategory.BH: (
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
"""Parsers for RAW (base64-encoded bytes) values."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
import struct
|
||||
from typing import Self
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class ElectricityData:
|
||||
"""Electricity RAW value."""
|
||||
|
||||
current: float
|
||||
power: float
|
||||
voltage: float
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, raw: bytes) -> Self | None:
|
||||
"""Parse bytes and return an ElectricityValue object."""
|
||||
# Format:
|
||||
# - legacy: 8 bytes
|
||||
# - v01: [ver=0x01][len=0x0F][data(15 bytes)]
|
||||
# - v02: [ver=0x02][len=0x0F][data(15 bytes)][sign_bitmap(1 byte)]
|
||||
# Data layout (big-endian):
|
||||
# - voltage: 2B, unit 0.1 V
|
||||
# - current: 3B, unit 0.001 A (i.e., mA)
|
||||
# - active power: 3B, unit 0.001 kW (i.e., W)
|
||||
# - reactive power: 3B, unit 0.001 kVar
|
||||
# - apparent power: 3B, unit 0.001 kVA
|
||||
# - power factor: 1B, unit 0.01
|
||||
# Sign bitmap (v02 only, 1 bit means negative):
|
||||
# - bit0 current
|
||||
# - bit1 active power
|
||||
# - bit2 reactive
|
||||
# - bit3 power factor
|
||||
|
||||
is_v1 = len(raw) == 17 and raw[0:2] == b"\x01\x0f"
|
||||
is_v2 = len(raw) == 18 and raw[0:2] == b"\x02\x0f"
|
||||
if is_v1 or is_v2:
|
||||
data = raw[2:17]
|
||||
|
||||
voltage = struct.unpack(">H", data[0:2])[0] / 10.0
|
||||
current = struct.unpack(">L", b"\x00" + data[2:5])[0]
|
||||
power = struct.unpack(">L", b"\x00" + data[5:8])[0]
|
||||
|
||||
if is_v2:
|
||||
sign_bitmap = raw[17]
|
||||
if sign_bitmap & 0x01:
|
||||
current = -current
|
||||
if sign_bitmap & 0x02:
|
||||
power = -power
|
||||
|
||||
return cls(current=current, power=power, voltage=voltage)
|
||||
|
||||
if len(raw) >= 8:
|
||||
voltage = struct.unpack(">H", raw[0:2])[0] / 10.0
|
||||
current = struct.unpack(">L", b"\x00" + raw[2:5])[0]
|
||||
power = struct.unpack(">L", b"\x00" + raw[5:8])[0]
|
||||
return cls(current=current, power=power, voltage=voltage)
|
||||
|
||||
return None
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeEnumWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.select import SelectEntity, SelectEntityDescription
|
||||
@@ -13,7 +15,6 @@ 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 DeviceWrapper, 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.
|
||||
|
||||
@@ -4,6 +4,24 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
DPCodeTypeInformationWrapper,
|
||||
DPCodeWrapper,
|
||||
)
|
||||
from tuya_device_handlers.device_wrapper.sensor import (
|
||||
DeltaIntegerWrapper,
|
||||
ElectricityCurrentJsonWrapper,
|
||||
ElectricityCurrentRawWrapper,
|
||||
ElectricityPowerJsonWrapper,
|
||||
ElectricityPowerRawWrapper,
|
||||
ElectricityVoltageJsonWrapper,
|
||||
ElectricityVoltageRawWrapper,
|
||||
WindDirectionEnumWrapper,
|
||||
)
|
||||
from tuya_device_handlers.type_information import IntegerTypeInformation
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
@@ -38,138 +56,10 @@ from .const import (
|
||||
DPCode,
|
||||
)
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DeviceWrapper,
|
||||
DPCodeDeltaIntegerWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
DPCodeJsonWrapper,
|
||||
DPCodeRawWrapper,
|
||||
DPCodeTypeInformationWrapper,
|
||||
DPCodeWrapper,
|
||||
)
|
||||
from .raw_data_models import ElectricityData
|
||||
from .type_information import EnumTypeInformation, IntegerTypeInformation
|
||||
|
||||
|
||||
class _WindDirectionWrapper(DPCodeTypeInformationWrapper[EnumTypeInformation]):
|
||||
"""Custom DPCode Wrapper for converting enum to wind direction."""
|
||||
|
||||
_DPTYPE = EnumTypeInformation
|
||||
|
||||
_WIND_DIRECTIONS = {
|
||||
"north": 0.0,
|
||||
"north_north_east": 22.5,
|
||||
"north_east": 45.0,
|
||||
"east_north_east": 67.5,
|
||||
"east": 90.0,
|
||||
"east_south_east": 112.5,
|
||||
"south_east": 135.0,
|
||||
"south_south_east": 157.5,
|
||||
"south": 180.0,
|
||||
"south_south_west": 202.5,
|
||||
"south_west": 225.0,
|
||||
"west_south_west": 247.5,
|
||||
"west": 270.0,
|
||||
"west_north_west": 292.5,
|
||||
"north_west": 315.0,
|
||||
"north_north_west": 337.5,
|
||||
}
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (raw_value := device.status.get(self.dpcode)) in self.type_information.range:
|
||||
return self._WIND_DIRECTIONS.get(raw_value)
|
||||
return None
|
||||
|
||||
|
||||
class _JsonElectricityCurrentWrapper(DPCodeJsonWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity current from JSON."""
|
||||
|
||||
native_unit = UnitOfElectricCurrent.AMPERE
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (status := super().read_device_status(device)) is None:
|
||||
return None
|
||||
return status.get("electricCurrent")
|
||||
|
||||
|
||||
class _JsonElectricityPowerWrapper(DPCodeJsonWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity power from JSON."""
|
||||
|
||||
native_unit = UnitOfPower.KILO_WATT
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (status := super().read_device_status(device)) is None:
|
||||
return None
|
||||
return status.get("power")
|
||||
|
||||
|
||||
class _JsonElectricityVoltageWrapper(DPCodeJsonWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity voltage from JSON."""
|
||||
|
||||
native_unit = UnitOfElectricPotential.VOLT
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (status := super().read_device_status(device)) is None:
|
||||
return None
|
||||
return status.get("voltage")
|
||||
|
||||
|
||||
class _RawElectricityDataWrapper(DPCodeRawWrapper):
|
||||
"""Custom DPCode Wrapper for extracting ElectricityData from base64."""
|
||||
|
||||
def _convert(self, value: ElectricityData) -> float:
|
||||
"""Extract specific value from T."""
|
||||
raise NotImplementedError
|
||||
|
||||
def read_device_status(self, device: CustomerDevice) -> float | None:
|
||||
"""Read the device value for the dpcode."""
|
||||
if (raw_value := super().read_device_status(device)) is None or (
|
||||
value := ElectricityData.from_bytes(raw_value)
|
||||
) is None:
|
||||
return None
|
||||
return self._convert(value)
|
||||
|
||||
|
||||
class _RawElectricityCurrentWrapper(_RawElectricityDataWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity current from base64."""
|
||||
|
||||
native_unit = UnitOfElectricCurrent.MILLIAMPERE
|
||||
suggested_unit = UnitOfElectricCurrent.AMPERE
|
||||
|
||||
def _convert(self, value: ElectricityData) -> float:
|
||||
"""Extract specific value from ElectricityData."""
|
||||
return value.current
|
||||
|
||||
|
||||
class _RawElectricityPowerWrapper(_RawElectricityDataWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity power from base64."""
|
||||
|
||||
native_unit = UnitOfPower.WATT
|
||||
suggested_unit = UnitOfPower.KILO_WATT
|
||||
|
||||
def _convert(self, value: ElectricityData) -> float:
|
||||
"""Extract specific value from ElectricityData."""
|
||||
return value.power
|
||||
|
||||
|
||||
class _RawElectricityVoltageWrapper(_RawElectricityDataWrapper):
|
||||
"""Custom DPCode Wrapper for extracting electricity voltage from base64."""
|
||||
|
||||
native_unit = UnitOfElectricPotential.VOLT
|
||||
|
||||
def _convert(self, value: ElectricityData) -> float:
|
||||
"""Extract specific value from ElectricityData."""
|
||||
return value.voltage
|
||||
|
||||
|
||||
CURRENT_WRAPPER = (_RawElectricityCurrentWrapper, _JsonElectricityCurrentWrapper)
|
||||
POWER_WRAPPER = (_RawElectricityPowerWrapper, _JsonElectricityPowerWrapper)
|
||||
VOLTAGE_WRAPPER = (_RawElectricityVoltageWrapper, _JsonElectricityVoltageWrapper)
|
||||
CURRENT_WRAPPER = (ElectricityCurrentRawWrapper, ElectricityCurrentJsonWrapper)
|
||||
POWER_WRAPPER = (ElectricityPowerRawWrapper, ElectricityPowerJsonWrapper)
|
||||
VOLTAGE_WRAPPER = (ElectricityVoltageRawWrapper, ElectricityVoltageJsonWrapper)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -1069,7 +959,7 @@ SENSORS: dict[DeviceCategory, tuple[TuyaSensorEntityDescription, ...]] = {
|
||||
translation_key="wind_direction",
|
||||
device_class=SensorDeviceClass.WIND_DIRECTION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
wrapper_class=(_WindDirectionWrapper,),
|
||||
wrapper_class=(WindDirectionEnumWrapper,),
|
||||
),
|
||||
TuyaSensorEntityDescription(
|
||||
key=DPCode.DEW_POINT_TEMP,
|
||||
@@ -1743,7 +1633,7 @@ def _get_dpcode_wrapper(
|
||||
# Check for integer type first, using delta wrapper only for sum report_type
|
||||
if type_information := IntegerTypeInformation.find_dpcode(device, dpcode):
|
||||
if type_information.report_type == "sum":
|
||||
return DPCodeDeltaIntegerWrapper(type_information.dpcode, type_information)
|
||||
return DeltaIntegerWrapper(type_information.dpcode, type_information)
|
||||
return DPCodeIntegerWrapper(type_information.dpcode, type_information)
|
||||
|
||||
return DPCodeEnumWrapper.find_dpcode(device, dpcode)
|
||||
|
||||
@@ -4,6 +4,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeBooleanWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.siren import (
|
||||
@@ -19,7 +21,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper
|
||||
|
||||
SIRENS: dict[DeviceCategory, tuple[SirenEntityDescription, ...]] = {
|
||||
DeviceCategory.CO2BJ: (
|
||||
|
||||
@@ -5,6 +5,8 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeBooleanWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
@@ -27,7 +29,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
"""Type information classes for the Tuya integration."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, ClassVar, Self, cast
|
||||
|
||||
from tuya_sharing import CustomerDevice
|
||||
|
||||
from homeassistant.util.json import json_loads_object
|
||||
|
||||
from .const import LOGGER, DPType
|
||||
from .util import parse_dptype
|
||||
|
||||
# Dictionary to track logged warnings to avoid spamming logs
|
||||
# Keyed by device ID
|
||||
DEVICE_WARNINGS: dict[str, set[str]] = {}
|
||||
|
||||
|
||||
def _should_log_warning(device_id: str, warning_key: str) -> bool:
|
||||
"""Check if a warning has already been logged for a device and add it if not.
|
||||
|
||||
Returns: True if the warning should be logged, False if it was already logged.
|
||||
"""
|
||||
if (device_warnings := DEVICE_WARNINGS.get(device_id)) is None:
|
||||
device_warnings = set()
|
||||
DEVICE_WARNINGS[device_id] = device_warnings
|
||||
if warning_key in device_warnings:
|
||||
return False
|
||||
DEVICE_WARNINGS[device_id].add(warning_key)
|
||||
return True
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class TypeInformation[T]:
|
||||
"""Type information.
|
||||
|
||||
As provided by the SDK, from `device.function` / `device.status_range`.
|
||||
"""
|
||||
|
||||
_DPTYPE: ClassVar[DPType]
|
||||
dpcode: str
|
||||
type_data: str
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> T | None:
|
||||
"""Read and process raw value against this type information.
|
||||
|
||||
Base implementation does no validation, subclasses may override to provide
|
||||
specific validation.
|
||||
"""
|
||||
return raw_value
|
||||
|
||||
@classmethod
|
||||
def _from_json(
|
||||
cls, dpcode: str, type_data: str, *, report_type: str | None
|
||||
) -> Self | None:
|
||||
"""Load JSON string and return a TypeInformation object."""
|
||||
return cls(dpcode=dpcode, type_data=type_data)
|
||||
|
||||
@classmethod
|
||||
def find_dpcode(
|
||||
cls,
|
||||
device: CustomerDevice,
|
||||
dpcodes: str | tuple[str, ...] | None,
|
||||
*,
|
||||
prefer_function: bool = False,
|
||||
) -> Self | None:
|
||||
"""Find type information for a matching DP code available for this device."""
|
||||
if dpcodes is None:
|
||||
return None
|
||||
|
||||
if not isinstance(dpcodes, tuple):
|
||||
dpcodes = (dpcodes,)
|
||||
|
||||
lookup_tuple = (
|
||||
(device.function, device.status_range)
|
||||
if prefer_function
|
||||
else (device.status_range, device.function)
|
||||
)
|
||||
|
||||
for dpcode in dpcodes:
|
||||
report_type = (
|
||||
sr.report_type if (sr := device.status_range.get(dpcode)) else None
|
||||
)
|
||||
for device_specs in lookup_tuple:
|
||||
if (
|
||||
(current_definition := device_specs.get(dpcode))
|
||||
and parse_dptype(current_definition.type) is cls._DPTYPE
|
||||
and (
|
||||
type_information := cls._from_json(
|
||||
dpcode=dpcode,
|
||||
type_data=current_definition.values,
|
||||
report_type=report_type,
|
||||
)
|
||||
)
|
||||
):
|
||||
return type_information
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class BitmapTypeInformation(TypeInformation[int]):
|
||||
"""Bitmap type information."""
|
||||
|
||||
_DPTYPE = DPType.BITMAP
|
||||
|
||||
label: list[str]
|
||||
|
||||
@classmethod
|
||||
def _from_json(
|
||||
cls, dpcode: str, type_data: str, *, report_type: str | None
|
||||
) -> Self | None:
|
||||
"""Load JSON string and return a BitmapTypeInformation object."""
|
||||
if not (parsed := cast(dict[str, Any] | None, json_loads_object(type_data))):
|
||||
return None
|
||||
return cls(
|
||||
dpcode=dpcode,
|
||||
type_data=type_data,
|
||||
label=parsed["label"],
|
||||
)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class BooleanTypeInformation(TypeInformation[bool]):
|
||||
"""Boolean type information."""
|
||||
|
||||
_DPTYPE = DPType.BOOLEAN
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> bool | None:
|
||||
"""Read and process raw value against this type information."""
|
||||
if raw_value is None:
|
||||
return None
|
||||
# Validate input against defined range
|
||||
if raw_value not in (True, False):
|
||||
if _should_log_warning(
|
||||
device.id, f"boolean_out_range|{self.dpcode}|{raw_value}"
|
||||
):
|
||||
LOGGER.warning(
|
||||
"Found invalid boolean value `%s` for datapoint `%s` in product "
|
||||
"id `%s`, expected one of `%s`; please report this defect to "
|
||||
"Tuya support",
|
||||
raw_value,
|
||||
self.dpcode,
|
||||
device.product_id,
|
||||
(True, False),
|
||||
)
|
||||
return None
|
||||
return raw_value
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class EnumTypeInformation(TypeInformation[str]):
|
||||
"""Enum type information."""
|
||||
|
||||
_DPTYPE = DPType.ENUM
|
||||
|
||||
range: list[str]
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> str | None:
|
||||
"""Read and process raw value against this type information."""
|
||||
if raw_value is None:
|
||||
return None
|
||||
# Validate input against defined range
|
||||
if raw_value not in self.range:
|
||||
if _should_log_warning(
|
||||
device.id, f"enum_out_range|{self.dpcode}|{raw_value}"
|
||||
):
|
||||
LOGGER.warning(
|
||||
"Found invalid enum value `%s` for datapoint `%s` in product "
|
||||
"id `%s`, expected one of `%s`; please report this defect to "
|
||||
"Tuya support",
|
||||
raw_value,
|
||||
self.dpcode,
|
||||
device.product_id,
|
||||
self.range,
|
||||
)
|
||||
return None
|
||||
return raw_value
|
||||
|
||||
@classmethod
|
||||
def _from_json(
|
||||
cls, dpcode: str, type_data: str, *, report_type: str | None
|
||||
) -> Self | None:
|
||||
"""Load JSON string and return an EnumTypeInformation object."""
|
||||
if not (parsed := json_loads_object(type_data)):
|
||||
return None
|
||||
return cls(
|
||||
dpcode=dpcode,
|
||||
type_data=type_data,
|
||||
**cast(dict[str, list[str]], parsed),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class IntegerTypeInformation(TypeInformation[float]):
|
||||
"""Integer type information."""
|
||||
|
||||
_DPTYPE = DPType.INTEGER
|
||||
|
||||
min: int
|
||||
max: int
|
||||
scale: int
|
||||
step: int
|
||||
unit: str | None = None
|
||||
report_type: str | None
|
||||
|
||||
def scale_value(self, value: int) -> float:
|
||||
"""Scale a value."""
|
||||
return value / (10**self.scale)
|
||||
|
||||
def scale_value_back(self, value: float) -> int:
|
||||
"""Return raw value for scaled."""
|
||||
return round(value * (10**self.scale))
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> float | None:
|
||||
"""Read and process raw value against this type information."""
|
||||
if raw_value is None:
|
||||
return None
|
||||
# Validate input against defined range
|
||||
if not isinstance(raw_value, int) or not (self.min <= raw_value <= self.max):
|
||||
if _should_log_warning(
|
||||
device.id, f"integer_out_range|{self.dpcode}|{raw_value}"
|
||||
):
|
||||
LOGGER.warning(
|
||||
"Found invalid integer value `%s` for datapoint `%s` in product "
|
||||
"id `%s`, expected integer value between %s and %s; please report "
|
||||
"this defect to Tuya support",
|
||||
raw_value,
|
||||
self.dpcode,
|
||||
device.product_id,
|
||||
self.min,
|
||||
self.max,
|
||||
)
|
||||
|
||||
return None
|
||||
return raw_value / (10**self.scale)
|
||||
|
||||
@classmethod
|
||||
def _from_json(
|
||||
cls, dpcode: str, type_data: str, *, report_type: str | None
|
||||
) -> Self | None:
|
||||
"""Load JSON string and return an IntegerTypeInformation object."""
|
||||
if not (parsed := cast(dict[str, Any] | None, json_loads_object(type_data))):
|
||||
return None
|
||||
|
||||
return cls(
|
||||
dpcode=dpcode,
|
||||
type_data=type_data,
|
||||
min=int(parsed["min"]),
|
||||
max=int(parsed["max"]),
|
||||
scale=int(parsed["scale"]),
|
||||
step=int(parsed["step"]),
|
||||
unit=parsed.get("unit"),
|
||||
report_type=report_type,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class JsonTypeInformation(TypeInformation[dict[str, Any]]):
|
||||
"""Json type information."""
|
||||
|
||||
_DPTYPE = DPType.JSON
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> dict[str, Any] | None:
|
||||
"""Read and process raw value against this type information."""
|
||||
if raw_value is None:
|
||||
return None
|
||||
return json_loads_object(raw_value)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class RawTypeInformation(TypeInformation[bytes]):
|
||||
"""Raw type information."""
|
||||
|
||||
_DPTYPE = DPType.RAW
|
||||
|
||||
def process_raw_value(
|
||||
self, raw_value: Any | None, device: CustomerDevice
|
||||
) -> bytes | None:
|
||||
"""Read and process raw value against this type information."""
|
||||
if raw_value is None:
|
||||
return None
|
||||
return base64.b64decode(raw_value)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class StringTypeInformation(TypeInformation[str]):
|
||||
"""String type information."""
|
||||
|
||||
_DPTYPE = DPType.STRING
|
||||
@@ -2,27 +2,11 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from tuya_sharing import CustomerDevice
|
||||
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
|
||||
from .const import DOMAIN, DPCode, DPType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .type_information import IntegerTypeInformation
|
||||
|
||||
_DPTYPE_MAPPING: dict[str, DPType] = {
|
||||
"bitmap": DPType.BITMAP,
|
||||
"bool": DPType.BOOLEAN,
|
||||
"enum": DPType.ENUM,
|
||||
"json": DPType.JSON,
|
||||
"raw": DPType.RAW,
|
||||
"string": DPType.STRING,
|
||||
"value": DPType.INTEGER,
|
||||
}
|
||||
from .const import DOMAIN, DPCode
|
||||
|
||||
|
||||
def get_dpcode(
|
||||
@@ -46,90 +30,6 @@ def get_dpcode(
|
||||
return None
|
||||
|
||||
|
||||
def parse_dptype(dptype: str) -> DPType | None:
|
||||
"""Parse DPType from device DPCode information."""
|
||||
try:
|
||||
return DPType(dptype)
|
||||
except ValueError:
|
||||
# Sometimes, we get ill-formed DPTypes from the cloud,
|
||||
# this fixes them and maps them to the correct DPType.
|
||||
return _DPTYPE_MAPPING.get(dptype)
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class RemapHelper:
|
||||
"""Helper class for remapping values."""
|
||||
|
||||
source_min: int
|
||||
source_max: int
|
||||
target_min: int
|
||||
target_max: int
|
||||
|
||||
@classmethod
|
||||
def from_type_information(
|
||||
cls,
|
||||
type_information: IntegerTypeInformation,
|
||||
target_min: int,
|
||||
target_max: int,
|
||||
) -> RemapHelper:
|
||||
"""Create RemapHelper from IntegerTypeInformation."""
|
||||
return cls(
|
||||
source_min=type_information.min,
|
||||
source_max=type_information.max,
|
||||
target_min=target_min,
|
||||
target_max=target_max,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_function_data(
|
||||
cls, function_data: dict[str, Any], target_min: int, target_max: int
|
||||
) -> RemapHelper:
|
||||
"""Create RemapHelper from function_data."""
|
||||
return cls(
|
||||
source_min=function_data["min"],
|
||||
source_max=function_data["max"],
|
||||
target_min=target_min,
|
||||
target_max=target_max,
|
||||
)
|
||||
|
||||
def remap_value_to(self, value: float, *, reverse: bool = False) -> float:
|
||||
"""Remap a value from this range to a new range."""
|
||||
return self.remap_value(
|
||||
value,
|
||||
self.source_min,
|
||||
self.source_max,
|
||||
self.target_min,
|
||||
self.target_max,
|
||||
reverse=reverse,
|
||||
)
|
||||
|
||||
def remap_value_from(self, value: float, *, reverse: bool = False) -> float:
|
||||
"""Remap a value from its current range to this range."""
|
||||
return self.remap_value(
|
||||
value,
|
||||
self.target_min,
|
||||
self.target_max,
|
||||
self.source_min,
|
||||
self.source_max,
|
||||
reverse=reverse,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def remap_value(
|
||||
value: float,
|
||||
from_min: float,
|
||||
from_max: float,
|
||||
to_min: float,
|
||||
to_max: float,
|
||||
*,
|
||||
reverse: bool = False,
|
||||
) -> float:
|
||||
"""Remap a value from its current range, to a new range."""
|
||||
if reverse:
|
||||
value = from_max - value + from_min
|
||||
return ((value - from_min) / (from_max - from_min)) * (to_max - to_min) + to_min
|
||||
|
||||
|
||||
class ActionDPCodeNotFoundError(ServiceValidationError):
|
||||
"""Custom exception for action DP code not found errors."""
|
||||
|
||||
|
||||
@@ -4,6 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Self
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
)
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
@@ -18,7 +23,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper, DPCodeEnumWrapper
|
||||
|
||||
|
||||
class _VacuumActivityWrapper(DeviceWrapper):
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from tuya_device_handlers.device_wrapper.base import DeviceWrapper
|
||||
from tuya_device_handlers.device_wrapper.common import DPCodeBooleanWrapper
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.valve import (
|
||||
@@ -17,7 +19,6 @@ 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 DeviceWrapper, DPCodeBooleanWrapper
|
||||
|
||||
VALVES: dict[DeviceCategory, tuple[ValveEntityDescription, ...]] = {
|
||||
DeviceCategory.SFKZQ: (
|
||||
|
||||
3
requirements_all.txt
generated
3
requirements_all.txt
generated
@@ -3061,6 +3061,9 @@ ttls==1.8.3
|
||||
# homeassistant.components.thethingsnetwork
|
||||
ttn_client==1.2.3
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-device-handlers==0.0.10
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-device-sharing-sdk==0.2.8
|
||||
|
||||
|
||||
3
requirements_test_all.txt
generated
3
requirements_test_all.txt
generated
@@ -2558,6 +2558,9 @@ ttls==1.8.3
|
||||
# homeassistant.components.thethingsnetwork
|
||||
ttn_client==1.2.3
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-device-handlers==0.0.10
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-device-sharing-sdk==0.2.8
|
||||
|
||||
|
||||
@@ -5704,7 +5704,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -5716,7 +5716,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_current-state]
|
||||
@@ -5725,7 +5725,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': '断路器HA Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_current',
|
||||
@@ -5764,7 +5764,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -5776,7 +5776,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_power-state]
|
||||
@@ -5785,7 +5785,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': '断路器HA Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_power',
|
||||
@@ -5833,7 +5833,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_voltage-state]
|
||||
@@ -5842,7 +5842,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': '断路器HA Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.duan_lu_qi_ha_phase_a_voltage',
|
||||
@@ -6225,7 +6225,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -6237,7 +6237,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_a_current-state]
|
||||
@@ -6246,7 +6246,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Edesanya Energy Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_a_current',
|
||||
@@ -6285,7 +6285,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -6297,7 +6297,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_a_power-state]
|
||||
@@ -6306,7 +6306,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Edesanya Energy Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_a_power',
|
||||
@@ -6354,7 +6354,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_a_voltage-state]
|
||||
@@ -6363,7 +6363,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Edesanya Energy Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_a_voltage',
|
||||
@@ -6402,7 +6402,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -6414,7 +6414,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_current',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_belectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_b_current-state]
|
||||
@@ -6423,7 +6423,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Edesanya Energy Phase B current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_b_current',
|
||||
@@ -6462,7 +6462,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -6474,7 +6474,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_power',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_bpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_b_power-state]
|
||||
@@ -6483,7 +6483,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Edesanya Energy Phase B power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_b_power',
|
||||
@@ -6531,7 +6531,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_voltage',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_bvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_b_voltage-state]
|
||||
@@ -6540,7 +6540,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Edesanya Energy Phase B voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_b_voltage',
|
||||
@@ -6579,7 +6579,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -6591,7 +6591,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_current',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_celectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_c_current-state]
|
||||
@@ -6600,7 +6600,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Edesanya Energy Phase C current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_c_current',
|
||||
@@ -6639,7 +6639,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -6651,7 +6651,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_power',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_cpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_c_power-state]
|
||||
@@ -6660,7 +6660,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Edesanya Energy Phase C power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_c_power',
|
||||
@@ -6708,7 +6708,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_voltage',
|
||||
'unique_id': 'tuya.vcrfgwvbuybgnj3zqldphase_cvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.edesanya_energy_phase_c_voltage-state]
|
||||
@@ -6717,7 +6717,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Edesanya Energy Phase C voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.edesanya_energy_phase_c_voltage',
|
||||
@@ -12443,7 +12443,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -12455,7 +12455,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_a_current-state]
|
||||
@@ -12464,7 +12464,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Medidor de Energia Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_a_current',
|
||||
@@ -12503,7 +12503,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -12515,7 +12515,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_a_power-state]
|
||||
@@ -12524,7 +12524,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Medidor de Energia Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_a_power',
|
||||
@@ -12572,7 +12572,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_a_voltage-state]
|
||||
@@ -12581,7 +12581,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Medidor de Energia Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_a_voltage',
|
||||
@@ -12620,7 +12620,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -12632,7 +12632,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_current',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_belectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_b_current-state]
|
||||
@@ -12641,7 +12641,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Medidor de Energia Phase B current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_b_current',
|
||||
@@ -12680,7 +12680,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -12692,7 +12692,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_power',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_bpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_b_power-state]
|
||||
@@ -12701,7 +12701,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Medidor de Energia Phase B power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_b_power',
|
||||
@@ -12749,7 +12749,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_voltage',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_bvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_b_voltage-state]
|
||||
@@ -12758,7 +12758,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Medidor de Energia Phase B voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_b_voltage',
|
||||
@@ -12797,7 +12797,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -12809,7 +12809,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_current',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_celectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_c_current-state]
|
||||
@@ -12818,7 +12818,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Medidor de Energia Phase C current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_c_current',
|
||||
@@ -12857,7 +12857,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -12869,7 +12869,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_power',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_cpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_c_power-state]
|
||||
@@ -12878,7 +12878,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Medidor de Energia Phase C power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_c_power',
|
||||
@@ -12926,7 +12926,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_voltage',
|
||||
'unique_id': 'tuya.6pd3bkidqldphase_cvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.medidor_de_energia_phase_c_voltage-state]
|
||||
@@ -12935,7 +12935,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Medidor de Energia Phase C voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.medidor_de_energia_phase_c_voltage',
|
||||
@@ -13145,7 +13145,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -13157,7 +13157,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.nnqlg0rxryraf8ezbdnzphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.meter_phase_a_current-state]
|
||||
@@ -13166,7 +13166,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Meter Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.meter_phase_a_current',
|
||||
@@ -13205,7 +13205,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -13217,7 +13217,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.nnqlg0rxryraf8ezbdnzphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.meter_phase_a_power-state]
|
||||
@@ -13226,7 +13226,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Meter Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.meter_phase_a_power',
|
||||
@@ -13274,7 +13274,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.nnqlg0rxryraf8ezbdnzphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.meter_phase_a_voltage-state]
|
||||
@@ -13283,7 +13283,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Meter Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.meter_phase_a_voltage',
|
||||
@@ -13436,7 +13436,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -13448,7 +13448,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_a_current-state]
|
||||
@@ -13457,7 +13457,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_a_current',
|
||||
@@ -13496,7 +13496,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -13508,7 +13508,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_a_power-state]
|
||||
@@ -13517,7 +13517,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_a_power',
|
||||
@@ -13565,7 +13565,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_a_voltage-state]
|
||||
@@ -13574,7 +13574,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_a_voltage',
|
||||
@@ -13613,7 +13613,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -13625,7 +13625,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_current',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_belectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_b_current-state]
|
||||
@@ -13634,7 +13634,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase B current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_b_current',
|
||||
@@ -13673,7 +13673,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -13685,7 +13685,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_power',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_bpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_b_power-state]
|
||||
@@ -13694,7 +13694,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase B power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_b_power',
|
||||
@@ -13742,7 +13742,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_voltage',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_bvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_b_voltage-state]
|
||||
@@ -13751,7 +13751,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase B voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_b_voltage',
|
||||
@@ -13790,7 +13790,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -13802,7 +13802,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_current',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_celectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_c_current-state]
|
||||
@@ -13811,7 +13811,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase C current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_c_current',
|
||||
@@ -13850,7 +13850,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -13862,7 +13862,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_power',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_cpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_c_power-state]
|
||||
@@ -13871,7 +13871,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase C power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_c_power',
|
||||
@@ -13919,7 +13919,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_voltage',
|
||||
'unique_id': 'tuya.obb7p55c0us6rdxkqldphase_cvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_phase_c_voltage-state]
|
||||
@@ -13928,7 +13928,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'Metering_3PN_WiFi_stable Phase C voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.metering_3pn_wifi_stable_phase_c_voltage',
|
||||
@@ -15238,7 +15238,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -15250,7 +15250,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_a_current-state]
|
||||
@@ -15259,7 +15259,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_a_current',
|
||||
@@ -15298,7 +15298,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -15310,7 +15310,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_a_power-state]
|
||||
@@ -15319,7 +15319,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_a_power',
|
||||
@@ -15367,7 +15367,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_a_voltage-state]
|
||||
@@ -15376,7 +15376,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_a_voltage',
|
||||
@@ -15415,7 +15415,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -15427,7 +15427,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_current',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_belectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_b_current-state]
|
||||
@@ -15436,7 +15436,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase B current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_b_current',
|
||||
@@ -15475,7 +15475,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -15487,7 +15487,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_power',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_bpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_b_power-state]
|
||||
@@ -15496,7 +15496,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase B power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_b_power',
|
||||
@@ -15544,7 +15544,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_b_voltage',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_bvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_b_voltage-state]
|
||||
@@ -15553,7 +15553,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase B voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_b_voltage',
|
||||
@@ -15592,7 +15592,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'suggested_unit_of_measurement': 'A',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||
@@ -15604,7 +15604,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_current',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_celectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_c_current-state]
|
||||
@@ -15613,7 +15613,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase C current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_c_current',
|
||||
@@ -15652,7 +15652,7 @@
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
'sensor.private': dict({
|
||||
'suggested_unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'suggested_unit_of_measurement': 'kW',
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
|
||||
@@ -15664,7 +15664,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_power',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_cpower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_c_power-state]
|
||||
@@ -15673,7 +15673,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase C power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_c_power',
|
||||
@@ -15721,7 +15721,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_c_voltage',
|
||||
'unique_id': 'tuya.bcyciyhhu1g2gk9rqldphase_cvoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.p1_energia_elettrica_phase_c_voltage-state]
|
||||
@@ -15730,7 +15730,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'P1 Energia Elettrica Phase C voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.p1_energia_elettrica_phase_c_voltage',
|
||||
@@ -24155,7 +24155,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_current',
|
||||
'unique_id': 'tuya.9oh1h1uyalfykgg4bdnzphase_aelectriccurrent',
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_phase_a_current-state]
|
||||
@@ -24164,7 +24164,7 @@
|
||||
'device_class': 'current',
|
||||
'friendly_name': 'XOCA-DAC212XC V2-S1 Phase A current',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||
'unit_of_measurement': 'A',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.xoca_dac212xc_v2_s1_phase_a_current',
|
||||
@@ -24212,7 +24212,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_power',
|
||||
'unique_id': 'tuya.9oh1h1uyalfykgg4bdnzphase_apower',
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_phase_a_power-state]
|
||||
@@ -24221,7 +24221,7 @@
|
||||
'device_class': 'power',
|
||||
'friendly_name': 'XOCA-DAC212XC V2-S1 Phase A power',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
|
||||
'unit_of_measurement': 'kW',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.xoca_dac212xc_v2_s1_phase_a_power',
|
||||
@@ -24269,7 +24269,7 @@
|
||||
'supported_features': 0,
|
||||
'translation_key': 'phase_a_voltage',
|
||||
'unique_id': 'tuya.9oh1h1uyalfykgg4bdnzphase_avoltage',
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
})
|
||||
# ---
|
||||
# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_phase_a_voltage-state]
|
||||
@@ -24278,7 +24278,7 @@
|
||||
'device_class': 'voltage',
|
||||
'friendly_name': 'XOCA-DAC212XC V2-S1 Phase A voltage',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfElectricPotential.VOLT: 'V'>,
|
||||
'unit_of_measurement': 'V',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.xoca_dac212xc_v2_s1_phase_a_voltage',
|
||||
|
||||
Reference in New Issue
Block a user