ESPHome 2025.5.0
Loading...
Searching...
No Matches
proto.h
Go to the documentation of this file.
1#pragma once
2
4#include "esphome/core/log.h"
6
7#include <vector>
8
9#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
10#define HAS_PROTO_MESSAGE_DUMP
11#endif
12
13namespace esphome {
14namespace api {
15
18 public:
20 explicit ProtoVarInt(uint64_t value) : value_(value) {}
21
22 static optional<ProtoVarInt> parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed) {
23 if (len == 0) {
24 if (consumed != nullptr)
25 *consumed = 0;
26 return {};
27 }
28
29 // Most common case: single-byte varint (values 0-127)
30 if ((buffer[0] & 0x80) == 0) {
31 if (consumed != nullptr)
32 *consumed = 1;
33 return ProtoVarInt(buffer[0]);
34 }
35
36 // General case for multi-byte varints
37 // Since we know buffer[0]'s high bit is set, initialize with its value
38 uint64_t result = buffer[0] & 0x7F;
39 uint8_t bitpos = 7;
40
41 // Start from the second byte since we've already processed the first
42 for (uint32_t i = 1; i < len; i++) {
43 uint8_t val = buffer[i];
44 result |= uint64_t(val & 0x7F) << uint64_t(bitpos);
45 bitpos += 7;
46 if ((val & 0x80) == 0) {
47 if (consumed != nullptr)
48 *consumed = i + 1;
49 return ProtoVarInt(result);
50 }
51 }
52
53 if (consumed != nullptr)
54 *consumed = 0;
55 return {}; // Incomplete or invalid varint
56 }
57
58 uint32_t as_uint32() const { return this->value_; }
59 uint64_t as_uint64() const { return this->value_; }
60 bool as_bool() const { return this->value_; }
61 template<typename T> T as_enum() const { return static_cast<T>(this->as_uint32()); }
62 int32_t as_int32() const {
63 // Not ZigZag encoded
64 return static_cast<int32_t>(this->as_int64());
65 }
66 int64_t as_int64() const {
67 // Not ZigZag encoded
68 return static_cast<int64_t>(this->value_);
69 }
70 int32_t as_sint32() const {
71 // with ZigZag encoding
72 if (this->value_ & 1) {
73 return static_cast<int32_t>(~(this->value_ >> 1));
74 } else {
75 return static_cast<int32_t>(this->value_ >> 1);
76 }
77 }
78 int64_t as_sint64() const {
79 // with ZigZag encoding
80 if (this->value_ & 1) {
81 return static_cast<int64_t>(~(this->value_ >> 1));
82 } else {
83 return static_cast<int64_t>(this->value_ >> 1);
84 }
85 }
97 void encode_to_buffer_unchecked(uint8_t *buffer, size_t len) {
98 uint64_t val = this->value_;
99 if (val <= 0x7F) {
100 buffer[0] = val;
101 return;
102 }
103 size_t i = 0;
104 while (val && i < len) {
105 uint8_t temp = val & 0x7F;
106 val >>= 7;
107 if (val) {
108 buffer[i++] = temp | 0x80;
109 } else {
110 buffer[i++] = temp;
111 }
112 }
113 }
114 void encode(std::vector<uint8_t> &out) {
115 uint64_t val = this->value_;
116 if (val <= 0x7F) {
117 out.push_back(val);
118 return;
119 }
120 while (val) {
121 uint8_t temp = val & 0x7F;
122 val >>= 7;
123 if (val) {
124 out.push_back(temp | 0x80);
125 } else {
126 out.push_back(temp);
127 }
128 }
129 }
130
131 protected:
132 uint64_t value_;
133};
134
136 public:
137 explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {}
138 std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_); }
139 template<class C> C as_message() const {
140 auto msg = C();
141 msg.decode(this->value_, this->length_);
142 return msg;
143 }
144
145 protected:
146 const uint8_t *const value_;
147 const size_t length_;
148};
149
151 public:
152 explicit Proto32Bit(uint32_t value) : value_(value) {}
153 uint32_t as_fixed32() const { return this->value_; }
154 int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
155 float as_float() const {
156 union {
157 uint32_t raw;
158 float value;
159 } s{};
160 s.raw = this->value_;
161 return s.value;
162 }
163
164 protected:
165 const uint32_t value_;
166};
167
169 public:
170 explicit Proto64Bit(uint64_t value) : value_(value) {}
171 uint64_t as_fixed64() const { return this->value_; }
172 int64_t as_sfixed64() const { return static_cast<int64_t>(this->value_); }
173 double as_double() const {
174 union {
175 uint64_t raw;
176 double value;
177 } s{};
178 s.raw = this->value_;
179 return s.value;
180 }
181
182 protected:
183 const uint64_t value_;
184};
185
187 public:
188 ProtoWriteBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {}
189 void write(uint8_t value) { this->buffer_->push_back(value); }
190 void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); }
191 void encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); }
204 void encode_field_raw(uint32_t field_id, uint32_t type) {
205 uint32_t val = (field_id << 3) | (type & 0b111);
206 this->encode_varint_raw(val);
207 }
208 void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) {
209 if (len == 0 && !force)
210 return;
211
212 this->encode_field_raw(field_id, 2); // type 2: Length-delimited string
213 this->encode_varint_raw(len);
214 auto *data = reinterpret_cast<const uint8_t *>(string);
215 this->buffer_->insert(this->buffer_->end(), data, data + len);
216 }
217 void encode_string(uint32_t field_id, const std::string &value, bool force = false) {
218 this->encode_string(field_id, value.data(), value.size());
219 }
220 void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) {
221 this->encode_string(field_id, reinterpret_cast<const char *>(data), len, force);
222 }
223 void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) {
224 if (value == 0 && !force)
225 return;
226 this->encode_field_raw(field_id, 0); // type 0: Varint - uint32
227 this->encode_varint_raw(value);
228 }
229 void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) {
230 if (value == 0 && !force)
231 return;
232 this->encode_field_raw(field_id, 0); // type 0: Varint - uint64
233 this->encode_varint_raw(ProtoVarInt(value));
234 }
235 void encode_bool(uint32_t field_id, bool value, bool force = false) {
236 if (!value && !force)
237 return;
238 this->encode_field_raw(field_id, 0); // type 0: Varint - bool
239 this->write(0x01);
240 }
241 void encode_fixed32(uint32_t field_id, uint32_t value, bool force = false) {
242 if (value == 0 && !force)
243 return;
244
245 this->encode_field_raw(field_id, 5); // type 5: 32-bit fixed32
246 this->write((value >> 0) & 0xFF);
247 this->write((value >> 8) & 0xFF);
248 this->write((value >> 16) & 0xFF);
249 this->write((value >> 24) & 0xFF);
250 }
251 void encode_fixed64(uint32_t field_id, uint64_t value, bool force = false) {
252 if (value == 0 && !force)
253 return;
254
255 this->encode_field_raw(field_id, 1); // type 1: 64-bit fixed64
256 this->write((value >> 0) & 0xFF);
257 this->write((value >> 8) & 0xFF);
258 this->write((value >> 16) & 0xFF);
259 this->write((value >> 24) & 0xFF);
260 this->write((value >> 32) & 0xFF);
261 this->write((value >> 40) & 0xFF);
262 this->write((value >> 48) & 0xFF);
263 this->write((value >> 56) & 0xFF);
264 }
265 template<typename T> void encode_enum(uint32_t field_id, T value, bool force = false) {
266 this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
267 }
268 void encode_float(uint32_t field_id, float value, bool force = false) {
269 if (value == 0.0f && !force)
270 return;
271
272 union {
273 float value;
274 uint32_t raw;
275 } val{};
276 val.value = value;
277 this->encode_fixed32(field_id, val.raw);
278 }
279 void encode_int32(uint32_t field_id, int32_t value, bool force = false) {
280 if (value < 0) {
281 // negative int32 is always 10 byte long
282 this->encode_int64(field_id, value, force);
283 return;
284 }
285 this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
286 }
287 void encode_int64(uint32_t field_id, int64_t value, bool force = false) {
288 this->encode_uint64(field_id, static_cast<uint64_t>(value), force);
289 }
290 void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
291 uint32_t uvalue;
292 if (value < 0) {
293 uvalue = ~(value << 1);
294 } else {
295 uvalue = value << 1;
296 }
297 this->encode_uint32(field_id, uvalue, force);
298 }
299 void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
300 uint64_t uvalue;
301 if (value < 0) {
302 uvalue = ~(value << 1);
303 } else {
304 uvalue = value << 1;
305 }
306 this->encode_uint64(field_id, uvalue, force);
307 }
308 template<class C> void encode_message(uint32_t field_id, const C &value, bool force = false) {
309 this->encode_field_raw(field_id, 2); // type 2: Length-delimited message
310 size_t begin = this->buffer_->size();
311
312 value.encode(*this);
313
314 const uint32_t nested_length = this->buffer_->size() - begin;
315 // add size varint
316 std::vector<uint8_t> var;
317 ProtoVarInt(nested_length).encode(var);
318 this->buffer_->insert(this->buffer_->begin() + begin, var.begin(), var.end());
319 }
320 std::vector<uint8_t> *get_buffer() const { return buffer_; }
321
322 protected:
323 std::vector<uint8_t> *buffer_;
324};
325
327 public:
328 virtual ~ProtoMessage() = default;
329 virtual void encode(ProtoWriteBuffer buffer) const = 0;
330 void decode(const uint8_t *buffer, size_t length);
331 virtual void calculate_size(uint32_t &total_size) const = 0;
332#ifdef HAS_PROTO_MESSAGE_DUMP
333 std::string dump() const;
334 virtual void dump_to(std::string &out) const = 0;
335#endif
336
337 protected:
338 virtual bool decode_varint(uint32_t field_id, ProtoVarInt value) { return false; }
339 virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value) { return false; }
340 virtual bool decode_32bit(uint32_t field_id, Proto32Bit value) { return false; }
341 virtual bool decode_64bit(uint32_t field_id, Proto64Bit value) { return false; }
342};
343
344template<typename T> const char *proto_enum_to_string(T value);
345
347 public:
348 protected:
349 virtual bool is_authenticated() = 0;
350 virtual bool is_connection_setup() = 0;
351 virtual void on_fatal_error() = 0;
352 virtual void on_unauthenticated_access() = 0;
353 virtual void on_no_setup_connection() = 0;
361 virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
362 virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) = 0;
363 virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
364
365 // Optimized method that pre-allocates buffer based on message size
366 template<class C> bool send_message_(const C &msg, uint32_t message_type) {
367 uint32_t msg_size = 0;
368 msg.calculate_size(msg_size);
369
370 // Create a pre-sized buffer
371 auto buffer = this->create_buffer(msg_size);
372
373 // Encode message into the buffer
374 msg.encode(buffer);
375
376 // Send the buffer
377 return this->send_buffer(buffer, message_type);
378 }
379};
380
381} // namespace api
382} // namespace esphome
uint8_t raw[35]
Definition bl0939.h:0
uint32_t as_fixed32() const
Definition proto.h:153
int32_t as_sfixed32() const
Definition proto.h:154
float as_float() const
Definition proto.h:155
const uint32_t value_
Definition proto.h:165
Proto32Bit(uint32_t value)
Definition proto.h:152
Proto64Bit(uint64_t value)
Definition proto.h:170
double as_double() const
Definition proto.h:173
uint64_t as_fixed64() const
Definition proto.h:171
const uint64_t value_
Definition proto.h:183
int64_t as_sfixed64() const
Definition proto.h:172
const uint8_t *const value_
Definition proto.h:146
ProtoLengthDelimited(const uint8_t *value, size_t length)
Definition proto.h:137
std::string as_string() const
Definition proto.h:138
virtual bool decode_64bit(uint32_t field_id, Proto64Bit value)
Definition proto.h:341
virtual void calculate_size(uint32_t &total_size) const =0
virtual void encode(ProtoWriteBuffer buffer) const =0
std::string dump() const
Definition proto.cpp:84
virtual ~ProtoMessage()=default
virtual bool decode_32bit(uint32_t field_id, Proto32Bit value)
Definition proto.h:340
virtual void dump_to(std::string &out) const =0
virtual bool decode_length(uint32_t field_id, ProtoLengthDelimited value)
Definition proto.h:339
virtual bool decode_varint(uint32_t field_id, ProtoVarInt value)
Definition proto.h:338
void decode(const uint8_t *buffer, size_t length)
Definition proto.cpp:10
virtual void on_unauthenticated_access()=0
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size)=0
Create a buffer with a reserved size.
virtual void on_fatal_error()=0
virtual bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)=0
virtual bool is_connection_setup()=0
virtual bool is_authenticated()=0
virtual bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data)=0
virtual void on_no_setup_connection()=0
bool send_message_(const C &msg, uint32_t message_type)
Definition proto.h:366
Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit.
Definition proto.h:17
int32_t as_sint32() const
Definition proto.h:70
uint64_t as_uint64() const
Definition proto.h:59
void encode_to_buffer_unchecked(uint8_t *buffer, size_t len)
Encode the varint value to a pre-allocated buffer without bounds checking.
Definition proto.h:97
void encode(std::vector< uint8_t > &out)
Definition proto.h:114
int64_t as_int64() const
Definition proto.h:66
int64_t as_sint64() const
Definition proto.h:78
bool as_bool() const
Definition proto.h:60
uint32_t as_uint32() const
Definition proto.h:58
ProtoVarInt(uint64_t value)
Definition proto.h:20
int32_t as_int32() const
Definition proto.h:62
static optional< ProtoVarInt > parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed)
Definition proto.h:22
void encode_varint_raw(uint32_t value)
Definition proto.h:191
void encode_string(uint32_t field_id, const std::string &value, bool force=false)
Definition proto.h:217
void write(uint8_t value)
Definition proto.h:189
void encode_enum(uint32_t field_id, T value, bool force=false)
Definition proto.h:265
void encode_int64(uint32_t field_id, int64_t value, bool force=false)
Definition proto.h:287
void encode_float(uint32_t field_id, float value, bool force=false)
Definition proto.h:268
void encode_int32(uint32_t field_id, int32_t value, bool force=false)
Definition proto.h:279
void encode_sint64(uint32_t field_id, int64_t value, bool force=false)
Definition proto.h:299
void encode_message(uint32_t field_id, const C &value, bool force=false)
Definition proto.h:308
void encode_string(uint32_t field_id, const char *string, size_t len, bool force=false)
Definition proto.h:208
void encode_bool(uint32_t field_id, bool value, bool force=false)
Definition proto.h:235
ProtoWriteBuffer(std::vector< uint8_t > *buffer)
Definition proto.h:188
void encode_uint64(uint32_t field_id, uint64_t value, bool force=false)
Definition proto.h:229
void encode_fixed64(uint32_t field_id, uint64_t value, bool force=false)
Definition proto.h:251
void encode_uint32(uint32_t field_id, uint32_t value, bool force=false)
Definition proto.h:223
void encode_sint32(uint32_t field_id, int32_t value, bool force=false)
Definition proto.h:290
void encode_field_raw(uint32_t field_id, uint32_t type)
Encode a field key (tag/wire type combination).
Definition proto.h:204
std::vector< uint8_t > * get_buffer() const
Definition proto.h:320
void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force=false)
Definition proto.h:220
void encode_fixed32(uint32_t field_id, uint32_t value, bool force=false)
Definition proto.h:241
void encode_varint_raw(ProtoVarInt value)
Definition proto.h:190
std::vector< uint8_t > * buffer_
Definition proto.h:323
uint8_t type
mopeka_std_values val[4]
const char * proto_enum_to_string(T value)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301
uint16_t length
Definition tt21100.cpp:0