ESPHome 2026.5.1
Loading...
Searching...
No Matches
hitachi_ac344.cpp
Go to the documentation of this file.
1#include "hitachi_ac344.h"
2
4
5static const char *const TAG = "climate.hitachi_ac344";
6
7void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data) {
8 if (offset >= 8 || !nbits)
9 return; // Short circuit as it won't change.
10 // Calculate the mask for the supplied value.
11 uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
12 // Calculate the mask & clear the space for the data.
13 // Clear the destination bits.
14 *dst &= ~(uint8_t) (mask << offset);
15 // Merge in the data.
16 *dst |= ((data & mask) << offset);
17}
18
19void set_bit(uint8_t *const data, const uint8_t position, const bool on) {
20 uint8_t mask = 1 << position;
21 if (on) {
22 *data |= mask;
23 } else {
24 *data &= ~mask;
25 }
26}
27
28uint8_t *invert_byte_pairs(uint8_t *ptr, const uint16_t length) {
29 for (uint16_t i = 1; i < length; i += 2) {
30 // Code done this way to avoid a compiler warning bug.
31 uint8_t inv = ~*(ptr + i - 1);
32 *(ptr + i) = inv;
33 }
34 return ptr;
35}
36
38
43
45
47 uint8_t new_mode = mode;
48 switch (mode) {
49 // Fan mode sets a special temp.
52 break;
56 break;
57 default:
58 new_mode = HITACHI_AC344_MODE_COOL;
59 }
61 if (new_mode != HITACHI_AC344_MODE_FAN)
63 set_fan_(get_fan_()); // Reset the fan speed after the mode change.
64 set_power_(true);
65}
66
67void HitachiClimate::set_temp_(uint8_t celsius, bool set_previous) {
68 uint8_t temp;
69 temp = std::min(celsius, HITACHI_AC344_TEMP_MAX);
70 temp = std::max(temp, HITACHI_AC344_TEMP_MIN);
72 if (previous_temp_ > temp) {
74 } else if (previous_temp_ < temp) {
76 }
77 if (set_previous)
78 previous_temp_ = temp;
79}
80
82
83void HitachiClimate::set_fan_(uint8_t speed) {
84 uint8_t new_speed = std::max(speed, HITACHI_AC344_FAN_MIN);
85 uint8_t fan_max = HITACHI_AC344_FAN_MAX;
86
87 // Only 2 x low speeds in Dry mode or Auto
89 fan_max = HITACHI_AC344_FAN_AUTO;
90 } else if (get_mode_() == HITACHI_AC344_MODE_DRY) {
93 // Fan Mode does not have auto. Set to safe low
94 new_speed = HITACHI_AC344_FAN_MIN;
95 }
96
97 new_speed = std::min(new_speed, fan_max);
98 // Handle the setting the button value if we are going to change the value.
99 if (new_speed != get_fan_())
101 // Set the values
102
104 remote_state_[9] = 0x92;
105
106 // When fan is at min/max, additional bytes seem to be set
107 if (new_speed == HITACHI_AC344_FAN_MIN)
108 remote_state_[9] = 0x98;
109 remote_state_[29] = 0x01;
110}
111
113 uint8_t button = get_button_(); // Get the current button value.
114 if (on) {
115 button = HITACHI_AC344_BUTTON_SWINGV; // Set the button to SwingV.
116 } else if (button == HITACHI_AC344_BUTTON_SWINGV) { // Asked to unset it
117 // It was set previous, so use Power as a default
119 }
120 set_button_(button);
121}
122
124
129
133
142
146
148
150
152 switch (this->mode) {
155 break;
158 break;
161 break;
164 break;
167 break;
169 set_power_(false);
170 break;
171 default:
172 ESP_LOGW(TAG, "Unsupported mode: %s", LOG_STR_ARG(climate_mode_to_string(this->mode)));
173 }
174
175 set_temp_(static_cast<uint8_t>(this->target_temperature));
176
177 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
180 break;
183 break;
186 break;
189 default:
191 }
192
193 switch (this->swing_mode) {
195 set_swing_v_(true);
197 break;
199 set_swing_v_(true);
201 break;
203 set_swing_v_(false);
205 break;
207 set_swing_v_(false);
209 break;
210 }
211
212 // TODO: find change value to set button, now always set to power button
214
216
217 auto transmit = this->transmitter_->transmit();
218 auto *data = transmit.get_data();
219 data->set_carrier_frequency(HITACHI_AC344_FREQ);
220
221 uint8_t repeat = 0;
222 for (uint8_t r = 0; r <= repeat; r++) {
223 // Header
225 // Data
226 for (uint8_t i : remote_state_) {
227 for (uint8_t j = 0; j < 8; j++) {
228 data->mark(HITACHI_AC344_BIT_MARK);
229 bool bit = i & (1 << j);
231 }
232 }
233 // Footer
235 }
236 transmit.perform();
237
238 dump_state_("Sent", remote_state_);
239}
240
241bool HitachiClimate::parse_mode_(const uint8_t remote_state[]) {
242 uint8_t power = remote_state[HITACHI_AC344_POWER_BYTE];
243 ESP_LOGV(TAG, "Power: %02X %02X", remote_state[HITACHI_AC344_POWER_BYTE], power);
244 uint8_t mode = remote_state[HITACHI_AC344_MODE_BYTE] & 0xF;
245 ESP_LOGV(TAG, "Mode: %02X %02X", remote_state[HITACHI_AC344_MODE_BYTE], mode);
246 if (power == HITACHI_AC344_POWER_ON) {
247 switch (mode) {
249 this->mode = climate::CLIMATE_MODE_COOL;
250 break;
252 this->mode = climate::CLIMATE_MODE_DRY;
253 break;
255 this->mode = climate::CLIMATE_MODE_HEAT;
256 break;
259 break;
262 break;
263 }
264 } else {
265 this->mode = climate::CLIMATE_MODE_OFF;
266 }
267 return true;
268}
269
270bool HitachiClimate::parse_temperature_(const uint8_t remote_state[]) {
271 uint8_t temperature =
274 ESP_LOGV(TAG, "Temperature: %02X %02u %04f", remote_state[HITACHI_AC344_TEMP_BYTE], temperature,
275 this->target_temperature);
276 return true;
277}
278
279bool HitachiClimate::parse_fan_(const uint8_t remote_state[]) {
280 uint8_t fan_mode = remote_state[HITACHI_AC344_FAN_BYTE] >> 4 & 0xF;
281 ESP_LOGV(TAG, "Fan: %02X %02X", remote_state[HITACHI_AC344_FAN_BYTE], fan_mode);
282 switch (fan_mode) {
285 this->fan_mode = climate::CLIMATE_FAN_LOW;
286 break;
288 this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
289 break;
292 this->fan_mode = climate::CLIMATE_FAN_HIGH;
293 break;
295 this->fan_mode = climate::CLIMATE_FAN_AUTO;
296 break;
297 }
298 return true;
299}
300
301bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
302 uint8_t swing_modeh =
304 ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC344_SWINGH_BYTE], swing_modeh);
305
306 if ((swing_modeh & 0x3) == 0x3) {
308 } else {
310 }
311
312 return true;
313}
314
316 // Validate header
317 if (!data.expect_item(HITACHI_AC344_HDR_MARK, HITACHI_AC344_HDR_SPACE)) {
318 ESP_LOGVV(TAG, "Header fail");
319 return false;
320 }
321
322 uint8_t recv_state[HITACHI_AC344_STATE_LENGTH] = {0};
323 // Read all bytes.
324 for (uint8_t pos = 0; pos < HITACHI_AC344_STATE_LENGTH; pos++) {
325 // Read bit
326 for (int8_t bit = 0; bit < 8; bit++) {
327 if (data.expect_item(HITACHI_AC344_BIT_MARK, HITACHI_AC344_ONE_SPACE)) {
328 recv_state[pos] |= 1 << bit;
329 } else if (!data.expect_item(HITACHI_AC344_BIT_MARK, HITACHI_AC344_ZERO_SPACE)) {
330 ESP_LOGVV(TAG, "Byte %d bit %d fail", pos, bit);
331 return false;
332 }
333 }
334 }
335
336 // Validate footer
337 if (!data.expect_mark(HITACHI_AC344_BIT_MARK)) {
338 ESP_LOGVV(TAG, "Footer fail");
339 return false;
340 }
341
342 dump_state_("Recv", recv_state);
343
344 // parse mode
345 this->parse_mode_(recv_state);
346 // parse temperature
347 this->parse_temperature_(recv_state);
348 // parse fan
349 this->parse_fan_(recv_state);
350 // parse swingv
351 this->parse_swing_(recv_state);
352 this->publish_state();
353 for (uint8_t i = 0; i < HITACHI_AC344_STATE_LENGTH; i++)
354 remote_state_[i] = recv_state[i];
355
356 return true;
357}
358
359void HitachiClimate::dump_state_(const char action[], uint8_t state[]) {
360 for (uint16_t i = 0; i < HITACHI_AC344_STATE_LENGTH - 10; i += 10) {
361 ESP_LOGV(TAG, "%s: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", action, state[i + 0], state[i + 1],
362 state[i + 2], state[i + 3], state[i + 4], state[i + 5], state[i + 6], state[i + 7], state[i + 8],
363 state[i + 9]);
364 }
365 ESP_LOGV(TAG, "%s: %02X %02X %02X", action, state[40], state[41], state[42]);
366}
367
368} // namespace esphome::hitachi_ac344
BedjetMode mode
BedJet operating mode.
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
ClimateAction action
The active state of the climate device.
Definition climate.h:296
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:437
bool on_receive(remote_base::RemoteReceiveData data) override
void dump_state_(const char action[], uint8_t remote_state[])
bool parse_temperature_(const uint8_t remote_state[])
bool parse_mode_(const uint8_t remote_state[])
void set_temp_(uint8_t celsius, bool set_previous=true)
bool parse_fan_(const uint8_t remote_state[])
uint8_t remote_state_[HITACHI_AC344_STATE_LENGTH]
bool parse_swing_(const uint8_t remote_state[])
float position
Definition cover.h:0
int speed
Definition fan.h:3
bool state
Definition fan.h:2
@ 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_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.
const uint8_t HITACHI_AC344_SWINGV_OFFSET
const uint8_t HITACHI_AC344_TEMP_MIN
const uint8_t HITACHI_AC344_BUTTON_FAN
const uint16_t HITACHI_AC344_BIT_MARK
void set_bit(uint8_t *const data, const uint8_t position, const bool on)
const uint8_t HITACHI_AC344_BUTTON_BYTE
const uint8_t HITACHI_AC344_TEMP_BYTE
const uint8_t HITACHI_AC344_MODE_BYTE
const uint8_t HITACHI_AC344_SWINGV_BYTE
const uint16_t HITACHI_AC344_ZERO_SPACE
const uint8_t HITACHI_AC344_SWINGH_SIZE
const uint8_t HITACHI_AC344_FAN_MIN
const uint8_t HITACHI_AC344_BUTTON_POWER
uint8_t * invert_byte_pairs(uint8_t *ptr, const uint16_t length)
const uint8_t HITACHI_AC344_BUTTON_SWINGH
const uint8_t HITACHI_AC344_FAN_MAX
const uint8_t HITACHI_AC344_MODE_DRY
const uint16_t HITACHI_AC344_HDR_SPACE
const uint8_t HITACHI_AC344_FAN_MAX_DRY
const uint8_t HITACHI_AC344_MODE_FAN
void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data)
const uint16_t HITACHI_AC344_FREQ
const uint8_t HITACHI_AC344_SWINGH_AUTO
const uint8_t HITACHI_AC344_BUTTON_TEMP_DOWN
const uint8_t HITACHI_AC344_MODE_AUTO
const uint8_t HITACHI_AC344_BUTTON_TEMP_UP
const uint8_t HITACHI_AC344_MODE_COOL
const uint16_t HITACHI_AC344_STATE_LENGTH
const uint8_t HITACHI_AC344_SWINGH_OFFSET
const uint8_t HITACHI_AC344_POWER_ON
const uint8_t HITACHI_AC344_TEMP_SIZE
const uint8_t HITACHI_AC344_FAN_HIGH
const uint8_t HITACHI_AC344_MODE_HEAT
const uint8_t HITACHI_AC344_FAN_BYTE
const uint16_t HITACHI_AC344_HDR_MARK
const uint8_t HITACHI_AC344_SWINGH_LEFT_MAX
const uint8_t HITACHI_AC344_TEMP_MAX
const uint8_t HITACHI_AC344_TEMP_OFFSET
const uint8_t HITACHI_AC344_FAN_LOW
const uint32_t HITACHI_AC344_MIN_GAP
const uint8_t HITACHI_AC344_FAN_MEDIUM
const uint8_t HITACHI_AC344_POWER_OFF
const uint8_t HITACHI_AC344_SWINGH_MIDDLE
const uint8_t HITACHI_AC344_POWER_BYTE
const uint8_t HITACHI_AC344_FAN_AUTO
const uint16_t HITACHI_AC344_ONE_SPACE
const uint8_t HITACHI_AC344_SWINGH_BYTE
const uint8_t HITACHI_AC344_BUTTON_SWINGV
const uint8_t HITACHI_AC344_TEMP_FAN
size_t size_t pos
Definition helpers.h:1038
uint16_t temperature
Definition sun_gtil2.cpp:12
uint16_t length
Definition tt21100.cpp:0