ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ld2410s.cpp
Go to the documentation of this file.
1#include "ld2410s.h"
2#include "ld2410s_number.h"
3#include <algorithm>
4#include <cstring>
6#include "esphome/core/hal.h"
8#include "esphome/core/log.h"
9
11
12ESPHOME_LOG_TAG(TAG, "ld2410s");
13
14static constexpr uint8_t SHORT_DATA_FRAME_HEADER = 0x6E;
15static constexpr uint8_t SHORT_DATA_FRAME_FOOTER[] PROGMEM = {0x62};
16static constexpr uint8_t SHORT_DATA_FRAME_SIZE = 5; // header, state, distance low, distance high, footer
17static constexpr uint8_t STD_DATA_FRAME_HEADER[] PROGMEM = {0xF4, 0xF3, 0xF2, 0xF1};
18static constexpr uint8_t STD_DATA_FRAME_FOOTER[] PROGMEM = {0xF8, 0xF7, 0xF6, 0xF5};
19static constexpr uint8_t CMD_FRAME_HEADER[] PROGMEM = {0xFD, 0xFC, 0xFB, 0xFA};
20static constexpr uint8_t CMD_FRAME_FOOTER[] PROGMEM = {0x04, 0x03, 0x02, 0x01};
21static constexpr uint8_t LONG_HEADER_SIZE = 4;
22static constexpr uint8_t LENGTH_FIELD_SIZE = 2;
23static constexpr uint8_t LONG_PAYLOAD_POS = LONG_HEADER_SIZE + LENGTH_FIELD_SIZE;
24
25static constexpr uint16_t CMD_CONFIRMATION = 0x0100; // set in the command word of an acknowledgement
26static constexpr uint16_t CONFIG_MODE_START_CMD = 0x00FF;
27static constexpr uint16_t CONFIG_MODE_START_VALUE = 0x0001;
28static constexpr uint16_t CONFIG_MODE_END_CMD = 0x00FE;
29static constexpr uint16_t VERSION_READ_CMD = 0x0000;
30static constexpr uint16_t PARAMETERS_WRITE_CMD = 0x0070;
31static constexpr uint16_t PARAMETERS_READ_CMD = 0x0071;
32static constexpr uint16_t OUTPUT_MODE_SWITCH_CMD = 0x007A;
33// Minimal output mode (short frames carrying presence and distance only) is selected by six zero bytes
34static constexpr uint8_t OUTPUT_MODE_MINIMAL_SIZE = 6;
35// The parameter write carries a 16-bit key and a 32-bit value per parameter, the read only the keys
36static constexpr uint8_t PARAMETER_KEY_SIZE = 2;
37static constexpr uint8_t PARAMETER_VALUE_SIZE = 4;
38static constexpr uint8_t PARAMETERS_WRITE_SIZE = PARAMETER_COUNT * (PARAMETER_KEY_SIZE + PARAMETER_VALUE_SIZE);
39static constexpr uint8_t CMD_FRAME_MAX_SIZE = LONG_PAYLOAD_POS + 2 + PARAMETERS_WRITE_SIZE + sizeof(CMD_FRAME_FOOTER);
40// Keys of the parameters, in Parameter order
41#ifdef USE_LD2410S_PARAMETERS
42static constexpr uint16_t PARAMETER_KEYS[] PROGMEM = {0x0005, 0x000A, 0x0006, 0x0002, 0x000C, 0x000B};
43static_assert(sizeof(PARAMETER_KEYS) / sizeof(PARAMETER_KEYS[0]) == PARAMETER_COUNT, "one key per parameter");
44#endif
45// The version answer: 4 bytes device type, then major, minor and patch as 16-bit words
46static constexpr uint8_t VERSION_TYPE_SIZE = 4;
47static constexpr uint8_t VERSION_SIZE = VERSION_TYPE_SIZE + 3 * 2;
48
49// Everything the module needs at start: configuration mode on, read the version and parameters when
50// an entity shows them, pick the output mode, configuration mode off
51static constexpr uint16_t INIT_SEQUENCE[] PROGMEM = {
52 CONFIG_MODE_START_CMD,
53#ifdef USE_LD2410S_VERSION
54 VERSION_READ_CMD,
55#endif
56#ifdef USE_LD2410S_PARAMETERS
57 PARAMETERS_READ_CMD,
58#endif
59 OUTPUT_MODE_SWITCH_CMD, CONFIG_MODE_END_CMD,
60};
61#ifdef USE_LD2410S_PARAMETERS
62static constexpr uint16_t WRITE_SEQUENCE[] PROGMEM = {CONFIG_MODE_START_CMD, PARAMETERS_WRITE_CMD, CONFIG_MODE_END_CMD};
63#endif
64static constexpr uint8_t INIT_SEQUENCE_LENGTH = sizeof(INIT_SEQUENCE) / sizeof(INIT_SEQUENCE[0]);
65#ifdef USE_LD2410S_PARAMETERS
66static constexpr uint8_t WRITE_SEQUENCE_LENGTH = sizeof(WRITE_SEQUENCE) / sizeof(WRITE_SEQUENCE[0]);
67#endif
68static constexpr uint8_t STEP_MAX_TIMEOUTS = 2;
69static constexpr uint32_t ACK_TIMEOUT_MS = 300;
70static constexpr uint32_t COMMAND_GAP_MS = 300; // pause after an acknowledgement before the next command
71static constexpr uint32_t REINIT_PAUSE_MS = 15000; // pause before starting over after the module stopped answering
72static constexpr uint32_t LINK_TIMEOUT_MS = 5000; // the module streams frames continuously; silence means it is gone
73
74static constexpr uint8_t DATA_TYPE_STANDARD = 0x01;
75
76void LD2410SComponent::dump_config() {
77 ESP_LOGCONFIG(TAG, "LD2410S:");
78#ifdef USE_BINARY_SENSOR
79 LOG_BINARY_SENSOR(" ", "Has Target", this->target_binary_sensor_);
80#endif
81#ifdef USE_SENSOR
82 LOG_SENSOR_WITH_DEDUP_SAFE(" ", "Distance", this->distance_sensor_);
83#endif
84#ifdef USE_LD2410S_VERSION
85 LOG_TEXT_SENSOR(" ", "Version", this->version_text_sensor_);
86#endif
87#if defined(USE_NUMBER) && defined(USE_LD2410S_PARAMETERS)
88 for (auto *number : this->numbers_) {
89 LOG_NUMBER(" ", "Setting", number);
90 }
91#endif
92#if defined(USE_SELECT) && defined(USE_LD2410S_PARAMETERS)
93 LOG_SELECT(" ", "Response Speed", this->response_speed_select_);
94#endif
95}
96
98 uint8_t chunk[16];
99 // Take the count once so one pass handles a bounded number of bytes
100 size_t avail = this->available();
101 while (avail > 0) {
102 const size_t len = std::min(avail, sizeof(chunk));
103 if (!this->read_array(chunk, len)) {
104 ESP_LOGV(TAG, "UART read of %u bytes failed", static_cast<unsigned>(len));
105 break;
106 }
107 for (size_t i = 0; i < len; i++) {
108 this->receive_byte_(chunk[i]);
109 }
110 avail -= len;
111 }
113 if (this->sequence_ == nullptr) {
114 if (!this->init_done_) {
115 this->start_sequence_(INIT_SEQUENCE, INIT_SEQUENCE_LENGTH, now);
116#ifdef USE_LD2410S_PARAMETERS
117 } else if (this->parameters_dirty_) {
118 this->parameters_dirty_ = false;
119 this->start_sequence_(WRITE_SEQUENCE, WRITE_SEQUENCE_LENGTH, this->next_send_at_);
120#endif
121 }
122 }
123 this->run_sequence_(now);
124 if (this->init_done_ && now - this->last_frame_at_ > LINK_TIMEOUT_MS) {
125 // The count tells real silence apart from frames that never parse (wrong baud rate or firmware)
126 ESP_LOGW(TAG, "No data for %" PRIu32 " s (%u frames dropped), starting over", LINK_TIMEOUT_MS / 1000,
127 this->dropped_frames_);
128 this->dropped_frames_ = 0;
129 this->restart_init_(now);
130 }
131}
132
133#ifdef USE_LD2410S_PARAMETERS
134bool LD2410SComponent::set_parameter(Parameter parameter, uint8_t value) {
135 // All six are written together, so the other five must be the module's own values
136 if (!this->init_done_) {
137 ESP_LOGW(TAG, "Parameters not read yet, change ignored");
138 return false;
139 }
140 if (!this->parameters_known_) {
141 ESP_LOGW(TAG, "The module reported a parameter out of range, changes are disabled");
142 return false;
143 }
144 this->parameters_[static_cast<uint8_t>(parameter)] = value;
145 this->parameters_dirty_ = true; // written by loop() once no sequence is running
146 return true;
147}
148#endif
149
151 this->init_done_ = false;
152 this->status_set_warning(); // cleared again when the new init sequence is acknowledged
153#ifdef USE_LD2410S_PARAMETERS
154 // The module's own values count again once it is set up anew
155 if (this->parameters_dirty_) {
156 ESP_LOGW(TAG, "Dropping the pending parameter change, the module's values are read back");
157 }
158 this->parameters_dirty_ = false;
159 this->parameters_known_ = false; // a refused value may sit in parameters_ until the read replaces it
160#endif
161 this->start_sequence_(INIT_SEQUENCE, INIT_SEQUENCE_LENGTH, at);
162}
163
164void LD2410SComponent::start_sequence_(const uint16_t *sequence, uint8_t length, uint32_t now) {
165 this->sequence_ = sequence;
166 this->sequence_len_ = length;
167 this->step_ = 0;
168 this->step_timeouts_ = 0;
169 this->awaiting_ack_ = false;
170 this->next_send_at_ = now;
171}
172
174
176 if (this->sequence_ == nullptr || static_cast<int32_t>(now - this->next_send_at_) < 0) {
177 return;
178 }
179 const uint16_t command = this->current_command_();
180 if (this->awaiting_ack_) {
181 if (++this->step_timeouts_ > STEP_MAX_TIMEOUTS) {
182 ESP_LOGW(TAG, "No acknowledgement for command %04X, starting over in %" PRIu32 " s", command,
183 REINIT_PAUSE_MS / 1000);
184 // Leave configuration mode whatever state the module is in, then begin again
185 this->send_command_(CONFIG_MODE_END_CMD);
186 this->restart_init_(now + REINIT_PAUSE_MS);
187 return;
188 }
189 ESP_LOGD(TAG, "No acknowledgement for command %04X, resending", command);
190 }
191 this->send_command_(command);
192 this->awaiting_ack_ = true;
193 this->next_send_at_ = now + ACK_TIMEOUT_MS;
194}
195
196void LD2410SComponent::send_command_(uint16_t command) {
197 uint8_t frame[CMD_FRAME_MAX_SIZE];
198 progmem_memcpy(frame, CMD_FRAME_HEADER, LONG_HEADER_SIZE);
199 uint8_t pos = LONG_PAYLOAD_POS;
200 frame[pos++] = command & 0xFF;
201 frame[pos++] = command >> 8;
202 switch (command) {
203 case OUTPUT_MODE_SWITCH_CMD:
204 memset(&frame[pos], 0, OUTPUT_MODE_MINIMAL_SIZE);
205 pos += OUTPUT_MODE_MINIMAL_SIZE;
206 break;
207 case CONFIG_MODE_START_CMD:
208 frame[pos++] = CONFIG_MODE_START_VALUE & 0xFF;
209 frame[pos++] = CONFIG_MODE_START_VALUE >> 8;
210 break;
211#ifdef USE_LD2410S_PARAMETERS
212 case PARAMETERS_READ_CMD:
213 case PARAMETERS_WRITE_CMD:
214 for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
215 const uint16_t key = progmem_read_uint16(&PARAMETER_KEYS[i]);
216 frame[pos++] = key & 0xFF;
217 frame[pos++] = key >> 8;
218 if (command == PARAMETERS_WRITE_CMD) {
219 const uint32_t value = this->parameters_[i]; // a 32-bit field on the wire
220 for (uint8_t shift = 0; shift < 32; shift += 8) {
221 frame[pos++] = (value >> shift) & 0xFF;
222 }
223 }
224 }
225 break;
226#endif
227 default:
228 break;
229 }
230 frame[LONG_HEADER_SIZE] = pos - LONG_PAYLOAD_POS; // payload length, little-endian
231 frame[LONG_HEADER_SIZE + 1] = 0;
232 progmem_memcpy(&frame[pos], CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER));
233 pos += sizeof(CMD_FRAME_FOOTER);
234 this->write_array(frame, pos);
235#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
236 char hex_buf[format_hex_pretty_size(CMD_FRAME_MAX_SIZE)];
237 ESP_LOGVV(TAG, "> %s", format_hex_pretty_to(hex_buf, frame, pos, ' '));
238#endif
239}
240
242 if (this->rx_len_ >= RX_BUFFER_SIZE) {
243 this->reset_frame_();
244 }
245 this->rx_buffer_[this->rx_len_++] = byte;
246
247 if (this->frame_type_ == FrameType::NONE) {
248 if (this->rx_len_ == 1 && byte == SHORT_DATA_FRAME_HEADER) {
250 this->expected_len_ = SHORT_DATA_FRAME_SIZE;
251 return;
252 }
253 // The two long headers are told apart once all four bytes are in
254 uint8_t std_header[LONG_HEADER_SIZE];
255 uint8_t cmd_header[LONG_HEADER_SIZE];
256 progmem_memcpy(std_header, STD_DATA_FRAME_HEADER, LONG_HEADER_SIZE);
257 progmem_memcpy(cmd_header, CMD_FRAME_HEADER, LONG_HEADER_SIZE);
258 const bool std_prefix = memcmp(this->rx_buffer_, std_header, this->rx_len_) == 0;
259 const bool cmd_prefix = memcmp(this->rx_buffer_, cmd_header, this->rx_len_) == 0;
260 if (std_prefix || cmd_prefix) {
261 if (this->rx_len_ == LONG_HEADER_SIZE) {
263 }
264 return;
265 }
266 // Not a header: drop what was collected, and try this byte as the start of the next frame
267 const bool retry = this->rx_len_ > 1;
268 this->reset_frame_();
269 if (retry) {
270 this->receive_byte_(byte);
271 }
272 return;
273 }
274
275 if (this->expected_len_ == 0) {
276 if (this->rx_len_ < LONG_PAYLOAD_POS) {
277 return;
278 }
279 // Standard data and command frames carry a little-endian payload length after the header
280 const uint16_t payload_len =
281 encode_uint16(this->rx_buffer_[LONG_HEADER_SIZE + 1], this->rx_buffer_[LONG_HEADER_SIZE]);
282 if (payload_len > RX_BUFFER_SIZE - LONG_PAYLOAD_POS - sizeof(CMD_FRAME_FOOTER)) {
283 ESP_LOGV(TAG, "Dropping frame with a %u byte payload, larger than the receive buffer", payload_len);
284 this->count_dropped_frame_();
285 this->reset_frame_();
286 return;
287 }
288 this->expected_len_ = LONG_PAYLOAD_POS + payload_len + sizeof(CMD_FRAME_FOOTER);
289 return;
290 }
291
293 return;
294 }
295 if (this->handle_frame_() || this->rescanning_) {
296 this->reset_frame_();
297 return;
298 }
299 // A truncated long frame swallowed the bytes that followed it; try them again as new frames, once
300 uint8_t rest[RX_BUFFER_SIZE];
301 const uint8_t rest_len = this->rx_len_ - 1;
302 memcpy(rest, &this->rx_buffer_[1], rest_len);
303 this->reset_frame_();
304 this->rescanning_ = true;
305 for (uint8_t i = 0; i < rest_len; i++) {
306 this->receive_byte_(rest[i]);
307 }
308 this->rescanning_ = false;
309}
310
312 const uint8_t *footer_src;
313 uint8_t footer_size = sizeof(CMD_FRAME_FOOTER);
314 uint8_t payload_pos = LONG_PAYLOAD_POS;
315 switch (this->frame_type_) {
317 footer_src = SHORT_DATA_FRAME_FOOTER;
318 footer_size = sizeof(SHORT_DATA_FRAME_FOOTER);
319 payload_pos = 1;
320 break;
322 footer_src = STD_DATA_FRAME_FOOTER;
323 break;
324 default:
325 footer_src = CMD_FRAME_FOOTER;
326 break;
327 }
328 uint8_t footer[sizeof(CMD_FRAME_FOOTER)];
329 progmem_memcpy(footer, footer_src, footer_size);
330 if (memcmp(&this->rx_buffer_[this->rx_len_ - footer_size], footer, footer_size) != 0) {
331#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
332 char hex_buf[format_hex_pretty_size(RX_BUFFER_SIZE)];
333 ESP_LOGV(TAG, "Footer does not match header: %s",
334 format_hex_pretty_to(hex_buf, this->rx_buffer_, this->rx_len_, ' '));
335#endif
336 this->count_dropped_frame_();
337 return false;
338 }
339 const uint8_t *payload = &this->rx_buffer_[payload_pos];
340 const uint16_t payload_len = this->rx_len_ - payload_pos - footer_size;
341 switch (this->frame_type_) {
344 if (!this->handle_data_frame_(payload, payload_len)) {
345 this->count_dropped_frame_();
346 break;
347 }
349 this->dropped_frames_ = 0;
350 break;
351 default:
352 this->handle_command_ack_(payload, payload_len);
353 break;
354 }
355 return true;
356}
357
358bool LD2410SComponent::handle_data_frame_(const uint8_t *payload, uint16_t len) {
359 // Short frames carry [state][distance low][distance high]; standard frames put a type byte first, and the
360 // module only sends them before the init sequence switches it to minimal output
361 const uint8_t *data = payload;
362 if (this->frame_type_ == FrameType::STD_DATA) {
363 if (len < 4 || payload[0] != DATA_TYPE_STANDARD) {
364 if (len >= 1) {
365 ESP_LOGV(TAG, "Ignoring data frame type %02X", payload[0]);
366 }
367 return true;
368 }
369 data = payload + 1;
370 }
371 const uint8_t state = data[0];
372 const uint16_t distance = encode_uint16(data[2], data[1]);
373 // States 0 and 1 mean no target, 2 and 3 a target; anything else is line noise that happened to
374 // carry the header and footer bytes
375 if (state > 3) {
376 ESP_LOGV(TAG, "Dropping frame with impossible state %u", state);
377 return false;
378 }
379 this->publish_target_(state > 1, distance);
380 return true;
381}
382
383void LD2410SComponent::handle_command_ack_(const uint8_t *payload, uint16_t len) {
384 if (len < 4) {
385 ESP_LOGV(TAG, "Acknowledgement too short (%u bytes)", len);
386 return;
387 }
388 const uint16_t command_word = encode_uint16(payload[1], payload[0]);
389 const uint16_t ack = encode_uint16(payload[3], payload[2]);
390 if (!this->awaiting_ack_) {
391 ESP_LOGV(TAG, "Unexpected acknowledgement %04X", command_word);
392 return;
393 }
394 const uint16_t command = this->current_command_();
395 if (command_word != (command | CMD_CONFIRMATION)) {
396 ESP_LOGV(TAG, "Unexpected acknowledgement %04X", command_word);
397 return;
398 }
399#ifdef USE_LD2410S_PARAMETERS
400 if (ack != 0 && command == PARAMETERS_WRITE_CMD) {
401 // Resending the same values would be rejected again; leave configuration mode and read the
402 // module's own values back, which republishes them
403 ESP_LOGW(TAG, "Module rejected the parameters, ack %04X", ack);
404 this->send_command_(CONFIG_MODE_END_CMD);
405 this->restart_init_(App.get_loop_component_start_time() + COMMAND_GAP_MS);
406 return;
407 }
408#endif
409 if (ack != 0) {
410 // Leave the command pending so the timeout resends it
411 ESP_LOGW(TAG, "Module rejected command %04X, ack %04X", command, ack);
412 return;
413 }
414 // A short answer leaves the read pending the same way, so init cannot finish without the values
415#ifdef USE_LD2410S_PARAMETERS
416 if (command == PARAMETERS_READ_CMD && !this->handle_parameters_(&payload[4], len - 4))
417 return;
418#endif
419#ifdef USE_LD2410S_VERSION
420 if (command == VERSION_READ_CMD && !this->handle_version_(&payload[4], len - 4))
421 return;
422#endif
423 this->awaiting_ack_ = false;
424 this->step_timeouts_ = 0;
426 this->next_send_at_ = now + COMMAND_GAP_MS;
427 if (++this->step_ < this->sequence_len_) {
428 return;
429 }
430 const bool was_init = this->sequence_ == INIT_SEQUENCE;
431 this->sequence_ = nullptr;
432 if (was_init) {
433 ESP_LOGD(TAG, "Setup done");
434 this->init_done_ = true;
435 this->last_frame_at_ = now;
436 this->status_clear_warning();
437 }
438}
439
440#ifdef USE_LD2410S_PARAMETERS
441// The answer lists the parameter values in key order, 32 bits each; returns false when it is cut short
442bool LD2410SComponent::handle_parameters_(const uint8_t *values, uint16_t len) {
443 if (len < PARAMETER_COUNT * PARAMETER_VALUE_SIZE) {
444 ESP_LOGW(TAG, "Parameter answer too short (%u bytes)", len);
445 return false;
446 }
447 // Every parameter must fit the low byte of its little-endian value; otherwise nothing is stored or
448 // published and writes stay refused, so a cut-down value is never shown or sent back
449 for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
450 const uint8_t *v = &values[i * PARAMETER_VALUE_SIZE];
451 if ((v[1] | v[2] | v[3]) != 0) {
452 ESP_LOGW(TAG, "Parameter %u out of range: %" PRIu32 ", changes stay disabled", i,
453 encode_uint32(v[3], v[2], v[1], v[0]));
454 this->parameters_known_ = false;
455#ifdef USE_NUMBER
456 // A value a number showed before the module answered is not confirmed
457 for (auto *number : this->numbers_) {
458 if (number != nullptr) {
459 number->publish_state(NAN);
460 }
461 }
462#endif
463 return true;
464 }
465 }
466 for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
467 this->parameters_[i] = values[i * PARAMETER_VALUE_SIZE];
468 }
469 this->parameters_known_ = true;
470 this->publish_parameters_();
471 ESP_LOGD(TAG, "Parameters: gates %u to %u, no delay %u s, frequencies %u/%u dHz, response speed %u",
472 this->parameters_[1], this->parameters_[0], this->parameters_[2], this->parameters_[3], this->parameters_[4],
473 this->parameters_[5]);
474 return true;
475}
476#endif
477
478#ifdef USE_LD2410S_VERSION
479// Returns false when the answer is cut short
480bool LD2410SComponent::handle_version_(const uint8_t *values, uint16_t len) {
481 if (len < VERSION_SIZE) {
482 ESP_LOGW(TAG, "Version answer too short (%u bytes)", len);
483 return false;
484 }
485 const uint8_t *v = &values[VERSION_TYPE_SIZE];
486 char version[18];
487 snprintf(version, sizeof(version), "%u.%u.%u", encode_uint16(v[1], v[0]), encode_uint16(v[3], v[2]),
488 encode_uint16(v[5], v[4]));
489 ESP_LOGD(TAG, "Firmware %s", version);
490 if (this->version_text_sensor_ != nullptr) {
491 this->version_text_sensor_->publish_state(version);
492 }
493 return true;
494}
495#endif
496
497void LD2410SComponent::publish_target_(bool target, uint16_t distance) {
498#ifdef USE_BINARY_SENSOR
499 if (this->target_binary_sensor_ != nullptr) {
500 this->target_binary_sensor_->publish_state(target);
501 }
502#endif
503#ifdef USE_SENSOR
504 // The module keeps reporting the last distance after the target left
505 SAFE_PUBLISH_SENSOR(this->distance_sensor_, target ? distance : 0);
506#endif
507}
508
509#ifdef USE_LD2410S_PARAMETERS
511#ifdef USE_NUMBER
512 for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
513 if (this->numbers_[i] != nullptr) {
514 this->numbers_[i]->publish_raw(this->parameters_[i]);
515 }
516 }
517#endif
518#ifdef USE_SELECT
519 if (this->response_speed_select_ != nullptr) {
520 const uint8_t speed = this->parameters_[static_cast<uint8_t>(Parameter::PARAMETER_RESPONSE_SPEED)];
521 for (uint8_t i = 0; i < RESPONSE_SPEED_COUNT; i++) {
522 if (progmem_read_byte(&RESPONSE_SPEEDS[i]) == speed) {
523 this->response_speed_select_->publish_state(i);
524 return;
525 }
526 }
527 ESP_LOGV(TAG, "Unknown response speed %u", speed);
528 }
529#endif
530}
531#endif
532
533} // namespace esphome::ld2410s
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.
virtual void loop()
This method will be called repeatedly.
Definition component.cpp:86
void status_clear_warning()
Definition component.h:291
void handle_command_ack_(const uint8_t *payload, uint16_t len)
Definition ld2410s.cpp:383
bool handle_version_(const uint8_t *values, uint16_t len)
Definition ld2410s.cpp:480
bool handle_frame_()
Returns false when the footer does not match, so the bytes can be scanned again.
Definition ld2410s.cpp:311
void start_sequence_(const uint16_t *sequence, uint8_t length, uint32_t now)
Definition ld2410s.cpp:164
uint8_t parameters_[PARAMETER_COUNT]
Definition ld2410s.h:119
void publish_target_(bool target, uint16_t distance)
Definition ld2410s.cpp:497
void send_command_(uint16_t command)
Definition ld2410s.cpp:196
LD2410SNumber * numbers_[PARAMETER_COUNT]
Definition ld2410s.h:112
uint8_t rx_buffer_[RX_BUFFER_SIZE]
Definition ld2410s.h:121
bool handle_parameters_(const uint8_t *values, uint16_t len)
Definition ld2410s.cpp:442
bool handle_data_frame_(const uint8_t *payload, uint16_t len)
Returns false for a data frame whose state byte is impossible, so it counts as dropped.
Definition ld2410s.cpp:358
void receive_byte_(uint8_t byte)
Definition ld2410s.cpp:241
void run_sequence_(uint32_t now)
Definition ld2410s.cpp:175
optional< std::array< uint8_t, N > > read_array()
Definition uart.h:40
void write_array(const uint8_t *data, size_t len)
Definition uart.h:27
int speed
Definition fan.h:3
bool state
Definition fan.h:2
constexpr float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM
Definition bme680.cpp:26
ESPHOME_LOG_TAG(TAG, "ld2410s")
Parameter
The module's common parameters, in the order the parameter read answers them.
Definition ld2410s.h:28
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
const void size_t len
Definition hal.h:68
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
Definition helpers.cpp:498
size_t size_t pos
Definition helpers.h:1179
uint16_t progmem_read_uint16(const uint16_t *addr)
Definition hal.h:53
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Definition helpers.h:1533
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition helpers.h:988
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:980
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t progmem_read_byte(const uint8_t *addr)
Definition hal.h:51
static void uint32_t
uint8_t ack
uint16_t length
Definition tt21100.cpp:0