-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsensor.py
More file actions
118 lines (96 loc) · 4.11 KB
/
Copy pathsensor.py
File metadata and controls
118 lines (96 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .api import apply_transform
from .coordinator import ST480Coordinator
async def async_setup_entry(hass, entry, async_add_entities):
coord: ST480Coordinator = hass.data[DOMAIN][entry.entry_id]
regs = getattr(coord, "regs", [])
async_add_entities([ST480Sensor(coord, r) for r in regs], True)
class ST480Sensor(CoordinatorEntity[ST480Coordinator], SensorEntity):
def __init__(self, coordinator: ST480Coordinator, reg: dict):
super().__init__(coordinator)
self._reg = reg
self._gt = reg["gt"]
self._transform = reg.get("transform", {"type": "raw"})
self._value_type = reg.get("value_type")
self._enum_map = reg.get("enum_map")
self._last_good = None
self._attr_name = reg.get("name_en") or reg.get("name_cs") or str(self._gt)
self._attr_unique_id = f"{coordinator.api.host}_{self._gt}_{reg.get('key', self._gt)}"
self._attr_device_class = reg.get("device_class")
self._attr_state_class = reg.get("state_class")
self._attr_native_unit_of_measurement = reg.get("unit")
self._attr_icon = reg.get("icon")
@property
def available(self) -> bool:
raw = self.coordinator.data.get(self._gt) if self.coordinator.data else None
return bool(getattr(self.coordinator, "last_update_success", False)) and (
raw is not None or self._last_good is not None
)
def _render_enum_text(self, raw):
try:
code = int(raw)
except (TypeError, ValueError):
return None
maps = getattr(self.coordinator, "state_maps", {}) or {}
mapping = maps.get(self._enum_map or "", {}) or {}
item = mapping.get(code)
if isinstance(item, dict):
return item.get("cs") or item.get("en") or f"Unknown ({code})"
return f"Unknown ({code})"
@property
def extra_state_attributes(self):
if self._value_type == "enum_text":
raw = self.coordinator.data.get(self._gt) if self.coordinator.data else None
try:
if raw is not None:
return {"code": int(raw)}
except (TypeError, ValueError):
return {}
return {}
@property
def icon(self):
if self._value_type == "enum_text":
raw = self.coordinator.data.get(self._gt) if self.coordinator.data else None
try:
code = int(raw) if raw is not None else None
except (TypeError, ValueError):
code = None
if code in (2, 46): # operation / modulation
return "mdi:fire"
if code in (75, 80): # sustain
return "mdi:fireplace"
if code in (21, 22): # errors
return "mdi:alert"
return self._attr_icon
@property
def device_info(self):
return {
"identifiers": {(DOMAIN, self.coordinator.api.host)},
"name": "TECH ST-480",
"manufacturer": "TECH Controllers",
"model": "ST-480 + ST-500",
}
@property
def native_value(self):
raw = self.coordinator.data.get(self._gt) if self.coordinator.data else None
if self._value_type == "enum_text":
out = self._render_enum_text(raw) if raw is not None else None
elif self._value_type == "int":
try:
out = int(raw) if raw is not None else None
except (TypeError, ValueError):
out = None
else:
out = apply_transform(raw, self._transform) if raw is not None else None
# apply outdoor temperature offset
if out is not None and self._reg.get("key") == "t_outdoor":
offset = getattr(self.coordinator, "outdoor_temp_offset", 0.0)
if offset:
out = round(float(out) + offset, 1)
if out is None:
return self._last_good
self._last_good = out
return out