ESPHome  2024.12.2
mitsubishi.cpp
Go to the documentation of this file.
1 #include "mitsubishi.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace mitsubishi {
6 
7 static const char *const TAG = "mitsubishi.climate";
8 
9 const uint8_t MITSUBISHI_OFF = 0x00;
10 
11 const uint8_t MITSUBISHI_MODE_AUTO = 0x20;
12 const uint8_t MITSUBISHI_MODE_COOL = 0x18;
13 const uint8_t MITSUBISHI_MODE_DRY = 0x10;
14 const uint8_t MITSUBISHI_MODE_FAN_ONLY = 0x38;
15 const uint8_t MITSUBISHI_MODE_HEAT = 0x08;
16 
17 const uint8_t MITSUBISHI_MODE_A_HEAT = 0x00;
18 const uint8_t MITSUBISHI_MODE_A_DRY = 0x02;
19 const uint8_t MITSUBISHI_MODE_A_COOL = 0x06;
20 const uint8_t MITSUBISHI_MODE_A_AUTO = 0x06;
21 
22 const uint8_t MITSUBISHI_WIDE_VANE_SWING = 0xC0;
23 
24 const uint8_t MITSUBISHI_FAN_AUTO = 0x00;
25 
26 const uint8_t MITSUBISHI_VERTICAL_VANE_SWING = 0x38;
27 
28 // const uint8_t MITSUBISHI_AUTO = 0X80;
29 const uint8_t MITSUBISHI_OTHERWISE = 0X40;
30 const uint8_t MITSUBISHI_POWERFUL = 0x08;
31 
32 // Optional presets used to enable some model features
33 const uint8_t MITSUBISHI_ECONOCOOL = 0x20;
34 const uint8_t MITSUBISHI_NIGHTMODE = 0xC1;
35 
36 // Pulse parameters in usec
37 const uint16_t MITSUBISHI_BIT_MARK = 430;
38 const uint16_t MITSUBISHI_ONE_SPACE = 1250;
39 const uint16_t MITSUBISHI_ZERO_SPACE = 390;
40 const uint16_t MITSUBISHI_HEADER_MARK = 3500;
41 const uint16_t MITSUBISHI_HEADER_SPACE = 1700;
42 const uint16_t MITSUBISHI_MIN_GAP = 17500;
43 
44 // Marker bytes
45 const uint8_t MITSUBISHI_BYTE00 = 0X23;
46 const uint8_t MITSUBISHI_BYTE01 = 0XCB;
47 const uint8_t MITSUBISHI_BYTE02 = 0X26;
48 const uint8_t MITSUBISHI_BYTE03 = 0X01;
49 const uint8_t MITSUBISHI_BYTE04 = 0X00;
50 const uint8_t MITSUBISHI_BYTE13 = 0X00;
51 const uint8_t MITSUBISHI_BYTE16 = 0X00;
52 
61 
62  if (this->supports_cool_)
64  if (this->supports_heat_)
66 
67  if (this->supports_cool_ && this->supports_heat_)
69 
70  if (this->supports_dry_)
72  if (this->supports_fan_only_)
74 
75  // Default to only 3 levels in ESPHome even if most unit supports 4. The 3rd level is not used.
78  if (this->fan_mode_ == MITSUBISHI_FAN_Q4L)
80  if (/*this->fan_mode_ == MITSUBISHI_FAN_5L ||*/ this->fan_mode_ >= MITSUBISHI_FAN_4L)
81  traits.add_supported_fan_mode(climate::CLIMATE_FAN_MIDDLE); // Shouldn't be used for this but it helps
82 
85 
88 
89  return traits;
90 }
91 
93  // Byte 0-4: Constant: 0x23, 0xCB, 0x26, 0x01, 0x00
94  // Byte 5: On=0x20, Off: 0x00
95  // Byte 6: MODE (See MODEs above (Heat/Dry/Cool/Auto/FanOnly)
96  // Byte 7: TEMP bits 0,1,2,3, added to MITSUBISHI_TEMP_MIN
97  // Example: 0x00 = 0°C+MITSUBISHI_TEMP_MIN = 16°C; 0x07 = 7°C+MITSUBISHI_TEMP_MIN = 23°C
98  // Byte 8: MODE_A & Wide Vane (if present)
99  // MODE_A bits 0,1,2 different than Byte 6 (See MODE_As above)
100  // Wide Vane bits 4,5,6,7 (Middle = 0x30)
101  // Byte 9: FAN/Vertical Vane/Switch To Auto
102  // FAN (Speed) bits 0,1,2
103  // Vertical Vane bits 3,4,5 (Auto = 0x00)
104  // Switch To Auto bits 6,7
105  // Byte 10: CLOCK Current time as configured on remote (0x00=Not used)
106  // Byte 11: END CLOCK Stop time of HVAC (0x00 for no setting)
107  // Byte 12: START CLOCK Start time of HVAC (0x00 for no setting)
108  // Byte 13: Constant 0x00
109  // Byte 14: HVAC specfic, i.e. ECONO COOL, CLEAN MODE, always 0x00
110  // Byte 15: HVAC specfic, i.e. POWERFUL, SMART SET, PLASMA, always 0x00
111  // Byte 16: Constant 0x00
112  // Byte 17: Checksum: SUM[Byte0...Byte16]
113  uint8_t remote_state[18] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
114  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
115 
116  switch (this->mode) {
118  remote_state[6] = MITSUBISHI_MODE_HEAT;
119  remote_state[8] = MITSUBISHI_MODE_A_HEAT;
120  break;
122  remote_state[6] = MITSUBISHI_MODE_DRY;
123  remote_state[8] = MITSUBISHI_MODE_A_DRY;
124  break;
126  remote_state[6] = MITSUBISHI_MODE_COOL;
127  remote_state[8] = MITSUBISHI_MODE_A_COOL;
128  break;
130  remote_state[6] = MITSUBISHI_MODE_AUTO;
131  remote_state[8] = MITSUBISHI_MODE_A_AUTO;
132  break;
134  remote_state[6] = MITSUBISHI_MODE_FAN_ONLY;
135  remote_state[8] = MITSUBISHI_MODE_A_AUTO;
136  break;
138  default:
139  remote_state[6] = MITSUBISHI_MODE_COOL;
140  remote_state[8] = MITSUBISHI_MODE_A_COOL;
141  if (this->supports_heat_) {
142  remote_state[6] = MITSUBISHI_MODE_HEAT;
143  remote_state[8] = MITSUBISHI_MODE_A_HEAT;
144  }
145  remote_state[5] = MITSUBISHI_OFF;
146  break;
147  }
148 
149  // Temperature
150  if (this->mode == climate::CLIMATE_MODE_DRY) {
151  remote_state[7] = 24 - MITSUBISHI_TEMP_MIN; // Remote sends always 24°C if "Dry" mode is selected
152  } else {
153  remote_state[7] = (uint8_t) roundf(
155  }
156 
157  // Wide Vane
158  switch (this->swing_mode) {
161  remote_state[8] = remote_state[8] | MITSUBISHI_WIDE_VANE_SWING; // Wide Vane Swing
162  break;
164  default:
165  remote_state[8] = remote_state[8] | this->default_horizontal_direction_; // Off--> horizontal default position
166  break;
167  }
168 
169  ESP_LOGD(TAG, "default_horizontal_direction_: %02X", this->default_horizontal_direction_);
170 
171  // Fan Speed & Vertical Vane
172  // Map of Climate fan mode to this device expected value
173  // For 3Level: Low = 1, Medium = 2, High = 3
174  // For 4Level: Low = 1, Middle = 2, Medium = 3, High = 4
175  // For 5Level: Low = 1, Middle = 2, Medium = 3, High = 4
176  // For 4Level + Quiet: Low = 1, Middle = 2, Medium = 3, High = 4, Quiet = 5
177 
178  switch (this->fan_mode.value()) {
180  remote_state[9] = 1;
181  break;
183  if (this->fan_mode_ == MITSUBISHI_FAN_3L) {
184  remote_state[9] = 2;
185  } else {
186  remote_state[9] = 3;
187  }
188  break;
190  if (this->fan_mode_ == MITSUBISHI_FAN_3L) {
191  remote_state[9] = 3;
192  } else {
193  remote_state[9] = 4;
194  }
195  break;
197  remote_state[9] = 2;
198  break;
200  remote_state[9] = 5;
201  break;
202  default:
203  remote_state[9] = MITSUBISHI_FAN_AUTO;
204  break;
205  }
206 
207  ESP_LOGD(TAG, "fan: %02x state: %02x", this->fan_mode.value(), remote_state[9]);
208 
209  // Vertical Vane
210  switch (this->swing_mode) {
213  remote_state[9] = remote_state[9] | MITSUBISHI_VERTICAL_VANE_SWING | MITSUBISHI_OTHERWISE; // Vane Swing
214  break;
216  default:
217  remote_state[9] = remote_state[9] | this->default_vertical_direction_ |
218  MITSUBISHI_OTHERWISE; // Off--> vertical default position
219  break;
220  }
221 
222  ESP_LOGD(TAG, "default_vertical_direction_: %02X", this->default_vertical_direction_);
223 
224  // Special modes
225  switch (this->preset.value()) {
227  remote_state[6] = MITSUBISHI_MODE_COOL | MITSUBISHI_OTHERWISE;
228  remote_state[8] = (remote_state[8] & ~7) | MITSUBISHI_MODE_A_COOL;
229  remote_state[14] = MITSUBISHI_ECONOCOOL;
230  break;
232  remote_state[9] = MITSUBISHI_FAN_AUTO;
233  remote_state[14] = MITSUBISHI_NIGHTMODE;
234  break;
236  remote_state[6] |= MITSUBISHI_OTHERWISE;
237  remote_state[15] = MITSUBISHI_POWERFUL;
238  break;
240  default:
241  break;
242  }
243 
244  // Checksum
245  for (int i = 0; i < 17; i++) {
246  remote_state[17] += remote_state[i];
247  }
248 
249  ESP_LOGD(TAG, "sending: %02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X",
250  remote_state[0], remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5],
251  remote_state[6], remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11],
252  remote_state[12], remote_state[13], remote_state[14], remote_state[15], remote_state[16], remote_state[17]);
253 
254  auto transmit = this->transmitter_->transmit();
255  auto *data = transmit.get_data();
256 
257  data->set_carrier_frequency(38000);
258  // repeat twice
259  for (uint8_t r = 0; r < 2; r++) {
260  // Header
261  data->mark(MITSUBISHI_HEADER_MARK);
262  data->space(MITSUBISHI_HEADER_SPACE);
263  // Data
264  for (uint8_t i : remote_state) {
265  for (uint8_t j = 0; j < 8; j++) {
266  data->mark(MITSUBISHI_BIT_MARK);
267  bool bit = i & (1 << j);
268  data->space(bit ? MITSUBISHI_ONE_SPACE : MITSUBISHI_ZERO_SPACE);
269  }
270  }
271  // Footer
272  if (r == 0) {
273  data->mark(MITSUBISHI_BIT_MARK);
274  data->space(MITSUBISHI_MIN_GAP); // Pause before repeating
275  }
276  }
277  data->mark(MITSUBISHI_BIT_MARK);
278 
279  transmit.perform();
280 }
281 
282 bool MitsubishiClimate::parse_state_frame_(const uint8_t frame[]) { return false; }
283 
285  uint8_t state_frame[18] = {};
286 
287  if (!data.expect_item(MITSUBISHI_HEADER_MARK, MITSUBISHI_HEADER_SPACE)) {
288  ESP_LOGV(TAG, "Header fail");
289  return false;
290  }
291 
292  for (uint8_t pos = 0; pos < 18; pos++) {
293  uint8_t byte = 0;
294  for (int8_t bit = 0; bit < 8; bit++) {
295  if (data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ONE_SPACE)) {
296  byte |= 1 << bit;
297  } else if (!data.expect_item(MITSUBISHI_BIT_MARK, MITSUBISHI_ZERO_SPACE)) {
298  ESP_LOGV(TAG, "Byte %d bit %d fail", pos, bit);
299  return false;
300  }
301  }
302  state_frame[pos] = byte;
303 
304  // Check Header && Footer
305  if ((pos == 0 && byte != MITSUBISHI_BYTE00) || (pos == 1 && byte != MITSUBISHI_BYTE01) ||
306  (pos == 2 && byte != MITSUBISHI_BYTE02) || (pos == 3 && byte != MITSUBISHI_BYTE03) ||
307  (pos == 4 && byte != MITSUBISHI_BYTE04) || (pos == 13 && byte != MITSUBISHI_BYTE13) ||
308  (pos == 16 && byte != MITSUBISHI_BYTE16)) {
309  ESP_LOGV(TAG, "Bytes 0,1,2,3,4,13 or 16 fail - invalid value");
310  return false;
311  }
312  }
313 
314  // On/Off and Mode
315  if (state_frame[5] == MITSUBISHI_OFF) {
317  } else {
318  switch (state_frame[6]) {
321  break;
322  case MITSUBISHI_MODE_DRY:
324  break;
327  break;
330  break;
333  break;
334  }
335  }
336 
337  // Temp
338  this->target_temperature = state_frame[7] + MITSUBISHI_TEMP_MIN;
339 
340  // Fan
341  uint8_t fan = state_frame[9] & 0x07; //(Bit 0,1,2 = Speed)
342  // Map of Climate fan mode to this device expected value
343  // For 3Level: Low = 1, Medium = 2, High = 3
344  // For 4Level: Low = 1, Middle = 2, Medium = 3, High = 4
345  // For 5Level: Low = 1, Middle = 2, Medium = 3, High = 4
346  // For 4Level + Quiet: Low = 1, Middle = 2, Medium = 3, High = 4, Quiet = 5
347  climate::ClimateFanMode modes_mapping[8] = {
355  climate::CLIMATE_FAN_AUTO};
356  this->fan_mode = modes_mapping[fan];
357 
358  // Wide Vane
359  uint8_t wide_vane = state_frame[8] & 0xF0; // Bits 4,5,6,7
360  switch (wide_vane) {
363  break;
364  default:
366  break;
367  }
368 
369  // Vertical Vane
370  uint8_t vertical_vane = state_frame[9] & 0x38; // Bits 3,4,5
371  switch (vertical_vane) {
375  } else {
377  }
378  break;
379  }
380 
381  switch (state_frame[14]) {
384  break;
387  break;
388  }
389 
390  ESP_LOGV(TAG, "Receiving: %s", format_hex_pretty(state_frame, 18).c_str());
391 
392  this->publish_state();
393  return true;
394 }
395 
396 } // namespace mitsubishi
397 } // namespace esphome
The fan mode is set to Low.
Definition: climate_mode.h:54
const uint16_t MITSUBISHI_MIN_GAP
Definition: mitsubishi.cpp:42
value_type const & value() const
Definition: optional.h:89
const uint16_t MITSUBISHI_ONE_SPACE
Definition: mitsubishi.cpp:38
The fan mode is set to Quiet.
Definition: climate_mode.h:66
bool parse_state_frame_(const uint8_t frame[])
Definition: mitsubishi.cpp:282
const uint8_t MITSUBISHI_BYTE01
Definition: mitsubishi.cpp:46
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition: climate.h:202
const uint8_t MITSUBISHI_BYTE13
Definition: mitsubishi.cpp:50
void set_visual_temperature_step(float temperature_step)
const uint8_t MITSUBISHI_MODE_COOL
Definition: mitsubishi.cpp:12
The fan mode is set to Both.
Definition: climate_mode.h:74
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
Definition: helpers.cpp:369
const uint8_t MITSUBISHI_BYTE02
Definition: mitsubishi.cpp:47
const uint8_t MITSUBISHI_MODE_A_COOL
Definition: mitsubishi.cpp:19
const uint8_t MITSUBISHI_BYTE00
Definition: mitsubishi.cpp:45
float target_temperature
The target temperature of the climate device.
Definition: climate.h:186
void set_carrier_frequency(uint32_t carrier_frequency)
Definition: remote_base.h:34
The fan mode is set to Middle.
Definition: climate_mode.h:60
const uint8_t MITSUBISHI_MODE_A_AUTO
Definition: mitsubishi.cpp:20
This class contains all static data for climate devices.
void set_visual_min_temperature(float visual_min_temperature)
The climate device is set to heat to reach the target temperature.
Definition: climate_mode.h:18
const uint8_t MITSUBISHI_VERTICAL_VANE_SWING
Definition: mitsubishi.cpp:26
const uint8_t MITSUBISHI_POWERFUL
Definition: mitsubishi.cpp:30
ClimateMode mode
The active mode of the climate device.
Definition: climate.h:173
const uint8_t MITSUBISHI_ECONOCOOL
Definition: mitsubishi.cpp:33
const uint8_t MITSUBISHI_MODE_A_DRY
Definition: mitsubishi.cpp:18
const uint8_t MITSUBISHI_OTHERWISE
Definition: mitsubishi.cpp:29
const uint8_t MITSUBISHI_MODE_HEAT
Definition: mitsubishi.cpp:15
The climate device is set to dry/humidity mode.
Definition: climate_mode.h:22
const uint8_t MITSUBISHI_MODE_A_HEAT
Definition: mitsubishi.cpp:17
const uint8_t MITSUBISHI_BYTE04
Definition: mitsubishi.cpp:49
void set_supported_presets(std::set< ClimatePreset > presets)
climate::ClimateTraits traits() override
Definition: mitsubishi.cpp:53
const uint8_t MITSUBISHI_BYTE16
Definition: mitsubishi.cpp:51
const uint16_t MITSUBISHI_BIT_MARK
Definition: mitsubishi.cpp:37
const uint8_t MITSUBISHI_OFF
Definition: mitsubishi.cpp:9
Device is prepared for sleep.
Definition: climate_mode.h:96
const uint8_t MITSUBISHI_WIDE_VANE_SWING
Definition: mitsubishi.cpp:22
bool on_receive(remote_base::RemoteReceiveData data) override
Definition: mitsubishi.cpp:284
HorizontalDirection default_horizontal_direction_
Definition: mitsubishi.h:76
The fan mode is set to Horizontal.
Definition: climate_mode.h:78
The climate device is set to cool to reach the target temperature.
Definition: climate_mode.h:16
const uint8_t MITSUBISHI_FAN_AUTO
Definition: mitsubishi.cpp:24
void set_supported_fan_modes(std::set< ClimateFanMode > modes)
The fan mode is set to Auto.
Definition: climate_mode.h:52
optional< ClimatePreset > preset
The active preset of the climate device.
Definition: climate.h:208
const uint8_t MITSUBISHI_TEMP_MAX
Definition: mitsubishi.h:12
const uint16_t MITSUBISHI_HEADER_SPACE
Definition: mitsubishi.cpp:41
void set_supported_modes(std::set< ClimateMode > modes)
const uint16_t MITSUBISHI_HEADER_MARK
Definition: mitsubishi.cpp:40
RemoteTransmitterBase * transmitter_
Definition: remote_base.h:276
void set_visual_max_temperature(float visual_max_temperature)
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:76
void add_supported_fan_mode(ClimateFanMode mode)
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition: climate.cpp:395
The fan mode is set to High.
Definition: climate_mode.h:58
The swing mode is set to Off.
Definition: climate_mode.h:72
The climate device is off.
Definition: climate_mode.h:12
const uint8_t MITSUBISHI_NIGHTMODE
Definition: mitsubishi.cpp:34
void set_supports_action(bool supports_action)
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition: climate.h:199
const uint8_t MITSUBISHI_MODE_FAN_ONLY
Definition: mitsubishi.cpp:14
Device is in boost preset.
Definition: climate_mode.h:90
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void set_supported_swing_modes(std::set< ClimateSwingMode > modes)
Device is running an energy-saving preset.
Definition: climate_mode.h:94
const uint8_t MITSUBISHI_BYTE03
Definition: mitsubishi.cpp:48
void set_supports_current_temperature(bool supports_current_temperature)
const uint8_t MITSUBISHI_TEMP_MIN
Definition: mitsubishi.h:11
The fan mode is set to Medium.
Definition: climate_mode.h:56
const uint8_t MITSUBISHI_MODE_DRY
Definition: mitsubishi.cpp:13
bool expect_item(uint32_t mark, uint32_t space)
Definition: remote_base.cpp:74
const uint16_t MITSUBISHI_ZERO_SPACE
Definition: mitsubishi.cpp:39
The climate device only has the fan enabled, no heating or cooling is taking place.
Definition: climate_mode.h:20
VerticalDirection default_vertical_direction_
Definition: mitsubishi.h:77
sensor::Sensor * sensor_
Definition: climate_ir.h:67
void add_supported_mode(ClimateMode mode)
const uint8_t MITSUBISHI_MODE_AUTO
Definition: mitsubishi.cpp:11