ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
zhlt01.cpp
Go to the documentation of this file.
1#include "zhlt01.h"
2#include "esphome/core/log.h"
3
4namespace esphome::zhlt01 {
5
6static const char *const TAG = "zhlt01.climate";
7
9 uint8_t ir_message[12] = {0};
10
11 // Byte 1 : Timer
12 ir_message[1] = 0x00; // Timer off
13
14 // Byte 3 : Turbo mode
16 ir_message[3] = AC1_FAN_TURBO;
17 }
18
19 // Byte 5 : Last pressed button
20 ir_message[5] = 0x00; // fixed as power button
21
22 // Byte 7 : Power | Swing | Fan
23 // -- Power
24 if (this->mode == climate::CLIMATE_MODE_OFF) {
25 ir_message[7] = AC1_POWER_OFF;
26 } else {
27 ir_message[7] = AC1_POWER_ON;
28 }
29
30 // -- Swing
31 switch (this->swing_mode) {
33 ir_message[7] |= AC1_HDIR_FIXED | AC1_VDIR_FIXED;
34 break;
36 ir_message[7] |= AC1_HDIR_SWING | AC1_VDIR_FIXED;
37 break;
39 ir_message[7] |= AC1_HDIR_FIXED | AC1_VDIR_SWING;
40 break;
42 ir_message[7] |= AC1_HDIR_SWING | AC1_VDIR_SWING;
43 break;
44 default:
45 break;
46 }
47
48 // -- Fan
49 switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) {
51 ir_message[7] |= AC1_FAN3;
52 break;
54 ir_message[7] |= AC1_FAN_SILENT;
55 break;
56 default:
57 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
59 ir_message[7] |= AC1_FAN1;
60 break;
62 ir_message[7] |= AC1_FAN2;
63 break;
65 ir_message[7] |= AC1_FAN3;
66 break;
68 ir_message[7] |= AC1_FAN_AUTO;
69 break;
70 default:
71 break;
72 }
73 }
74
75 // Byte 9 : AC Mode | Temperature
76 // -- AC Mode
77 switch (this->mode) {
80 ir_message[9] = AC1_MODE_AUTO;
81 break;
83 ir_message[9] = AC1_MODE_COOL;
84 break;
86 ir_message[9] = AC1_MODE_HEAT;
87 break;
89 ir_message[9] = AC1_MODE_DRY;
90 break;
92 ir_message[9] = AC1_MODE_FAN;
93 break;
94 default:
95 break;
96 }
97
98 // -- Temperature
99 ir_message[9] |= (uint8_t) (this->target_temperature - 16.0f);
100
101 // Byte 11 : Remote control ID
102 ir_message[11] = 0xD5;
103
104 // Set checksum bytes
105 for (int i = 0; i < 12; i += 2) {
106 ir_message[i] = ~ir_message[i + 1];
107 }
108
109 // Send the code
110 auto transmit = this->transmitter_->transmit();
111 auto *data = transmit.get_data();
112
113 data->set_carrier_frequency(38000); // 38 kHz PWM
114
115 // Header
116 data->mark(AC1_HDR_MARK);
117 data->space(AC1_HDR_SPACE);
118
119 // Data
120 for (uint8_t i : ir_message) {
121 for (uint8_t j = 0; j < 8; j++) {
122 data->mark(AC1_BIT_MARK);
123 bool bit = i & (1 << j);
124 data->space(bit ? AC1_ONE_SPACE : AC1_ZERO_SPACE);
125 }
126 }
127
128 // Footer
129 data->mark(AC1_BIT_MARK);
130 data->space(0);
131
132 transmit.perform();
133}
134
136 // Validate header
137 if (!data.expect_item(AC1_HDR_MARK, AC1_HDR_SPACE)) {
138 ESP_LOGV(TAG, "Header fail");
139 return false;
140 }
141
142 // Decode IR message
143 uint8_t ir_message[12] = {0};
144 // Read all bytes
145 for (int i = 0; i < 12; i++) {
146 // Read bit
147 for (int j = 0; j < 8; j++) {
148 if (data.expect_item(AC1_BIT_MARK, AC1_ONE_SPACE)) {
149 ir_message[i] |= 1 << j;
150 } else if (!data.expect_item(AC1_BIT_MARK, AC1_ZERO_SPACE)) {
151 ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
152 return false;
153 }
154 }
155 ESP_LOGVV(TAG, "Byte %d %02X", i, ir_message[i]);
156 }
157
158 // Validate footer
159 if (!data.expect_mark(AC1_BIT_MARK)) {
160 ESP_LOGV(TAG, "Footer fail");
161 return false;
162 }
163
164 // Validate checksum
165 for (int i = 0; i < 12; i += 2) {
166 if (ir_message[i] != (uint8_t) (~ir_message[i + 1])) {
167 ESP_LOGV(TAG, "Byte %d checksum incorrect (%02X != %02X)", i, ir_message[i], (uint8_t) (~ir_message[i + 1]));
168 return false;
169 }
170 }
171
172 // Validate remote control ID
173 if (ir_message[11] != 0xD5) {
174 ESP_LOGV(TAG, "Invalid remote control ID");
175 return false;
176 }
177
178 // All is good to go
179
180 if ((ir_message[7] & AC1_POWER_ON) == 0) {
182 } else {
183 // Vertical swing
184 if ((ir_message[7] & 0x0C) == AC1_VDIR_FIXED) {
185 if ((ir_message[7] & 0x10) == AC1_HDIR_FIXED) {
187 } else {
189 }
190 } else {
191 if ((ir_message[7] & 0x10) == AC1_HDIR_FIXED) {
193 } else {
195 }
196 }
197
198 // Preset + Fan speed
199 if ((ir_message[3] & AC1_FAN_TURBO) == AC1_FAN_TURBO) {
202 } else if ((ir_message[7] & 0xE1) == AC1_FAN_SILENT) {
205 } else if ((ir_message[7] & 0xE1) == AC1_FAN_AUTO) {
207 } else if ((ir_message[7] & 0xE1) == AC1_FAN1) {
209 } else if ((ir_message[7] & 0xE1) == AC1_FAN2) {
211 } else if ((ir_message[7] & 0xE1) == AC1_FAN3) {
213 }
214
215 // AC Mode
216 if ((ir_message[9] & 0xE0) == AC1_MODE_COOL) {
218 } else if ((ir_message[9] & 0xE0) == AC1_MODE_HEAT) {
220 } else if ((ir_message[9] & 0xE0) == AC1_MODE_DRY) {
222 } else if ((ir_message[9] & 0xE0) == AC1_MODE_FAN) {
224 } else {
226 }
227
228 // Taregt Temperature
229 this->target_temperature = (ir_message[9] & 0x1F) + 16.0f;
230 }
231
232 this->publish_state();
233 return true;
234}
235
236} // namespace esphome::zhlt01
ClimateMode mode
The active mode of the climate device.
Definition climate.h:293
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:287
float target_temperature
The target temperature of the climate device.
Definition climate.h:274
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:299
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:437
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:290
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
Definition zhlt01.cpp:135
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition zhlt01.cpp:8
@ CLIMATE_PRESET_NONE
No preset is active.
@ CLIMATE_PRESET_BOOST
Device is in boost preset.
@ CLIMATE_PRESET_SLEEP
Device is prepared for sleep.
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_HORIZONTAL
The fan mode is set to Horizontal.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
@ CLIMATE_SWING_BOTH
The fan mode is set to Both.
@ CLIMATE_MODE_DRY
The climate device is set to dry/humidity mode.
@ CLIMATE_MODE_FAN_ONLY
The climate device only has the fan enabled, no heating or cooling is taking place.
@ CLIMATE_MODE_HEAT
The climate device is set to heat to reach the target temperature.
@ CLIMATE_MODE_COOL
The climate device is set to cool to reach the target temperature.
@ CLIMATE_MODE_HEAT_COOL
The climate device is set to heat/cool to reach the target temperature.
@ CLIMATE_MODE_OFF
The climate device is off.
@ CLIMATE_MODE_AUTO
The climate device is adjusting the temperature dynamically.
@ CLIMATE_FAN_MEDIUM
The fan mode is set to Medium.
@ CLIMATE_FAN_ON
The fan mode is set to On.
@ CLIMATE_FAN_AUTO
The fan mode is set to Auto.
@ CLIMATE_FAN_LOW
The fan mode is set to Low.
@ CLIMATE_FAN_HIGH
The fan mode is set to High.