Skip to content

Commit a11cd7f

Browse files
authored
Added and implemented
generate_command(self, command): Formats the command string; prefix with ESC R, end with a checksum and & sign.
1 parent cdb5887 commit a11cd7f

File tree

1 file changed

+58
-51
lines changed

1 file changed

+58
-51
lines changed

custom_components/duepi_evo/climate.py

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@
4747

4848
_LOGGER = logging.getLogger(__name__)
4949

50-
SUPPORT_FLAGS = ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE | ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
50+
SUPPORT_FLAGS = (
51+
ClimateEntityFeature.TARGET_TEMPERATURE
52+
| ClimateEntityFeature.FAN_MODE
53+
| ClimateEntityFeature.TURN_OFF
54+
| ClimateEntityFeature.TURN_ON
55+
)
5156

5257
"""
5358
Supported hvac modes:
@@ -87,36 +92,37 @@
8792
)
8893

8994
# constants
90-
STATE_ACK = 0x00000020
91-
STATE_ECO = 0x10000000
95+
STATE_ACK = 0x00000020
96+
STATE_ECO = 0x10000000
9297
STATE_CLEAN = 0x04000000
93-
STATE_COOL = 0x08000000
94-
STATE_OFF = 0x00000020
95-
STATE_ON = 0x02000000
98+
STATE_COOL = 0x08000000
99+
STATE_OFF = 0x00000020
100+
STATE_ON = 0x02000000
96101
STATE_START = 0x01000000
97102

98-
GET_ERRORSTATE = "\x1bRDA00067&"
99-
GET_EXHFANSPEED = "\x1bREF0006D&"
100-
GET_FLUGASTEMP = "\x1bRD000056&"
101-
GET_PELLETSPEED = "\x1bRD40005A&"
102-
GET_SETPOINT = "\x1bRC60005B&"
103-
GET_STATUS = "\x1bRD90005f&"
104-
GET_TEMPERATURE = "\x1bRD100057&"
105-
GET_POWERLEVEL = "\x1bRD300059&"
106-
107-
REMOTE_RESET = "\x1bRD60005C&"
108-
109-
SET_AUGERCOR = "\x1bRD50005A&"
110-
SET_EXTRACTORCOR = "\x1bRD50005B&"
111-
SET_TEMPERATURE = "\x1bRF2xx0yy&"
112-
SET_PELLETCOR = "\x1bRD50005B&"
113-
SET_POWERLEVEL = "\x1bRF00x0yy&"
114-
SET_POWEROFF = "\x1bRF000058&"
115-
SET_POWERON = "\x1bRF001059&"
103+
GET_ERRORSTATE = "DA000"
104+
GET_EXHFANSPEED = "EF000"
105+
GET_FLUGASTEMP = "D0000"
106+
GET_PELLETSPEED = "D4000"
107+
GET_SETPOINT = "C6000"
108+
GET_STATUS = "D9000"
109+
GET_TEMPERATURE = "D1000"
110+
GET_POWERLEVEL = "D3000"
111+
112+
REMOTE_RESET = "D6000"
113+
114+
SET_AUGERCOR = "D5000" #one of these is faulty
115+
SET_EXTRACTORCOR = "D5000" #only not sure which one (neither one is in use any way)
116+
SET_PELLETCOR = "D5000"
117+
SET_POWEROFF = "F0000"
118+
SET_POWERON = "F0010"
119+
SET_POWERLEVEL = "F00x0"
120+
SET_TEMPERATURE = "F2xx0"
116121

117122
# Set to True for stoves that support setpoint retrieval
118123
SUPPORT_SETPOINT = False
119124

125+
120126
async def async_setup_platform(
121127
hass: HomeAssistant,
122128
config: ConfigType,
@@ -132,9 +138,12 @@ class DuepiEvoDevice(ClimateEntity):
132138
"""Representation of a DuepiEvoDevice."""
133139

134140
def __init__(self, session, config) -> None:
135-
136141
self._enable_turn_on_off_backwards_compatibility = False
137-
self._attr_supported_features = ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON
142+
self._attr_supported_features = (
143+
ClimateEntityFeature.TARGET_TEMPERATURE
144+
| ClimateEntityFeature.TURN_OFF
145+
| ClimateEntityFeature.TURN_ON
146+
)
138147

139148
"""Initialize the DuepiEvoDevice."""
140149
self._session = session
@@ -281,6 +290,13 @@ def fan_modes(self) -> list[str]:
281290
"""Return the list of available fan modes."""
282291
return self._fan_modes
283292

293+
def generate_command(self, command):
294+
"""Format the command string prefix with ESC R, end with a checksum and & sign."""
295+
command = "R" + command #R is part of the checksum calculation
296+
total_sum = sum(ord(char) for char in command)
297+
lsb = total_sum & 0xFF
298+
return "\x1b" + command + format(lsb, "02X") + "&"
299+
284300
async def async_set_fan_mode(self, fan_mode: str) -> None:
285301
"""Set the fan mode."""
286302
if fan_mode == "":
@@ -292,11 +308,10 @@ async def async_set_fan_mode(self, fan_mode: str) -> None:
292308
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
293309
sock.settimeout(3.0)
294310
sock.connect((self._host, self._port))
295-
code_hex_str = hex(88 + self._fan_mode_map[fan_mode])
296-
data_yy = SET_POWERLEVEL.replace("yy", code_hex_str[2:4])
297311
power_level_hex_str = hex(self._fan_mode_map[fan_mode])
298-
data_xx = data_yy.replace("x", power_level_hex_str[2:3])
299-
sock.send(data_xx.encode())
312+
data = SET_POWERLEVEL.replace("x", power_level_hex_str[2:3])
313+
data = self.generate_command(data)
314+
sock.send(data.encode())
300315
data_from_server = sock.recv(10).decode()
301316
current_state = int(data_from_server[1:9], 16)
302317
if not (STATE_ACK & current_state):
@@ -327,17 +342,9 @@ async def async_set_temperature(self, **kwargs: Any) -> None:
327342
sock.settimeout(3.0)
328343
sock.connect((self._host, self._port))
329344
set_point_int = int(target_temperature)
330-
OFFSET = (
331-
97 if set_point_int < 16 else
332-
75 if set_point_int <= 25 else
333-
82 if set_point_int <= 31 else
334-
60
335-
)
336-
code_hex_str = f"{(set_point_int + OFFSET):02X}"
337345
set_point_hex_str = f"{set_point_int:02X}"
338-
data = SET_TEMPERATURE \
339-
.replace("xx", set_point_hex_str) \
340-
.replace("yy", code_hex_str)
346+
data = SET_TEMPERATURE.replace("xx", set_point_hex_str)
347+
data = self.generate_command(data)
341348
sock.send(data.encode())
342349
data_from_server = sock.recv(10).decode()
343350
current_state = int(data_from_server[1:9], 16)
@@ -369,7 +376,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
369376
sock.settimeout(3.0)
370377
sock.connect((self._host, self._port))
371378
if hvac_mode == "off":
372-
sock.send(SET_POWEROFF.encode())
379+
sock.send(self.generate_command(SET_POWEROFF).encode())
373380
data_from_server = sock.recv(10).decode()
374381
current_state = int(data_from_server[1:9], 16)
375382
if not (STATE_ACK & current_state):
@@ -378,7 +385,7 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
378385
)
379386
self._hvac_mode = HVACMode.OFF
380387
elif hvac_mode == "heat":
381-
sock.send(SET_POWERON.encode())
388+
sock.send(self.generate_command(SET_POWERON).encode())
382389
data_from_server = sock.recv(10).decode()
383390
current_state = int(data_from_server[1:9], 16)
384391
if not (STATE_ACK & current_state):
@@ -442,7 +449,7 @@ async def get_data(self, support_setpoint) -> None:
442449
sock.connect((self._host, self._port))
443450

444451
# Get Burner status
445-
sock.send(GET_STATUS.encode())
452+
sock.send(self.generate_command(GET_STATUS).encode())
446453
data_from_server = sock.recv(10).decode()
447454
currentstate = int(data_from_server[1:9], 16)
448455
if STATE_START & currentstate:
@@ -461,37 +468,37 @@ async def get_data(self, support_setpoint) -> None:
461468
status = "Unknown state"
462469

463470
# Get Ambient temperature
464-
sock.send(GET_TEMPERATURE.encode())
471+
sock.send(self.generate_command(GET_TEMPERATURE).encode())
465472
data_from_server = sock.recv(10).decode()
466473
if len(data_from_server) != 0:
467474
current_temperature = int(data_from_server[1:5], 16) / 10.0
468475

469476
# Get Fan mode (also called fan speed or power level)
470-
sock.send(GET_POWERLEVEL.encode())
477+
sock.send(self.generate_command(GET_POWERLEVEL).encode())
471478
data_from_server = sock.recv(10).decode()
472479
if len(data_from_server) != 0:
473480
fan_mode = int(data_from_server[1:5], 16)
474481

475482
# Get pellet speed
476-
sock.send(GET_PELLETSPEED.encode())
483+
sock.send(self.generate_command(GET_PELLETSPEED).encode())
477484
data_from_server = sock.recv(10).decode()
478485
if len(data_from_server) != 0:
479486
pellet_speed = int(data_from_server[1:5], 16)
480487

481488
# Get FluGas temperature
482-
sock.send(GET_FLUGASTEMP.encode())
489+
sock.send(self.generate_command(GET_FLUGASTEMP).encode())
483490
data_from_server = sock.recv(10).decode()
484491
if len(data_from_server) != 0:
485492
current_flugastemp = int(data_from_server[1:5], 16)
486493

487494
# Get Exhaust Fan speed
488-
sock.send(GET_EXHFANSPEED.encode())
495+
sock.send(self.generate_command(GET_EXHFANSPEED).encode())
489496
data_from_server = sock.recv(10).decode()
490497
if len(data_from_server) != 0:
491498
current_exhfanspeed = int(data_from_server[1:5], 16) * 10
492499

493500
# Get Error code
494-
sock.send(GET_ERRORSTATE.encode())
501+
sock.send(self.generate_command(GET_ERRORSTATE).encode())
495502
data_from_server = sock.recv(10).decode()
496503
if len(data_from_server) != 0:
497504
error_code_decimal = int(data_from_server[1:5], 16)
@@ -502,7 +509,7 @@ async def get_data(self, support_setpoint) -> None:
502509
)
503510

504511
# Get & validate target temperature (Setpoint)
505-
sock.send(GET_SETPOINT.encode())
512+
sock.send(self.generate_command(GET_SETPOINT).encode())
506513
data_from_server = sock.recv(10).decode()
507514
if len(data_from_server) != 0:
508515
target_temperature = int(data_from_server[1:5], 16)
@@ -553,7 +560,7 @@ async def remote_reset(self, error_code) -> None:
553560
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
554561
sock.settimeout(3.0)
555562
sock.connect((self._host, self._port))
556-
sock.send(REMOTE_RESET.encode())
563+
sock.send(self.generate_command(REMOTE_RESET).encode())
557564
data_from_server = sock.recv(10).decode()
558565
data_from_server = data_from_server[1:9]
559566
currentstate = int(data_from_server, 16)

0 commit comments

Comments
 (0)