ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
daikin.cpp
Go to the documentation of this file.
1#include "daikin.h"
5
6namespace esphome::daikin {
7
8ESPHOME_LOG_TAG(TAG, "daikin.climate");
9
10static constexpr uint32_t BOOST_TIMEOUT_ID = 0;
11
12static constexpr uint8_t DAIKIN_HEADER_BYTE0 = 0x11;
13static constexpr uint8_t DAIKIN_HEADER_BYTE1 = 0xDA;
14static constexpr uint8_t DAIKIN_HEADER_BYTE2 = 0x27;
15static constexpr uint8_t DAIKIN_HEADER_BYTE3 = 0x00;
16static constexpr uint8_t DAIKIN_FRAME_TYPE_INDEX = 4;
17static constexpr uint8_t DAIKIN_FRAME_HEADER_SIZE = DAIKIN_FRAME_TYPE_INDEX + 1;
18static constexpr uint8_t DAIKIN_STATE_FRAME_OFFSET = 2 * DAIKIN_COMFORT_FRAME_SIZE;
19
22 // A boost preset restored from flash gets its timer too
23 this->update_boost_timer_(false);
24}
25
27 const bool was_boost = this->preset == climate::CLIMATE_PRESET_BOOST;
29 this->update_boost_timer_(was_boost);
30}
31
33 uint8_t remote_state[35] = {0x11, 0xDA, 0x27, 0x00, 0xC5, 0x00, 0x00, 0x00, 0x11, 0xDA, 0x27, 0x00,
34 0x42, 0x49, 0x05, 0xA2, 0x11, 0xDA, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00};
36
37 this->set_presets_(remote_state);
38 remote_state[21] = this->operation_mode_();
39 remote_state[22] = this->temperature_();
40 uint16_t fan_speed = this->fan_speed_();
41 remote_state[24] = fan_speed >> 8;
42 remote_state[25] = fan_speed & 0xff;
43
44 remote_state[7] = sum_bytes(remote_state, 7);
45 remote_state[34] = sum_bytes(remote_state + 16, 18);
46
47 auto transmit = this->transmitter_->transmit();
48 auto *data = transmit.get_data();
49 data->set_carrier_frequency(DAIKIN_IR_FREQUENCY);
50
51 data->mark(DAIKIN_HEADER_MARK);
52 data->space(DAIKIN_HEADER_SPACE);
53 data->item_bytes<DAIKIN_BIT_TIMINGS>(remote_state, DAIKIN_COMFORT_FRAME_SIZE);
54 data->mark(DAIKIN_BIT_MARK);
55 data->space(DAIKIN_MESSAGE_SPACE);
56 data->mark(DAIKIN_HEADER_MARK);
57 data->space(DAIKIN_HEADER_SPACE);
58
59 data->item_bytes<DAIKIN_BIT_TIMINGS>(remote_state + DAIKIN_COMFORT_FRAME_SIZE, DAIKIN_COMFORT_FRAME_SIZE);
60 data->mark(DAIKIN_BIT_MARK);
61 data->space(DAIKIN_MESSAGE_SPACE);
62 data->mark(DAIKIN_HEADER_MARK);
63 data->space(DAIKIN_HEADER_SPACE);
64
65 data->item_bytes<DAIKIN_BIT_TIMINGS>(remote_state + DAIKIN_STATE_FRAME_OFFSET, DAIKIN_STATE_FRAME_SIZE);
66 data->mark(DAIKIN_BIT_MARK);
67 data->space(0);
68
69 transmit.perform();
70}
71
73 uint8_t operating_mode = DAIKIN_MODE_ON;
74 switch (this->mode) {
76 operating_mode |= DAIKIN_MODE_COOL;
77 break;
79 operating_mode |= DAIKIN_MODE_DRY;
80 break;
82 operating_mode |= DAIKIN_MODE_HEAT;
83 break;
85 operating_mode |= DAIKIN_MODE_AUTO;
86 break;
88 operating_mode |= DAIKIN_MODE_FAN;
89 break;
91 default:
92 operating_mode = DAIKIN_MODE_OFF;
93 break;
94 }
95
96 return operating_mode;
97}
98
99uint16_t DaikinClimate::fan_speed_() const {
100 uint16_t fan_speed;
101 switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
103 fan_speed = DAIKIN_FAN_SILENT << 8;
104 break;
106 fan_speed = DAIKIN_FAN_1 << 8;
107 break;
109 fan_speed = DAIKIN_FAN_3 << 8;
110 break;
112 fan_speed = DAIKIN_FAN_5 << 8;
113 break;
115 default:
116 fan_speed = DAIKIN_FAN_AUTO << 8;
117 }
118
119 // If swing is enabled switch first 4 bits to 1111
120 switch (this->swing_mode) {
122 fan_speed |= 0x0F00;
123 break;
125 fan_speed |= 0x000F;
126 break;
128 fan_speed |= 0x0F0F;
129 break;
130 default:
131 break;
132 }
133 return fan_speed;
134}
135
137 // Force special temperatures depending on the mode
138 switch (this->mode) {
140 return 0x32;
142 return 0xc0;
143 default:
144 return static_cast<uint8_t>(
145 roundf(clamp<float>(this->target_temperature, DAIKIN_TEMP_MIN, DAIKIN_TEMP_MAX) * 2.0f));
146 }
147}
148
149void DaikinClimate::set_presets_(uint8_t *remote_state) const {
150 switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) {
152 remote_state[29] = DAIKIN_PRESET_POWERFUL_ON;
153 break;
155 remote_state[29] = DAIKIN_PRESET_QUIET_ON;
156 break;
158 remote_state[32] = DAIKIN_PRESET_ECONO_ON;
159 break;
161 remote_state[32] = DAIKIN_PRESET_SENSOR_ON;
162 break;
164 remote_state[6] = DAIKIN_PRESET_COMFORT_ON; // the only preset carried by the first frame
165 break;
166 default:
167 break;
168 }
169}
170
172 const bool is_boost = this->preset == climate::CLIMATE_PRESET_BOOST;
173 if (is_boost && !was_boost) {
174 this->set_timeout(BOOST_TIMEOUT_ID, DAIKIN_BOOST_DURATION_MS, [this]() { this->cancel_boost_mode_(); });
175 } else if (was_boost && !is_boost) {
176 this->cancel_timeout(BOOST_TIMEOUT_ID);
177 }
178}
179
182 return;
183 ESP_LOGD(TAG, "Boost ended");
185 this->publish_state();
186}
187
188bool DaikinClimate::parse_state_frame_(const uint8_t frame[]) {
189 const bool was_boost = this->preset == climate::CLIMATE_PRESET_BOOST;
190 uint8_t mode = frame[5];
191 // Temperature is given in degrees celcius * 2
192 // only update for states that use the temperature
193 uint8_t temperature = frame[6];
194 if (mode & DAIKIN_MODE_ON) {
195 switch (mode & 0xF0) {
196 case DAIKIN_MODE_COOL:
197 this->mode = climate::CLIMATE_MODE_COOL;
198 this->target_temperature = static_cast<float>(temperature * 0.5f);
199 break;
200 case DAIKIN_MODE_DRY:
201 this->mode = climate::CLIMATE_MODE_DRY;
202 break;
203 case DAIKIN_MODE_HEAT:
204 this->mode = climate::CLIMATE_MODE_HEAT;
205 this->target_temperature = static_cast<float>(temperature * 0.5f);
206 break;
207 case DAIKIN_MODE_AUTO:
209 this->target_temperature = static_cast<float>(temperature * 0.5f);
210 break;
211 case DAIKIN_MODE_FAN:
213 break;
214 }
215 } else {
216 this->mode = climate::CLIMATE_MODE_OFF;
217 }
218 uint8_t fan_mode = frame[8];
219 uint8_t swing_mode = frame[9];
220 if (fan_mode & 0xF && swing_mode & 0xF) {
221 this->swing_mode = climate::CLIMATE_SWING_BOTH;
222 } else if (fan_mode & 0xF) {
223 this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
224 } else if (swing_mode & 0xF) {
225 this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
226 } else {
227 this->swing_mode = climate::CLIMATE_SWING_OFF;
228 }
229 switch (fan_mode & 0xF0) {
230 case DAIKIN_FAN_1:
231 case DAIKIN_FAN_2:
232 this->fan_mode = climate::CLIMATE_FAN_LOW;
233 break;
234 case DAIKIN_FAN_3:
235 this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
236 break;
237 case DAIKIN_FAN_4:
238 case DAIKIN_FAN_5:
239 this->fan_mode = climate::CLIMATE_FAN_HIGH;
240 break;
241 case DAIKIN_FAN_AUTO:
242 this->fan_mode = climate::CLIMATE_FAN_AUTO;
243 break;
245 this->fan_mode = climate::CLIMATE_FAN_QUIET;
246 break;
247 }
248
249 // Comfort lives in the first frame, recorded as pending until this frame proves the transmission valid
250 // A comfort frame whose own state frame never came must not attach to a later transmission
252 const PendingComfort comfort = now - this->pending_comfort_at_ <= DAIKIN_TRANSMISSION_MS
253 ? this->pending_comfort_
256 if (frame[13] & DAIKIN_PRESET_POWERFUL_ON) {
258 } else if (frame[13] & DAIKIN_PRESET_QUIET_ON) {
260 } else if (frame[16] & DAIKIN_PRESET_ECONO_ON) {
262 } else if (frame[16] & DAIKIN_PRESET_SENSOR_ON) {
264 } else if (comfort == PendingComfort::PENDING_COMFORT_ON) {
267 // Without a comfort frame in this transmission a current comfort preset is left alone
269 }
270 this->update_boost_timer_(was_boost);
271
272 this->publish_state();
273 return true;
274}
275
277 uint8_t frame[DAIKIN_STATE_FRAME_SIZE];
278 if (!data.expect_item(DAIKIN_HEADER_MARK, DAIKIN_HEADER_SPACE)) {
279 return false;
280 }
281
282 // Frame header, then the frame type that sets the frame size
283 if (!data.expect_bytes<DAIKIN_BIT_TIMINGS>(frame, DAIKIN_FRAME_HEADER_SIZE) || frame[0] != DAIKIN_HEADER_BYTE0 ||
284 frame[1] != DAIKIN_HEADER_BYTE1 || frame[2] != DAIKIN_HEADER_BYTE2 || frame[3] != DAIKIN_HEADER_BYTE3) {
285 return false;
286 }
287 uint8_t frame_size = DAIKIN_STATE_FRAME_SIZE;
288 if (frame[DAIKIN_FRAME_TYPE_INDEX] == DAIKIN_FRAME_TYPE_COMFORT) {
289 frame_size = DAIKIN_COMFORT_FRAME_SIZE;
290 } else if (frame[DAIKIN_FRAME_TYPE_INDEX] != DAIKIN_FRAME_TYPE_STATE) {
291 return false;
292 }
293 if (!data.expect_bytes<DAIKIN_BIT_TIMINGS>(frame + DAIKIN_FRAME_HEADER_SIZE, frame_size - DAIKIN_FRAME_HEADER_SIZE)) {
294 return false;
295 }
296 if (frame[frame_size - 1] != sum_bytes(frame, frame_size - 1)) {
297 return false;
298 }
299
300 if (frame_size == DAIKIN_COMFORT_FRAME_SIZE) {
301 // Nothing changes yet: the state frame that follows applies it once it has passed its own checksum
305 return true;
306 }
307 return this->parse_state_frame_(frame);
308}
309
310} // namespace esphome::daikin
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
bool cancel_timeout(const char *name)
Cancel a timeout function.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
Definition component.cpp:96
This class is used to encode all control actions on a climate device.
Definition climate.h:31
ClimateMode mode
The active mode of the climate device.
Definition climate.h:317
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
Definition climate.h:311
float target_temperature
The target temperature of the climate device.
Definition climate.h:298
ClimateSwingMode swing_mode
The active swing mode of the climate device.
Definition climate.h:323
void publish_state()
Publish the state of the climate device, to be called from integrations.
Definition climate.cpp:432
optional< ClimatePreset > preset
The active preset of the climate device.
Definition climate.h:314
void control(const climate::ClimateCall &call) override
Override control to change settings of the climate device.
bool parse_state_frame_(const uint8_t frame[])
Definition daikin.cpp:188
uint8_t temperature_() const
Definition daikin.cpp:136
PendingComfort
What the 0xC5 frame of the current transmission said about comfort, applied by the state frame.
Definition daikin.h:87
void control(const climate::ClimateCall &call) override
Definition daikin.cpp:26
uint8_t operation_mode_() const
Definition daikin.cpp:72
uint16_t fan_speed_() const
Definition daikin.cpp:99
PendingComfort pending_comfort_
Definition daikin.h:88
void transmit_state() override
Definition daikin.cpp:32
bool on_receive(remote_base::RemoteReceiveData data) override
Definition daikin.cpp:276
void set_presets_(uint8_t *remote_state) const
Definition daikin.cpp:149
void update_boost_timer_(bool was_boost)
Arms or cancels the boost timer when the preset moves into or out of boost.
Definition daikin.cpp:171
@ CLIMATE_PRESET_NONE
No preset is active.
@ CLIMATE_PRESET_COMFORT
Device is in comfort preset.
@ CLIMATE_PRESET_BOOST
Device is in boost preset.
@ CLIMATE_PRESET_ACTIVITY
Device is reacting to activity (e.g., movement sensors)
@ CLIMATE_PRESET_SLEEP
Device is prepared for sleep.
@ CLIMATE_PRESET_ECO
Device is running an energy-saving preset.
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_HORIZONTAL
The fan mode is set to Horizontal.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
@ CLIMATE_SWING_BOTH
The fan mode is set to Both.
@ 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_QUIET
The fan mode is set to Quiet.
@ CLIMATE_FAN_HIGH
The fan mode is set to High.
const uint8_t DAIKIN_MODE_AUTO
Definition daikin.h:13
const uint8_t DAIKIN_COMFORT_FRAME_SIZE
Definition daikin.h:56
const uint8_t DAIKIN_MODE_OFF
Definition daikin.h:18
const uint8_t DAIKIN_PRESET_POWERFUL_ON
Definition daikin.h:32
const uint8_t DAIKIN_STATE_FRAME_SIZE
Definition daikin.h:55
const uint32_t DAIKIN_BIT_MARK
Definition daikin.h:45
const uint8_t DAIKIN_TEMP_MIN
Definition daikin.h:9
ESPHOME_LOG_TAG(TAG, "daikin.climate")
const uint8_t DAIKIN_FRAME_TYPE_COMFORT
Definition daikin.h:54
const uint8_t DAIKIN_PRESET_QUIET_ON
Definition daikin.h:33
const uint32_t DAIKIN_IR_FREQUENCY
Definition daikin.h:42
const uint8_t DAIKIN_FAN_4
Definition daikin.h:27
const uint8_t DAIKIN_FRAME_TYPE_STATE
Definition daikin.h:53
const uint32_t DAIKIN_HEADER_MARK
Definition daikin.h:43
const uint8_t DAIKIN_PRESET_SENSOR_ON
Definition daikin.h:35
const uint8_t DAIKIN_MODE_COOL
Definition daikin.h:14
const uint8_t DAIKIN_FAN_5
Definition daikin.h:28
const uint32_t DAIKIN_BOOST_DURATION_MS
Definition daikin.h:37
const uint8_t DAIKIN_PRESET_COMFORT_ON
Definition daikin.h:31
const uint32_t DAIKIN_MESSAGE_SPACE
Definition daikin.h:50
const uint32_t DAIKIN_HEADER_SPACE
Definition daikin.h:44
const uint8_t DAIKIN_FAN_SILENT
Definition daikin.h:23
const uint8_t DAIKIN_MODE_DRY
Definition daikin.h:16
const uint8_t DAIKIN_FAN_2
Definition daikin.h:25
const uint8_t DAIKIN_MODE_ON
Definition daikin.h:19
const uint32_t DAIKIN_TRANSMISSION_MS
Definition daikin.h:39
const uint8_t DAIKIN_FAN_1
Definition daikin.h:24
const uint8_t DAIKIN_FAN_AUTO
Definition daikin.h:22
const uint8_t DAIKIN_FAN_3
Definition daikin.h:26
const uint8_t DAIKIN_TEMP_MAX
Definition daikin.h:10
const uint8_t DAIKIN_PRESET_ECONO_ON
Definition daikin.h:34
const uint8_t DAIKIN_MODE_HEAT
Definition daikin.h:15
const uint8_t DAIKIN_MODE_FAN
Definition daikin.h:17
constexpr uint8_t sum_bytes(const uint8_t *data, size_t len, uint8_t sum=0)
Add up the bytes of data with size len, truncated to 8 bits: the checksum many serial and IR protocol...
Definition helpers.h:911
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12