Skip to content

Commit 24f0774

Browse files
authored
Refactor fault handling and remove mode_selection
Removed mode_selection from SENSOR_TYPES and NUMBER_TYPES. Added fault description and per-bit fault binary sensors for better fault reporting.
1 parent 8ea0569 commit 24f0774

1 file changed

Lines changed: 136 additions & 28 deletions

File tree

  • custom_components/tuya_heat_pump/models

custom_components/tuya_heat_pump/models/ew8plw.py

Lines changed: 136 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
# contributed via raw_explorer.py's "text" field type — see the
1616
# TEXT_TYPES block at the bottom of this file.
1717
# - work_state (dp 3) and fault (dp 4) are read-only (accessMode "ro").
18-
# - mode_selection (dp 106) is a Default/ECO enum, exposed as a switch
19-
# (on = ECO, off = Default).
2018
# - Everything else here is accessMode "rw".
2119
# ====================================================
2220

@@ -27,6 +25,32 @@
2725
"name": "Work State",
2826
"icon": "mdi:coffee-maker",
2927
},
28+
# Fault Description (dp_id: 4) — Tuya's label array for this DP is
29+
# already in English (unusual, most devices need Chinese
30+
# translation), so used as-is, just cleaned up for readability.
31+
# 11-bit bitmap, decodes into readable fault name(s), lists all
32+
# active faults if more than one bit is set at once.
33+
"fault": {
34+
"dp_id": 4,
35+
"code": "fault",
36+
"name": "Fault Description",
37+
"icon": "mdi:alert-circle",
38+
"conversion": (
39+
"', '.join(n for b, n in ["
40+
"(1,'Heating Fault'),"
41+
"(2,'NTC Sensor Fault'),"
42+
"(4,'Blocked'),"
43+
"(8,'Front Door Open'),"
44+
"(16,'Brew Unit Misplaced'),"
45+
"(32,'Water Empty'),"
46+
"(64,'Trash Can Misplaced'),"
47+
"(128,'Bean Container Empty'),"
48+
"(256,'Residual Container Full'),"
49+
"(512,'Milk Cup Missing'),"
50+
"(1024,'Water Tank Misplaced')"
51+
"] if value & b) or 'OK'"
52+
),
53+
},
3054
}
3155

3256
BINARY_SENSOR_TYPES = {
@@ -37,6 +61,88 @@
3761
"device_class": "problem",
3862
"conversion": "value != 0",
3963
},
64+
# Per-bit fault binary sensors — all share the same "fault" DP
65+
# (dp_id 4) via an explicit "code" override, each checking one bit
66+
# with its own mask. Added alongside the readable multi-fault
67+
# SENSOR_TYPES entry above so both approaches can be compared in
68+
# practice — keep whichever turns out more useful, or both.
69+
"fault_heating_fault": {
70+
"dp_id": 4,
71+
"code": "fault",
72+
"name": "Heating Fault",
73+
"device_class": "problem",
74+
"conversion": "bool(value & 1)",
75+
},
76+
"fault_ntc_fault": {
77+
"dp_id": 4,
78+
"code": "fault",
79+
"name": "NTC Sensor Fault",
80+
"device_class": "problem",
81+
"conversion": "bool(value & 2)",
82+
},
83+
"fault_blocking": {
84+
"dp_id": 4,
85+
"code": "fault",
86+
"name": "Blocked",
87+
"device_class": "problem",
88+
"conversion": "bool(value & 4)",
89+
},
90+
"fault_frontdoor_open": {
91+
"dp_id": 4,
92+
"code": "fault",
93+
"name": "Front Door Open",
94+
"device_class": "problem",
95+
"conversion": "bool(value & 8)",
96+
},
97+
"fault_bu_misplaced": {
98+
"dp_id": 4,
99+
"code": "fault",
100+
"name": "Brew Unit Misplaced",
101+
"device_class": "problem",
102+
"conversion": "bool(value & 16)",
103+
},
104+
"fault_water_empty": {
105+
"dp_id": 4,
106+
"code": "fault",
107+
"name": "Water Empty",
108+
"device_class": "problem",
109+
"conversion": "bool(value & 32)",
110+
},
111+
"fault_trashcan_misplaced": {
112+
"dp_id": 4,
113+
"code": "fault",
114+
"name": "Trash Can Misplaced",
115+
"device_class": "problem",
116+
"conversion": "bool(value & 64)",
117+
},
118+
"fault_beancontainer_empty": {
119+
"dp_id": 4,
120+
"code": "fault",
121+
"name": "Bean Container Empty",
122+
"device_class": "problem",
123+
"conversion": "bool(value & 128)",
124+
},
125+
"fault_residual_full": {
126+
"dp_id": 4,
127+
"code": "fault",
128+
"name": "Residual Container Full",
129+
"device_class": "problem",
130+
"conversion": "bool(value & 256)",
131+
},
132+
"fault_milkcup_missing": {
133+
"dp_id": 4,
134+
"code": "fault",
135+
"name": "Milk Cup Missing",
136+
"device_class": "problem",
137+
"conversion": "bool(value & 512)",
138+
},
139+
"fault_watertank_misplaced": {
140+
"dp_id": 4,
141+
"code": "fault",
142+
"name": "Water Tank Misplaced",
143+
"device_class": "problem",
144+
"conversion": "bool(value & 1024)",
145+
},
40146
}
41147

42148
SWITCH_TYPES = {
@@ -131,14 +237,6 @@
131237
"icon": "mdi:coffee-to-go",
132238
"conversion": "value in [1, True, '1', 'true', 'on', 'yes', 'enable', 'open']",
133239
},
134-
"mode_selection": {
135-
"dp_id": 106,
136-
"code": "mode_selection",
137-
"name": "Eco Mode",
138-
"icon": "mdi:leaf",
139-
"conversion": "value == 'ECO'",
140-
"api_conversion": "'ECO' if value else 'Default'",
141-
},
142240
}
143241

144242
NUMBER_TYPES = {
@@ -160,11 +258,8 @@
160258
"name": "Drink Selection",
161259
"icon": "mdi:coffee",
162260
"options": {
163-
"Americano": "Americano",
164-
"IcedAmericano": "Iced Americano",
165-
"Hotmilk": "Hot Milk",
166-
"Cappuccino": "Cappuccino",
167261
"Espresso": "Espresso",
262+
"Americano": "Americano",
168263
"Lungo": "Lungo",
169264
"CaffeLatte": "Caffe Latte",
170265
"LatteMacchiato": "Latte Macchiato",
@@ -174,9 +269,12 @@
174269
"RistrettoBianco": "Ristretto Bianco",
175270
"FlatWhite": "Flat White",
176271
"Cortado": "Cortado",
272+
"IcedAmericano": "Iced Americano",
177273
"IcedLatte": "Iced Latte",
178-
"Hotwater": "Cold Brew",
274+
"Hotwater": "Hot Water",
275+
"Hotmilk": "Hot Milk",
179276
"TravelMug": "Travel Mug",
277+
"Cappuccino": "Cappuccino",
180278
},
181279
},
182280
"aso_timer": {
@@ -196,58 +294,68 @@
196294
"24hours": "24 Hours",
197295
},
198296
},
297+
"mode_selection": {
298+
"dp_id": 106,
299+
"code": "mode_selection",
300+
"name": "Mode",
301+
"icon": "mdi:leaf",
302+
"options": {
303+
"Default": "Default",
304+
"ECO": "Eco",
305+
},
306+
},
199307
"last_profile": {
200308
"dp_id": 113,
201309
"code": "last_profile",
202310
"name": "Active Profile",
203311
"icon": "mdi:account",
204312
"options": {
313+
"guest": "Guest",
205314
"orange": "Orange",
206315
"violet": "Violet",
207316
"blue": "Blue",
208317
"green": "Green",
209-
"guest": "Guest",
210318
},
211319
},
212320
}
213321

214322
# --- merge into TEXT_TYPES (from raw_explorer.py, unchanged) ---
215323
TEXT_TYPES = globals().get("TEXT_TYPES", {})
216324
TEXT_TYPES.update({
217-
"username_orange": {
325+
"orange_username": {
218326
"dp_id": 108,
219-
"code": "username_orange",
327+
"code": "orange_username",
220328
"raw_source": "orange_username",
221329
"field_index": 0,
222330
"encoding": "utf8_string",
223331
"max_length": 16,
224-
"name": "Username Orange",
332+
"name": "Orange Username",
225333
},
226-
"username_violet": {
334+
"violet_username": {
227335
"dp_id": 109,
228-
"code": "username_violet",
336+
"code": "violet_username",
229337
"raw_source": "violet_username",
230338
"field_index": 0,
231339
"encoding": "utf8_string",
232340
"max_length": 16,
233-
"name": "Username Violet",
341+
"name": "Violet Username",
234342
},
235-
"username_blue": {
343+
"blue_username": {
236344
"dp_id": 110,
237-
"code": "username_blue",
345+
"code": "blue_username",
238346
"raw_source": "blue_username",
239347
"field_index": 0,
240348
"encoding": "utf8_string",
241349
"max_length": 16,
242-
"name": "Username Blue",
350+
"name": "Blue Username",
243351
},
244-
"username_green": {
352+
"green_username": {
245353
"dp_id": 111,
246-
"code": "username_green",
354+
"code": "green_username",
247355
"raw_source": "green_username",
248356
"field_index": 0,
249357
"encoding": "utf8_string",
250358
"max_length": 16,
251-
"name": "Username Green",
359+
"name": "Green Username",
252360
},
253361
})

0 commit comments

Comments
 (0)