Move tuya models to separate module (#148550)

This commit is contained in:
epenet 2025-07-10 15:54:05 +02:00 committed by GitHub
parent 12f913e737
commit eb20292683
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 144 additions and 127 deletions

View File

@ -20,7 +20,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import EnumTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import EnumTypeData
@dataclass(frozen=True)

View File

@ -25,7 +25,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import IntegerTypeData
TUYA_HVAC_TO_HA = {
"auto": HVACMode.HEAT_COOL,

View File

@ -21,7 +21,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import IntegerTypeData
@dataclass(frozen=True)

View File

@ -2,11 +2,7 @@
from __future__ import annotations
import base64
from dataclasses import dataclass
import json
import struct
from typing import Any, Literal, Self, overload
from typing import Any, Literal, overload
from tuya_sharing import CustomerDevice, Manager
@ -15,7 +11,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity
from .const import DOMAIN, LOGGER, TUYA_HA_SIGNAL_UPDATE_ENTITY, DPCode, DPType
from .util import remap_value
from .models import EnumTypeData, IntegerTypeData
_DPTYPE_MAPPING: dict[str, DPType] = {
"Bitmap": DPType.RAW,
@ -29,118 +25,6 @@ _DPTYPE_MAPPING: dict[str, DPType] = {
}
@dataclass
class IntegerTypeData:
"""Integer Type Data."""
dpcode: DPCode
min: int
max: int
scale: float
step: float
unit: str | None = None
type: str | None = None
@property
def max_scaled(self) -> float:
"""Return the max scaled."""
return self.scale_value(self.max)
@property
def min_scaled(self) -> float:
"""Return the min scaled."""
return self.scale_value(self.min)
@property
def step_scaled(self) -> float:
"""Return the step scaled."""
return self.step / (10**self.scale)
def scale_value(self, value: float) -> float:
"""Scale a value."""
return value / (10**self.scale)
def scale_value_back(self, value: float) -> int:
"""Return raw value for scaled."""
return int(value * (10**self.scale))
def remap_value_to(
self,
value: float,
to_min: float = 0,
to_max: float = 255,
reverse: bool = False,
) -> float:
"""Remap a value from this range to a new range."""
return remap_value(value, self.min, self.max, to_min, to_max, reverse)
def remap_value_from(
self,
value: float,
from_min: float = 0,
from_max: float = 255,
reverse: bool = False,
) -> float:
"""Remap a value from its current range to this range."""
return remap_value(value, from_min, from_max, self.min, self.max, reverse)
@classmethod
def from_json(cls, dpcode: DPCode, data: str) -> IntegerTypeData | None:
"""Load JSON string and return a IntegerTypeData object."""
if not (parsed := json.loads(data)):
return None
return cls(
dpcode,
min=int(parsed["min"]),
max=int(parsed["max"]),
scale=float(parsed["scale"]),
step=max(float(parsed["step"]), 1),
unit=parsed.get("unit"),
type=parsed.get("type"),
)
@dataclass
class EnumTypeData:
"""Enum Type Data."""
dpcode: DPCode
range: list[str]
@classmethod
def from_json(cls, dpcode: DPCode, data: str) -> EnumTypeData | None:
"""Load JSON string and return a EnumTypeData object."""
if not (parsed := json.loads(data)):
return None
return cls(dpcode, **parsed)
@dataclass
class ElectricityTypeData:
"""Electricity Type Data."""
electriccurrent: str | None = None
power: str | None = None
voltage: str | None = None
@classmethod
def from_json(cls, data: str) -> Self:
"""Load JSON string and return a ElectricityTypeData object."""
return cls(**json.loads(data.lower()))
@classmethod
def from_raw(cls, data: str) -> Self:
"""Decode base64 string and return a ElectricityTypeData object."""
raw = base64.b64decode(data)
voltage = struct.unpack(">H", raw[0:2])[0] / 10.0
electriccurrent = struct.unpack(">L", b"\x00" + raw[2:5])[0] / 1000.0
power = struct.unpack(">L", b"\x00" + raw[5:8])[0] / 1000.0
return cls(
electriccurrent=str(electriccurrent), power=str(power), voltage=str(voltage)
)
class TuyaEntity(Entity):
"""Tuya base device."""

View File

@ -22,7 +22,8 @@ from homeassistant.util.percentage import (
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import EnumTypeData, IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import EnumTypeData, IntegerTypeData
TUYA_SUPPORT_TYPE = {
"cs", # Dehumidifier

View File

@ -19,7 +19,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import IntegerTypeData
@dataclass(frozen=True)

View File

@ -25,7 +25,8 @@ from homeassistant.util import color as color_util
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType, WorkMode
from .entity import IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import IntegerTypeData
from .util import remap_value

View File

@ -0,0 +1,124 @@
"""Tuya Home Assistant Base Device Model."""
from __future__ import annotations
import base64
from dataclasses import dataclass
import json
import struct
from typing import Self
from .const import DPCode
from .util import remap_value
@dataclass
class IntegerTypeData:
"""Integer Type Data."""
dpcode: DPCode
min: int
max: int
scale: float
step: float
unit: str | None = None
type: str | None = None
@property
def max_scaled(self) -> float:
"""Return the max scaled."""
return self.scale_value(self.max)
@property
def min_scaled(self) -> float:
"""Return the min scaled."""
return self.scale_value(self.min)
@property
def step_scaled(self) -> float:
"""Return the step scaled."""
return self.step / (10**self.scale)
def scale_value(self, value: float) -> float:
"""Scale a value."""
return value / (10**self.scale)
def scale_value_back(self, value: float) -> int:
"""Return raw value for scaled."""
return int(value * (10**self.scale))
def remap_value_to(
self,
value: float,
to_min: float = 0,
to_max: float = 255,
reverse: bool = False,
) -> float:
"""Remap a value from this range to a new range."""
return remap_value(value, self.min, self.max, to_min, to_max, reverse)
def remap_value_from(
self,
value: float,
from_min: float = 0,
from_max: float = 255,
reverse: bool = False,
) -> float:
"""Remap a value from its current range to this range."""
return remap_value(value, from_min, from_max, self.min, self.max, reverse)
@classmethod
def from_json(cls, dpcode: DPCode, data: str) -> IntegerTypeData | None:
"""Load JSON string and return a IntegerTypeData object."""
if not (parsed := json.loads(data)):
return None
return cls(
dpcode,
min=int(parsed["min"]),
max=int(parsed["max"]),
scale=float(parsed["scale"]),
step=max(float(parsed["step"]), 1),
unit=parsed.get("unit"),
type=parsed.get("type"),
)
@dataclass
class EnumTypeData:
"""Enum Type Data."""
dpcode: DPCode
range: list[str]
@classmethod
def from_json(cls, dpcode: DPCode, data: str) -> EnumTypeData | None:
"""Load JSON string and return a EnumTypeData object."""
if not (parsed := json.loads(data)):
return None
return cls(dpcode, **parsed)
@dataclass
class ElectricityTypeData:
"""Electricity Type Data."""
electriccurrent: str | None = None
power: str | None = None
voltage: str | None = None
@classmethod
def from_json(cls, data: str) -> Self:
"""Load JSON string and return a ElectricityTypeData object."""
return cls(**json.loads(data.lower()))
@classmethod
def from_raw(cls, data: str) -> Self:
"""Decode base64 string and return a ElectricityTypeData object."""
raw = base64.b64decode(data)
voltage = struct.unpack(">H", raw[0:2])[0] / 10.0
electriccurrent = struct.unpack(">L", b"\x00" + raw[2:5])[0] / 1000.0
power = struct.unpack(">L", b"\x00" + raw[5:8])[0] / 1000.0
return cls(
electriccurrent=str(electriccurrent), power=str(power), voltage=str(voltage)
)

View File

@ -16,7 +16,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import DEVICE_CLASS_UNITS, DOMAIN, TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import IntegerTypeData
# All descriptions can be found here. Mostly the Integer data types in the
# default instructions set of each category end up being a number.

View File

@ -35,7 +35,8 @@ from .const import (
DPType,
UnitOfMeasurement,
)
from .entity import ElectricityTypeData, EnumTypeData, IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import ElectricityTypeData, EnumTypeData, IntegerTypeData
@dataclass(frozen=True)

View File

@ -17,7 +17,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import TuyaConfigEntry
from .const import TUYA_DISCOVERY_NEW, DPCode, DPType
from .entity import EnumTypeData, IntegerTypeData, TuyaEntity
from .entity import TuyaEntity
from .models import EnumTypeData, IntegerTypeData
TUYA_MODE_RETURN_HOME = "chargego"
TUYA_STATUS_TO_HA = {