esphome 2025.7.0b1__py3-none-any.whl → 2025.7.0b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. esphome/components/api/__init__.py +19 -5
  2. esphome/components/api/api_connection.cpp +53 -175
  3. esphome/components/api/api_connection.h +28 -25
  4. esphome/components/api/api_frame_helper.cpp +2 -3
  5. esphome/components/api/api_frame_helper.h +7 -9
  6. esphome/components/api/api_pb2.cpp +1862 -5133
  7. esphome/components/api/api_pb2.h +291 -533
  8. esphome/components/api/api_pb2_dump.cpp +99 -0
  9. esphome/components/api/api_pb2_service.cpp +4 -0
  10. esphome/components/api/api_pb2_service.h +6 -0
  11. esphome/components/api/api_server.cpp +2 -9
  12. esphome/components/api/api_server.h +7 -33
  13. esphome/components/api/custom_api_device.h +8 -0
  14. esphome/components/api/list_entities.cpp +2 -0
  15. esphome/components/api/list_entities.h +3 -1
  16. esphome/components/api/proto.h +506 -23
  17. esphome/components/api/user_services.h +2 -0
  18. esphome/components/debug/debug_esp32.cpp +2 -0
  19. esphome/components/esp32/__init__.py +1 -0
  20. esphome/components/esp32_camera/__init__.py +1 -1
  21. esphome/components/esp32_touch/esp32_touch_v1.cpp +12 -10
  22. esphome/components/esp8266/__init__.py +1 -0
  23. esphome/components/esp_ldo/__init__.py +10 -8
  24. esphome/components/esp_ldo/esp_ldo.h +3 -0
  25. esphome/components/gpio/binary_sensor/__init__.py +24 -3
  26. esphome/components/host/__init__.py +1 -0
  27. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  28. esphome/components/ld2410/ld2410.cpp +12 -28
  29. esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
  30. esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
  31. esphome/components/ld2420/ld2420.cpp +66 -57
  32. esphome/components/ld2420/ld2420.h +9 -11
  33. esphome/components/ld2420/number/gate_config_number.cpp +1 -1
  34. esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
  35. esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
  36. esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
  37. esphome/components/libretiny/__init__.py +1 -0
  38. esphome/components/lvgl/widgets/meter.py +20 -13
  39. esphome/components/mqtt/mqtt_backend_esp32.cpp +6 -2
  40. esphome/components/packet_transport/packet_transport.cpp +3 -0
  41. esphome/components/rp2040/__init__.py +1 -0
  42. esphome/components/substitutions/__init__.py +5 -2
  43. esphome/components/sx126x/__init__.py +3 -3
  44. esphome/components/sx127x/__init__.py +2 -2
  45. esphome/components/usb_host/usb_host_client.cpp +10 -10
  46. esphome/components/usb_uart/cp210x.cpp +1 -1
  47. esphome/components/usb_uart/usb_uart.cpp +41 -44
  48. esphome/components/usb_uart/usb_uart.h +4 -3
  49. esphome/const.py +1 -1
  50. esphome/core/component.cpp +8 -8
  51. esphome/core/component_iterator.cpp +4 -2
  52. esphome/core/component_iterator.h +3 -3
  53. esphome/core/defines.h +1 -1
  54. esphome/core/entity_helpers.py +6 -0
  55. esphome/core/helpers.h +1 -1
  56. esphome/core/scheduler.cpp +9 -12
  57. esphome/core/scheduler.h +0 -3
  58. esphome/wizard.py +1 -1
  59. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/METADATA +2 -2
  60. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/RECORD +64 -65
  61. esphome/components/api/api_pb2_size.h +0 -359
  62. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/WHEEL +0 -0
  63. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/entry_points.txt +0 -0
  64. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/licenses/LICENSE +0 -0
  65. {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b3.dist-info}/top_level.txt +0 -0
@@ -20,14 +20,16 @@ adjusted_ids = set()
20
20
 
21
21
  CONFIG_SCHEMA = cv.All(
22
22
  cv.ensure_list(
23
- {
24
- cv.GenerateID(): cv.declare_id(EspLdo),
25
- cv.Required(CONF_VOLTAGE): cv.All(
26
- cv.voltage, cv.float_range(min=0.5, max=2.7)
27
- ),
28
- cv.Required(CONF_CHANNEL): cv.one_of(*CHANNELS, int=True),
29
- cv.Optional(CONF_ADJUSTABLE, default=False): cv.boolean,
30
- }
23
+ cv.COMPONENT_SCHEMA.extend(
24
+ {
25
+ cv.GenerateID(): cv.declare_id(EspLdo),
26
+ cv.Required(CONF_VOLTAGE): cv.All(
27
+ cv.voltage, cv.float_range(min=0.5, max=2.7)
28
+ ),
29
+ cv.Required(CONF_CHANNEL): cv.one_of(*CHANNELS, int=True),
30
+ cv.Optional(CONF_ADJUSTABLE, default=False): cv.boolean,
31
+ }
32
+ )
31
33
  ),
32
34
  cv.only_with_esp_idf,
33
35
  only_on_variant(supported=[VARIANT_ESP32P4]),
@@ -17,6 +17,9 @@ class EspLdo : public Component {
17
17
  void set_adjustable(bool adjustable) { this->adjustable_ = adjustable; }
18
18
  void set_voltage(float voltage) { this->voltage_ = voltage; }
19
19
  void adjust_voltage(float voltage);
20
+ float get_setup_priority() const override {
21
+ return setup_priority::BUS; // LDO setup should be done early
22
+ }
20
23
 
21
24
  protected:
22
25
  int channel_;
@@ -1,11 +1,16 @@
1
+ import logging
2
+
1
3
  from esphome import pins
2
4
  import esphome.codegen as cg
3
5
  from esphome.components import binary_sensor
4
6
  import esphome.config_validation as cv
5
- from esphome.const import CONF_PIN
7
+ from esphome.const import CONF_ID, CONF_NAME, CONF_NUMBER, CONF_PIN
8
+ from esphome.core import CORE
6
9
 
7
10
  from .. import gpio_ns
8
11
 
12
+ _LOGGER = logging.getLogger(__name__)
13
+
9
14
  GPIOBinarySensor = gpio_ns.class_(
10
15
  "GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
11
16
  )
@@ -41,6 +46,22 @@ async def to_code(config):
41
46
  pin = await cg.gpio_pin_expression(config[CONF_PIN])
42
47
  cg.add(var.set_pin(pin))
43
48
 
44
- cg.add(var.set_use_interrupt(config[CONF_USE_INTERRUPT]))
45
- if config[CONF_USE_INTERRUPT]:
49
+ # Check for ESP8266 GPIO16 interrupt limitation
50
+ # GPIO16 on ESP8266 is a special pin that doesn't support interrupts through
51
+ # the Arduino attachInterrupt() function. This is the only known GPIO pin
52
+ # across all supported platforms that has this limitation, so we handle it
53
+ # here instead of in the platform-specific code.
54
+ use_interrupt = config[CONF_USE_INTERRUPT]
55
+ if use_interrupt and CORE.is_esp8266 and config[CONF_PIN][CONF_NUMBER] == 16:
56
+ _LOGGER.warning(
57
+ "GPIO binary_sensor '%s': GPIO16 on ESP8266 doesn't support interrupts. "
58
+ "Falling back to polling mode (same as in ESPHome <2025.7). "
59
+ "The sensor will work exactly as before, but other pins have better "
60
+ "performance with interrupts.",
61
+ config.get(CONF_NAME, config[CONF_ID]),
62
+ )
63
+ use_interrupt = False
64
+
65
+ cg.add(var.set_use_interrupt(use_interrupt))
66
+ if use_interrupt:
46
67
  cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE]))
@@ -45,3 +45,4 @@ async def to_code(config):
45
45
  cg.add_define("ESPHOME_BOARD", "host")
46
46
  cg.add_platformio_option("platform", "platformio/native")
47
47
  cg.add_platformio_option("lib_ldf_mode", "off")
48
+ cg.add_platformio_option("lib_compat_mode", "strict")
@@ -180,7 +180,7 @@ async def to_code(config):
180
180
  await speaker.register_speaker(var, config)
181
181
 
182
182
  if config[CONF_DAC_TYPE] == "internal":
183
- cg.add(var.set_internal_dac_mode(config[CONF_CHANNEL]))
183
+ cg.add(var.set_internal_dac_mode(config[CONF_MODE]))
184
184
  else:
185
185
  cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN]))
186
186
  if use_legacy():
@@ -178,13 +178,8 @@ static constexpr uint8_t NO_MAC[] = {0x08, 0x05, 0x04, 0x03, 0x02, 0x01};
178
178
 
179
179
  static inline int two_byte_to_int(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; }
180
180
 
181
- static bool validate_header_footer(const uint8_t *header_footer, const uint8_t *buffer) {
182
- for (uint8_t i = 0; i < HEADER_FOOTER_SIZE; i++) {
183
- if (header_footer[i] != buffer[i]) {
184
- return false; // Mismatch in header/footer
185
- }
186
- }
187
- return true; // Valid header/footer
181
+ static inline bool validate_header_footer(const uint8_t *header_footer, const uint8_t *buffer) {
182
+ return std::memcmp(header_footer, buffer, HEADER_FOOTER_SIZE) == 0;
188
183
  }
189
184
 
190
185
  void LD2410Component::dump_config() {
@@ -300,14 +295,12 @@ void LD2410Component::send_command_(uint8_t command, const uint8_t *command_valu
300
295
  if (command_value != nullptr) {
301
296
  len += command_value_len;
302
297
  }
303
- uint8_t len_cmd[] = {lowbyte(len), highbyte(len), command, 0x00};
298
+ // 2 length bytes (low, high) + 2 command bytes (low, high)
299
+ uint8_t len_cmd[] = {len, 0x00, command, 0x00};
304
300
  this->write_array(len_cmd, sizeof(len_cmd));
305
-
306
301
  // command value bytes
307
302
  if (command_value != nullptr) {
308
- for (uint8_t i = 0; i < command_value_len; i++) {
309
- this->write_byte(command_value[i]);
310
- }
303
+ this->write_array(command_value, command_value_len);
311
304
  }
312
305
  // frame footer bytes
313
306
  this->write_array(CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER));
@@ -401,7 +394,7 @@ void LD2410Component::handle_periodic_data_() {
401
394
  /*
402
395
  Moving distance range: 18th byte
403
396
  Still distance range: 19th byte
404
- Moving enery: 20~28th bytes
397
+ Moving energy: 20~28th bytes
405
398
  */
406
399
  for (std::vector<sensor::Sensor *>::size_type i = 0; i != this->gate_move_sensors_.size(); i++) {
407
400
  sensor::Sensor *s = this->gate_move_sensors_[i];
@@ -480,7 +473,7 @@ bool LD2410Component::handle_ack_data_() {
480
473
  ESP_LOGE(TAG, "Invalid status");
481
474
  return true;
482
475
  }
483
- if (ld2410::two_byte_to_int(this->buffer_data_[8], this->buffer_data_[9]) != 0x00) {
476
+ if (this->buffer_data_[8] || this->buffer_data_[9]) {
484
477
  ESP_LOGW(TAG, "Invalid command: %02X, %02X", this->buffer_data_[8], this->buffer_data_[9]);
485
478
  return true;
486
479
  }
@@ -534,8 +527,8 @@ bool LD2410Component::handle_ack_data_() {
534
527
  const auto *light_function_str = find_str(LIGHT_FUNCTIONS_BY_UINT, this->light_function_);
535
528
  const auto *out_pin_level_str = find_str(OUT_PIN_LEVELS_BY_UINT, this->out_pin_level_);
536
529
  ESP_LOGV(TAG,
537
- "Light function is: %s\n"
538
- "Light threshold is: %u\n"
530
+ "Light function: %s\n"
531
+ "Light threshold: %u\n"
539
532
  "Out pin level: %s",
540
533
  light_function_str, this->light_threshold_, out_pin_level_str);
541
534
  #ifdef USE_SELECT
@@ -600,7 +593,7 @@ bool LD2410Component::handle_ack_data_() {
600
593
  break;
601
594
 
602
595
  case CMD_QUERY: { // Query parameters response
603
- if (this->buffer_data_[10] != 0xAA)
596
+ if (this->buffer_data_[10] != HEADER)
604
597
  return true; // value head=0xAA
605
598
  #ifdef USE_NUMBER
606
599
  /*
@@ -656,17 +649,11 @@ void LD2410Component::readline_(int readch) {
656
649
  if (this->buffer_pos_ < 4) {
657
650
  return; // Not enough data to process yet
658
651
  }
659
- if (this->buffer_data_[this->buffer_pos_ - 4] == DATA_FRAME_FOOTER[0] &&
660
- this->buffer_data_[this->buffer_pos_ - 3] == DATA_FRAME_FOOTER[1] &&
661
- this->buffer_data_[this->buffer_pos_ - 2] == DATA_FRAME_FOOTER[2] &&
662
- this->buffer_data_[this->buffer_pos_ - 1] == DATA_FRAME_FOOTER[3]) {
652
+ if (ld2410::validate_header_footer(DATA_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
663
653
  ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
664
654
  this->handle_periodic_data_();
665
655
  this->buffer_pos_ = 0; // Reset position index for next message
666
- } else if (this->buffer_data_[this->buffer_pos_ - 4] == CMD_FRAME_FOOTER[0] &&
667
- this->buffer_data_[this->buffer_pos_ - 3] == CMD_FRAME_FOOTER[1] &&
668
- this->buffer_data_[this->buffer_pos_ - 2] == CMD_FRAME_FOOTER[2] &&
669
- this->buffer_data_[this->buffer_pos_ - 1] == CMD_FRAME_FOOTER[3]) {
656
+ } else if (ld2410::validate_header_footer(CMD_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
670
657
  ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
671
658
  if (this->handle_ack_data_()) {
672
659
  this->buffer_pos_ = 0; // Reset position index for next message
@@ -772,7 +759,6 @@ void LD2410Component::set_max_distances_timeout() {
772
759
  0x00};
773
760
  this->set_config_mode_(true);
774
761
  this->send_command_(CMD_MAXDIST_DURATION, value, sizeof(value));
775
- delay(50); // NOLINT
776
762
  this->query_parameters_();
777
763
  this->set_timeout(200, [this]() { this->restart_and_read_all_info(); });
778
764
  this->set_config_mode_(false);
@@ -802,7 +788,6 @@ void LD2410Component::set_gate_threshold(uint8_t gate) {
802
788
  0x01, 0x00, lowbyte(motion), highbyte(motion), 0x00, 0x00,
803
789
  0x02, 0x00, lowbyte(still), highbyte(still), 0x00, 0x00};
804
790
  this->send_command_(CMD_GATE_SENS, value, sizeof(value));
805
- delay(50); // NOLINT
806
791
  this->query_parameters_();
807
792
  this->set_config_mode_(false);
808
793
  }
@@ -833,7 +818,6 @@ void LD2410Component::set_light_out_control() {
833
818
  this->set_config_mode_(true);
834
819
  uint8_t value[4] = {this->light_function_, this->light_threshold_, this->out_pin_level_, 0x00};
835
820
  this->send_command_(CMD_SET_LIGHT_CONTROL, value, sizeof(value));
836
- delay(50); // NOLINT
837
821
  this->query_light_control_();
838
822
  this->set_timeout(200, [this]() { this->restart_and_read_all_info(); });
839
823
  this->set_config_mode_(false);
@@ -5,10 +5,10 @@
5
5
  namespace esphome {
6
6
  namespace ld2420 {
7
7
 
8
- static const char *const TAG = "LD2420.binary_sensor";
8
+ static const char *const TAG = "ld2420.binary_sensor";
9
9
 
10
10
  void LD2420BinarySensor::dump_config() {
11
- ESP_LOGCONFIG(TAG, "LD2420 BinarySensor:");
11
+ ESP_LOGCONFIG(TAG, "Binary Sensor:");
12
12
  LOG_BINARY_SENSOR(" ", "Presence", this->presence_bsensor_);
13
13
  }
14
14
 
@@ -2,7 +2,7 @@
2
2
  #include "esphome/core/helpers.h"
3
3
  #include "esphome/core/log.h"
4
4
 
5
- static const char *const TAG = "LD2420.button";
5
+ static const char *const TAG = "ld2420.button";
6
6
 
7
7
  namespace esphome {
8
8
  namespace ld2420 {
@@ -137,7 +137,7 @@ static const std::string OP_SIMPLE_MODE_STRING = "Simple";
137
137
  // Memory-efficient lookup tables
138
138
  struct StringToUint8 {
139
139
  const char *str;
140
- uint8_t value;
140
+ const uint8_t value;
141
141
  };
142
142
 
143
143
  static constexpr StringToUint8 OP_MODE_BY_STR[] = {
@@ -155,8 +155,9 @@ static constexpr const char *ERR_MESSAGE[] = {
155
155
  // Helper function for lookups
156
156
  template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) {
157
157
  for (const auto &entry : arr) {
158
- if (str == entry.str)
158
+ if (str == entry.str) {
159
159
  return entry.value;
160
+ }
160
161
  }
161
162
  return 0xFF; // Not found
162
163
  }
@@ -326,15 +327,8 @@ void LD2420Component::revert_config_action() {
326
327
 
327
328
  void LD2420Component::loop() {
328
329
  // If there is a active send command do not process it here, the send command call will handle it.
329
- if (!this->get_cmd_active_()) {
330
- if (!this->available())
331
- return;
332
- static uint8_t buffer[2048];
333
- static uint8_t rx_data;
334
- while (this->available()) {
335
- rx_data = this->read();
336
- this->readline_(rx_data, buffer, sizeof(buffer));
337
- }
330
+ while (!this->cmd_active_ && this->available()) {
331
+ this->readline_(this->read(), this->buffer_data_, MAX_LINE_LENGTH);
338
332
  }
339
333
  }
340
334
 
@@ -365,8 +359,9 @@ void LD2420Component::auto_calibrate_sensitivity() {
365
359
 
366
360
  // Store average and peak values
367
361
  this->gate_avg[gate] = sum / CALIBRATE_SAMPLES;
368
- if (this->gate_peak[gate] < peak)
362
+ if (this->gate_peak[gate] < peak) {
369
363
  this->gate_peak[gate] = peak;
364
+ }
370
365
 
371
366
  uint32_t calculated_value =
372
367
  (static_cast<uint32_t>(this->gate_peak[gate]) + (move_factor * static_cast<uint32_t>(this->gate_peak[gate])));
@@ -403,8 +398,9 @@ void LD2420Component::set_operating_mode(const std::string &state) {
403
398
  }
404
399
  } else {
405
400
  // Set the current data back so we don't have new data that can be applied in error.
406
- if (this->get_calibration_())
401
+ if (this->get_calibration_()) {
407
402
  memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
403
+ }
408
404
  this->set_calibration_(false);
409
405
  }
410
406
  } else {
@@ -414,30 +410,32 @@ void LD2420Component::set_operating_mode(const std::string &state) {
414
410
  }
415
411
 
416
412
  void LD2420Component::readline_(int rx_data, uint8_t *buffer, int len) {
417
- static int pos = 0;
418
-
419
- if (rx_data >= 0) {
420
- if (pos < len - 1) {
421
- buffer[pos++] = rx_data;
422
- buffer[pos] = 0;
423
- } else {
424
- pos = 0;
425
- }
426
- if (pos >= 4) {
427
- if (memcmp(&buffer[pos - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) {
428
- this->set_cmd_active_(false); // Set command state to inactive after responce.
429
- this->handle_ack_data_(buffer, pos);
430
- pos = 0;
431
- } else if ((buffer[pos - 2] == 0x0D && buffer[pos - 1] == 0x0A) &&
432
- (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) {
433
- this->handle_simple_mode_(buffer, pos);
434
- pos = 0;
435
- } else if ((memcmp(&buffer[pos - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) &&
436
- (this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) {
437
- this->handle_energy_mode_(buffer, pos);
438
- pos = 0;
439
- }
440
- }
413
+ if (rx_data < 0) {
414
+ return; // No data available
415
+ }
416
+ if (this->buffer_pos_ < len - 1) {
417
+ buffer[this->buffer_pos_++] = rx_data;
418
+ buffer[this->buffer_pos_] = 0;
419
+ } else {
420
+ // We should never get here, but just in case...
421
+ ESP_LOGW(TAG, "Max command length exceeded; ignoring");
422
+ this->buffer_pos_ = 0;
423
+ }
424
+ if (this->buffer_pos_ < 4) {
425
+ return; // Not enough data to process yet
426
+ }
427
+ if (memcmp(&buffer[this->buffer_pos_ - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) {
428
+ this->cmd_active_ = false; // Set command state to inactive after response
429
+ this->handle_ack_data_(buffer, this->buffer_pos_);
430
+ this->buffer_pos_ = 0;
431
+ } else if ((buffer[this->buffer_pos_ - 2] == 0x0D && buffer[this->buffer_pos_ - 1] == 0x0A) &&
432
+ (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) {
433
+ this->handle_simple_mode_(buffer, this->buffer_pos_);
434
+ this->buffer_pos_ = 0;
435
+ } else if ((memcmp(&buffer[this->buffer_pos_ - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) &&
436
+ (this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) {
437
+ this->handle_energy_mode_(buffer, this->buffer_pos_);
438
+ this->buffer_pos_ = 0;
441
439
  }
442
440
  }
443
441
 
@@ -462,8 +460,9 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) {
462
460
 
463
461
  // Resonable refresh rate for home assistant database size health
464
462
  const int32_t current_millis = App.get_loop_component_start_time();
465
- if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS)
463
+ if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS) {
466
464
  return;
465
+ }
467
466
  this->last_periodic_millis = current_millis;
468
467
  for (auto &listener : this->listeners_) {
469
468
  listener->on_distance(this->get_distance_());
@@ -506,14 +505,16 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
506
505
  }
507
506
  }
508
507
  outbuf[index] = '\0';
509
- if (index > 1)
508
+ if (index > 1) {
510
509
  this->set_distance_(strtol(outbuf, &endptr, 10));
510
+ }
511
511
 
512
512
  if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) {
513
513
  // Resonable refresh rate for home assistant database size health
514
514
  const int32_t current_millis = App.get_loop_component_start_time();
515
- if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS)
515
+ if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS) {
516
516
  return;
517
+ }
517
518
  this->last_normal_periodic_millis = current_millis;
518
519
  for (auto &listener : this->listeners_)
519
520
  listener->on_distance(this->get_distance_());
@@ -593,11 +594,12 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
593
594
  int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
594
595
  uint32_t start_millis = millis();
595
596
  uint8_t error = 0;
596
- uint8_t ack_buffer[64];
597
- uint8_t cmd_buffer[64];
597
+ uint8_t ack_buffer[MAX_LINE_LENGTH];
598
+ uint8_t cmd_buffer[MAX_LINE_LENGTH];
598
599
  this->cmd_reply_.ack = false;
599
- if (frame.command != CMD_RESTART)
600
- this->set_cmd_active_(true); // Restart does not reply, thus no ack state required.
600
+ if (frame.command != CMD_RESTART) {
601
+ this->cmd_active_ = true;
602
+ } // Restart does not reply, thus no ack state required
601
603
  uint8_t retry = 3;
602
604
  while (retry) {
603
605
  frame.length = 0;
@@ -619,9 +621,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
619
621
 
620
622
  memcpy(cmd_buffer + frame.length, &frame.footer, sizeof(frame.footer));
621
623
  frame.length += sizeof(frame.footer);
622
- for (uint16_t index = 0; index < frame.length; index++) {
623
- this->write_byte(cmd_buffer[index]);
624
- }
624
+ this->write_array(cmd_buffer, frame.length);
625
625
 
626
626
  error = 0;
627
627
  if (frame.command == CMD_RESTART) {
@@ -630,7 +630,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
630
630
 
631
631
  while (!this->cmd_reply_.ack) {
632
632
  while (this->available()) {
633
- this->readline_(read(), ack_buffer, sizeof(ack_buffer));
633
+ this->readline_(this->read(), ack_buffer, sizeof(ack_buffer));
634
634
  }
635
635
  delay_microseconds_safe(1450);
636
636
  // Wait on an Rx from the LD2420 for up to 3 1 second loops, otherwise it could trigger a WDT.
@@ -641,10 +641,12 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
641
641
  break;
642
642
  }
643
643
  }
644
- if (this->cmd_reply_.ack)
644
+ if (this->cmd_reply_.ack) {
645
645
  retry = 0;
646
- if (this->cmd_reply_.error > 0)
646
+ }
647
+ if (this->cmd_reply_.error > 0) {
647
648
  this->handle_cmd_error(error);
649
+ }
648
650
  }
649
651
  return error;
650
652
  }
@@ -764,8 +766,9 @@ void LD2420Component::set_system_mode(uint16_t mode) {
764
766
  cmd_frame.data_length += sizeof(unknown_parm);
765
767
  cmd_frame.footer = CMD_FRAME_FOOTER;
766
768
  ESP_LOGV(TAG, "Sending write system mode command: %2X", cmd_frame.command);
767
- if (this->send_cmd_from_array(cmd_frame) == 0)
769
+ if (this->send_cmd_from_array(cmd_frame) == 0) {
768
770
  this->set_mode_(mode);
771
+ }
769
772
  }
770
773
 
771
774
  void LD2420Component::get_firmware_version_() {
@@ -840,18 +843,24 @@ void LD2420Component::set_gate_threshold(uint8_t gate) {
840
843
 
841
844
  #ifdef USE_NUMBER
842
845
  void LD2420Component::init_gate_config_numbers() {
843
- if (this->gate_timeout_number_ != nullptr)
846
+ if (this->gate_timeout_number_ != nullptr) {
844
847
  this->gate_timeout_number_->publish_state(static_cast<uint16_t>(this->current_config.timeout));
845
- if (this->gate_select_number_ != nullptr)
848
+ }
849
+ if (this->gate_select_number_ != nullptr) {
846
850
  this->gate_select_number_->publish_state(0);
847
- if (this->min_gate_distance_number_ != nullptr)
851
+ }
852
+ if (this->min_gate_distance_number_ != nullptr) {
848
853
  this->min_gate_distance_number_->publish_state(static_cast<uint16_t>(this->current_config.min_gate));
849
- if (this->max_gate_distance_number_ != nullptr)
854
+ }
855
+ if (this->max_gate_distance_number_ != nullptr) {
850
856
  this->max_gate_distance_number_->publish_state(static_cast<uint16_t>(this->current_config.max_gate));
851
- if (this->gate_move_sensitivity_factor_number_ != nullptr)
857
+ }
858
+ if (this->gate_move_sensitivity_factor_number_ != nullptr) {
852
859
  this->gate_move_sensitivity_factor_number_->publish_state(this->gate_move_sensitivity_factor);
853
- if (this->gate_still_sensitivity_factor_number_ != nullptr)
860
+ }
861
+ if (this->gate_still_sensitivity_factor_number_ != nullptr) {
854
862
  this->gate_still_sensitivity_factor_number_->publish_state(this->gate_still_sensitivity_factor);
863
+ }
855
864
  for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
856
865
  if (this->gate_still_threshold_numbers_[gate] != nullptr) {
857
866
  this->gate_still_threshold_numbers_[gate]->publish_state(
@@ -20,8 +20,9 @@
20
20
  namespace esphome {
21
21
  namespace ld2420 {
22
22
 
23
- static const uint8_t TOTAL_GATES = 16;
24
23
  static const uint8_t CALIBRATE_SAMPLES = 64;
24
+ static const uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer
25
+ static const uint8_t TOTAL_GATES = 16;
25
26
 
26
27
  enum OpMode : uint8_t {
27
28
  OP_NORMAL_MODE = 1,
@@ -118,10 +119,10 @@ class LD2420Component : public Component, public uart::UARTDevice {
118
119
 
119
120
  float gate_move_sensitivity_factor{0.5};
120
121
  float gate_still_sensitivity_factor{0.5};
121
- int32_t last_periodic_millis = millis();
122
- int32_t report_periodic_millis = millis();
123
- int32_t monitor_periodic_millis = millis();
124
- int32_t last_normal_periodic_millis = millis();
122
+ int32_t last_periodic_millis{0};
123
+ int32_t report_periodic_millis{0};
124
+ int32_t monitor_periodic_millis{0};
125
+ int32_t last_normal_periodic_millis{0};
125
126
  uint16_t radar_data[TOTAL_GATES][CALIBRATE_SAMPLES];
126
127
  uint16_t gate_avg[TOTAL_GATES];
127
128
  uint16_t gate_peak[TOTAL_GATES];
@@ -161,8 +162,6 @@ class LD2420Component : public Component, public uart::UARTDevice {
161
162
  void set_presence_(bool presence) { this->presence_ = presence; };
162
163
  uint16_t get_distance_() { return this->distance_; };
163
164
  void set_distance_(uint16_t distance) { this->distance_ = distance; };
164
- bool get_cmd_active_() { return this->cmd_active_; };
165
- void set_cmd_active_(bool active) { this->cmd_active_ = active; };
166
165
  void handle_simple_mode_(const uint8_t *inbuf, int len);
167
166
  void handle_energy_mode_(uint8_t *buffer, int len);
168
167
  void handle_ack_data_(uint8_t *buffer, int len);
@@ -181,12 +180,11 @@ class LD2420Component : public Component, public uart::UARTDevice {
181
180
  std::vector<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(16);
182
181
  #endif
183
182
 
184
- uint32_t max_distance_gate_;
185
- uint32_t min_distance_gate_;
183
+ uint16_t distance_{0};
186
184
  uint16_t system_mode_;
187
185
  uint16_t gate_energy_[TOTAL_GATES];
188
- uint16_t distance_{0};
189
- uint8_t config_checksum_{0};
186
+ uint8_t buffer_pos_{0}; // where to resume processing/populating buffer
187
+ uint8_t buffer_data_[MAX_LINE_LENGTH];
190
188
  char firmware_ver_[8]{"v0.0.0"};
191
189
  bool cmd_active_{false};
192
190
  bool presence_{false};
@@ -2,7 +2,7 @@
2
2
  #include "esphome/core/helpers.h"
3
3
  #include "esphome/core/log.h"
4
4
 
5
- static const char *const TAG = "LD2420.number";
5
+ static const char *const TAG = "ld2420.number";
6
6
 
7
7
  namespace esphome {
8
8
  namespace ld2420 {
@@ -5,7 +5,7 @@
5
5
  namespace esphome {
6
6
  namespace ld2420 {
7
7
 
8
- static const char *const TAG = "LD2420.select";
8
+ static const char *const TAG = "ld2420.select";
9
9
 
10
10
  void LD2420Select::control(const std::string &value) {
11
11
  this->publish_state(value);
@@ -5,10 +5,10 @@
5
5
  namespace esphome {
6
6
  namespace ld2420 {
7
7
 
8
- static const char *const TAG = "LD2420.sensor";
8
+ static const char *const TAG = "ld2420.sensor";
9
9
 
10
10
  void LD2420Sensor::dump_config() {
11
- ESP_LOGCONFIG(TAG, "LD2420 Sensor:");
11
+ ESP_LOGCONFIG(TAG, "Sensor:");
12
12
  LOG_SENSOR(" ", "Distance", this->distance_sensor_);
13
13
  }
14
14
 
@@ -5,10 +5,10 @@
5
5
  namespace esphome {
6
6
  namespace ld2420 {
7
7
 
8
- static const char *const TAG = "LD2420.text_sensor";
8
+ static const char *const TAG = "ld2420.text_sensor";
9
9
 
10
10
  void LD2420TextSensor::dump_config() {
11
- ESP_LOGCONFIG(TAG, "LD2420 TextSensor:");
11
+ ESP_LOGCONFIG(TAG, "Text Sensor:");
12
12
  LOG_TEXT_SENSOR(" ", "Firmware", this->fw_version_text_sensor_);
13
13
  }
14
14
 
@@ -268,6 +268,7 @@ async def component_to_code(config):
268
268
 
269
269
  # disable library compatibility checks
270
270
  cg.add_platformio_option("lib_ldf_mode", "off")
271
+ cg.add_platformio_option("lib_compat_mode", "soft")
271
272
  # include <Arduino.h> in every file
272
273
  cg.add_platformio_option("build_src_flags", "-include Arduino.h")
273
274
  # dummy version code