ESPHome  2021.11.3
whirlpool.cpp
Go to the documentation of this file.
1 #include "whirlpool.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace whirlpool {
6 
7 static const char *const TAG = "whirlpool.climate";
8 
9 const uint16_t WHIRLPOOL_HEADER_MARK = 9000;
10 const uint16_t WHIRLPOOL_HEADER_SPACE = 4494;
11 const uint16_t WHIRLPOOL_BIT_MARK = 572;
12 const uint16_t WHIRLPOOL_ONE_SPACE = 1659;
13 const uint16_t WHIRLPOOL_ZERO_SPACE = 553;
14 const uint32_t WHIRLPOOL_GAP = 7960;
15 
16 const uint32_t WHIRLPOOL_CARRIER_FREQUENCY = 38000;
17 
18 const uint8_t WHIRLPOOL_STATE_LENGTH = 21;
19 
20 const uint8_t WHIRLPOOL_HEAT = 0;
21 const uint8_t WHIRLPOOL_DRY = 3;
22 const uint8_t WHIRLPOOL_COOL = 2;
23 const uint8_t WHIRLPOOL_FAN = 4;
24 const uint8_t WHIRLPOOL_AUTO = 1;
25 
26 const uint8_t WHIRLPOOL_FAN_AUTO = 0;
27 const uint8_t WHIRLPOOL_FAN_HIGH = 1;
28 const uint8_t WHIRLPOOL_FAN_MED = 2;
29 const uint8_t WHIRLPOOL_FAN_LOW = 3;
30 
31 const uint8_t WHIRLPOOL_SWING_MASK = 128;
32 
33 const uint8_t WHIRLPOOL_POWER = 0x04;
34 
36  uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0};
37  remote_state[0] = 0x83;
38  remote_state[1] = 0x06;
39  remote_state[6] = 0x80;
40  // MODEL DG11J191
41  remote_state[18] = 0x08;
42 
43  auto powered_on = this->mode != climate::CLIMATE_MODE_OFF;
44  if (powered_on != this->powered_on_assumed) {
45  // Set power toggle command
46  remote_state[2] = 4;
47  remote_state[15] = 1;
48  this->powered_on_assumed = powered_on;
49  }
50  switch (this->mode) {
52  // set fan auto
53  // set temp auto temp
54  // set sleep false
55  remote_state[3] = WHIRLPOOL_AUTO;
56  remote_state[15] = 0x17;
57  break;
59  remote_state[3] = WHIRLPOOL_HEAT;
60  remote_state[15] = 6;
61  break;
63  remote_state[3] = WHIRLPOOL_COOL;
64  remote_state[15] = 6;
65  break;
67  remote_state[3] = WHIRLPOOL_DRY;
68  remote_state[15] = 6;
69  break;
71  remote_state[3] = WHIRLPOOL_FAN;
72  remote_state[15] = 6;
73  break;
75  default:
76  break;
77  }
78 
79  // Temperature
80  auto temp = (uint8_t) roundf(clamp(this->target_temperature, this->temperature_min_(), this->temperature_max_()));
81  remote_state[3] |= (uint8_t)(temp - this->temperature_min_()) << 4;
82 
83  // Fan speed
84  switch (this->fan_mode.value()) {
86  remote_state[2] |= WHIRLPOOL_FAN_HIGH;
87  break;
89  remote_state[2] |= WHIRLPOOL_FAN_MED;
90  break;
92  remote_state[2] |= WHIRLPOOL_FAN_LOW;
93  break;
94  default:
95  break;
96  }
97 
98  // Swing
99  ESP_LOGV(TAG, "send swing %s", this->send_swing_cmd_ ? "true" : "false");
100  if (this->send_swing_cmd_) {
102  remote_state[2] |= 128;
103  remote_state[8] |= 64;
104  }
105  }
106 
107  // Checksum
108  for (uint8_t i = 2; i < 13; i++)
109  remote_state[13] ^= remote_state[i];
110  for (uint8_t i = 14; i < 20; i++)
111  remote_state[20] ^= remote_state[i];
112 
113  ESP_LOGV(TAG,
114  "Sending: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
115  "%02X %02X %02X",
116  remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5],
117  remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11],
118  remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17],
119  remote_state[18], remote_state[19], remote_state[20]);
120 
121  // Send code
122  auto transmit = this->transmitter_->transmit();
123  auto data = transmit.get_data();
124 
125  data->set_carrier_frequency(38000);
126 
127  // Header
128  data->mark(WHIRLPOOL_HEADER_MARK);
129  data->space(WHIRLPOOL_HEADER_SPACE);
130  // Data
131  auto bytes_sent = 0;
132  for (uint8_t i : remote_state) {
133  for (uint8_t j = 0; j < 8; j++) {
134  data->mark(WHIRLPOOL_BIT_MARK);
135  bool bit = i & (1 << j);
136  data->space(bit ? WHIRLPOOL_ONE_SPACE : WHIRLPOOL_ZERO_SPACE);
137  }
138  bytes_sent++;
139  if (bytes_sent == 6 || bytes_sent == 14) {
140  // Divider
141  data->mark(WHIRLPOOL_BIT_MARK);
142  data->space(WHIRLPOOL_GAP);
143  }
144  }
145  // Footer
146  data->mark(WHIRLPOOL_BIT_MARK);
147 
148  transmit.perform();
149 }
150 
152  // Validate header
153  if (!data.expect_item(WHIRLPOOL_HEADER_MARK, WHIRLPOOL_HEADER_SPACE)) {
154  ESP_LOGV(TAG, "Header fail");
155  return false;
156  }
157 
158  uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0};
159  // Read all bytes.
160  for (int i = 0; i < WHIRLPOOL_STATE_LENGTH; i++) {
161  // Read bit
162  if (i == 6 || i == 14) {
163  if (!data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_GAP))
164  return false;
165  }
166  for (int j = 0; j < 8; j++) {
167  if (data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_ONE_SPACE))
168  remote_state[i] |= 1 << j;
169 
170  else if (!data.expect_item(WHIRLPOOL_BIT_MARK, WHIRLPOOL_ZERO_SPACE)) {
171  ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
172  return false;
173  }
174  }
175 
176  ESP_LOGVV(TAG, "Byte %d %02X", i, remote_state[i]);
177  }
178  // Validate footer
179  if (!data.expect_mark(WHIRLPOOL_BIT_MARK)) {
180  ESP_LOGV(TAG, "Footer fail");
181  return false;
182  }
183 
184  uint8_t checksum13 = 0;
185  uint8_t checksum20 = 0;
186  // Calculate checksum and compare with signal value.
187  for (uint8_t i = 2; i < 13; i++)
188  checksum13 ^= remote_state[i];
189  for (uint8_t i = 14; i < 20; i++)
190  checksum20 ^= remote_state[i];
191 
192  if (checksum13 != remote_state[13] || checksum20 != remote_state[20]) {
193  ESP_LOGVV(TAG, "Checksum fail");
194  return false;
195  }
196 
197  ESP_LOGV(
198  TAG,
199  "Received: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
200  "%02X %02X %02X",
201  remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5],
202  remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11],
203  remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17],
204  remote_state[18], remote_state[19], remote_state[20]);
205 
206  // verify header remote code
207  if (remote_state[0] != 0x83 || remote_state[1] != 0x06)
208  return false;
209 
210  // powr on/off button
211  ESP_LOGV(TAG, "Power: %02X", (remote_state[2] & WHIRLPOOL_POWER));
212 
213  if ((remote_state[2] & WHIRLPOOL_POWER) == WHIRLPOOL_POWER) {
214  auto powered_on = this->mode != climate::CLIMATE_MODE_OFF;
215 
216  if (powered_on) {
218  this->powered_on_assumed = false;
219  } else {
220  this->powered_on_assumed = true;
221  }
222  }
223 
224  // Set received mode
225  if (powered_on_assumed) {
226  auto mode = remote_state[3] & 0x7;
227  ESP_LOGV(TAG, "Mode: %02X", mode);
228  switch (mode) {
229  case WHIRLPOOL_HEAT:
231  break;
232  case WHIRLPOOL_COOL:
234  break;
235  case WHIRLPOOL_DRY:
237  break;
238  case WHIRLPOOL_FAN:
240  break;
241  case WHIRLPOOL_AUTO:
243  break;
244  }
245  }
246 
247  // Set received temp
248  int temp = remote_state[3] & 0xF0;
249  ESP_LOGVV(TAG, "Temperature Raw: %02X", temp);
250  temp = (uint8_t) temp >> 4;
251  temp += static_cast<int>(this->temperature_min_());
252  ESP_LOGVV(TAG, "Temperature Climate: %u", temp);
253  this->target_temperature = temp;
254 
255  // Set received fan speed
256  auto fan = remote_state[2] & 0x03;
257  ESP_LOGVV(TAG, "Fan: %02X", fan);
258  switch (fan) {
259  case WHIRLPOOL_FAN_HIGH:
261  break;
262  case WHIRLPOOL_FAN_MED:
264  break;
265  case WHIRLPOOL_FAN_LOW:
267  break;
268  case WHIRLPOOL_FAN_AUTO:
269  default:
271  break;
272  }
273 
274  // Set received swing status
275  if ((remote_state[2] & WHIRLPOOL_SWING_MASK) == WHIRLPOOL_SWING_MASK && remote_state[8] == 0x40) {
276  ESP_LOGVV(TAG, "Swing toggle pressed ");
277  if (this->swing_mode == climate::CLIMATE_SWING_OFF) {
279  } else {
281  }
282  }
283 
284  this->publish_state();
285  return true;
286 }
287 
288 } // namespace whirlpool
289 } // namespace esphome
The fan mode is set to Low.
Definition: climate_mode.h:54
value_type const & value() const
Definition: optional.h:89
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition: climate.h:204
const uint16_t WHIRLPOOL_BIT_MARK
Definition: whirlpool.cpp:11
const uint32_t WHIRLPOOL_GAP
Definition: whirlpool.cpp:14
const uint8_t WHIRLPOOL_AUTO
Definition: whirlpool.cpp:24
const uint16_t WHIRLPOOL_HEADER_MARK
Definition: whirlpool.cpp:9
const uint8_t WHIRLPOOL_FAN
Definition: whirlpool.cpp:23
float target_temperature
The target temperature of the climate device.
Definition: climate.h:183
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:30
const uint16_t WHIRLPOOL_HEADER_SPACE
Definition: whirlpool.cpp:10
const uint16_t WHIRLPOOL_ZERO_SPACE
Definition: whirlpool.cpp:13
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
const uint8_t WHIRLPOOL_DRY
Definition: whirlpool.cpp:21
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:175
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition: whirlpool.cpp:35
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
const uint16_t WHIRLPOOL_ONE_SPACE
Definition: whirlpool.cpp:12
const uint8_t WHIRLPOOL_FAN_LOW
Definition: whirlpool.cpp:29
const uint8_t WHIRLPOOL_FAN_AUTO
Definition: whirlpool.cpp:26
const uint8_t WHIRLPOOL_SWING_MASK
Definition: whirlpool.cpp:31
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
The fan mode is set to Auto.
Definition: climate_mode.h:52
T clamp(const T val, const T min, const T max)
Clamp the value between min and max.
Definition: helpers.cpp:321
const uint8_t WHIRLPOOL_POWER
Definition: whirlpool.cpp:33
The climate device is set to heat/cool to reach the target temperature.
Definition: climate_mode.h:14
The fan mode is set to Vertical.
Definition: climate_mode.h:74
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition: climate.cpp:380
The fan mode is set to High.
Definition: climate_mode.h:58
The swing mode is set to Off.
Definition: climate_mode.h:70
The climate device is off.
Definition: climate_mode.h:12
const uint32_t WHIRLPOOL_CARRIER_FREQUENCY
Definition: whirlpool.cpp:16
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition: climate.h:198
Library based on https://github.com/miguelbalboa/rfid and adapted to ESPHome by . ...
Definition: a4988.cpp:4
const uint8_t WHIRLPOOL_STATE_LENGTH
Definition: whirlpool.cpp:18
const uint8_t WHIRLPOOL_COOL
Definition: whirlpool.cpp:22
The fan mode is set to Medium.
Definition: climate_mode.h:56
const uint8_t WHIRLPOOL_FAN_HIGH
Definition: whirlpool.cpp:27
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
Definition: whirlpool.cpp:151
bool expect_item(uint32_t mark, uint32_t space)
Definition: remote_base.h:111
The climate device only has the fan enabled, no heating or cooling is taking place.
Definition: climate_mode.h:20
const uint8_t WHIRLPOOL_FAN_MED
Definition: whirlpool.cpp:28
remote_transmitter::RemoteTransmitterComponent * transmitter_
Definition: climate_ir.h:65
const uint8_t WHIRLPOOL_HEAT
Definition: whirlpool.cpp:20