[ld2420] Memory optimization, code clean-up (#9426)

This commit is contained in:
Keith Burzinski 2025-07-11 22:33:36 -05:00 committed by Jesse Hills
parent 18787b0be0
commit 097aac2183
No known key found for this signature in database
GPG Key ID: BEAAE804EFD8E83A
8 changed files with 84 additions and 77 deletions

View File

@ -5,10 +5,10 @@
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {
static const char *const TAG = "LD2420.binary_sensor"; static const char *const TAG = "ld2420.binary_sensor";
void LD2420BinarySensor::dump_config() { void LD2420BinarySensor::dump_config() {
ESP_LOGCONFIG(TAG, "LD2420 BinarySensor:"); ESP_LOGCONFIG(TAG, "Binary Sensor:");
LOG_BINARY_SENSOR(" ", "Presence", this->presence_bsensor_); LOG_BINARY_SENSOR(" ", "Presence", this->presence_bsensor_);
} }

View File

@ -2,7 +2,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
static const char *const TAG = "LD2420.button"; static const char *const TAG = "ld2420.button";
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {

View File

@ -137,7 +137,7 @@ static const std::string OP_SIMPLE_MODE_STRING = "Simple";
// Memory-efficient lookup tables // Memory-efficient lookup tables
struct StringToUint8 { struct StringToUint8 {
const char *str; const char *str;
uint8_t value; const uint8_t value;
}; };
static constexpr StringToUint8 OP_MODE_BY_STR[] = { static constexpr StringToUint8 OP_MODE_BY_STR[] = {
@ -155,8 +155,9 @@ static constexpr const char *ERR_MESSAGE[] = {
// Helper function for lookups // Helper function for lookups
template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) { template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) {
for (const auto &entry : arr) { for (const auto &entry : arr) {
if (str == entry.str) if (str == entry.str) {
return entry.value; return entry.value;
}
} }
return 0xFF; // Not found return 0xFF; // Not found
} }
@ -326,15 +327,8 @@ void LD2420Component::revert_config_action() {
void LD2420Component::loop() { void LD2420Component::loop() {
// If there is a active send command do not process it here, the send command call will handle it. // If there is a active send command do not process it here, the send command call will handle it.
if (!this->get_cmd_active_()) { while (!this->cmd_active_ && this->available()) {
if (!this->available()) this->readline_(this->read(), this->buffer_data_, MAX_LINE_LENGTH);
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));
}
} }
} }
@ -365,8 +359,9 @@ void LD2420Component::auto_calibrate_sensitivity() {
// Store average and peak values // Store average and peak values
this->gate_avg[gate] = sum / CALIBRATE_SAMPLES; this->gate_avg[gate] = sum / CALIBRATE_SAMPLES;
if (this->gate_peak[gate] < peak) if (this->gate_peak[gate] < peak) {
this->gate_peak[gate] = peak; this->gate_peak[gate] = peak;
}
uint32_t calculated_value = uint32_t calculated_value =
(static_cast<uint32_t>(this->gate_peak[gate]) + (move_factor * static_cast<uint32_t>(this->gate_peak[gate]))); (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) {
} }
} else { } else {
// Set the current data back so we don't have new data that can be applied in error. // 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)); memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
}
this->set_calibration_(false); this->set_calibration_(false);
} }
} else { } 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) { void LD2420Component::readline_(int rx_data, uint8_t *buffer, int len) {
static int pos = 0; if (rx_data < 0) {
return; // No data available
if (rx_data >= 0) { }
if (pos < len - 1) { if (this->buffer_pos_ < len - 1) {
buffer[pos++] = rx_data; buffer[this->buffer_pos_++] = rx_data;
buffer[pos] = 0; buffer[this->buffer_pos_] = 0;
} else { } else {
pos = 0; // We should never get here, but just in case...
} ESP_LOGW(TAG, "Max command length exceeded; ignoring");
if (pos >= 4) { this->buffer_pos_ = 0;
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. if (this->buffer_pos_ < 4) {
this->handle_ack_data_(buffer, pos); return; // Not enough data to process yet
pos = 0; }
} else if ((buffer[pos - 2] == 0x0D && buffer[pos - 1] == 0x0A) && if (memcmp(&buffer[this->buffer_pos_ - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) {
(this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) { this->cmd_active_ = false; // Set command state to inactive after response
this->handle_simple_mode_(buffer, pos); this->handle_ack_data_(buffer, this->buffer_pos_);
pos = 0; this->buffer_pos_ = 0;
} else if ((memcmp(&buffer[pos - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) && } else if ((buffer[this->buffer_pos_ - 2] == 0x0D && buffer[this->buffer_pos_ - 1] == 0x0A) &&
(this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) { (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) {
this->handle_energy_mode_(buffer, pos); this->handle_simple_mode_(buffer, this->buffer_pos_);
pos = 0; 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 // Resonable refresh rate for home assistant database size health
const int32_t current_millis = App.get_loop_component_start_time(); 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; return;
}
this->last_periodic_millis = current_millis; this->last_periodic_millis = current_millis;
for (auto &listener : this->listeners_) { for (auto &listener : this->listeners_) {
listener->on_distance(this->get_distance_()); listener->on_distance(this->get_distance_());
@ -506,14 +505,16 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
} }
} }
outbuf[index] = '\0'; outbuf[index] = '\0';
if (index > 1) if (index > 1) {
this->set_distance_(strtol(outbuf, &endptr, 10)); this->set_distance_(strtol(outbuf, &endptr, 10));
}
if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) { if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) {
// Resonable refresh rate for home assistant database size health // Resonable refresh rate for home assistant database size health
const int32_t current_millis = App.get_loop_component_start_time(); 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; return;
}
this->last_normal_periodic_millis = current_millis; this->last_normal_periodic_millis = current_millis;
for (auto &listener : this->listeners_) for (auto &listener : this->listeners_)
listener->on_distance(this->get_distance_()); 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) { int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
uint32_t start_millis = millis(); uint32_t start_millis = millis();
uint8_t error = 0; uint8_t error = 0;
uint8_t ack_buffer[64]; uint8_t ack_buffer[MAX_LINE_LENGTH];
uint8_t cmd_buffer[64]; uint8_t cmd_buffer[MAX_LINE_LENGTH];
this->cmd_reply_.ack = false; this->cmd_reply_.ack = false;
if (frame.command != CMD_RESTART) if (frame.command != CMD_RESTART) {
this->set_cmd_active_(true); // Restart does not reply, thus no ack state required. this->cmd_active_ = true;
} // Restart does not reply, thus no ack state required
uint8_t retry = 3; uint8_t retry = 3;
while (retry) { while (retry) {
frame.length = 0; 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)); memcpy(cmd_buffer + frame.length, &frame.footer, sizeof(frame.footer));
frame.length += sizeof(frame.footer); frame.length += sizeof(frame.footer);
for (uint16_t index = 0; index < frame.length; index++) { this->write_array(cmd_buffer, frame.length);
this->write_byte(cmd_buffer[index]);
}
error = 0; error = 0;
if (frame.command == CMD_RESTART) { if (frame.command == CMD_RESTART) {
@ -630,7 +630,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
while (!this->cmd_reply_.ack) { while (!this->cmd_reply_.ack) {
while (this->available()) { while (this->available()) {
this->readline_(read(), ack_buffer, sizeof(ack_buffer)); this->readline_(this->read(), ack_buffer, sizeof(ack_buffer));
} }
delay_microseconds_safe(1450); delay_microseconds_safe(1450);
// Wait on an Rx from the LD2420 for up to 3 1 second loops, otherwise it could trigger a WDT. // 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; break;
} }
} }
if (this->cmd_reply_.ack) if (this->cmd_reply_.ack) {
retry = 0; retry = 0;
if (this->cmd_reply_.error > 0) }
if (this->cmd_reply_.error > 0) {
this->handle_cmd_error(error); this->handle_cmd_error(error);
}
} }
return error; return error;
} }
@ -764,8 +766,9 @@ void LD2420Component::set_system_mode(uint16_t mode) {
cmd_frame.data_length += sizeof(unknown_parm); cmd_frame.data_length += sizeof(unknown_parm);
cmd_frame.footer = CMD_FRAME_FOOTER; cmd_frame.footer = CMD_FRAME_FOOTER;
ESP_LOGV(TAG, "Sending write system mode command: %2X", cmd_frame.command); 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); this->set_mode_(mode);
}
} }
void LD2420Component::get_firmware_version_() { void LD2420Component::get_firmware_version_() {
@ -840,18 +843,24 @@ void LD2420Component::set_gate_threshold(uint8_t gate) {
#ifdef USE_NUMBER #ifdef USE_NUMBER
void LD2420Component::init_gate_config_numbers() { 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<uint16_t>(this->current_config.timeout)); this->gate_timeout_number_->publish_state(static_cast<uint16_t>(this->current_config.timeout));
if (this->gate_select_number_ != nullptr) }
if (this->gate_select_number_ != nullptr) {
this->gate_select_number_->publish_state(0); 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<uint16_t>(this->current_config.min_gate)); this->min_gate_distance_number_->publish_state(static_cast<uint16_t>(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<uint16_t>(this->current_config.max_gate)); this->max_gate_distance_number_->publish_state(static_cast<uint16_t>(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); 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); this->gate_still_sensitivity_factor_number_->publish_state(this->gate_still_sensitivity_factor);
}
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) { for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
if (this->gate_still_threshold_numbers_[gate] != nullptr) { if (this->gate_still_threshold_numbers_[gate] != nullptr) {
this->gate_still_threshold_numbers_[gate]->publish_state( this->gate_still_threshold_numbers_[gate]->publish_state(

View File

@ -20,8 +20,9 @@
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {
static const uint8_t TOTAL_GATES = 16;
static const uint8_t CALIBRATE_SAMPLES = 64; 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 { enum OpMode : uint8_t {
OP_NORMAL_MODE = 1, OP_NORMAL_MODE = 1,
@ -118,10 +119,10 @@ class LD2420Component : public Component, public uart::UARTDevice {
float gate_move_sensitivity_factor{0.5}; float gate_move_sensitivity_factor{0.5};
float gate_still_sensitivity_factor{0.5}; float gate_still_sensitivity_factor{0.5};
int32_t last_periodic_millis = millis(); int32_t last_periodic_millis{0};
int32_t report_periodic_millis = millis(); int32_t report_periodic_millis{0};
int32_t monitor_periodic_millis = millis(); int32_t monitor_periodic_millis{0};
int32_t last_normal_periodic_millis = millis(); int32_t last_normal_periodic_millis{0};
uint16_t radar_data[TOTAL_GATES][CALIBRATE_SAMPLES]; uint16_t radar_data[TOTAL_GATES][CALIBRATE_SAMPLES];
uint16_t gate_avg[TOTAL_GATES]; uint16_t gate_avg[TOTAL_GATES];
uint16_t gate_peak[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; }; void set_presence_(bool presence) { this->presence_ = presence; };
uint16_t get_distance_() { return this->distance_; }; uint16_t get_distance_() { return this->distance_; };
void set_distance_(uint16_t distance) { this->distance_ = 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_simple_mode_(const uint8_t *inbuf, int len);
void handle_energy_mode_(uint8_t *buffer, int len); void handle_energy_mode_(uint8_t *buffer, int len);
void handle_ack_data_(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<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(16); std::vector<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(16);
#endif #endif
uint32_t max_distance_gate_; uint16_t distance_{0};
uint32_t min_distance_gate_;
uint16_t system_mode_; uint16_t system_mode_;
uint16_t gate_energy_[TOTAL_GATES]; uint16_t gate_energy_[TOTAL_GATES];
uint16_t distance_{0}; uint8_t buffer_pos_{0}; // where to resume processing/populating buffer
uint8_t config_checksum_{0}; uint8_t buffer_data_[MAX_LINE_LENGTH];
char firmware_ver_[8]{"v0.0.0"}; char firmware_ver_[8]{"v0.0.0"};
bool cmd_active_{false}; bool cmd_active_{false};
bool presence_{false}; bool presence_{false};

View File

@ -2,7 +2,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
static const char *const TAG = "LD2420.number"; static const char *const TAG = "ld2420.number";
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {

View File

@ -5,7 +5,7 @@
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {
static const char *const TAG = "LD2420.select"; static const char *const TAG = "ld2420.select";
void LD2420Select::control(const std::string &value) { void LD2420Select::control(const std::string &value) {
this->publish_state(value); this->publish_state(value);

View File

@ -5,10 +5,10 @@
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {
static const char *const TAG = "LD2420.sensor"; static const char *const TAG = "ld2420.sensor";
void LD2420Sensor::dump_config() { void LD2420Sensor::dump_config() {
ESP_LOGCONFIG(TAG, "LD2420 Sensor:"); ESP_LOGCONFIG(TAG, "Sensor:");
LOG_SENSOR(" ", "Distance", this->distance_sensor_); LOG_SENSOR(" ", "Distance", this->distance_sensor_);
} }

View File

@ -5,10 +5,10 @@
namespace esphome { namespace esphome {
namespace ld2420 { namespace ld2420 {
static const char *const TAG = "LD2420.text_sensor"; static const char *const TAG = "ld2420.text_sensor";
void LD2420TextSensor::dump_config() { void LD2420TextSensor::dump_config() {
ESP_LOGCONFIG(TAG, "LD2420 TextSensor:"); ESP_LOGCONFIG(TAG, "Text Sensor:");
LOG_TEXT_SENSOR(" ", "Firmware", this->fw_version_text_sensor_); LOG_TEXT_SENSOR(" ", "Firmware", this->fw_version_text_sensor_);
} }