ESPHome  2023.5.5
sml_parser.cpp
Go to the documentation of this file.
1 #include "esphome/core/helpers.h"
2 #include "constants.h"
3 #include "sml_parser.h"
4 
5 namespace esphome {
6 namespace sml {
7 
8 SmlFile::SmlFile(bytes buffer) : buffer_(std::move(buffer)) {
9  // extract messages
10  this->pos_ = 0;
11  while (this->pos_ < this->buffer_.size()) {
12  if (this->buffer_[this->pos_] == 0x00)
13  break; // fill byte detected -> no more messages
14 
15  SmlNode message = SmlNode();
16  if (!this->setup_node(&message))
17  break;
18  this->messages.emplace_back(message);
19  }
20 }
21 
23  uint8_t type = this->buffer_[this->pos_] >> 4; // type including overlength info
24  uint8_t length = this->buffer_[this->pos_] & 0x0f; // length including TL bytes
25  bool is_list = (type & 0x07) == SML_LIST;
26  bool has_extended_length = type & 0x08; // we have a long list/value (>15 entries)
27  uint8_t parse_length = length;
28  if (has_extended_length) {
29  length = (length << 4) + (this->buffer_[this->pos_ + 1] & 0x0f);
30  parse_length = length - 1;
31  this->pos_ += 1;
32  }
33 
34  if (this->pos_ + parse_length >= this->buffer_.size())
35  return false;
36 
37  node->type = type & 0x07;
38  node->nodes.clear();
39  node->value_bytes.clear();
40  if (this->buffer_[this->pos_] == 0x00) { // end of message
41  this->pos_ += 1;
42  } else if (is_list) { // list
43  this->pos_ += 1;
44  node->nodes.reserve(parse_length);
45  for (size_t i = 0; i != parse_length; i++) {
46  SmlNode child_node = SmlNode();
47  if (!this->setup_node(&child_node))
48  return false;
49  node->nodes.emplace_back(child_node);
50  }
51  } else { // value
52  node->value_bytes =
53  bytes(this->buffer_.begin() + this->pos_ + 1, this->buffer_.begin() + this->pos_ + parse_length);
54  this->pos_ += parse_length;
55  }
56  return true;
57 }
58 
59 std::vector<ObisInfo> SmlFile::get_obis_info() {
60  std::vector<ObisInfo> obis_info;
61  for (auto const &message : messages) {
62  SmlNode message_body = message.nodes[3];
63  uint16_t message_type = bytes_to_uint(message_body.nodes[0].value_bytes);
64  if (message_type != SML_GET_LIST_RES)
65  continue;
66 
67  SmlNode get_list_response = message_body.nodes[1];
68  bytes server_id = get_list_response.nodes[1].value_bytes;
69  SmlNode val_list = get_list_response.nodes[4];
70 
71  for (auto const &val_list_entry : val_list.nodes) {
72  obis_info.emplace_back(server_id, val_list_entry);
73  }
74  }
75  return obis_info;
76 }
77 
78 std::string bytes_repr(const bytes &buffer) {
79  std::string repr;
80  for (auto const value : buffer) {
81  repr += str_sprintf("%02x", value & 0xff);
82  }
83  return repr;
84 }
85 
86 uint64_t bytes_to_uint(const bytes &buffer) {
87  uint64_t val = 0;
88  for (auto const value : buffer) {
89  val = (val << 8) + value;
90  }
91  return val;
92 }
93 
94 int64_t bytes_to_int(const bytes &buffer) {
95  uint64_t tmp = bytes_to_uint(buffer);
96  int64_t val;
97 
98  switch (buffer.size()) {
99  case 1: // int8
100  val = (int8_t) tmp;
101  break;
102  case 2: // int16
103  val = (int16_t) tmp;
104  break;
105  case 4: // int32
106  val = (int32_t) tmp;
107  break;
108  default: // int64
109  val = (int64_t) tmp;
110  }
111  return val;
112 }
113 
114 std::string bytes_to_string(const bytes &buffer) { return std::string(buffer.begin(), buffer.end()); }
115 
116 ObisInfo::ObisInfo(bytes server_id, SmlNode val_list_entry) : server_id(std::move(server_id)) {
117  this->code = val_list_entry.nodes[0].value_bytes;
118  this->status = val_list_entry.nodes[1].value_bytes;
119  this->unit = bytes_to_uint(val_list_entry.nodes[3].value_bytes);
120  this->scaler = bytes_to_int(val_list_entry.nodes[4].value_bytes);
121  SmlNode value_node = val_list_entry.nodes[5];
122  this->value = value_node.value_bytes;
123  this->value_type = value_node.type;
124 }
125 
126 std::string ObisInfo::code_repr() const {
127  return str_sprintf("%d-%d:%d.%d.%d", this->code[0], this->code[1], this->code[2], this->code[3], this->code[4]);
128 }
129 
130 } // namespace sml
131 } // namespace esphome
std::string bytes_repr(const bytes &buffer)
Definition: sml_parser.cpp:78
SmlFile(bytes buffer)
Definition: sml_parser.cpp:8
STL namespace.
int64_t bytes_to_int(const bytes &buffer)
Definition: sml_parser.cpp:94
mopeka_std_values val[4]
uint64_t bytes_to_uint(const bytes &buffer)
Definition: sml_parser.cpp:86
std::string bytes_to_string(const bytes &buffer)
Definition: sml_parser.cpp:114
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:214
uint8_t type
ObisInfo(bytes server_id, SmlNode val_list_entry)
Definition: sml_parser.cpp:116
std::vector< ObisInfo > get_obis_info()
Definition: sml_parser.cpp:59
Definition: a4988.cpp:4
std::vector< uint8_t > bytes
Definition: sml_parser.h:12
bool setup_node(SmlNode *node)
Definition: sml_parser.cpp:22
const bytes buffer_
Definition: sml_parser.h:42
std::string code_repr() const
Definition: sml_parser.cpp:126
std::vector< SmlNode > messages
Definition: sml_parser.h:38
std::vector< SmlNode > nodes
Definition: sml_parser.h:18