ESPHome 2025.5.0
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 {
5namespace zhlt01 {
6
7static const char *const TAG = "zhlt01.climate";
8
10 uint8_t ir_message[12] = {0};
11
12 // Byte 1 : Timer
13 ir_message[1] = 0x00; // Timer off
14
15 // Byte 3 : Turbo mode
17 ir_message[3] = AC1_FAN_TURBO;
18 }
19
20 // Byte 5 : Last pressed button
21 ir_message[5] = 0x00; // fixed as power button
22
23 // Byte 7 : Power | Swing | Fan
24 // -- Power
25 if (this->mode == climate::CLIMATE_MODE_OFF) {
26 ir_message[7] = AC1_POWER_OFF;
27 } else {
28 ir_message[7] = AC1_POWER_ON;
29 }
30
31 // -- Swing
32 switch (this->swing_mode) {
34 ir_message[7] |= AC1_HDIR_FIXED | AC1_VDIR_FIXED;
35 break;
37 ir_message[7] |= AC1_HDIR_SWING | AC1_VDIR_FIXED;
38 break;
40 ir_message[7] |= AC1_HDIR_FIXED | AC1_VDIR_SWING;
41 break;
43 ir_message[7] |= AC1_HDIR_SWING | AC1_VDIR_SWING;
44 break;
45 default:
46 break;
47 }
48
49 // -- Fan
50 switch (this->preset.value()) {
52 ir_message[7] |= AC1_FAN3;
53 break;
55 ir_message[7] |= AC1_FAN_SILENT;
56 break;
57 default:
58 switch (this->fan_mode.value()) {
60 ir_message[7] |= AC1_FAN1;
61 break;
63 ir_message[7] |= AC1_FAN2;
64 break;
66 ir_message[7] |= AC1_FAN3;
67 break;
69 ir_message[7] |= AC1_FAN_AUTO;
70 break;
71 default:
72 break;
73 }
74 }
75
76 // Byte 9 : AC Mode | Temperature
77 // -- AC Mode
78 switch (this->mode) {
81 ir_message[9] = AC1_MODE_AUTO;
82 break;
84 ir_message[9] = AC1_MODE_COOL;
85 break;
87 ir_message[9] = AC1_MODE_HEAT;
88 break;
90 ir_message[9] = AC1_MODE_DRY;
91 break;
93 ir_message[9] = AC1_MODE_FAN;
94 break;
95 default:
96 break;
97 }
98
99 // -- Temperature
100 ir_message[9] |= (uint8_t) (this->target_temperature - 16.0f);
101
102 // Byte 11 : Remote control ID
103 ir_message[11] = 0xD5;
104
105 // Set checksum bytes
106 for (int i = 0; i < 12; i += 2) {
107 ir_message[i] = ~ir_message[i + 1];
108 }
109
110 // Send the code
111 auto transmit = this->transmitter_->transmit();
112 auto *data = transmit.get_data();
113
114 data->set_carrier_frequency(38000); // 38 kHz PWM
115
116 // Header
117 data->mark(AC1_HDR_MARK);
118 data->space(AC1_HDR_SPACE);
119
120 // Data
121 for (uint8_t i : ir_message) {
122 for (uint8_t j = 0; j < 8; j++) {
123 data->mark(AC1_BIT_MARK);
124 bool bit = i & (1 << j);
125 data->space(bit ? AC1_ONE_SPACE : AC1_ZERO_SPACE);
126 }
127 }
128
129 // Footer
130 data->mark(AC1_BIT_MARK);
131 data->space(0);
132
133 transmit.perform();
134}
135
137 // Validate header
138 if (!data.expect_item(AC1_HDR_MARK, AC1_HDR_SPACE)) {
139 ESP_LOGV(TAG, "Header fail");
140 return false;
141 }
142
143 // Decode IR message
144 uint8_t ir_message[12] = {0};
145 // Read all bytes
146 for (int i = 0; i < 12; i++) {
147 // Read bit
148 for (int j = 0; j < 8; j++) {
149 if (data.expect_item(AC1_BIT_MARK, AC1_ONE_SPACE)) {
150 ir_message[i] |= 1 << j;
151 } else if (!data.expect_item(AC1_BIT_MARK, AC1_ZERO_SPACE)) {
152 ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
153 return false;
154 }
155 }
156 ESP_LOGVV(TAG, "Byte %d %02X", i, ir_message[i]);
157 }
158
159 // Validate footer
160 if (!data.expect_mark(AC1_BIT_MARK)) {
161 ESP_LOGV(TAG, "Footer fail");
162 return false;
163 }
164
165 // Validate checksum
166 for (int i = 0; i < 12; i += 2) {
167 if (ir_message[i] != (uint8_t) (~ir_message[i + 1])) {
168 ESP_LOGV(TAG, "Byte %d checksum incorrect (%02X != %02X)", i, ir_message[i], (uint8_t) (~ir_message[i + 1]));
169 return false;
170 }
171 }
172
173 // Validate remote control ID
174 if (ir_message[11] != 0xD5) {
175 ESP_LOGV(TAG, "Invalid remote control ID");
176 return false;
177 }
178
179 // All is good to go
180
181 if ((ir_message[7] & AC1_POWER_ON) == 0) {
183 } else {
184 // Vertical swing
185 if ((ir_message[7] & 0x0C) == AC1_VDIR_FIXED) {
186 if ((ir_message[7] & 0x10) == AC1_HDIR_FIXED) {
188 } else {
190 }
191 } else {
192 if ((ir_message[7] & 0x10) == AC1_HDIR_FIXED) {
194 } else {
196 }
197 }
198
199 // Preset + Fan speed
200 if ((ir_message[3] & AC1_FAN_TURBO) == AC1_FAN_TURBO) {
203 } else if ((ir_message[7] & 0xE1) == AC1_FAN_SILENT) {
206 } else if ((ir_message[7] & 0xE1) == AC1_FAN_AUTO) {
208 } else if ((ir_message[7] & 0xE1) == AC1_FAN1) {
210 } else if ((ir_message[7] & 0xE1) == AC1_FAN2) {
212 } else if ((ir_message[7] & 0xE1) == AC1_FAN3) {
214 }
215
216 // AC Mode
217 if ((ir_message[9] & 0xE0) == AC1_MODE_COOL) {
219 } else if ((ir_message[9] & 0xE0) == AC1_MODE_HEAT) {
221 } else if ((ir_message[9] & 0xE0) == AC1_MODE_DRY) {
223 } else if ((ir_message[9] & 0xE0) == AC1_MODE_FAN) {
225 } else {
227 }
228
229 // Taregt Temperature
230 this->target_temperature = (ir_message[9] & 0x1F) + 16.0f;
231 }
232
233 this->publish_state();
234 return true;
235}
236
237} // namespace zhlt01
238} // namespace esphome
ClimateMode mode
The active mode of the climate device.
Definition climate.h:173
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:199
float target_temperature
The target temperature of the climate device.
Definition climate.h:186
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:202
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:395
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:208
value_type const & value() const
Definition optional.h:89
bool expect_item(uint32_t mark, uint32_t space)
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:34
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
Definition zhlt01.cpp:136
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition zhlt01.cpp:9
@ 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_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.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7