Skip to content

Commit 182d508

Browse files
authored
fix(e2): fix e2 device full tank/temperature error (#371)
1. try to debug and fix wuwentao/midea_ac_lan#427 2. try to fix wuwentao/midea_ac_lan#546 3. add more attrs for e2 device 4. add more debug output for wuwentao/midea_ac_lan#385 5. once debug done, will split to different PRs.
1 parent c83b7af commit 182d508

File tree

2 files changed

+193
-30
lines changed

2 files changed

+193
-30
lines changed

midealocal/devices/e2/__init__.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,35 @@ class DeviceAttributes(StrEnum):
5050
heating_time_remaining = "heating_time_remaining"
5151
water_consumption = "water_consumption"
5252
heating_power = "heating_power"
53+
fast_hot_power = "fast_hot_power"
54+
water_flow = "water_flow"
55+
sterilization = "sterilization"
56+
heat_water_level = "heat_water_level"
57+
eplus = "eplus"
58+
fast_wash = "fast_wash"
59+
half_heat = "half_heat"
60+
summer = "summer"
61+
winter = "winter"
62+
efficient = "efficient"
63+
night = "night"
64+
screen_off = "screen_off"
65+
sleep = "sleep"
66+
cloud = "cloud"
67+
appoint_wash = "appoint_wash"
68+
now_wash = "now_wash"
69+
smart_sterilize = "smart_sterilize"
70+
sterilize_high_temp = "sterilize_high_temp"
71+
uv_sterilize = "uv_sterilize"
72+
discharge_status = "discharge_status"
73+
top_temp = "top_temp"
74+
bottom_heat = "bottom_heat"
75+
top_heat = "top_heat"
76+
water_cyclic = "water_cyclic"
77+
water_system = "water_system"
78+
in_temperature = "in_temperature"
79+
day_water_consumption = "day_water_consumption"
80+
volume = "volume"
81+
rate = "rate"
5382

5483

5584
class MideaE2Device(MideaDevice):
@@ -92,18 +121,54 @@ def __init__(
92121
DeviceAttributes.heating_time_remaining: 0,
93122
DeviceAttributes.water_consumption: None,
94123
DeviceAttributes.heating_power: None,
124+
DeviceAttributes.fast_hot_power: None,
125+
DeviceAttributes.water_flow: None,
126+
DeviceAttributes.sterilization: None,
127+
DeviceAttributes.heat_water_level: None,
128+
DeviceAttributes.eplus: None,
129+
DeviceAttributes.fast_wash: None,
130+
DeviceAttributes.half_heat: None,
131+
DeviceAttributes.summer: None,
132+
DeviceAttributes.winter: None,
133+
DeviceAttributes.efficient: None,
134+
DeviceAttributes.night: None,
135+
DeviceAttributes.screen_off: None,
136+
DeviceAttributes.sleep: None,
137+
DeviceAttributes.cloud: None,
138+
DeviceAttributes.appoint_wash: None,
139+
DeviceAttributes.now_wash: None,
140+
DeviceAttributes.smart_sterilize: None,
141+
DeviceAttributes.sterilize_high_temp: None,
142+
DeviceAttributes.uv_sterilize: None,
143+
DeviceAttributes.discharge_status: None,
144+
DeviceAttributes.top_temp: None,
145+
DeviceAttributes.bottom_heat: None,
146+
DeviceAttributes.top_heat: None,
147+
DeviceAttributes.water_cyclic: None,
148+
DeviceAttributes.water_system: None,
149+
DeviceAttributes.in_temperature: None,
150+
DeviceAttributes.day_water_consumption: None,
151+
DeviceAttributes.volume: None,
152+
DeviceAttributes.rate: None,
95153
},
96154
)
97155
self._default_old_protocol = OldProtocol.auto
98156
self._old_protocol = self._default_old_protocol
99157
# target_temperature step
100158
self._temperature_step: float | None = None
101159
self._default_temperature_step = 1.0
160+
self._precision_halves: bool | None = None
161+
self._default_precision_halves = False
102162
self.set_customize(customize)
103163

164+
@property
165+
def precision_halves(self) -> bool | None:
166+
"""Midea E2 device precision halves."""
167+
return self._precision_halves
168+
104169
@property
105170
def temperature_step(self) -> float | None:
106-
"""Midea E3 device target temperature step."""
171+
"""Midea E2 device target temperature step."""
107172
return self._temperature_step
108173

109174
def _normalize_old_protocol(self, value: str | bool | int) -> OldProtocol:
@@ -157,7 +222,7 @@ def set_attribute(self, attr: str, value: bool | float | str) -> None:
157222
]:
158223
old_protocol = self._normalize_old_protocol(self._old_protocol)
159224
if attr == DeviceAttributes.target_temperature:
160-
value = value * 2
225+
value = value if self._precision_halves else value * 2
161226
if attr == DeviceAttributes.power:
162227
message = MessagePower(self._message_protocol_version)
163228
message.power = bool(value)
@@ -172,6 +237,8 @@ def set_attribute(self, attr: str, value: bool | float | str) -> None:
172237
def set_customize(self, customize: str) -> None:
173238
"""Midea E2 device set customize."""
174239
self._old_protocol = self._default_old_protocol
240+
self._temperature_step = self._default_temperature_step
241+
self._precision_halves = self._default_precision_halves
175242
if customize and len(customize) > 0:
176243
try:
177244
params = json.loads(customize)
@@ -180,13 +247,16 @@ def set_customize(self, customize: str) -> None:
180247
params["old_protocol"],
181248
)
182249
if params and "temperature_step" in params:
183-
self._temperature_step = params.get("temperature_step")
250+
self._temperature_step = float(params.get("temperature_step"))
251+
if params and "precision_halves" in params:
252+
self._precision_halves = params.get("precision_halves")
184253
except Exception:
185254
_LOGGER.exception("[%s] Set customize error", self.device_id)
186255
self.update_all(
187256
{
188257
"temperature_step": self._temperature_step,
189258
"old_protocol": self._old_protocol,
259+
"precision_halves": self._precision_halves,
190260
},
191261
)
192262

midealocal/devices/e2/message.py

Lines changed: 120 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def _body(self) -> bytearray:
7474

7575

7676
class MessageNewProtocolSet(MessageE2Base):
77-
"""E2 message new protocol set."""
77+
"""E2 message new protocol set(T_0000_E2_24.lua:flag == false: else)."""
7878

7979
def __init__(self, protocol_version: int) -> None:
8080
"""Initialize E2 message new protocol set."""
@@ -85,26 +85,79 @@ def __init__(self, protocol_version: int) -> None:
8585
)
8686
self.target_temperature: float | None = None
8787
self.variable_heating: bool | None = None
88+
self.sterilization: bool | None = None
8889
self.whole_tank_heating: bool | None = None
90+
self.protect: bool | None = None
91+
self.sleep: bool | None = None
92+
self.big_water: bool | None = None
93+
self.auto_off: bool | None = None
94+
self.safe: bool | None = None
95+
self.screen_off: bool | None = None
96+
self.wash_temperature: float | None = None
97+
self.always_fell: bool | None = None
98+
self.smart_sterilize: bool | None = None
99+
self.uv_sterilize: bool | None = None
89100

90101
@property
91102
def _body(self) -> bytearray:
92-
byte1 = 0x00
93-
byte2 = 0x00
103+
byte12 = 0x00
104+
byte13 = 0x00
94105
if self.target_temperature is not None:
95-
byte1 = 0x07
96-
byte2 = int(self.target_temperature) & 0xFF
106+
byte12 = 0x07
107+
byte13 = int(self.target_temperature) & 0xFF
97108
elif self.whole_tank_heating is not None:
98-
byte1 = 0x04
99-
byte2 = 0x02 if self.whole_tank_heating else 0x01
109+
byte12 = 0x04
110+
# byte2 0x02/whole_heat 0x01/half_heat
111+
byte13 = 0x02 if self.whole_tank_heating else 0x01
112+
# frequency_hot
100113
elif self.variable_heating is not None:
101-
byte1 = 0x10
102-
byte2 = 0x01 if self.variable_heating else 0x00
103-
return bytearray([byte1, byte2])
114+
byte12 = 0x10
115+
byte13 = 0x01 if self.variable_heating else 0x00
116+
# sterilization
117+
elif self.sterilization is not None:
118+
byte12 = 0x0D
119+
byte13 = 0x01 if self.sterilization else 0x00
120+
# protect
121+
elif self.protect is not None:
122+
byte12 = 0x05
123+
byte13 = 0x01 if self.protect else 0x00
124+
# sleep
125+
elif self.sleep is not None:
126+
byte12 = 0x0E
127+
byte13 = 0x01 if self.sleep else 0x00
128+
# big_water
129+
elif self.big_water is not None:
130+
byte12 = 0x11
131+
byte13 = 0x01 if self.big_water else 0x00
132+
# auto_off
133+
elif self.auto_off is not None:
134+
byte12 = 0x14
135+
byte13 = 0x01 if self.auto_off else 0x00
136+
# safe
137+
elif self.safe is not None:
138+
byte12 = 0x06
139+
byte13 = 0x01 if self.safe else 0x00
140+
# screen_off
141+
elif self.screen_off is not None:
142+
byte12 = 0x0F
143+
byte13 = 0x01 if self.screen_off else 0x00
144+
# wash_temperature
145+
elif self.wash_temperature is not None:
146+
byte12 = 0x16
147+
byte13 = int(self.wash_temperature) & 0xFF
148+
# smart_sterilize
149+
elif self.smart_sterilize is not None:
150+
byte12 = 0x1B
151+
byte13 = 0x01 if self.smart_sterilize else 0x00
152+
# uv_sterilize
153+
elif self.uv_sterilize is not None:
154+
byte12 = 0x1D
155+
byte13 = 0x01 if self.uv_sterilize else 0x00
156+
return bytearray([byte12, byte13])
104157

105158

106159
class MessageSet(MessageE2Base):
107-
"""E2 message set."""
160+
"""E2 message set(T_0000_E2_24.lua: else)."""
108161

109162
def __init__(self, protocol_version: int) -> None:
110163
"""Initialize E2 message set."""
@@ -129,15 +182,15 @@ def _body(self) -> bytearray:
129182
variable_heating = 0x10 if self.variable_heating else 0x00
130183
return bytearray(
131184
[
132-
0x01,
133-
0x00,
134-
0x80,
135-
whole_tank_heating | protection,
136-
target_temperature,
137-
0x00,
138-
0x00,
139-
0x00,
140-
variable_heating,
185+
0x01, # byte12
186+
0x00, # byte13
187+
0x80, # byte14
188+
whole_tank_heating | protection, # byte15
189+
target_temperature, # byte16
190+
0x00, # byte17
191+
0x00, # byte18
192+
0x00, # byte19
193+
variable_heating, # byte20
141194
0x00,
142195
0x00,
143196
0x00,
@@ -152,24 +205,64 @@ def _body(self) -> bytearray:
152205

153206

154207
class E2GeneralMessageBody(MessageBody):
155-
"""E2 message general body."""
208+
"""E2 message general body(T_0000_E2_24.lua)."""
156209

157210
def __init__(self, body: bytearray) -> None:
158211
"""Initialize E2 message general body."""
159212
super().__init__(body)
160213
self.power = (body[2] & 0x01) > 0
161-
self.heating = (body[2] & 0x04) > 0
162-
self.keep_warm = (body[2] & 0x08) > 0
163-
self.variable_heating = (body[2] & 0x80) > 0
164-
self.current_temperature = body[4]
165-
self.whole_tank_heating = (body[7] & 0x08) > 0
214+
self.fast_hot_power = (body[2] & 0x02) > 0 # fast_hot_power
215+
self.heating = (body[2] & 0x04) > 0 # hot_power
216+
self.keep_warm = (body[2] & 0x08) > 0 # warm_power
217+
self.water_flow = (body[2] & 0x10) > 0 # water_flow
218+
self.sterilization = (body[2] & 0x40) > 0 # sterilization
219+
self.variable_heating = (body[2] & 0x80) > 0 # frequency_hot
220+
self.current_temperature = float(body[4])
221+
self.heat_water_level = body[5] # heat_water_level
222+
self.eplus = (body[7] & 0x01) > 0 # eplus
223+
self.fast_wash = (body[7] & 0x02) > 0 # fast_wash
224+
self.half_heat = (body[7] & 0x04) > 0 # half_heat
225+
self.whole_tank_heating = (body[7] & 0x08) > 0 # whole_heat
226+
self.summer = (body[7] & 0x10) > 0
227+
self.winter = (body[7] & 0x20) > 0
228+
self.efficient = (body[7] & 0x40) > 0
229+
self.night = (body[7] & 0x80) > 0
230+
self.screen_off = (body[8] & 0x08) > 0
231+
self.sleep = (body[8] & 0x10) > 0
232+
self.cloud = (body[8] & 0x20) > 0
233+
self.appoint_wash = (body[8] & 0x40) > 0
234+
self.now_wash = (body[8] & 0x80) > 0
235+
# end_time_hour/end_time_minute
166236
self.heating_time_remaining = body[9] * 60 + body[10]
167-
self.target_temperature = body[11]
237+
self.target_temperature = float(body[11])
238+
self.smart_sterilize = (body[12] & 0x20) > 0
239+
self.sterilize_high_temp = (body[12] & 0x40) > 0
240+
self.uv_sterilize = (body[12] & 0x80) > 0
241+
self.discharge_status = body[13]
242+
self.top_temp = body[14]
243+
self.bottom_heat = (body[15] & 0x01) > 0
244+
self.top_heat = (body[15] & 0x02) > 0
245+
self.water_cyclic = (body[15] & 0x80) > 0
246+
self.water_system = body[16]
247+
# in_temperature
248+
self.in_temperature = float(body[18]) if len(body) > PROTECTION_BYTE else None
249+
# protect
168250
self.protection = (
169251
((body[22] & 0x02) > 0) if len(body) > PROTECTION_BYTE else False
170252
)
253+
# waterday_lowbyte/waterday_highbyte
254+
if len(body) > WATER_CONSUMPTION_BYTE:
255+
self.day_water_consumption = body[20] + (body[21] << 8)
256+
# passwater_lowbyte/passwater_highbyte
171257
if len(body) > WATER_CONSUMPTION_BYTE:
172258
self.water_consumption = body[24] + (body[25] << 8)
259+
# volume
260+
if len(body) > HEATING_POWER_BYTE:
261+
self.volume = body[27]
262+
# rate
263+
if len(body) > HEATING_POWER_BYTE:
264+
self.rate = body[28] * 100
265+
# cur_rate
173266
if len(body) > HEATING_POWER_BYTE:
174267
self.heating_power = body[34] * 100
175268

0 commit comments

Comments
 (0)