1 """Tuya Home Assistant Base Device Model."""
3 from __future__
import annotations
6 from dataclasses
import dataclass
9 from typing
import Any, Literal, Self, overload
11 from tuya_sharing
import CustomerDevice, Manager
17 from .const
import DOMAIN, LOGGER, TUYA_HA_SIGNAL_UPDATE_ENTITY, DPCode, DPType
18 from .util
import remap_value
20 _DPTYPE_MAPPING: dict[str, DPType] = {
23 "bool": DPType.BOOLEAN,
27 "string": DPType.STRING,
28 "value": DPType.INTEGER,
34 """Integer Type Data."""
41 unit: str |
None =
None
42 type: str |
None =
None
46 """Return the max scaled."""
51 """Return the min scaled."""
56 """Return the step scaled."""
57 return self.step / (10**self.scale)
61 return value / (10**self.scale)
64 """Return raw value for scaled."""
65 return int(value * (10**self.scale))
72 reverse: bool =
False,
74 """Remap a value from this range to a new range."""
75 return remap_value(value, self.min, self.max, to_min, to_max, reverse)
81 from_max: float = 255,
82 reverse: bool =
False,
84 """Remap a value from its current range to this range."""
85 return remap_value(value, from_min, from_max, self.min, self.max, reverse)
88 def from_json(cls, dpcode: DPCode, data: str) -> IntegerTypeData |
None:
89 """Load JSON string and return a IntegerTypeData object."""
90 if not (parsed := json.loads(data)):
95 min=
int(parsed[
"min"]),
96 max=
int(parsed[
"max"]),
97 scale=
float(parsed[
"scale"]),
99 unit=parsed.get(
"unit"),
100 type=parsed.get(
"type"),
106 """Enum Type Data."""
112 def from_json(cls, dpcode: DPCode, data: str) -> EnumTypeData |
None:
113 """Load JSON string and return a EnumTypeData object."""
114 if not (parsed := json.loads(data)):
116 return cls(dpcode, **parsed)
121 """Electricity Type Data."""
123 electriccurrent: str |
None =
None
124 power: str |
None =
None
125 voltage: str |
None =
None
129 """Load JSON string and return a ElectricityTypeData object."""
130 return cls(**json.loads(data.lower()))
134 """Decode base64 string and return a ElectricityTypeData object."""
135 raw = base64.b64decode(data)
136 voltage = struct.unpack(
">H", raw[0:2])[0] / 10.0
137 electriccurrent = struct.unpack(
">L", b
"\x00" + raw[2:5])[0] / 1000.0
138 power = struct.unpack(
">L", b
"\x00" + raw[5:8])[0] / 1000.0
140 electriccurrent=
str(electriccurrent), power=
str(power), voltage=
str(voltage)
145 """Tuya base device."""
147 _attr_has_entity_name =
True
148 _attr_should_poll =
False
150 def __init__(self, device: CustomerDevice, device_manager: Manager) ->
None:
151 """Init TuyaHaEntity."""
160 """Return a device description for device registry."""
162 identifiers={(DOMAIN, self.
devicedevice.id)},
164 name=self.
devicedevice.name,
165 model=self.
devicedevice.product_name,
166 model_id=self.
devicedevice.product_id,
171 """Return if the device is available."""
172 return self.
devicedevice.online
177 dpcodes: str | DPCode | tuple[DPCode, ...] |
None,
179 prefer_function: bool =
False,
180 dptype: Literal[DPType.ENUM],
181 ) -> EnumTypeData |
None: ...
186 dpcodes: str | DPCode | tuple[DPCode, ...] |
None,
188 prefer_function: bool =
False,
189 dptype: Literal[DPType.INTEGER],
190 ) -> IntegerTypeData |
None: ...
195 dpcodes: str | DPCode | tuple[DPCode, ...] |
None,
197 prefer_function: bool =
False,
198 ) -> DPCode |
None: ...
202 dpcodes: str | DPCode | tuple[DPCode, ...] |
None,
204 prefer_function: bool =
False,
205 dptype: DPType |
None =
None,
206 ) -> DPCode | EnumTypeData | IntegerTypeData |
None:
207 """Find a matching DP code available on for this device."""
211 if isinstance(dpcodes, str):
212 dpcodes = (
DPCode(dpcodes),)
213 elif not isinstance(dpcodes, tuple):
216 order = [
"status_range",
"function"]
218 order = [
"function",
"status_range"]
223 order.append(
"status")
225 for dpcode
in dpcodes:
227 if dpcode
not in getattr(self.
devicedevice, key):
230 dptype == DPType.ENUM
231 and getattr(self.
devicedevice, key)[dpcode].type == DPType.ENUM
234 enum_type := EnumTypeData.from_json(
235 dpcode, getattr(self.
devicedevice, key)[dpcode].values
242 dptype == DPType.INTEGER
243 and getattr(self.
devicedevice, key)[dpcode].type == DPType.INTEGER
246 integer_type := IntegerTypeData.from_json(
247 dpcode, getattr(self.
devicedevice, key)[dpcode].values
253 if dptype
not in (DPType.ENUM, DPType.INTEGER):
259 self, dpcode: DPCode |
None, prefer_function: bool =
False
261 """Find a matching DPCode data type available on for this device."""
265 order = [
"status_range",
"function"]
267 order = [
"function",
"status_range"]
269 if dpcode
in getattr(self.
devicedevice, key):
270 current_type = getattr(self.
devicedevice, key)[dpcode].type
272 return DPType(current_type)
276 return _DPTYPE_MAPPING.get(current_type)
281 """Call when entity is added to hass."""
285 f
"{TUYA_HA_SIGNAL_UPDATE_ENTITY}_{self.device.id}",
291 self, updated_status_properties: list[str] |
None
296 """Send command to the device."""
297 LOGGER.debug(
"Sending commands for device %s: %s", self.
devicedevice.id, commands)
Self from_raw(cls, str data)
Self from_json(cls, str data)
EnumTypeData|None from_json(cls, DPCode dpcode, str data)
float scale_value(self, float value)
IntegerTypeData|None from_json(cls, DPCode dpcode, str data)
int scale_value_back(self, float value)
float remap_value_from(self, float value, float from_min=0, float from_max=255, bool reverse=False)
float remap_value_to(self, float value, float to_min=0, float to_max=255, bool reverse=False)
None __init__(self, CustomerDevice device, Manager device_manager)
None _send_command(self, list[dict[str, Any]] commands)
DeviceInfo device_info(self)
None _handle_state_update(self, list[str]|None updated_status_properties)
EnumTypeData|None find_dpcode(self, str|DPCode|tuple[DPCode,...]|None dpcodes, *bool prefer_function=False, Literal[DPType.ENUM] dptype)
DPType|None get_dptype(self, DPCode|None dpcode, bool prefer_function=False)
None async_added_to_hass(self)
None async_write_ha_state(self)
None async_on_remove(self, CALLBACK_TYPE func)
float remap_value(float value, float from_min=0, float from_max=255, float to_min=0, float to_max=255, bool reverse=False)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)