ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
islandaire.cpp
Go to the documentation of this file.
1#include "islandaire.h"
3#include "esphome/core/log.h"
4
5#include <algorithm>
6#include <cmath>
7
9
10ESPHOME_LOG_TAG(TAG, "islandaire.climate");
11
12// 14-byte frame, LSB first:
13// Bytes 0-4: 0x22 preamble
14// Byte 5: power (0x20 off, 0x24 on); bit 3 (0x08) set while the auto-off timer is active
15// Byte 6: mode (0x01 heat, 0x03 cool, 0x04 fan only)
16// Byte 7: target temperature in °F (61-88)
17// Byte 8: fan speed (0x00 auto, 0x02 low, 0x04 high, 0x01 read as low too); bit 6 (0x40) set while the
18// timer is active
19// Byte 9: 0x00
20// Byte 10: auto-off timer in hours (1-12, 0 = off)
21// Bytes 11-12: 0x00
22// Byte 13: sum of bytes 0-12
23// The auto-off timer is not implemented: the unit switches itself off with no feedback, which
24// would leave the climate state stale.
25static constexpr uint8_t STATE_LENGTH = 14;
26static constexpr uint8_t PREAMBLE_LENGTH = 5;
27static constexpr uint8_t PREAMBLE = 0x22;
28
29static constexpr uint8_t POWER_OFF = 0x20;
30static constexpr uint8_t POWER_MASK = 0x04;
31static constexpr uint8_t POWER_ON = POWER_OFF | POWER_MASK;
32
33static constexpr uint8_t MODE_HEAT = 0x01;
34static constexpr uint8_t MODE_COOL = 0x03;
35static constexpr uint8_t MODE_FAN = 0x04;
36
37static constexpr uint8_t FAN_AUTO = 0x00;
38static constexpr uint8_t FAN_LOW_ALT = 0x01;
39static constexpr uint8_t FAN_LOW = 0x02;
40static constexpr uint8_t FAN_HIGH = 0x04;
41static constexpr uint8_t FAN_TIMER_FLAG = 0x40;
42
43static constexpr uint8_t TEMP_DEFAULT = 72;
44
45static constexpr uint16_t HEADER_MARK = 3608;
46static constexpr uint16_t HEADER_SPACE = 1520;
47static constexpr uint16_t BIT_MARK = 560;
48static constexpr uint16_t ONE_SPACE = 1208;
49static constexpr uint16_t ZERO_SPACE = 408;
50static constexpr uint32_t CARRIER_FREQUENCY = 38000;
51static constexpr remote_base::BitTimings BIT_TIMINGS{
52 .bit_mark = BIT_MARK, .one_space = ONE_SPACE, .zero_space = ZERO_SPACE};
53
55 ClimateIR::setup();
56 // The base class default assumes Celsius
57 if (std::isnan(this->target_temperature) || this->target_temperature < TEMP_MIN)
58 this->target_temperature = TEMP_DEFAULT;
59 this->target_temperature = std::min<float>(this->target_temperature, TEMP_MAX);
60}
61
63 // ClimateIR::dump_config() is not called: it prints the temperature range in Celsius
64 LOG_CLIMATE("", "Islandaire Climate", this);
65 ESP_LOGCONFIG(TAG, " Temperature range: %u to %u °F", TEMP_MIN, TEMP_MAX);
66}
67
73
75 uint8_t remote_state[STATE_LENGTH] = {0};
76
77 std::fill_n(remote_state, PREAMBLE_LENGTH, PREAMBLE);
78
79 remote_state[5] = this->mode == climate::CLIMATE_MODE_OFF ? POWER_OFF : POWER_ON;
80
81 switch (this->mode) {
83 remote_state[6] = MODE_HEAT;
84 break;
86 remote_state[6] = MODE_FAN;
87 break;
89 default:
90 remote_state[6] = MODE_COOL;
91 break;
92 }
93
94 // Whole degrees within the unit's range, stored as well so the published state matches what was sent
95 const auto temperature =
96 static_cast<uint8_t>(std::clamp<float>(std::round(this->target_temperature), TEMP_MIN, TEMP_MAX));
98 remote_state[7] = temperature;
99
100 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_AUTO)) {
102 remote_state[8] = FAN_LOW;
103 break;
105 remote_state[8] = FAN_HIGH;
106 break;
108 default:
109 remote_state[8] = FAN_AUTO;
110 break;
111 }
112
113 remote_state[STATE_LENGTH - 1] = sum_bytes(remote_state, STATE_LENGTH - 1);
114
115 ESP_LOGV_HEX(TAG, remote_state, STATE_LENGTH, STATE_LENGTH, "Sending: %s");
116
117 auto transmit = this->transmitter_->transmit();
118 auto *data = transmit.get_data();
119
120 data->set_carrier_frequency(CARRIER_FREQUENCY);
121
122 data->reserve(2 + STATE_LENGTH * 16 + 1);
123 data->item(HEADER_MARK, HEADER_SPACE);
124 data->item_bytes<BIT_TIMINGS>(remote_state, STATE_LENGTH);
125 data->mark(BIT_MARK);
126
127 transmit.perform();
128}
129
131 if (!data.expect_item(HEADER_MARK, HEADER_SPACE)) {
132 ESP_LOGVV(TAG, "Header fail");
133 return false;
134 }
135
136 uint8_t remote_state[STATE_LENGTH];
137 if (!data.expect_bytes<BIT_TIMINGS>(remote_state, STATE_LENGTH)) {
138 ESP_LOGVV(TAG, "Data fail");
139 return false;
140 }
141 if (!data.expect_mark(BIT_MARK)) {
142 ESP_LOGVV(TAG, "Footer fail");
143 return false;
144 }
145
146 if (sum_bytes(remote_state, STATE_LENGTH - 1) != remote_state[STATE_LENGTH - 1]) {
147 ESP_LOGVV(TAG, "Checksum fail");
148 return false;
149 }
150
151 for (uint8_t i = 0; i < PREAMBLE_LENGTH; i++) {
152 if (remote_state[i] != PREAMBLE)
153 return false;
154 }
155
156 ESP_LOGV_HEX(TAG, remote_state, STATE_LENGTH, STATE_LENGTH, "Received: %s");
157
158 if ((remote_state[5] & POWER_MASK) == 0) {
160 } else {
161 switch (remote_state[6]) {
162 case MODE_HEAT:
164 break;
165 case MODE_COOL:
167 break;
168 case MODE_FAN:
170 break;
171 default:
172 ESP_LOGV(TAG, "Unknown mode 0x%02X", remote_state[6]);
173 return false;
174 }
175 }
176
177 const uint8_t temp_f = remote_state[7];
178 if (temp_f >= TEMP_MIN && temp_f <= TEMP_MAX)
179 this->target_temperature = temp_f;
180
181 switch (remote_state[8] & ~FAN_TIMER_FLAG) {
182 case FAN_HIGH:
184 break;
185 case FAN_LOW:
186 case FAN_LOW_ALT:
188 break;
189 case FAN_AUTO:
190 default:
192 break;
193 }
194
195 this->publish_state();
196 return true;
197}
198
199} // namespace esphome::islandaire
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
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:432
void set_temperature_unit(TemperatureUnit unit)
bool on_receive(remote_base::RemoteReceiveData data) override
static constexpr uint8_t TEMP_MIN
Definition islandaire.h:10
climate::ClimateTraits traits() override
static constexpr uint8_t TEMP_MAX
Definition islandaire.h:11
@ 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_OFF
The climate device is off.
@ 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.
ESPHOME_LOG_TAG(TAG, "islandaire.climate")
constexpr uint8_t sum_bytes(const uint8_t *data, size_t len, uint8_t sum=0)
Add up the bytes of data with size len, truncated to 8 bits: the checksum many serial and IR protocol...
Definition helpers.h:894
static void uint32_t
A bit is a mark (one_mark or zero_mark, both bit_mark unless set) and a space (one_space or zero_spac...
Definition remote_base.h:29
uint16_t temperature
Definition sun_gtil2.cpp:12