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