Compare commits
No commits in common. "c9bbbd574ca1f637ba5263e9c07ded11816e7ee2" and "81bbd19c091ff4b650d5dfbef83ccbf866d917c6" have entirely different histories.
c9bbbd574c
...
81bbd19c09
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
@ -65,11 +66,7 @@ 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_) {
|
if (this->show_log_) ESP_LOGW(TAG, "Expected STRUCTURE or ARRAY after header, found type %02X at position %zu", start_type, this->pos_ - 1);
|
||||||
ESP_LOGW(TAG, "Expected STRUCTURE or ARRAY after header, found type %02X at position %zu",
|
|
||||||
start_type, this->pos_ - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,10 +76,7 @@ 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_) {
|
if (this->show_log_) ESP_LOGD(TAG, "Parsing completed. Processed %zu bytes, found %zu objects", this->pos_, this->objects_found_);
|
||||||
ESP_LOGD(TAG, "Parsing completed. Processed %zu bytes, found %zu objects", this->pos_, this->objects_found_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->objects_found_;
|
return this->objects_found_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,11 +250,7 @@ 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_) {
|
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");
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,11 +259,7 @@ 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_) {
|
if (this->show_log_) ESP_LOGV(TAG, "No progress parsing element %d at position %zu, aborting to avoid infinite loop", elements_consumed, original_position);
|
||||||
ESP_LOGV(TAG, "No progress parsing element %d at position %zu, aborting to avoid infinite loop",
|
|
||||||
elements_consumed, original_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -335,8 +321,7 @@ bool DlmsParser::try_match_patterns_(uint8_t elem_idx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat,
|
bool DlmsParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat, uint8_t &elements_consumed_at_level0) {
|
||||||
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;
|
||||||
|
|
@ -415,16 +400,10 @@ 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;
|
||||||
|
|
||||||
// Use stack-allocated buffer for OBIS to avoid heap allocation
|
std::string obis_str = this->obis_to_string_(c.obis);
|
||||||
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 &&
|
||||||
|
|
@ -438,7 +417,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_buf);
|
ESP_LOGI(TAG, "Found attribute descriptor: class_id=%d, obis=%s", cid, obis_str.c_str());
|
||||||
|
|
||||||
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",
|
||||||
|
|
@ -448,11 +427,9 @@ 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) {
|
||||||
char hex_buf[512];
|
ESP_LOGI(TAG, " as hex dump : %s", esphome::format_hex_pretty(c.value_ptr, c.value_len).c_str());
|
||||||
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_buf);
|
ESP_LOGI(TAG, " as string :'%s'", val_s.c_str());
|
||||||
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) {
|
||||||
|
|
@ -460,7 +437,7 @@ void DlmsParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptur
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->callback_(obis_str_buf, val_f, val_s_buf, is_numeric);
|
this->callback_(obis_str, val_f, val_s, is_numeric);
|
||||||
this->objects_found_++;
|
this->objects_found_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -468,9 +445,7 @@ 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) {
|
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]; };
|
||||||
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];
|
||||||
|
|
@ -506,24 +481,20 @@ float DlmsParser::data_as_float_(DlmsDataType value_type, const uint8_t *ptr, ui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlmsParser::data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len,
|
std::string DlmsParser::data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len) {
|
||||||
char *buffer, size_t max_len) {
|
if (!ptr || len == 0) return "";
|
||||||
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, char *out, size_t max_out) {
|
auto hex_of = [](const uint8_t *p, uint8_t l) {
|
||||||
if (max_out == 0) return;
|
std::ostringstream ss;
|
||||||
out[0] = '\0';
|
ss << std::hex << std::setfill('0');
|
||||||
size_t pos = 0;
|
for (uint8_t i = 0; i < l; i++) {
|
||||||
for (uint8_t i = 0; i < l && pos + 2 < max_out; i++) {
|
ss << std::setw(2) << static_cast<int>(p[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) {
|
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]; };
|
||||||
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];
|
||||||
|
|
@ -533,70 +504,58 @@ void DlmsParser::data_to_string_(DlmsDataType value_type, const uint8_t *ptr, ui
|
||||||
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:
|
||||||
size_t copy_len = std::min((size_t)len, max_len - 1);
|
return std::string(reinterpret_cast<const char *>(ptr), len);
|
||||||
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:
|
||||||
hex_of(ptr, len, buffer, max_len);
|
return hex_of(ptr, 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:
|
||||||
snprintf(buffer, max_len, "%u", static_cast<unsigned>(ptr[0]));
|
return std::to_string(static_cast<unsigned>(ptr[0]));
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT8:
|
case DLMS_DATA_TYPE_INT8:
|
||||||
snprintf(buffer, max_len, "%d", static_cast<int>(static_cast<int8_t>(ptr[0])));
|
return std::to_string(static_cast<int>(static_cast<int8_t>(ptr[0])));
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT16:
|
case DLMS_DATA_TYPE_UINT16:
|
||||||
if (len >= 2) snprintf(buffer, max_len, "%u", be16(ptr));
|
return len >= 2 ? std::to_string(be16(ptr)) : "";
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT16:
|
case DLMS_DATA_TYPE_INT16:
|
||||||
if (len >= 2) snprintf(buffer, max_len, "%d", static_cast<int16_t>(be16(ptr)));
|
return len >= 2 ? std::to_string(static_cast<int16_t>(be16(ptr))) : "";
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT32:
|
case DLMS_DATA_TYPE_UINT32:
|
||||||
if (len >= 4) snprintf(buffer, max_len, "%lu", (unsigned long)be32(ptr));
|
return len >= 4 ? std::to_string(be32(ptr)) : "";
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT32:
|
case DLMS_DATA_TYPE_INT32:
|
||||||
if (len >= 4) snprintf(buffer, max_len, "%ld", (long)static_cast<int32_t>(be32(ptr)));
|
return len >= 4 ? std::to_string(static_cast<int32_t>(be32(ptr))) : "";
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_UINT64:
|
case DLMS_DATA_TYPE_UINT64:
|
||||||
if (len >= 8) snprintf(buffer, max_len, "%llu", (unsigned long long)be64(ptr));
|
return len >= 8 ? std::to_string(be64(ptr)) : "";
|
||||||
break;
|
|
||||||
|
|
||||||
case DLMS_DATA_TYPE_INT64:
|
case DLMS_DATA_TYPE_INT64:
|
||||||
if (len >= 8) snprintf(buffer, max_len, "%lld", (long long)static_cast<int64_t>(be64(ptr)));
|
return len >= 8 ? std::to_string(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: {
|
||||||
snprintf(buffer, max_len, "%f", this->data_as_float_(value_type, ptr, len));
|
std::ostringstream ss;
|
||||||
break;
|
ss << this->data_as_float_(value_type, ptr, len);
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlmsParser::obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len) {
|
std::string DlmsParser::obis_to_string_(const uint8_t *obis) {
|
||||||
if (max_len > 0) buffer[0] = '\0';
|
char buf[32];
|
||||||
if (!obis || max_len == 0) return;
|
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]);
|
||||||
snprintf(buffer, max_len, "%u.%u.%u.%u.%u.%u", obis[0], obis[1], obis[2], obis[3], obis[4], obis[5]);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) {
|
const char *DlmsParser::dlms_data_type_to_string_(DlmsDataType vt) {
|
||||||
|
|
@ -639,7 +598,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::vector<std::string> tokens;
|
std::list<std::string> tokens;
|
||||||
std::string current;
|
std::string current;
|
||||||
int paren = 0;
|
int paren = 0;
|
||||||
for (char c : dsl) {
|
for (char c : dsl) {
|
||||||
|
|
@ -658,8 +617,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 (size_t i = 0; i < tokens.size(); i++) {
|
for (auto it = tokens.begin(); it != tokens.end(); ++it) {
|
||||||
std::string tok = tokens[i];
|
std::string tok = *it;
|
||||||
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});
|
||||||
|
|
@ -690,7 +649,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::vector<std::string> inner_tokens;
|
std::list<std::string> inner_tokens;
|
||||||
std::string cur;
|
std::string cur;
|
||||||
for (char c2 : inner) {
|
for (char c2 : inner) {
|
||||||
if (c2 == ',') {
|
if (c2 == ',') {
|
||||||
|
|
@ -704,9 +663,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.insert(inner_tokens.begin(), "DN");
|
inner_tokens.push_front("DN");
|
||||||
inner_tokens.push_back("UP");
|
inner_tokens.push_back("UP");
|
||||||
tokens.insert(tokens.begin() + i + 1, inner_tokens.begin(), inner_tokens.end());
|
tokens.insert(std::next(it), inner_tokens.begin(), inner_tokens.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace dlms_push {
|
namespace dlms_push {
|
||||||
|
|
@ -36,8 +37,7 @@ 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 char *obis_code, float float_val, const char *str_val,
|
using DlmsDataCallback = std::function<void(const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric)>;
|
||||||
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);
|
||||||
void data_to_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len, char *buffer, size_t max_len);
|
std::string data_as_string_(DlmsDataType value_type, const uint8_t *ptr, uint8_t len);
|
||||||
void obis_to_string_(const uint8_t *obis, char *buffer, size_t max_len);
|
std::string obis_to_string_(const uint8_t *obis);
|
||||||
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};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#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 {
|
||||||
|
|
@ -11,7 +10,7 @@ namespace dlms_push {
|
||||||
static const char *const TAG = "dlms_push";
|
static const char *const TAG = "dlms_push";
|
||||||
|
|
||||||
DlmsPushComponent::DlmsPushComponent() {
|
DlmsPushComponent::DlmsPushComponent() {
|
||||||
this->parser_ = std::make_unique<DlmsParser>();
|
this->parser_ = new DlmsParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlmsPushComponent::setup() {
|
void DlmsPushComponent::setup() {
|
||||||
|
|
@ -58,7 +57,7 @@ void DlmsPushComponent::dump_config() {
|
||||||
void DlmsPushComponent::loop() {
|
void DlmsPushComponent::loop() {
|
||||||
this->read_rx_buffer_();
|
this->read_rx_buffer_();
|
||||||
|
|
||||||
if (this->receiving_ && (App.get_loop_component_start_time()-this->last_rx_char_time_ > this->receive_timeout_ms_)) {
|
if (this->receiving_ && (millis() - this->last_rx_char_time_ > this->receive_timeout_ms_)) {
|
||||||
this->receiving_ = false;
|
this->receiving_ = false;
|
||||||
this->process_frame_();
|
this->process_frame_();
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +68,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_ = App.get_loop_component_start_time();
|
this->last_rx_char_time_ = millis();
|
||||||
|
|
||||||
while (this->available()) {
|
while (this->available()) {
|
||||||
if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) {
|
if (this->rx_buffer_len_ >= MAX_RX_BUFFER_SIZE) {
|
||||||
|
|
@ -96,21 +95,20 @@ 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 char *obis_code, float float_val, const char *str_val, bool is_numeric) {
|
auto callback = [this](const std::string &obis_code, float float_val, const std::string &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,
|
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_, this->rx_buffer_len_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->rx_buffer_len_ = 0;
|
this->rx_buffer_len_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val, const char *str_val, bool is_numeric) {
|
void DlmsPushComponent::on_data_parsed_(const std::string &obis_code, float float_val, const std::string &str_val, bool is_numeric) {
|
||||||
int updated_count = 0;
|
int updated_count = 0;
|
||||||
|
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
|
|
@ -118,7 +116,7 @@ void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val,
|
||||||
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, entry.sensor->get_name().c_str());
|
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), 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);
|
||||||
|
|
@ -132,7 +130,7 @@ void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val,
|
||||||
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, entry.sensor->get_name().c_str());
|
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), 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);
|
||||||
|
|
@ -147,7 +145,7 @@ void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val,
|
||||||
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, entry.sensor->get_name().c_str());
|
ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s'", obis_code.c_str(), 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);
|
||||||
|
|
@ -158,7 +156,7 @@ void DlmsPushComponent::on_data_parsed_(const char *obis_code, float float_val,
|
||||||
#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);
|
ESP_LOGV(TAG, "Received OBIS %s, but no sensors are registered for it.", obis_code.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 char *obis_code, float float_val, const char *str_val, bool is_numeric);
|
void on_data_parsed_(const std::string &obis_code, float float_val, const std::string &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};
|
||||||
|
|
||||||
std::unique_ptr<DlmsParser> parser_;
|
DlmsParser *parser_{nullptr};
|
||||||
|
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
struct NumericSensorEntry {
|
struct NumericSensorEntry {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue