ESPHome  2024.5.0
zhlt01.cpp
Go to the documentation of this file.
1 #include "zhlt01.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace zhlt01 {
6 
7 static 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
The fan mode is set to Low.
Definition: climate_mode.h:54
value_type const & value() const
Definition: optional.h:89
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition: climate.h:202
The fan mode is set to Both.
Definition: climate_mode.h:74
float target_temperature
The target temperature of the climate device.
Definition: climate.h:186
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:34
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:173
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
Device is prepared for sleep.
Definition: climate_mode.h:96
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
Definition: zhlt01.cpp:136
The fan mode is set to Horizontal.
Definition: climate_mode.h:78
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
The fan mode is set to Auto.
Definition: climate_mode.h:52
optional< ClimatePreset > preset
The active preset of the climate device.
Definition: climate.h:208
RemoteTransmitterBase * transmitter_
Definition: remote_base.h:276
The climate device is adjusting the temperatre dynamically.
Definition: climate_mode.h:27
The climate device is set to heat/cool to reach the target temperature.
Definition: climate_mode.h:14
The fan mode is set to Vertical.
Definition: climate_mode.h:76
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition: climate.cpp:395
The fan mode is set to High.
Definition: climate_mode.h:58
The swing mode is set to Off.
Definition: climate_mode.h:72
The climate device is off.
Definition: climate_mode.h:12
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition: climate.h:199
Device is in boost preset.
Definition: climate_mode.h:90
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition: zhlt01.cpp:9
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
The fan mode is set to Medium.
Definition: climate_mode.h:56
bool expect_item(uint32_t mark, uint32_t space)
Definition: remote_base.cpp:74
The climate device only has the fan enabled, no heating or cooling is taking place.
Definition: climate_mode.h:20