ESPHome  2021.11.3
coolix.cpp
Go to the documentation of this file.
1 #include "coolix.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace coolix {
6 
7 static const char *const TAG = "coolix.climate";
8 
9 const uint32_t COOLIX_OFF = 0xB27BE0;
10 const uint32_t COOLIX_SWING = 0xB26BE0;
11 const uint32_t COOLIX_LED = 0xB5F5A5;
12 const uint32_t COOLIX_SILENCE_FP = 0xB5F5B6;
13 
14 // On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore.
15 const uint8_t COOLIX_COOL = 0b0000;
16 const uint8_t COOLIX_DRY_FAN = 0b0100;
17 const uint8_t COOLIX_AUTO = 0b1000;
18 const uint8_t COOLIX_HEAT = 0b1100;
19 const uint32_t COOLIX_MODE_MASK = 0b1100;
20 const uint32_t COOLIX_FAN_MASK = 0xF000;
21 const uint32_t COOLIX_FAN_MODE_AUTO_DRY = 0x1000;
22 const uint32_t COOLIX_FAN_AUTO = 0xB000;
23 const uint32_t COOLIX_FAN_MIN = 0x9000;
24 const uint32_t COOLIX_FAN_MED = 0x5000;
25 const uint32_t COOLIX_FAN_MAX = 0x3000;
26 
27 // Temperature
29 const uint8_t COOLIX_FAN_TEMP_CODE = 0b11100000; // Part of Fan Mode.
30 const uint32_t COOLIX_TEMP_MASK = 0b11110000;
32  0b00000000, // 17C
33  0b00010000, // 18c
34  0b00110000, // 19C
35  0b00100000, // 20C
36  0b01100000, // 21C
37  0b01110000, // 22C
38  0b01010000, // 23C
39  0b01000000, // 24C
40  0b11000000, // 25C
41  0b11010000, // 26C
42  0b10010000, // 27C
43  0b10000000, // 28C
44  0b10100000, // 29C
45  0b10110000 // 30C
46 };
47 
48 // Constants
49 static const uint32_t BIT_MARK_US = 660;
50 static const uint32_t HEADER_MARK_US = 560 * 8;
51 static const uint32_t HEADER_SPACE_US = 560 * 8;
52 static const uint32_t BIT_ONE_SPACE_US = 1500;
53 static const uint32_t BIT_ZERO_SPACE_US = 450;
54 static const uint32_t FOOTER_MARK_US = BIT_MARK_US;
55 static const uint32_t FOOTER_SPACE_US = HEADER_SPACE_US;
56 
57 const uint16_t COOLIX_BITS = 24;
58 
60  uint32_t remote_state = 0xB20F00;
61 
62  if (send_swing_cmd_) {
63  send_swing_cmd_ = false;
64  remote_state = COOLIX_SWING;
65  } else {
66  switch (this->mode) {
68  remote_state |= COOLIX_COOL;
69  break;
71  remote_state |= COOLIX_HEAT;
72  break;
74  remote_state |= COOLIX_AUTO;
75  break;
78  remote_state |= COOLIX_DRY_FAN;
79  break;
81  default:
82  remote_state = COOLIX_OFF;
83  break;
84  }
85  if (this->mode != climate::CLIMATE_MODE_OFF) {
86  if (this->mode != climate::CLIMATE_MODE_FAN_ONLY) {
87  auto temp = (uint8_t) roundf(clamp<float>(this->target_temperature, COOLIX_TEMP_MIN, COOLIX_TEMP_MAX));
88  remote_state |= COOLIX_TEMP_MAP[temp - COOLIX_TEMP_MIN];
89  } else {
90  remote_state |= COOLIX_FAN_TEMP_CODE;
91  }
94  remote_state |= COOLIX_FAN_MODE_AUTO_DRY;
95  } else {
96  switch (this->fan_mode.value()) {
98  remote_state |= COOLIX_FAN_MAX;
99  break;
101  remote_state |= COOLIX_FAN_MED;
102  break;
104  remote_state |= COOLIX_FAN_MIN;
105  break;
107  default:
108  remote_state |= COOLIX_FAN_AUTO;
109  break;
110  }
111  }
112  }
113  }
114  ESP_LOGV(TAG, "Sending coolix code: 0x%02X", remote_state);
115 
116  auto transmit = this->transmitter_->transmit();
117  auto data = transmit.get_data();
118 
119  data->set_carrier_frequency(38000);
120  uint16_t repeat = 1;
121  for (uint16_t r = 0; r <= repeat; r++) {
122  // Header
123  data->mark(HEADER_MARK_US);
124  data->space(HEADER_SPACE_US);
125  // Data
126  // Break data into bytes, starting at the Most Significant
127  // Byte. Each byte then being sent normal, then followed inverted.
128  for (uint16_t i = 8; i <= COOLIX_BITS; i += 8) {
129  // Grab a bytes worth of data.
130  uint8_t byte = (remote_state >> (COOLIX_BITS - i)) & 0xFF;
131  // Normal
132  for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
133  data->mark(BIT_MARK_US);
134  data->space((byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
135  }
136  // Inverted
137  for (uint64_t mask = 1ULL << 7; mask; mask >>= 1) {
138  data->mark(BIT_MARK_US);
139  data->space(!(byte & mask) ? BIT_ONE_SPACE_US : BIT_ZERO_SPACE_US);
140  }
141  }
142  // Footer
143  data->mark(BIT_MARK_US);
144  data->space(FOOTER_SPACE_US); // Pause before repeating
145  }
146 
147  transmit.perform();
148 }
149 
151  // Decoded remote state y 3 bytes long code.
152  uint32_t remote_state = 0;
153  // The protocol sends the data twice, read here
154  uint32_t loop_read;
155  for (uint16_t loop = 1; loop <= 2; loop++) {
156  if (!data.expect_item(HEADER_MARK_US, HEADER_SPACE_US))
157  return false;
158  loop_read = 0;
159  for (uint8_t a_byte = 0; a_byte < 3; a_byte++) {
160  uint8_t byte = 0;
161  for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
162  if (data.expect_item(BIT_MARK_US, BIT_ONE_SPACE_US))
163  byte |= 1 << a_bit;
164  else if (!data.expect_item(BIT_MARK_US, BIT_ZERO_SPACE_US))
165  return false;
166  }
167  // Need to see this segment inverted
168  for (int8_t a_bit = 7; a_bit >= 0; a_bit--) {
169  bool bit = byte & (1 << a_bit);
170  if (!data.expect_item(BIT_MARK_US, bit ? BIT_ZERO_SPACE_US : BIT_ONE_SPACE_US))
171  return false;
172  }
173  // Receiving MSB first: reorder bytes
174  loop_read |= byte << ((2 - a_byte) * 8);
175  }
176  // Footer Mark
177  if (!data.expect_mark(BIT_MARK_US))
178  return false;
179  if (loop == 1) {
180  // Back up state on first loop
181  remote_state = loop_read;
182  if (!data.expect_space(FOOTER_SPACE_US))
183  return false;
184  }
185  }
186 
187  ESP_LOGV(TAG, "Decoded 0x%02X", remote_state);
188  if (remote_state != loop_read || (remote_state & 0xFF0000) != 0xB20000)
189  return false;
190 
191  if (remote_state == COOLIX_OFF) {
193  } else if (remote_state == COOLIX_SWING) {
194  this->swing_mode =
196  } else {
197  if ((remote_state & COOLIX_MODE_MASK) == COOLIX_HEAT)
199  else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_AUTO)
201  else if ((remote_state & COOLIX_MODE_MASK) == COOLIX_DRY_FAN) {
202  if ((remote_state & COOLIX_FAN_MASK) == COOLIX_FAN_MODE_AUTO_DRY)
204  else
206  } else
208 
209  // Fan Speed
210  if ((remote_state & COOLIX_FAN_AUTO) == COOLIX_FAN_AUTO || this->mode == climate::CLIMATE_MODE_HEAT_COOL ||
213  else if ((remote_state & COOLIX_FAN_MIN) == COOLIX_FAN_MIN)
215  else if ((remote_state & COOLIX_FAN_MED) == COOLIX_FAN_MED)
217  else if ((remote_state & COOLIX_FAN_MAX) == COOLIX_FAN_MAX)
219 
220  // Temperature
221  uint8_t temperature_code = remote_state & COOLIX_TEMP_MASK;
222  for (uint8_t i = 0; i < COOLIX_TEMP_RANGE; i++)
223  if (COOLIX_TEMP_MAP[i] == temperature_code)
225  }
226  this->publish_state();
227 
228  return true;
229 }
230 
231 } // namespace coolix
232 } // 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 uint32_t COOLIX_FAN_MED
Definition: coolix.cpp:24
virtual void loop()
This method will be called repeatedly.
Definition: component.cpp:48
const uint16_t COOLIX_BITS
Definition: coolix.cpp:57
const uint32_t COOLIX_MODE_MASK
Definition: coolix.cpp:19
float target_temperature
The target temperature of the climate device.
Definition: climate.h:183
const uint8_t COOLIX_COOL
Definition: coolix.cpp:15
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:30
const uint32_t COOLIX_FAN_MASK
Definition: coolix.cpp:20
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:175
const uint32_t COOLIX_TEMP_MASK
Definition: coolix.cpp:30
const uint8_t COOLIX_TEMP_MAX
Definition: coolix.h:10
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
const uint32_t COOLIX_OFF
Definition: coolix.cpp:9
const uint8_t COOLIX_TEMP_RANGE
Definition: coolix.cpp:28
const uint8_t COOLIX_TEMP_MIN
Definition: coolix.h:9
bool on_receive(remote_base::RemoteReceiveData data) override
Handle received IR Buffer.
Definition: coolix.cpp:150
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
const uint8_t COOLIX_HEAT
Definition: coolix.cpp:18
The fan mode is set to Auto.
Definition: climate_mode.h:52
const uint32_t COOLIX_FAN_MAX
Definition: coolix.cpp:25
const uint8_t COOLIX_FAN_TEMP_CODE
Definition: coolix.cpp:29
const uint32_t COOLIX_SWING
Definition: coolix.cpp:10
const uint32_t COOLIX_FAN_MIN
Definition: coolix.cpp:23
void transmit_state() override
Transmit via IR the state of this climate controller.
Definition: coolix.cpp:59
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
const uint32_t COOLIX_SILENCE_FP
Definition: coolix.cpp:12
const uint32_t COOLIX_FAN_AUTO
Definition: coolix.cpp:22
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 uint8_t COOLIX_TEMP_MAP[COOLIX_TEMP_RANGE]
Definition: coolix.cpp:31
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition: climate.h:198
const uint8_t COOLIX_DRY_FAN
Definition: coolix.cpp:16
Library based on https://github.com/miguelbalboa/rfid and adapted to ESPHome by . ...
Definition: a4988.cpp:4
const uint32_t COOLIX_LED
Definition: coolix.cpp:11
The fan mode is set to Medium.
Definition: climate_mode.h:56
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
remote_transmitter::RemoteTransmitterComponent * transmitter_
Definition: climate_ir.h:65
const uint32_t COOLIX_FAN_MODE_AUTO_DRY
Definition: coolix.cpp:21
const uint8_t COOLIX_AUTO
Definition: coolix.cpp:17