SML runtime optimizations (#8571)

This commit is contained in:
Marius Greuel 2025-04-15 21:58:14 +02:00 committed by GitHub
parent bc56d319b5
commit 7e133171e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 37 deletions

View File

@ -52,9 +52,8 @@ void Sml::loop() {
break; break;
// remove start/end sequence // remove start/end sequence
this->sml_data_.erase(this->sml_data_.begin(), this->sml_data_.begin() + START_SEQ.size()); this->process_sml_file_(
this->sml_data_.resize(this->sml_data_.size() - 8); BytesView(this->sml_data_).subview(START_SEQ.size(), this->sml_data_.size() - START_SEQ.size() - 8));
this->process_sml_file_(this->sml_data_);
} }
break; break;
}; };
@ -66,8 +65,8 @@ void Sml::add_on_data_callback(std::function<void(std::vector<uint8_t>, bool)> &
this->data_callbacks_.add(std::move(callback)); this->data_callbacks_.add(std::move(callback));
} }
void Sml::process_sml_file_(const bytes &sml_data) { void Sml::process_sml_file_(const BytesView &sml_data) {
SmlFile sml_file = SmlFile(sml_data); SmlFile sml_file(sml_data);
std::vector<ObisInfo> obis_info = sml_file.get_obis_info(); std::vector<ObisInfo> obis_info = sml_file.get_obis_info();
this->publish_obis_info_(obis_info); this->publish_obis_info_(obis_info);
@ -75,6 +74,7 @@ void Sml::process_sml_file_(const bytes &sml_data) {
} }
void Sml::log_obis_info_(const std::vector<ObisInfo> &obis_info_vec) { void Sml::log_obis_info_(const std::vector<ObisInfo> &obis_info_vec) {
#ifdef ESPHOME_LOG_HAS_DEBUG
ESP_LOGD(TAG, "OBIS info:"); ESP_LOGD(TAG, "OBIS info:");
for (auto const &obis_info : obis_info_vec) { for (auto const &obis_info : obis_info_vec) {
std::string info; std::string info;
@ -83,6 +83,7 @@ void Sml::log_obis_info_(const std::vector<ObisInfo> &obis_info_vec) {
info += " [0x" + bytes_repr(obis_info.value) + "]"; info += " [0x" + bytes_repr(obis_info.value) + "]";
ESP_LOGD(TAG, "%s", info.c_str()); ESP_LOGD(TAG, "%s", info.c_str());
} }
#endif
} }
void Sml::publish_obis_info_(const std::vector<ObisInfo> &obis_info_vec) { void Sml::publish_obis_info_(const std::vector<ObisInfo> &obis_info_vec) {
@ -92,10 +93,11 @@ void Sml::publish_obis_info_(const std::vector<ObisInfo> &obis_info_vec) {
} }
void Sml::publish_value_(const ObisInfo &obis_info) { void Sml::publish_value_(const ObisInfo &obis_info) {
const auto obis_code = obis_info.code_repr();
for (auto const &sml_listener : sml_listeners_) { for (auto const &sml_listener : sml_listeners_) {
if ((!sml_listener->server_id.empty()) && (bytes_repr(obis_info.server_id) != sml_listener->server_id)) if ((!sml_listener->server_id.empty()) && (bytes_repr(obis_info.server_id) != sml_listener->server_id))
continue; continue;
if (obis_info.code_repr() != sml_listener->obis_code) if (obis_code != sml_listener->obis_code)
continue; continue;
sml_listener->publish_val(obis_info); sml_listener->publish_val(obis_info);
} }

View File

@ -27,7 +27,7 @@ class Sml : public Component, public uart::UARTDevice {
void add_on_data_callback(std::function<void(std::vector<uint8_t>, bool)> &&callback); void add_on_data_callback(std::function<void(std::vector<uint8_t>, bool)> &&callback);
protected: protected:
void process_sml_file_(const bytes &sml_data); void process_sml_file_(const BytesView &sml_data);
void log_obis_info_(const std::vector<ObisInfo> &obis_info_vec); void log_obis_info_(const std::vector<ObisInfo> &obis_info_vec);
void publish_obis_info_(const std::vector<ObisInfo> &obis_info_vec); void publish_obis_info_(const std::vector<ObisInfo> &obis_info_vec);
char check_start_end_bytes_(uint8_t byte); char check_start_end_bytes_(uint8_t byte);

View File

@ -5,17 +5,17 @@
namespace esphome { namespace esphome {
namespace sml { namespace sml {
SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) { SmlFile::SmlFile(const BytesView &buffer) : buffer_(buffer) {
// extract messages // extract messages
this->pos_ = 0; this->pos_ = 0;
while (this->pos_ < this->buffer_.size()) { while (this->pos_ < this->buffer_.size()) {
if (this->buffer_[this->pos_] == 0x00) if (this->buffer_[this->pos_] == 0x00)
break; // EndOfSmlMsg break; // EndOfSmlMsg
SmlNode message = SmlNode(); SmlNode message;
if (!this->setup_node(&message)) if (!this->setup_node(&message))
break; break;
this->messages.emplace_back(message); this->messages.emplace_back(std::move(message));
} }
} }
@ -62,22 +62,20 @@ bool SmlFile::setup_node(SmlNode *node) {
return false; return false;
node->type = type; node->type = type;
node->nodes.clear();
node->value_bytes.clear();
if (type == SML_LIST) { if (type == SML_LIST) {
node->nodes.reserve(length); node->nodes.reserve(length);
for (size_t i = 0; i != length; i++) { for (size_t i = 0; i != length; i++) {
SmlNode child_node = SmlNode(); SmlNode child_node;
if (!this->setup_node(&child_node)) if (!this->setup_node(&child_node))
return false; return false;
node->nodes.emplace_back(child_node); node->nodes.emplace_back(std::move(child_node));
} }
} else { } else {
// Value starts at the current position // Value starts at the current position
// Value ends "length" bytes later, // Value ends "length" bytes later,
// (since the TL field is counted but already subtracted from length) // (since the TL field is counted but already subtracted from length)
node->value_bytes = bytes(this->buffer_.begin() + this->pos_, this->buffer_.begin() + this->pos_ + length); node->value_bytes = buffer_.subview(this->pos_, length);
// Increment the pointer past all consumed bytes // Increment the pointer past all consumed bytes
this->pos_ += length; this->pos_ += length;
} }
@ -87,14 +85,14 @@ bool SmlFile::setup_node(SmlNode *node) {
std::vector<ObisInfo> SmlFile::get_obis_info() { std::vector<ObisInfo> SmlFile::get_obis_info() {
std::vector<ObisInfo> obis_info; std::vector<ObisInfo> obis_info;
for (auto const &message : messages) { for (auto const &message : messages) {
SmlNode message_body = message.nodes[3]; const auto &message_body = message.nodes[3];
uint16_t message_type = bytes_to_uint(message_body.nodes[0].value_bytes); uint16_t message_type = bytes_to_uint(message_body.nodes[0].value_bytes);
if (message_type != SML_GET_LIST_RES) if (message_type != SML_GET_LIST_RES)
continue; continue;
SmlNode get_list_response = message_body.nodes[1]; const auto &get_list_response = message_body.nodes[1];
bytes server_id = get_list_response.nodes[1].value_bytes; const auto &server_id = get_list_response.nodes[1].value_bytes;
SmlNode val_list = get_list_response.nodes[4]; const auto &val_list = get_list_response.nodes[4];
for (auto const &val_list_entry : val_list.nodes) { for (auto const &val_list_entry : val_list.nodes) {
obis_info.emplace_back(server_id, val_list_entry); obis_info.emplace_back(server_id, val_list_entry);
@ -103,7 +101,7 @@ std::vector<ObisInfo> SmlFile::get_obis_info() {
return obis_info; return obis_info;
} }
std::string bytes_repr(const bytes &buffer) { std::string bytes_repr(const BytesView &buffer) {
std::string repr; std::string repr;
for (auto const value : buffer) { for (auto const value : buffer) {
repr += str_sprintf("%02x", value & 0xff); repr += str_sprintf("%02x", value & 0xff);
@ -111,7 +109,7 @@ std::string bytes_repr(const bytes &buffer) {
return repr; return repr;
} }
uint64_t bytes_to_uint(const bytes &buffer) { uint64_t bytes_to_uint(const BytesView &buffer) {
uint64_t val = 0; uint64_t val = 0;
for (auto const value : buffer) { for (auto const value : buffer) {
val = (val << 8) + value; val = (val << 8) + value;
@ -119,7 +117,7 @@ uint64_t bytes_to_uint(const bytes &buffer) {
return val; return val;
} }
int64_t bytes_to_int(const bytes &buffer) { int64_t bytes_to_int(const BytesView &buffer) {
uint64_t tmp = bytes_to_uint(buffer); uint64_t tmp = bytes_to_uint(buffer);
int64_t val; int64_t val;
@ -135,14 +133,14 @@ int64_t bytes_to_int(const bytes &buffer) {
return val; return val;
} }
std::string bytes_to_string(const bytes &buffer) { return std::string(buffer.begin(), buffer.end()); } std::string bytes_to_string(const BytesView &buffer) { return std::string(buffer.begin(), buffer.end()); }
ObisInfo::ObisInfo(bytes server_id, SmlNode val_list_entry) : server_id(std::move(server_id)) { ObisInfo::ObisInfo(const BytesView &server_id, const SmlNode &val_list_entry) : server_id(server_id) {
this->code = val_list_entry.nodes[0].value_bytes; this->code = val_list_entry.nodes[0].value_bytes;
this->status = val_list_entry.nodes[1].value_bytes; this->status = val_list_entry.nodes[1].value_bytes;
this->unit = bytes_to_uint(val_list_entry.nodes[3].value_bytes); this->unit = bytes_to_uint(val_list_entry.nodes[3].value_bytes);
this->scaler = bytes_to_int(val_list_entry.nodes[4].value_bytes); this->scaler = bytes_to_int(val_list_entry.nodes[4].value_bytes);
SmlNode value_node = val_list_entry.nodes[5]; const auto &value_node = val_list_entry.nodes[5];
this->value = value_node.value_bytes; this->value = value_node.value_bytes;
this->value_type = value_node.type; this->value_type = value_node.type;
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cassert>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -11,44 +12,73 @@ namespace sml {
using bytes = std::vector<uint8_t>; using bytes = std::vector<uint8_t>;
class BytesView {
public:
BytesView() noexcept = default;
explicit BytesView(const uint8_t *first, size_t count) noexcept : data_{first}, count_{count} {}
explicit BytesView(const bytes &bytes) noexcept : data_{bytes.data()}, count_{bytes.size()} {}
size_t size() const noexcept { return count_; }
uint8_t operator[](size_t index) const noexcept {
assert(index < count_);
return data_[index];
}
BytesView subview(size_t offset, size_t count) const noexcept {
assert(offset + count <= count_);
return BytesView{data_ + offset, count};
}
const uint8_t *begin() const noexcept { return data_; }
const uint8_t *end() const noexcept { return data_ + count_; }
private:
const uint8_t *data_ = nullptr;
size_t count_ = 0;
};
class SmlNode { class SmlNode {
public: public:
uint8_t type; uint8_t type;
bytes value_bytes; BytesView value_bytes;
std::vector<SmlNode> nodes; std::vector<SmlNode> nodes;
}; };
class ObisInfo { class ObisInfo {
public: public:
ObisInfo(bytes server_id, SmlNode val_list_entry); ObisInfo(const BytesView &server_id, const SmlNode &val_list_entry);
bytes server_id; BytesView server_id;
bytes code; BytesView code;
bytes status; BytesView status;
char unit; char unit;
char scaler; char scaler;
bytes value; BytesView value;
uint16_t value_type; uint16_t value_type;
std::string code_repr() const; std::string code_repr() const;
}; };
class SmlFile { class SmlFile {
public: public:
SmlFile(bytes buffer); SmlFile(const BytesView &buffer);
bool setup_node(SmlNode *node); bool setup_node(SmlNode *node);
std::vector<SmlNode> messages; std::vector<SmlNode> messages;
std::vector<ObisInfo> get_obis_info(); std::vector<ObisInfo> get_obis_info();
protected: protected:
const bytes buffer_; const BytesView buffer_;
size_t pos_; size_t pos_;
}; };
std::string bytes_repr(const bytes &buffer); std::string bytes_repr(const BytesView &buffer);
uint64_t bytes_to_uint(const bytes &buffer); uint64_t bytes_to_uint(const BytesView &buffer);
int64_t bytes_to_int(const bytes &buffer); int64_t bytes_to_int(const BytesView &buffer);
std::string bytes_to_string(const bytes &buffer); std::string bytes_to_string(const BytesView &buffer);
} // namespace sml } // namespace sml
} // namespace esphome } // namespace esphome