ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
whirlpool.cpp
Go to the documentation of this file.
1#include "whirlpool.h"
2#include "esphome/core/log.h"
3
5
6static const char *const TAG = "whirlpool.climate";
7
8const uint16_t WHIRLPOOL_HEADER_MARK = 9000;
9const uint16_t WHIRLPOOL_HEADER_SPACE = 4494;
10const uint16_t WHIRLPOOL_BIT_MARK = 572;
11const uint16_t WHIRLPOOL_ONE_SPACE = 1659;
12const uint16_t WHIRLPOOL_ZERO_SPACE = 553;
14
16
17const uint8_t WHIRLPOOL_STATE_LENGTH = 21;
18
19const uint8_t WHIRLPOOL_HEAT = 0;
20const uint8_t WHIRLPOOL_DRY = 3;
21const uint8_t WHIRLPOOL_COOL = 2;
22const uint8_t WHIRLPOOL_FAN = 4;
23const uint8_t WHIRLPOOL_AUTO = 1;
24
25const uint8_t WHIRLPOOL_FAN_AUTO = 0;
26const uint8_t WHIRLPOOL_FAN_HIGH = 1;
27const uint8_t WHIRLPOOL_FAN_MED = 2;
28const uint8_t WHIRLPOOL_FAN_LOW = 3;
29
30const uint8_t WHIRLPOOL_SWING_MASK = 128;
31
32const uint8_t WHIRLPOOL_POWER = 0x04;
33
40
42 this->last_transmit_time_ = millis(); // setting the time of the last transmission.
43 uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0};
44 remote_state[0] = 0x83;
45 remote_state[1] = 0x06;
46 remote_state[6] = 0x80;
47 // MODEL DG11J191
48 remote_state[18] = 0x08;
49
50 auto powered_on = this->mode != climate::CLIMATE_MODE_OFF;
51 if (powered_on != this->powered_on_assumed) {
52 // Set power toggle command
53 remote_state[2] = 4;
54 remote_state[15] = 1;
55 this->powered_on_assumed = powered_on;
56 }
57 switch (this->mode) {
59 // set fan auto
60 // set temp auto temp
61 // set sleep false
62 remote_state[3] = WHIRLPOOL_AUTO;
63 remote_state[15] = 0x17;
64 break;
66 remote_state[3] = WHIRLPOOL_HEAT;
67 remote_state[15] = 6;
68 break;
70 remote_state[3] = WHIRLPOOL_COOL;
71 remote_state[15] = 6;
72 break;
74 remote_state[3] = WHIRLPOOL_DRY;
75 remote_state[15] = 6;
76 break;
78 remote_state[3] = WHIRLPOOL_FAN;
79 remote_state[15] = 6;
80 break;
82 default:
83 break;
84 }
85
86 // Temperature
87 auto temp = (uint8_t) roundf(clamp(this->target_temperature, this->temperature_min_(), this->temperature_max_()));
88 remote_state[3] |= (uint8_t) (temp - this->temperature_min_()) << 4;
89
90 // Fan speed
91 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
93 remote_state[2] |= WHIRLPOOL_FAN_HIGH;
94 break;
96 remote_state[2] |= WHIRLPOOL_FAN_MED;
97 break;
99 remote_state[2] |= WHIRLPOOL_FAN_LOW;
100 break;
101 default:
102 break;
103 }
104
105 // Swing
106 ESP_LOGV(TAG, "send swing %s", this->send_swing_cmd_ ? "true" : "false");
107 if (this->send_swing_cmd_) {
109 remote_state[2] |= 128;
110 remote_state[8] |= 64;
111 }
112 }
113
114 // Checksum
115 for (uint8_t i = 2; i < 13; i++)
116 remote_state[13] ^= remote_state[i];
117 for (uint8_t i = 14; i < 20; i++)
118 remote_state[20] ^= remote_state[i];
119
120 ESP_LOGV(TAG,
121 "Sending: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
122 "%02X %02X %02X",
123 remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5],
124 remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11],
125 remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17],
126 remote_state[18], remote_state[19], remote_state[20]);
127
128 // Send code
129 auto transmit = this->transmitter_->transmit();
130 auto *data = transmit.get_data();
131
132 data->set_carrier_frequency(38000);
133
134 // Header
135 data->mark(WHIRLPOOL_HEADER_MARK);
136 data->space(WHIRLPOOL_HEADER_SPACE);
137 // Data
138 auto bytes_sent = 0;
139 for (uint8_t i : remote_state) {
140 for (uint8_t j = 0; j < 8; j++) {
141 data->mark(WHIRLPOOL_BIT_MARK);
142 bool bit = i & (1 << j);
143 data->space(bit ? WHIRLPOOL_ONE_SPACE : WHIRLPOOL_ZERO_SPACE);
144 }
145 bytes_sent++;
146 if (bytes_sent == 6 || bytes_sent == 14) {
147 // Divider
148 data->mark(WHIRLPOOL_BIT_MARK);
149 data->space(WHIRLPOOL_GAP);
150 }
151 }
152 // Footer
153 data->mark(WHIRLPOOL_BIT_MARK);
154
155 transmit.perform();
156}
157
159 // Check if the esp isn't currently transmitting.
160 if (millis() - this->last_transmit_time_ < 500) {
161 ESP_LOGV(TAG, "Blocked receive because of current trasmittion");
162 return false;
163 }
164
165 // Validate header
166 if (!data.expect_item(WHIRLPOOL_HEADER_MARK, WHIRLPOOL_HEADER_SPACE)) {
167 ESP_LOGV(TAG, "Header fail");
168 return false;
169 }
170
171 uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0};
172 bool skip_footer = false;
173 // Read all bytes.
174 for (int i = 0; i < WHIRLPOOL_STATE_LENGTH; i++) {
175 // Read bit
176 if (i == 6 || i == 14) {
177 if (!data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_GAP))
178 return false;
179 }
180 if (i == 14 && !data.is_valid()) {
181 // Remote control only sent 14 bytes, nothing more to read, not even the footer
182 ESP_LOGV(TAG, "Remote control only sent %d bytes", i);
183 skip_footer = true;
184 break;
185 }
186
187 for (int j = 0; j < 8; j++) {
188 if (data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_ONE_SPACE)) {
189 remote_state[i] |= 1 << j;
190
191 } else if (!data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_ZERO_SPACE)) {
192 ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
193 return false;
194 }
195 }
196
197 ESP_LOGVV(TAG, "Byte %d %02X", i, remote_state[i]);
198 }
199 // Validate footer
200 if (!data.expect_mark(WHIRLPOOL_BIT_MARK) && !skip_footer) {
201 ESP_LOGV(TAG, "Footer fail");
202 return false;
203 }
204
205 uint8_t checksum13 = 0;
206 uint8_t checksum20 = 0;
207 // Calculate checksum and compare with signal value.
208 for (uint8_t i = 2; i < 13; i++)
209 checksum13 ^= remote_state[i];
210 for (uint8_t i = 14; i < 20; i++)
211 checksum20 ^= remote_state[i];
212
213 if (checksum13 != remote_state[13] || (!skip_footer && checksum20 != remote_state[20])) {
214 ESP_LOGVV(TAG, "Checksum fail");
215 return false;
216 }
217
218 ESP_LOGV(
219 TAG,
220 "Received: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
221 "%02X %02X %02X",
222 remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5],
223 remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11],
224 remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17],
225 remote_state[18], remote_state[19], remote_state[20]);
226
227 // verify header remote code
228 if (remote_state[0] != 0x83 || remote_state[1] != 0x06)
229 return false;
230
231 // powr on/off button
232 ESP_LOGV(TAG, "Power: %02X", (remote_state[2] & WHIRLPOOL_POWER));
233
234 if ((remote_state[2] & WHIRLPOOL_POWER) == WHIRLPOOL_POWER) {
235 auto powered_on = this->mode != climate::CLIMATE_MODE_OFF;
236
237 if (powered_on) {
239 this->powered_on_assumed = false;
240 } else {
241 this->powered_on_assumed = true;
242 }
243 }
244
245 // Set received mode
246 if (powered_on_assumed) {
247 auto mode = remote_state[3] & 0x7;
248 ESP_LOGV(TAG, "Mode: %02X", mode);
249 switch (mode) {
250 case WHIRLPOOL_HEAT:
252 break;
253 case WHIRLPOOL_COOL:
255 break;
256 case WHIRLPOOL_DRY:
258 break;
259 case WHIRLPOOL_FAN:
261 break;
262 case WHIRLPOOL_AUTO:
264 break;
265 }
266 }
267
268 // Set received temp
269 int temp = remote_state[3] & 0xF0;
270 ESP_LOGVV(TAG, "Temperature Raw: %02X", temp);
271 temp = (uint8_t) temp >> 4;
272 temp += static_cast<int>(this->temperature_min_());
273 ESP_LOGVV(TAG, "Temperature Climate: %u", temp);
274 this->target_temperature = temp;
275
276 // Set received fan speed
277 auto fan = remote_state[2] & 0x03;
278 ESP_LOGVV(TAG, "Fan: %02X", fan);
279 switch (fan) {
282 break;
285 break;
288 break;
290 default:
292 break;
293 }
294
295 // Set received swing status
296 if ((remote_state[2] & WHIRLPOOL_SWING_MASK) == WHIRLPOOL_SWING_MASK && remote_state[8] == 0x40) {
297 ESP_LOGVV(TAG, "Swing toggle pressed ");
300 } else {
302 }
303 }
304
305 this->publish_state();
306 return true;
307}
308
309} // namespace esphome::whirlpool
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
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:437
uint32_t last_transmit_time_
Set the time of the last transmission.
Definition whirlpool.h:50
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition whirlpool.cpp:41
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
@ 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 WHIRLPOOL_COOL
Definition whirlpool.cpp:21
const uint16_t WHIRLPOOL_BIT_MARK
Definition whirlpool.cpp:10
const float WHIRLPOOL_DG11J1_3A_TEMP_MAX
Definition whirlpool.h:14
const uint16_t WHIRLPOOL_HEADER_SPACE
Definition whirlpool.cpp:9
const uint8_t WHIRLPOOL_FAN_MED
Definition whirlpool.cpp:27
const uint8_t WHIRLPOOL_FAN_AUTO
Definition whirlpool.cpp:25
const uint8_t WHIRLPOOL_SWING_MASK
Definition whirlpool.cpp:30
const uint8_t WHIRLPOOL_STATE_LENGTH
Definition whirlpool.cpp:17
const uint32_t WHIRLPOOL_CARRIER_FREQUENCY
Definition whirlpool.cpp:15
const uint8_t WHIRLPOOL_FAN_LOW
Definition whirlpool.cpp:28
const uint16_t WHIRLPOOL_ZERO_SPACE
Definition whirlpool.cpp:12
const uint8_t WHIRLPOOL_DRY
Definition whirlpool.cpp:20
const uint16_t WHIRLPOOL_ONE_SPACE
Definition whirlpool.cpp:11
const uint16_t WHIRLPOOL_HEADER_MARK
Definition whirlpool.cpp:8
const float WHIRLPOOL_DG11J1_3A_TEMP_MIN
Definition whirlpool.h:15
const uint8_t WHIRLPOOL_HEAT
Definition whirlpool.cpp:19
const uint8_t WHIRLPOOL_AUTO
Definition whirlpool.cpp:23
const uint8_t WHIRLPOOL_POWER
Definition whirlpool.cpp:32
const uint8_t WHIRLPOOL_FAN
Definition whirlpool.cpp:22
const uint8_t WHIRLPOOL_FAN_HIGH
Definition whirlpool.cpp:26
const uint32_t WHIRLPOOL_GAP
Definition whirlpool.cpp:13
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:28
static void uint32_t