ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
hitachi_ac424.cpp
Go to the documentation of this file.
1#include "hitachi_ac424.h"
3
5
6ESPHOME_LOG_TAG(TAG, "climate.hitachi_ac424");
7
8void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data) {
9 if (offset >= 8 || !nbits)
10 return; // Short circuit as it won't change.
11 // Calculate the mask for the supplied value.
12 uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
13 // Calculate the mask & clear the space for the data.
14 // Clear the destination bits.
15 *dst &= ~(uint8_t) (mask << offset);
16 // Merge in the data.
17 *dst |= ((data & mask) << offset);
18}
19
20uint8_t *invert_byte_pairs(uint8_t *ptr, const uint16_t length) {
21 for (uint16_t i = 1; i < length; i += 2) {
22 // Code done this way to avoid a compiler warning bug.
23 uint8_t inv = ~*(ptr + i - 1);
24 *(ptr + i) = inv;
25 }
26 return ptr;
27}
28
30
35
37
39 uint8_t new_mode = mode;
40 switch (mode) {
41 // Fan mode sets a special temp.
44 break;
48 break;
49 default:
50 new_mode = HITACHI_AC424_MODE_COOL;
51 }
53 if (new_mode != HITACHI_AC424_MODE_FAN)
55 set_fan_(get_fan_()); // Reset the fan speed after the mode change.
56 set_power_(true);
57}
58
59void HitachiClimate::set_temp_(uint8_t celsius, bool set_previous) {
60 uint8_t temp;
61 temp = std::min(celsius, HITACHI_AC424_TEMP_MAX);
62 temp = std::max(temp, HITACHI_AC424_TEMP_MIN);
64 if (previous_temp_ > temp) {
66 } else if (previous_temp_ < temp) {
68 }
69 if (set_previous)
70 previous_temp_ = temp;
71}
72
74
75void HitachiClimate::set_fan_(uint8_t speed) {
76 uint8_t new_speed = std::max(speed, HITACHI_AC424_FAN_MIN);
77 uint8_t fan_max = HITACHI_AC424_FAN_MAX;
78
79 // Only 2 x low speeds in Dry mode or Auto
81 fan_max = HITACHI_AC424_FAN_AUTO;
82 } else if (get_mode_() == HITACHI_AC424_MODE_DRY) {
85 // Fan Mode does not have auto. Set to safe low
86 new_speed = HITACHI_AC424_FAN_MIN;
87 }
88
89 new_speed = std::min(new_speed, fan_max);
90 // Handle the setting the button value if we are going to change the value.
91 if (new_speed != get_fan_())
93 // Set the values
94
96 remote_state_[9] = 0x92;
97
98 // When fan is at min/max, additional bytes seem to be set
99 if (new_speed == HITACHI_AC424_FAN_MIN)
100 remote_state_[9] = 0x98;
101 remote_state_[29] = 0x01;
102}
103
105 uint8_t button = get_button_(); // Get the current button value.
106 if (on) {
107 button = HITACHI_AC424_BUTTON_SWINGV; // Set the button to SwingV.
108 } else if (button == HITACHI_AC424_BUTTON_SWINGV) { // Asked to unset it
109 // It was set previous, so use Power as a default
111 }
112 set_button_(button);
113}
114
116
121
125
134
139
141
143
145 switch (this->mode) {
148 break;
151 break;
154 break;
157 break;
160 break;
162 set_power_(false);
163 break;
164 default:
165 ESP_LOGW(TAG, "Unsupported mode: %s", LOG_STR_ARG(climate_mode_to_string(this->mode)));
166 }
167
168 set_temp_(static_cast<uint8_t>(this->target_temperature));
169
170 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
173 break;
176 break;
179 break;
182 default:
184 }
185
186 switch (this->swing_mode) {
188 set_swing_v_(true);
190 break;
192 set_swing_v_(true);
194 break;
196 set_swing_v_(false);
198 break;
200 set_swing_v_(false);
202 break;
203 }
204
205 // TODO: find change value to set button, now always set to power button
207
209
210 auto transmit = this->transmitter_->transmit();
211 auto *data = transmit.get_data();
212 data->set_carrier_frequency(HITACHI_AC424_FREQ);
213
214 uint8_t repeat = 0;
215 for (uint8_t r = 0; r <= repeat; r++) {
216 // Header
218 // Data
219 data->item_bytes<HITACHI_AC424_BIT_TIMINGS>(remote_state_, HITACHI_AC424_STATE_LENGTH);
220 // Footer
222 }
223 transmit.perform();
224
225 dump_state_("Sent", remote_state_);
226}
227
228bool HitachiClimate::parse_mode_(const uint8_t remote_state[]) {
229 uint8_t power = remote_state[HITACHI_AC424_POWER_BYTE];
230 ESP_LOGV(TAG, "Power: %02X %02X", remote_state[HITACHI_AC424_POWER_BYTE], power);
231 uint8_t mode = remote_state[HITACHI_AC424_MODE_BYTE] & 0xF;
232 ESP_LOGV(TAG, "Mode: %02X %02X", remote_state[HITACHI_AC424_MODE_BYTE], mode);
233 if (power == HITACHI_AC424_POWER_ON) {
234 switch (mode) {
236 this->mode = climate::CLIMATE_MODE_COOL;
237 break;
239 this->mode = climate::CLIMATE_MODE_DRY;
240 break;
242 this->mode = climate::CLIMATE_MODE_HEAT;
243 break;
246 break;
249 break;
250 default:
251 break;
252 }
253 } else {
254 this->mode = climate::CLIMATE_MODE_OFF;
255 }
256 return true;
257}
258
259bool HitachiClimate::parse_temperature_(const uint8_t remote_state[]) {
260 uint8_t temperature =
261 HITACHI_AC424_GETBITS8(remote_state[HITACHI_AC424_TEMP_BYTE], HITACHI_AC424_TEMP_OFFSET, HITACHI_AC424_TEMP_SIZE);
263 ESP_LOGV(TAG, "Temperature: %02X %02u %04f", remote_state[HITACHI_AC424_TEMP_BYTE], temperature,
264 this->target_temperature);
265 return true;
266}
267
268bool HitachiClimate::parse_fan_(const uint8_t remote_state[]) {
269 uint8_t fan_mode = remote_state[HITACHI_AC424_FAN_BYTE] >> 4 & 0xF;
270 ESP_LOGV(TAG, "Fan: %02X %02X", remote_state[HITACHI_AC424_FAN_BYTE], fan_mode);
271 switch (fan_mode) {
274 this->fan_mode = climate::CLIMATE_FAN_LOW;
275 break;
277 this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
278 break;
281 this->fan_mode = climate::CLIMATE_FAN_HIGH;
282 break;
284 this->fan_mode = climate::CLIMATE_FAN_AUTO;
285 break;
286 default:
287 break;
288 }
289 return true;
290}
291
292bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
293 uint8_t swing_modeh = HITACHI_AC424_GETBITS8(remote_state[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET,
295 ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC424_SWINGH_BYTE], swing_modeh);
296
297 if ((swing_modeh & 0x3) == 0x3) {
299 } else {
301 }
302
303 return true;
304}
305
307 // Validate header
308 if (!data.expect_item(HITACHI_AC424_HDR_MARK, HITACHI_AC424_HDR_SPACE)) {
309 ESP_LOGVV(TAG, "Header fail");
310 return false;
311 }
312
313 uint8_t recv_state[HITACHI_AC424_STATE_LENGTH];
314 if (!data.expect_bytes<HITACHI_AC424_BIT_TIMINGS>(recv_state, HITACHI_AC424_STATE_LENGTH)) {
315 ESP_LOGVV(TAG, "Data fail");
316 return false;
317 }
318
319 // Validate footer
320 if (!data.expect_mark(HITACHI_AC424_BIT_MARK)) {
321 ESP_LOGVV(TAG, "Footer fail");
322 return false;
323 }
324
325 dump_state_("Recv", recv_state);
326
327 // parse mode
328 this->parse_mode_(recv_state);
329 // parse temperature
330 this->parse_temperature_(recv_state);
331 // parse fan
332 this->parse_fan_(recv_state);
333 // parse swingv
334 this->parse_swing_(recv_state);
335 this->publish_state();
336 for (uint8_t i = 0; i < HITACHI_AC424_STATE_LENGTH; i++)
337 remote_state_[i] = recv_state[i];
338
339 return true;
340}
341
342void HitachiClimate::dump_state_(const char action[], uint8_t state[]) {
343 for (uint16_t i = 0; i < HITACHI_AC424_STATE_LENGTH - 10; i += 10) {
344 ESP_LOGV(TAG, "%s: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", action, state[i + 0], state[i + 1],
345 state[i + 2], state[i + 3], state[i + 4], state[i + 5], state[i + 6], state[i + 7], state[i + 8],
346 state[i + 9]);
347 }
348 ESP_LOGV(TAG, "%s: %02X %02X %02X", action, state[40], state[41], state[42]);
349}
350
351} // namespace esphome::hitachi_ac424
BedjetMode mode
BedJet operating mode.
ClimateMode mode
The active mode of the climate device.
Definition climate.h:317
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:311
float target_temperature
The target temperature of the climate device.
Definition climate.h:298
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:323
ClimateAction action
The active state of the climate device.
Definition climate.h:320
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:432
bool on_receive(remote_base::RemoteReceiveData data) override
bool parse_fan_(const uint8_t remote_state[])
bool parse_mode_(const uint8_t remote_state[])
bool parse_temperature_(const uint8_t remote_state[])
void dump_state_(const char action[], uint8_t remote_state[])
bool parse_swing_(const uint8_t remote_state[])
uint8_t remote_state_[HITACHI_AC424_STATE_LENGTH]
void set_temp_(uint8_t celsius, bool set_previous=false)
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_AC424_MODE_HEAT
const uint8_t HITACHI_AC424_FAN_MAX_DRY
const uint8_t HITACHI_AC424_SWINGH_MIDDLE
const uint8_t HITACHI_AC424_FAN_MIN
const uint8_t HITACHI_AC424_SWINGH_LEFT_MAX
const uint16_t HITACHI_AC424_HDR_MARK
const uint8_t HITACHI_AC424_BUTTON_SWINGV
const uint8_t HITACHI_AC424_FAN_AUTO
const uint8_t HITACHI_AC424_SWINGH_SIZE
const uint8_t HITACHI_AC424_MODE_DRY
const uint8_t HITACHI_AC424_POWER_OFF
const uint8_t HITACHI_AC424_MODE_AUTO
const uint8_t HITACHI_AC424_BUTTON_TEMP_UP
const uint16_t HITACHI_AC424_HDR_SPACE
const uint8_t HITACHI_AC424_BUTTON_SWINGH
const uint8_t HITACHI_AC424_BUTTON_FAN
const uint8_t HITACHI_AC424_TEMP_FAN
const uint8_t HITACHI_AC424_BUTTON_TEMP_DOWN
const uint8_t HITACHI_AC424_MODE_FAN
const uint8_t HITACHI_AC424_SWINGV_BYTE
ESPHOME_LOG_TAG(TAG, "climate.hitachi_ac424")
const uint8_t HITACHI_AC424_FAN_MAX
const uint8_t HITACHI_AC424_MODE_COOL
const uint32_t HITACHI_AC424_MIN_GAP
const uint8_t HITACHI_AC424_SWINGH_BYTE
const uint8_t HITACHI_AC424_TEMP_OFFSET
const uint8_t HITACHI_AC424_SWINGH_AUTO
const uint8_t HITACHI_AC424_TEMP_MAX
const uint8_t HITACHI_AC424_SWINGH_OFFSET
const uint8_t HITACHI_AC424_FAN_BYTE
const uint8_t HITACHI_AC424_TEMP_BYTE
const uint8_t HITACHI_AC424_TEMP_MIN
const uint8_t HITACHI_AC424_TEMP_SIZE
const uint16_t HITACHI_AC424_STATE_LENGTH
const uint8_t HITACHI_AC424_FAN_MEDIUM
uint8_t * invert_byte_pairs(uint8_t *ptr, const uint16_t length)
const uint8_t HITACHI_AC424_POWER_BYTE
const uint8_t HITACHI_AC424_FAN_HIGH
const uint8_t HITACHI_AC424_FAN_LOW
const uint16_t HITACHI_AC424_FREQ
const uint8_t HITACHI_AC424_MODE_BYTE
const uint16_t HITACHI_AC424_BIT_MARK
const uint8_t HITACHI_AC424_BUTTON_BYTE
const uint8_t HITACHI_AC424_BUTTON_POWER
void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data)
const uint8_t HITACHI_AC424_SWINGV_OFFSET
const uint8_t HITACHI_AC424_POWER_ON
ESPHOME_ALWAYS_INLINE constexpr void assign_bits(T &value, std::type_identity_t< T > mask, bool on)
Set the bits of mask in value when on is true, clear them otherwise.
Definition helpers.h:1072
uint16_t temperature
Definition sun_gtil2.cpp:12
uint16_t length
Definition tt21100.cpp:0