Compare commits

...

4 Commits

Author SHA1 Message Date
Tomer27cz c9bbbd574c line length limit 2026-03-07 21:14:45 +01:00
Tomer27cz a9e13b6e8c Optimize DlmsParser allocations and types
Use stack buffers and C-strings to avoid heap allocations, and modernize token handling and ownership.

- Replace heap-allocated std::string temporaries in dlms_parser.cpp with stack buffers and pass const char* to callbacks/logs to reduce allocations and copying.
- Change DlmsDataCallback signature to accept const char* for obis and string values; update DlmsPushComponent to match.
- Switch DlmsParser ownership to std::unique_ptr in DlmsPushComponent and add <memory> include.
- Replace std::list with std::vector for DSL token parsing, update iteration/insertion logic accordingly.
- Remove unused <list> include and adjust related function signatures/whitespace.

These changes improve performance and memory usage; note the callback/API signature change may require updating any external callers.
2026-03-07 20:58:19 +01:00
Tomer27cz 789611a611 Make DLMS string helpers write to buffer
Change DlmsParser::data_to_string_ and obis_to_string_ signatures to return void and write into the provided caller buffer instead of returning std::string (avoids allocations and clarifies ownership).

Also add #include "esphome/core/application.h" in dlms_push.cpp for required declarations.
2026-03-07 20:39:57 +01:00
Tomer27cz 8fc10fb496 Optimize DLMS parser buffers and RX timing
Replace heavy std::string/iostream usage in the DLMS parser with stack-allocated char buffers and snprintf to avoid heap allocations and reduce runtime overhead. Introduce buffer-based helpers (data_to_string_, obis_to_string_) and switch hex formatting to format_hex_pretty_to; remove <sstream>/<iomanip> and include <cstdio>. Update header signatures accordingly. Also change DlmsPushComponent to use App.get_loop_component_start_time() instead of millis() when tracking last_rx_char_time_ for RX timeout handling.

Files changed: components/dlms_push/dlms_parser.cpp/.h (buffer-based string helpers, logging, include changes), components/dlms_push/dlms_push.cpp (use App loop time for timeout).

Note: The string helper APIs were converted to buffer-oriented versions — update any callers to provide an output buffer.
2026-03-07 20:33:20 +01:00
4 changed files with 108 additions and 65 deletions

View File

@ -5,8 +5,7 @@
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <sstream> #include <cstdio>
#include <iomanip>
#include <algorithm> #include <algorithm>
namespace esphome { namespace esphome {
@ -66,7 +65,11 @@ size_t DlmsParser::parse(const uint8_t *buffer, size_t length, DlmsDataCallback
// First byte after flag should be the data type (usually Structure or Array) // First byte after flag should be the data type (usually Structure or Array)
uint8_t start_type = this->read_byte_(); uint8_t start_type = this->read_byte_();
if (start_type != DLMS_DATA_TYPE_STRUCTURE && start_type != DLMS_DATA_TYPE_ARRAY) { if (start_type != DLMS_DATA_TYPE_STRUCTURE && start_type != DLMS_DATA_TYPE_ARRAY) {
if (this->show_log_) ESP_LOGW(TAG, "Expected STRUCTURE or ARRAY after header, found type %02X at position %zu", start_type, this->pos_ - 1); if (this->show_log_) {
ESP_LOGW(TAG, "Expected STRUCTURE or ARRAY after header, found type %02X at position %zu",
start_type, this->pos_ - 1);
}
return 0; return 0;
} }
@ -76,7 +79,10 @@ size_t DlmsParser::parse(const uint8_t *buffer, size_t length, DlmsDataCallback
ESP_LOGV(TAG, "Some errors occurred parsing DLMS data, or unexpected end of buffer."); ESP_LOGV(TAG, "Some errors occurred parsing DLMS data, or unexpected end of buffer.");
} }
if (this->show_log_) ESP_LOGD(TAG, "Parsing completed. Processed %zu bytes, found %zu objects", this->pos_, this->objects_found_); if (this->show_log_) {
ESP_LOGD(TAG, "Parsing completed. Processed %zu bytes, found %zu objects", this->pos_, this->objects_found_);
}
return this->objects_found_; return this->objects_found_;
} }
@ -250,7 +256,11 @@ bool DlmsParser::parse_sequence_(uint8_t type, uint8_t depth) {
} }
if (this->pos_ >= this->buffer_len_) { if (this->pos_ >= this->buffer_len_) {
if (this->show_log_) ESP_LOGV(TAG, "Unexpected end while reading element %d of %s", elements_consumed + 1, type == DLMS_DATA_TYPE_STRUCTURE ? "STRUCTURE" : "ARRAY"); if (this->show_log_) {
ESP_LOGV(TAG, "Unexpected end while reading element %d of %s", elements_consumed + 1,
type == DLMS_DATA_TYPE_STRUCTURE ? "STRUCTURE" : "ARRAY");
}
return false; return false;
} }
@ -259,7 +269,11 @@ bool DlmsParser::parse_sequence_(uint8_t type, uint8_t depth) {
elements_consumed++; elements_consumed++;
if (this->pos_ == original_position) { if (this->pos_ == original_position) {
if (this->show_log_) ESP_LOGV(TAG, "No progress parsing element %d at position %zu, aborting to avoid infinite loop", elements_consumed, original_position); if (this->show_log_) {
ESP_LOGV(TAG, "No progress parsing element %d at position %zu, aborting to avoid infinite loop",
elements_consumed, original_position);
}
return false; return false;
} }
} }
@ -321,7 +335,8 @@ bool DlmsParser::try_match_patterns_(uint8_t elem_idx) {
return false; return false;
} }
bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat, uint8_t &elements_consumed_at_level0) { bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat,
uint8_t &elements_consumed_at_level0) {
AxdrCaptures cap{}; AxdrCaptures cap{};
elements_consumed_at_level0 = 0; elements_consumed_at_level0 = 0;
uint8_t level = 0; uint8_t level = 0;
@ -400,10 +415,16 @@ bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &p
void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c) { void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c) {
if (!c.obis || !this->callback_) return; if (!c.obis || !this->callback_) return;
std::string obis_str = this->obis_to_string_(c.obis); // Use stack-allocated buffer for OBIS to avoid heap allocation
char obis_str_buf[32];
this->obis_to_string_(c.obis, obis_str_buf, sizeof(obis_str_buf));
float raw_val_f = this->data_as_float_(c.value_type, c.value_ptr, c.value_len); float raw_val_f = this->data_as_float_(c.value_type, c.value_ptr, c.value_len);
float val_f = raw_val_f; float val_f = raw_val_f;
std::string val_s = this->data_as_string_(c.value_type, c.value_ptr, c.value_len);
// Use stack-allocated buffer for formatting data
char val_s_buf[128];
this->data_to_string_(c.value_type, c.value_ptr, c.value_len, val_s_buf, sizeof(val_s_buf));
bool is_numeric = (c.value_type != DLMS_DATA_TYPE_OCTET_STRING && bool is_numeric = (c.value_type != DLMS_DATA_TYPE_OCTET_STRING &&
c.value_type != DLMS_DATA_TYPE_STRING && c.value_type != DLMS_DATA_TYPE_STRING &&
@ -417,7 +438,7 @@ void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptur
ESP_LOGD(TAG, "Pattern match '%s' at idx %u ===============", pat.name.c_str(), c.elem_idx); ESP_LOGD(TAG, "Pattern match '%s' at idx %u ===============", pat.name.c_str(), c.elem_idx);
uint16_t cid = c.class_id ? c.class_id : pat.default_class_id; uint16_t cid = c.class_id ? c.class_id : pat.default_class_id;
ESP_LOGI(TAG, "Found attribute descriptor: class_id=%d, obis=%s", cid, obis_str.c_str()); ESP_LOGI(TAG, "Found attribute descriptor: class_id=%d, obis=%s", cid, obis_str_buf);
if (c.has_scaler_unit) { if (c.has_scaler_unit) {
ESP_LOGI(TAG, "Value type: %s, len %d, scaler %d, unit %d", ESP_LOGI(TAG, "Value type: %s, len %d, scaler %d, unit %d",
@ -427,9 +448,11 @@ void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptur
} }
if (c.value_ptr && c.value_len > 0) { if (c.value_ptr && c.value_len > 0) {
ESP_LOGI(TAG, " as hex dump : %s", esphome::format_hex_pretty(c.value_ptr, c.value_len).c_str()); char hex_buf[512];
esphome::format_hex_pretty_to(hex_buf, sizeof(hex_buf), c.value_ptr, c.value_len);
ESP_LOGI(TAG, " as hex dump : %s", hex_buf);
} }
ESP_LOGI(TAG, " as string :'%s'", val_s.c_str()); ESP_LOGI(TAG, " as string :'%s'", val_s_buf);
ESP_LOGI(TAG, " as number : %f", raw_val_f); ESP_LOGI(TAG, " as number : %f", raw_val_f);
if (c.has_scaler_unit && is_numeric) { if (c.has_scaler_unit && is_numeric) {
@ -437,7 +460,7 @@ void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptur
} }
} }
this->callback_(obis_str, val_f, val_s, is_numeric); this->callback_(obis_str_buf, val_f, val_s_buf, is_numeric);
this->objects_found_++; this->objects_found_++;
} }
@ -445,7 +468,9 @@ float DlmsParser::data_as_float_(DlmsDataType value_type, const uint8_t *ptr, ui
if (!ptr || len == 0) return 0.0f; if (!ptr || len == 0) return 0.0f;
auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); }; auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); };
auto be32 = [](const uint8_t *p) { return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; }; auto be32 = [](const uint8_t *p) {
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
};
auto be64 = [](const uint8_t *p) { auto be64 = [](const uint8_t *p) {
return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) | return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) |
((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | ((uint64_t)p[6] << 8) | (uint64_t)p[7]; ((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) | ((uint64_t)p[6] << 8) | (uint64_t)p[7];
@ -481,20 +506,24 @@ float DlmsParser::data_as_float_(DlmsDataType value_type, const uint8_t *ptr, ui
} }
} }
std::string DlmsParser::data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len) { void DlmsParser::data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len,
if (!ptr || len == 0) return ""; char *buffer, size_t max_len) {
if (max_len > 0) buffer[0] = '\0';
if (!ptr || len == 0 || max_len == 0) return;
auto hex_of = [](const uint8_t *p, uint8_t l) { auto hex_of = [](const uint8_t *p, uint8_t l, char *out, size_t max_out) {
std::ostringstream ss; if (max_out == 0) return;
ss << std::hex << std::setfill('0'); out[0] = '\0';
for (uint8_t i = 0; i < l; i++) { size_t pos = 0;
ss << std::setw(2) << static_cast<int>(p[i]); for (uint8_t i = 0; i < l && pos + 2 < max_out; i++) {
pos += snprintf(out + pos, max_out - pos, "%02x", p[i]);
} }
return ss.str();
}; };
auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); }; auto be16 = [](const uint8_t *p) { return (uint16_t)((p[0] << 8) | p[1]); };
auto be32 = [](const uint8_t *p) { return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3]; }; auto be32 = [](const uint8_t *p) {
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
};
auto be64 = [](const uint8_t *p) { auto be64 = [](const uint8_t *p) {
uint64_t v = 0; uint64_t v = 0;
for (int i = 0; i < 8; i++) v = (v << 8) | p[i]; for (int i = 0; i < 8; i++) v = (v << 8) | p[i];
@ -504,58 +533,70 @@ std::string DlmsParser::data_as_string_(DlmsDataType value_type, const uint8_t *
switch (value_type) { switch (value_type) {
case DLMS_DATA_TYPE_OCTET_STRING: case DLMS_DATA_TYPE_OCTET_STRING:
case DLMS_DATA_TYPE_STRING: case DLMS_DATA_TYPE_STRING:
case DLMS_DATA_TYPE_STRING_UTF8: case DLMS_DATA_TYPE_STRING_UTF8: {
return std::string(reinterpret_cast<const char *>(ptr), len); size_t copy_len = std::min((size_t)len, max_len - 1);
std::memcpy(buffer, ptr, copy_len);
buffer[copy_len] = '\0';
break;
}
case DLMS_DATA_TYPE_BIT_STRING: case DLMS_DATA_TYPE_BIT_STRING:
case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL:
case DLMS_DATA_TYPE_DATETIME: case DLMS_DATA_TYPE_DATETIME:
case DLMS_DATA_TYPE_DATE: case DLMS_DATA_TYPE_DATE:
case DLMS_DATA_TYPE_TIME: case DLMS_DATA_TYPE_TIME:
return hex_of(ptr, len); hex_of(ptr, len, buffer, max_len);
break;
case DLMS_DATA_TYPE_BOOLEAN: case DLMS_DATA_TYPE_BOOLEAN:
case DLMS_DATA_TYPE_ENUM: case DLMS_DATA_TYPE_ENUM:
case DLMS_DATA_TYPE_UINT8: case DLMS_DATA_TYPE_UINT8:
return std::to_string(static_cast<unsigned>(ptr[0])); snprintf(buffer, max_len, "%u", static_cast<unsigned>(ptr[0]));
break;
case DLMS_DATA_TYPE_INT8: case DLMS_DATA_TYPE_INT8:
return std::to_string(static_cast<int>(static_cast<int8_t>(ptr[0]))); snprintf(buffer, max_len, "%d", static_cast<int>(static_cast<int8_t>(ptr[0])));
break;
case DLMS_DATA_TYPE_UINT16: case DLMS_DATA_TYPE_UINT16:
return len >= 2 ? std::to_string(be16(ptr)) : ""; if (len >= 2) snprintf(buffer, max_len, "%u", be16(ptr));
break;
case DLMS_DATA_TYPE_INT16: case DLMS_DATA_TYPE_INT16:
return len >= 2 ? std::to_string(static_cast<int16_t>(be16(ptr))) : ""; if (len >= 2) snprintf(buffer, max_len, "%d", static_cast<int16_t>(be16(ptr)));
break;
case DLMS_DATA_TYPE_UINT32: case DLMS_DATA_TYPE_UINT32:
return len >= 4 ? std::to_string(be32(ptr)) : ""; if (len >= 4) snprintf(buffer, max_len, "%lu", (unsigned long)be32(ptr));
break;
case DLMS_DATA_TYPE_INT32: case DLMS_DATA_TYPE_INT32:
return len >= 4 ? std::to_string(static_cast<int32_t>(be32(ptr))) : ""; if (len >= 4) snprintf(buffer, max_len, "%ld", (long)static_cast<int32_t>(be32(ptr)));
break;
case DLMS_DATA_TYPE_UINT64: case DLMS_DATA_TYPE_UINT64:
return len >= 8 ? std::to_string(be64(ptr)) : ""; if (len >= 8) snprintf(buffer, max_len, "%llu", (unsigned long long)be64(ptr));
break;
case DLMS_DATA_TYPE_INT64: case DLMS_DATA_TYPE_INT64:
return len >= 8 ? std::to_string(static_cast<int64_t>(be64(ptr))) : ""; if (len >= 8) snprintf(buffer, max_len, "%lld", (long long)static_cast<int64_t>(be64(ptr)));
break;
case DLMS_DATA_TYPE_FLOAT32: case DLMS_DATA_TYPE_FLOAT32:
case DLMS_DATA_TYPE_FLOAT64: { case DLMS_DATA_TYPE_FLOAT64: {
std::ostringstream ss; snprintf(buffer, max_len, "%f", this->data_as_float_(value_type, ptr, len));
ss << this->data_as_float_(value_type, ptr, len); break;
return ss.str();
} }
default: default:
return ""; break;
} }
} }
std::string DlmsParser::obis_to_string_(const uint8_t *obis) { void DlmsParser::obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len) {
char buf[32]; if (max_len > 0) buffer[0] = '\0';
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]); if (!obis || max_len == 0) return;
return std::string(buf); snprintf(buffer, max_len, "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]);
} }
const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) { const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) {
@ -598,7 +639,7 @@ void DlmsParser::register_pattern_dsl_(const std::string &name, const std::strin
return s.substr(b, e - b + 1); return s.substr(b, e - b + 1);
}; };
std::list<std::string> tokens; std::vector<std::string> tokens;
std::string current; std::string current;
int paren = 0; int paren = 0;
for (char c : dsl) { for (char c : dsl) {
@ -617,8 +658,8 @@ void DlmsParser::register_pattern_dsl_(const std::string &name, const std::strin
} }
if (!current.empty()) tokens.push_back(trim(current)); if (!current.empty()) tokens.push_back(trim(current));
for (auto it = tokens.begin(); it != tokens.end(); ++it) { for (size_t i = 0; i < tokens.size(); i++) {
std::string tok = *it; std::string tok = tokens[i];
if (tok.empty()) continue; if (tok.empty()) continue;
if (tok == "F") pat.steps.push_back({AxdrTokenType::EXPECT_TO_BE_FIRST}); if (tok == "F") pat.steps.push_back({AxdrTokenType::EXPECT_TO_BE_FIRST});
@ -649,7 +690,7 @@ void DlmsParser::register_pattern_dsl_(const std::string &name, const std::strin
size_t r = tok.rfind(')'); size_t r = tok.rfind(')');
if (l != std::string::npos && r != std::string::npos && r > l + 1) { if (l != std::string::npos && r != std::string::npos && r > l + 1) {
std::string inner = tok.substr(l + 1, r - l - 1); std::string inner = tok.substr(l + 1, r - l - 1);
std::list<std::string> inner_tokens; std::vector<std::string> inner_tokens;
std::string cur; std::string cur;
for (char c2 : inner) { for (char c2 : inner) {
if (c2 == ',') { if (c2 == ',') {
@ -663,9 +704,9 @@ void DlmsParser::register_pattern_dsl_(const std::string &name, const std::strin
if (!inner_tokens.empty()) { if (!inner_tokens.empty()) {
pat.steps.push_back({AxdrTokenType::EXPECT_STRUCTURE_N, static_cast<uint8_t>(inner_tokens.size())}); pat.steps.push_back({AxdrTokenType::EXPECT_STRUCTURE_N, static_cast<uint8_t>(inner_tokens.size())});
inner_tokens.push_front("DN"); inner_tokens.insert(inner_tokens.begin(), "DN");
inner_tokens.push_back("UP"); inner_tokens.push_back("UP");
tokens.insert(std::next(it), inner_tokens.begin(), inner_tokens.end()); tokens.insert(tokens.begin() + i + 1, inner_tokens.begin(), inner_tokens.end());
} }
} }
} }

View File

@ -4,7 +4,6 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
namespace esphome { namespace esphome {
namespace dlms_push { namespace dlms_push {
@ -37,7 +36,8 @@ enum DlmsDataType : uint8_t {
}; };
// Callback for the hub: OBIS code (e.g. "1.0.1.8.0.255"), numeric value, string value, is_numeric flag // Callback for the hub: OBIS code (e.g. "1.0.1.8.0.255"), numeric value, string value, is_numeric flag
using DlmsDataCallback = std::function<void(const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric)>; using DlmsDataCallback = std::function<void(const char *obis_code, float float_val, const char *str_val,
bool is_numeric)>;
// --- Pattern Matching Enums & Structs --- // --- Pattern Matching Enums & Structs ---
enum class AxdrTokenType : uint8_t { enum class AxdrTokenType : uint8_t {
@ -113,8 +113,8 @@ class DlmsParser {
void emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c); void emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c);
float data_as_float_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len); float data_as_float_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len);
std::string data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len); void data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len, char *buffer, size_t max_len);
std::string obis_to_string_(const uint8_t *obis); void obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len);
const char *dlms_data_type_to_string_(DlmsDataType vt); const char *dlms_data_type_to_string_(DlmsDataType vt);
const uint8_t *buffer_{nullptr}; const uint8_t *buffer_{nullptr};

View File

@ -2,6 +2,7 @@
#include "dlms_parser.h" #include "dlms_parser.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
namespace esphome { namespace esphome {
@ -10,7 +11,7 @@ namespace dlms_push {
static const char *const TAG = "dlms_push"; static const char *const TAG = "dlms_push";
DlmsPushComponent::DlmsPushComponent() { DlmsPushComponent::DlmsPushComponent() {
this->parser_ = new DlmsParser(); this->parser_ = std::make_unique<DlmsParser>();
} }
void DlmsPushComponent::setup() { void DlmsPushComponent::setup() {
@ -57,7 +58,7 @@ void DlmsPushComponent::dump_config() {
void DlmsPushComponent::loop() { void DlmsPushComponent::loop() {
this->read_rx_buffer_(); this->read_rx_buffer_();
if (this->receiving_ && (millis() - this->last_rx_char_time_ > this->receive_timeout_ms_)) { if (this->receiving_ && (App.get_loop_component_start_time()-this->last_rx_char_time_ > this->receive_timeout_ms_)) {
this->receiving_ = false; this->receiving_ = false;
this->process_frame_(); this->process_frame_();
} }
@ -68,7 +69,7 @@ void DlmsPushComponent::read_rx_buffer_() {
if (available == 0) return; if (available == 0) return;
this->receiving_ = true; this->receiving_ = true;
this->last_rx_char_time_ = millis(); this->last_rx_char_time_ = App.get_loop_component_start_time();
while (this->available()) { while (this->available()) {
if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) { if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) {
@ -95,20 +96,21 @@ void DlmsPushComponent::process_frame_() {
ESP_LOGD(TAG, "PUSH frame size: %zu bytes", this->rx_buffer_len_); ESP_LOGD(TAG, "PUSH frame size: %zu bytes", this->rx_buffer_len_);
} }
auto callback = [this](const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric) { auto callback = [this](const char *obis_code, float float_val, const char *str_val, bool is_numeric) {
this->on_data_parsed_(obis_code, float_val, str_val, is_numeric); this->on_data_parsed_(obis_code, float_val, str_val, is_numeric);
}; };
size_t parsed_objects = this->parser_->parse(this->rx_buffer_.get(), this->rx_buffer_len_, callback, this->show_log_); size_t parsed_objects = this->parser_->parse(this->rx_buffer_.get(), this->rx_buffer_len_, callback, this->show_log_);
if (this->show_log_) { if (this->show_log_) {
ESP_LOGD(TAG, "PUSH data parsing complete: %zu objects, bytes consumed %zu/%zu", parsed_objects, this->rx_buffer_len_, this->rx_buffer_len_); ESP_LOGD(TAG, "PUSH data parsing complete: %zu objects, bytes consumed %zu/%zu", parsed_objects,
this->rx_buffer_len_, this->rx_buffer_len_);
} }
this->rx_buffer_len_ = 0; this->rx_buffer_len_ = 0;
} }
void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric) { void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val, const char *str_val, bool is_numeric) {
int updated_count = 0; int updated_count = 0;
#ifdef USE_SENSOR #ifdef USE_SENSOR
@ -116,7 +118,7 @@ void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float floa
for (const auto &entry : this->sensors_) { for (const auto &entry : this->sensors_) {
if (entry.obis == obis_code) { if (entry.obis == obis_code) {
if (this->show_log_) { if (this->show_log_) {
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), entry.sensor->get_name().c_str()); ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code, entry.sensor->get_name().c_str());
ESP_LOGD(TAG, "Publishing data"); ESP_LOGD(TAG, "Publishing data");
} }
entry.sensor->publish_state(float_val); entry.sensor->publish_state(float_val);
@ -130,7 +132,7 @@ void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float floa
for (const auto &entry : this->text_sensors_) { for (const auto &entry : this->text_sensors_) {
if (entry.obis == obis_code) { if (entry.obis == obis_code) {
if (this->show_log_) { if (this->show_log_) {
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), entry.sensor->get_name().c_str()); ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code, entry.sensor->get_name().c_str());
ESP_LOGD(TAG, "Publishing data"); ESP_LOGD(TAG, "Publishing data");
} }
entry.sensor->publish_state(str_val); entry.sensor->publish_state(str_val);
@ -145,7 +147,7 @@ void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float floa
for (const auto &entry : this->binary_sensors_) { for (const auto &entry : this->binary_sensors_) {
if (entry.obis == obis_code) { if (entry.obis == obis_code) {
if (this->show_log_) { if (this->show_log_) {
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), entry.sensor->get_name().c_str()); ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code, entry.sensor->get_name().c_str());
ESP_LOGD(TAG, "Publishing data"); ESP_LOGD(TAG, "Publishing data");
} }
entry.sensor->publish_state(state); entry.sensor->publish_state(state);
@ -156,7 +158,7 @@ void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float floa
#endif #endif
if (this->show_log_ && updated_count == 0) { if (this->show_log_ && updated_count == 0) {
ESP_LOGV(TAG, "Received OBIS %s, but no sensors are registered for it.", obis_code.c_str()); ESP_LOGV(TAG, "Received OBIS %s, but no sensors are registered for it.", obis_code);
} }
} }

View File

@ -14,9 +14,9 @@
#endif #endif
#include <vector> #include <vector>
#include <map>
#include <string> #include <string>
#include <array> #include <array>
#include <memory>
namespace esphome { namespace esphome {
namespace dlms_push { namespace dlms_push {
@ -50,7 +50,7 @@ class DlmsPushComponent : public Component, public uart::UARTDevice {
void read_rx_buffer_(); void read_rx_buffer_();
void process_frame_(); void process_frame_();
void on_data_parsed_(const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric); void on_data_parsed_(const char *obis_code, float float_val, const char *str_val, bool is_numeric);
uint32_t receive_timeout_ms_{50}; uint32_t receive_timeout_ms_{50};
bool show_log_{false}; bool show_log_{false};
@ -62,7 +62,7 @@ class DlmsPushComponent : public Component, public uart::UARTDevice {
uint32_t last_rx_char_time_{0}; uint32_t last_rx_char_time_{0};
bool receiving_{false}; bool receiving_{false};
DlmsParser *parser_{nullptr}; std::unique_ptr<DlmsParser> parser_;
#ifdef USE_SENSOR #ifdef USE_SENSOR
struct NumericSensorEntry { struct NumericSensorEntry {