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