mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	SML runtime optimizations (#8571)
This commit is contained in:
		| @@ -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); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user