From 097aac2183641c087f161b2b34648d26fbc497d2 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Fri, 11 Jul 2025 22:33:36 -0500 Subject: [PATCH] [ld2420] Memory optimization, code clean-up (#9426) --- .../binary_sensor/ld2420_binary_sensor.cpp | 4 +- .../ld2420/button/reconfig_buttons.cpp | 2 +- esphome/components/ld2420/ld2420.cpp | 123 ++++++++++-------- esphome/components/ld2420/ld2420.h | 20 ++- .../ld2420/number/gate_config_number.cpp | 2 +- .../ld2420/select/operating_mode_select.cpp | 2 +- .../ld2420/sensor/ld2420_sensor.cpp | 4 +- .../ld2420/text_sensor/text_sensor.cpp | 4 +- 8 files changed, 84 insertions(+), 77 deletions(-) diff --git a/esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp b/esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp index c6ea0a348b..d8632e9c19 100644 --- a/esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +++ b/esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp @@ -5,10 +5,10 @@ namespace esphome { namespace ld2420 { -static const char *const TAG = "LD2420.binary_sensor"; +static const char *const TAG = "ld2420.binary_sensor"; void LD2420BinarySensor::dump_config() { - ESP_LOGCONFIG(TAG, "LD2420 BinarySensor:"); + ESP_LOGCONFIG(TAG, "Binary Sensor:"); LOG_BINARY_SENSOR(" ", "Presence", this->presence_bsensor_); } diff --git a/esphome/components/ld2420/button/reconfig_buttons.cpp b/esphome/components/ld2420/button/reconfig_buttons.cpp index 3537c1d64a..fb8ec2b5a6 100644 --- a/esphome/components/ld2420/button/reconfig_buttons.cpp +++ b/esphome/components/ld2420/button/reconfig_buttons.cpp @@ -2,7 +2,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -static const char *const TAG = "LD2420.button"; +static const char *const TAG = "ld2420.button"; namespace esphome { namespace ld2420 { diff --git a/esphome/components/ld2420/ld2420.cpp b/esphome/components/ld2420/ld2420.cpp index 8a7d7de23b..0baff368c8 100644 --- a/esphome/components/ld2420/ld2420.cpp +++ b/esphome/components/ld2420/ld2420.cpp @@ -137,7 +137,7 @@ static const std::string OP_SIMPLE_MODE_STRING = "Simple"; // Memory-efficient lookup tables struct StringToUint8 { const char *str; - uint8_t value; + const uint8_t value; }; static constexpr StringToUint8 OP_MODE_BY_STR[] = { @@ -155,8 +155,9 @@ static constexpr const char *ERR_MESSAGE[] = { // Helper function for lookups template uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) { for (const auto &entry : arr) { - if (str == entry.str) + if (str == entry.str) { return entry.value; + } } return 0xFF; // Not found } @@ -326,15 +327,8 @@ void LD2420Component::revert_config_action() { void LD2420Component::loop() { // If there is a active send command do not process it here, the send command call will handle it. - if (!this->get_cmd_active_()) { - if (!this->available()) - return; - static uint8_t buffer[2048]; - static uint8_t rx_data; - while (this->available()) { - rx_data = this->read(); - this->readline_(rx_data, buffer, sizeof(buffer)); - } + while (!this->cmd_active_ && this->available()) { + this->readline_(this->read(), this->buffer_data_, MAX_LINE_LENGTH); } } @@ -365,8 +359,9 @@ void LD2420Component::auto_calibrate_sensitivity() { // Store average and peak values this->gate_avg[gate] = sum / CALIBRATE_SAMPLES; - if (this->gate_peak[gate] < peak) + if (this->gate_peak[gate] < peak) { this->gate_peak[gate] = peak; + } uint32_t calculated_value = (static_cast(this->gate_peak[gate]) + (move_factor * static_cast(this->gate_peak[gate]))); @@ -403,8 +398,9 @@ void LD2420Component::set_operating_mode(const std::string &state) { } } else { // Set the current data back so we don't have new data that can be applied in error. - if (this->get_calibration_()) + if (this->get_calibration_()) { memcpy(&this->new_config, &this->current_config, sizeof(this->current_config)); + } this->set_calibration_(false); } } else { @@ -414,30 +410,32 @@ void LD2420Component::set_operating_mode(const std::string &state) { } void LD2420Component::readline_(int rx_data, uint8_t *buffer, int len) { - static int pos = 0; - - if (rx_data >= 0) { - if (pos < len - 1) { - buffer[pos++] = rx_data; - buffer[pos] = 0; - } else { - pos = 0; - } - if (pos >= 4) { - if (memcmp(&buffer[pos - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) { - this->set_cmd_active_(false); // Set command state to inactive after responce. - this->handle_ack_data_(buffer, pos); - pos = 0; - } else if ((buffer[pos - 2] == 0x0D && buffer[pos - 1] == 0x0A) && - (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) { - this->handle_simple_mode_(buffer, pos); - pos = 0; - } else if ((memcmp(&buffer[pos - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) && - (this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) { - this->handle_energy_mode_(buffer, pos); - pos = 0; - } - } + if (rx_data < 0) { + return; // No data available + } + if (this->buffer_pos_ < len - 1) { + buffer[this->buffer_pos_++] = rx_data; + buffer[this->buffer_pos_] = 0; + } else { + // We should never get here, but just in case... + ESP_LOGW(TAG, "Max command length exceeded; ignoring"); + this->buffer_pos_ = 0; + } + if (this->buffer_pos_ < 4) { + return; // Not enough data to process yet + } + if (memcmp(&buffer[this->buffer_pos_ - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) { + this->cmd_active_ = false; // Set command state to inactive after response + this->handle_ack_data_(buffer, this->buffer_pos_); + this->buffer_pos_ = 0; + } else if ((buffer[this->buffer_pos_ - 2] == 0x0D && buffer[this->buffer_pos_ - 1] == 0x0A) && + (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) { + this->handle_simple_mode_(buffer, this->buffer_pos_); + this->buffer_pos_ = 0; + } else if ((memcmp(&buffer[this->buffer_pos_ - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) && + (this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) { + this->handle_energy_mode_(buffer, this->buffer_pos_); + this->buffer_pos_ = 0; } } @@ -462,8 +460,9 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) { // Resonable refresh rate for home assistant database size health const int32_t current_millis = App.get_loop_component_start_time(); - if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS) + if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS) { return; + } this->last_periodic_millis = current_millis; for (auto &listener : this->listeners_) { listener->on_distance(this->get_distance_()); @@ -506,14 +505,16 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) { } } outbuf[index] = '\0'; - if (index > 1) + if (index > 1) { this->set_distance_(strtol(outbuf, &endptr, 10)); + } if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) { // Resonable refresh rate for home assistant database size health const int32_t current_millis = App.get_loop_component_start_time(); - if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS) + if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS) { return; + } this->last_normal_periodic_millis = current_millis; for (auto &listener : this->listeners_) listener->on_distance(this->get_distance_()); @@ -593,11 +594,12 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) { int LD2420Component::send_cmd_from_array(CmdFrameT frame) { uint32_t start_millis = millis(); uint8_t error = 0; - uint8_t ack_buffer[64]; - uint8_t cmd_buffer[64]; + uint8_t ack_buffer[MAX_LINE_LENGTH]; + uint8_t cmd_buffer[MAX_LINE_LENGTH]; this->cmd_reply_.ack = false; - if (frame.command != CMD_RESTART) - this->set_cmd_active_(true); // Restart does not reply, thus no ack state required. + if (frame.command != CMD_RESTART) { + this->cmd_active_ = true; + } // Restart does not reply, thus no ack state required uint8_t retry = 3; while (retry) { frame.length = 0; @@ -619,9 +621,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) { memcpy(cmd_buffer + frame.length, &frame.footer, sizeof(frame.footer)); frame.length += sizeof(frame.footer); - for (uint16_t index = 0; index < frame.length; index++) { - this->write_byte(cmd_buffer[index]); - } + this->write_array(cmd_buffer, frame.length); error = 0; if (frame.command == CMD_RESTART) { @@ -630,7 +630,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) { while (!this->cmd_reply_.ack) { while (this->available()) { - this->readline_(read(), ack_buffer, sizeof(ack_buffer)); + this->readline_(this->read(), ack_buffer, sizeof(ack_buffer)); } delay_microseconds_safe(1450); // 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) { break; } } - if (this->cmd_reply_.ack) + if (this->cmd_reply_.ack) { retry = 0; - if (this->cmd_reply_.error > 0) + } + if (this->cmd_reply_.error > 0) { this->handle_cmd_error(error); + } } return error; } @@ -764,8 +766,9 @@ void LD2420Component::set_system_mode(uint16_t mode) { cmd_frame.data_length += sizeof(unknown_parm); cmd_frame.footer = CMD_FRAME_FOOTER; ESP_LOGV(TAG, "Sending write system mode command: %2X", cmd_frame.command); - if (this->send_cmd_from_array(cmd_frame) == 0) + if (this->send_cmd_from_array(cmd_frame) == 0) { this->set_mode_(mode); + } } void LD2420Component::get_firmware_version_() { @@ -840,18 +843,24 @@ void LD2420Component::set_gate_threshold(uint8_t gate) { #ifdef USE_NUMBER void LD2420Component::init_gate_config_numbers() { - if (this->gate_timeout_number_ != nullptr) + if (this->gate_timeout_number_ != nullptr) { this->gate_timeout_number_->publish_state(static_cast(this->current_config.timeout)); - if (this->gate_select_number_ != nullptr) + } + if (this->gate_select_number_ != nullptr) { this->gate_select_number_->publish_state(0); - if (this->min_gate_distance_number_ != nullptr) + } + if (this->min_gate_distance_number_ != nullptr) { this->min_gate_distance_number_->publish_state(static_cast(this->current_config.min_gate)); - if (this->max_gate_distance_number_ != nullptr) + } + if (this->max_gate_distance_number_ != nullptr) { this->max_gate_distance_number_->publish_state(static_cast(this->current_config.max_gate)); - if (this->gate_move_sensitivity_factor_number_ != nullptr) + } + if (this->gate_move_sensitivity_factor_number_ != nullptr) { this->gate_move_sensitivity_factor_number_->publish_state(this->gate_move_sensitivity_factor); - if (this->gate_still_sensitivity_factor_number_ != nullptr) + } + if (this->gate_still_sensitivity_factor_number_ != nullptr) { this->gate_still_sensitivity_factor_number_->publish_state(this->gate_still_sensitivity_factor); + } for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) { if (this->gate_still_threshold_numbers_[gate] != nullptr) { this->gate_still_threshold_numbers_[gate]->publish_state( diff --git a/esphome/components/ld2420/ld2420.h b/esphome/components/ld2420/ld2420.h index d574a25c89..812c408cfd 100644 --- a/esphome/components/ld2420/ld2420.h +++ b/esphome/components/ld2420/ld2420.h @@ -20,8 +20,9 @@ namespace esphome { namespace ld2420 { -static const uint8_t TOTAL_GATES = 16; static const uint8_t CALIBRATE_SAMPLES = 64; +static const uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer +static const uint8_t TOTAL_GATES = 16; enum OpMode : uint8_t { OP_NORMAL_MODE = 1, @@ -118,10 +119,10 @@ class LD2420Component : public Component, public uart::UARTDevice { float gate_move_sensitivity_factor{0.5}; float gate_still_sensitivity_factor{0.5}; - int32_t last_periodic_millis = millis(); - int32_t report_periodic_millis = millis(); - int32_t monitor_periodic_millis = millis(); - int32_t last_normal_periodic_millis = millis(); + int32_t last_periodic_millis{0}; + int32_t report_periodic_millis{0}; + int32_t monitor_periodic_millis{0}; + int32_t last_normal_periodic_millis{0}; uint16_t radar_data[TOTAL_GATES][CALIBRATE_SAMPLES]; uint16_t gate_avg[TOTAL_GATES]; uint16_t gate_peak[TOTAL_GATES]; @@ -161,8 +162,6 @@ class LD2420Component : public Component, public uart::UARTDevice { void set_presence_(bool presence) { this->presence_ = presence; }; uint16_t get_distance_() { return this->distance_; }; void set_distance_(uint16_t distance) { this->distance_ = distance; }; - bool get_cmd_active_() { return this->cmd_active_; }; - void set_cmd_active_(bool active) { this->cmd_active_ = active; }; void handle_simple_mode_(const uint8_t *inbuf, int len); void handle_energy_mode_(uint8_t *buffer, int len); void handle_ack_data_(uint8_t *buffer, int len); @@ -181,12 +180,11 @@ class LD2420Component : public Component, public uart::UARTDevice { std::vector gate_move_threshold_numbers_ = std::vector(16); #endif - uint32_t max_distance_gate_; - uint32_t min_distance_gate_; + uint16_t distance_{0}; uint16_t system_mode_; uint16_t gate_energy_[TOTAL_GATES]; - uint16_t distance_{0}; - uint8_t config_checksum_{0}; + uint8_t buffer_pos_{0}; // where to resume processing/populating buffer + uint8_t buffer_data_[MAX_LINE_LENGTH]; char firmware_ver_[8]{"v0.0.0"}; bool cmd_active_{false}; bool presence_{false}; diff --git a/esphome/components/ld2420/number/gate_config_number.cpp b/esphome/components/ld2420/number/gate_config_number.cpp index e5eaafb46d..a373753770 100644 --- a/esphome/components/ld2420/number/gate_config_number.cpp +++ b/esphome/components/ld2420/number/gate_config_number.cpp @@ -2,7 +2,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -static const char *const TAG = "LD2420.number"; +static const char *const TAG = "ld2420.number"; namespace esphome { namespace ld2420 { diff --git a/esphome/components/ld2420/select/operating_mode_select.cpp b/esphome/components/ld2420/select/operating_mode_select.cpp index 1c59f443a5..2d576e7cc6 100644 --- a/esphome/components/ld2420/select/operating_mode_select.cpp +++ b/esphome/components/ld2420/select/operating_mode_select.cpp @@ -5,7 +5,7 @@ namespace esphome { namespace ld2420 { -static const char *const TAG = "LD2420.select"; +static const char *const TAG = "ld2420.select"; void LD2420Select::control(const std::string &value) { this->publish_state(value); diff --git a/esphome/components/ld2420/sensor/ld2420_sensor.cpp b/esphome/components/ld2420/sensor/ld2420_sensor.cpp index 97f0c594b7..723604f396 100644 --- a/esphome/components/ld2420/sensor/ld2420_sensor.cpp +++ b/esphome/components/ld2420/sensor/ld2420_sensor.cpp @@ -5,10 +5,10 @@ namespace esphome { namespace ld2420 { -static const char *const TAG = "LD2420.sensor"; +static const char *const TAG = "ld2420.sensor"; void LD2420Sensor::dump_config() { - ESP_LOGCONFIG(TAG, "LD2420 Sensor:"); + ESP_LOGCONFIG(TAG, "Sensor:"); LOG_SENSOR(" ", "Distance", this->distance_sensor_); } diff --git a/esphome/components/ld2420/text_sensor/text_sensor.cpp b/esphome/components/ld2420/text_sensor/text_sensor.cpp index 1dcdcf7d60..73af3b3660 100644 --- a/esphome/components/ld2420/text_sensor/text_sensor.cpp +++ b/esphome/components/ld2420/text_sensor/text_sensor.cpp @@ -5,10 +5,10 @@ namespace esphome { namespace ld2420 { -static const char *const TAG = "LD2420.text_sensor"; +static const char *const TAG = "ld2420.text_sensor"; void LD2420TextSensor::dump_config() { - ESP_LOGCONFIG(TAG, "LD2420 TextSensor:"); + ESP_LOGCONFIG(TAG, "Text Sensor:"); LOG_TEXT_SENSOR(" ", "Firmware", this->fw_version_text_sensor_); }