esphome 2025.7.0b1__py3-none-any.whl → 2025.7.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/components/api/__init__.py +19 -5
- esphome/components/api/api_connection.cpp +53 -175
- esphome/components/api/api_connection.h +28 -25
- esphome/components/api/api_frame_helper.cpp +2 -3
- esphome/components/api/api_frame_helper.h +7 -9
- esphome/components/api/api_pb2.cpp +1862 -5133
- esphome/components/api/api_pb2.h +291 -533
- esphome/components/api/api_pb2_dump.cpp +99 -0
- esphome/components/api/api_pb2_service.cpp +4 -0
- esphome/components/api/api_pb2_service.h +6 -0
- esphome/components/api/api_server.cpp +2 -9
- esphome/components/api/api_server.h +7 -33
- esphome/components/api/custom_api_device.h +8 -0
- esphome/components/api/list_entities.cpp +2 -0
- esphome/components/api/list_entities.h +3 -1
- esphome/components/api/proto.h +506 -23
- esphome/components/api/user_services.h +2 -0
- esphome/components/debug/debug_esp32.cpp +2 -0
- esphome/components/esp32/__init__.py +1 -0
- esphome/components/esp32_camera/__init__.py +1 -1
- esphome/components/esp32_touch/esp32_touch_v1.cpp +12 -10
- esphome/components/esp8266/__init__.py +1 -0
- esphome/components/host/__init__.py +1 -0
- esphome/components/ld2410/ld2410.cpp +12 -28
- esphome/components/libretiny/__init__.py +1 -0
- esphome/components/mqtt/mqtt_backend_esp32.cpp +6 -2
- esphome/components/packet_transport/packet_transport.cpp +3 -0
- esphome/components/rp2040/__init__.py +1 -0
- esphome/components/sx126x/__init__.py +3 -3
- esphome/components/sx127x/__init__.py +2 -2
- esphome/components/usb_host/usb_host_client.cpp +10 -10
- esphome/components/usb_uart/cp210x.cpp +1 -1
- esphome/components/usb_uart/usb_uart.cpp +41 -44
- esphome/components/usb_uart/usb_uart.h +4 -3
- esphome/const.py +1 -1
- esphome/core/component_iterator.cpp +4 -2
- esphome/core/component_iterator.h +3 -3
- esphome/core/defines.h +1 -1
- esphome/core/entity_helpers.py +6 -0
- esphome/core/scheduler.cpp +9 -12
- esphome/core/scheduler.h +0 -3
- esphome/wizard.py +1 -1
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/METADATA +2 -2
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/RECORD +48 -49
- esphome/components/api/api_pb2_size.h +0 -359
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/WHEEL +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.7.0b1.dist-info → esphome-2025.7.0b2.dist-info}/top_level.txt +0 -0
esphome/components/api/proto.h
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include "esphome/core/helpers.h"
|
|
5
5
|
#include "esphome/core/log.h"
|
|
6
6
|
|
|
7
|
+
#include <cassert>
|
|
7
8
|
#include <vector>
|
|
8
9
|
|
|
9
10
|
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
|
@@ -59,7 +60,6 @@ class ProtoVarInt {
|
|
|
59
60
|
uint32_t as_uint32() const { return this->value_; }
|
|
60
61
|
uint64_t as_uint64() const { return this->value_; }
|
|
61
62
|
bool as_bool() const { return this->value_; }
|
|
62
|
-
template<typename T> T as_enum() const { return static_cast<T>(this->as_uint32()); }
|
|
63
63
|
int32_t as_int32() const {
|
|
64
64
|
// Not ZigZag encoded
|
|
65
65
|
return static_cast<int32_t>(this->as_int64());
|
|
@@ -133,15 +133,24 @@ class ProtoVarInt {
|
|
|
133
133
|
uint64_t value_;
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
+
// Forward declaration for decode_to_message and encode_to_writer
|
|
137
|
+
class ProtoMessage;
|
|
138
|
+
|
|
136
139
|
class ProtoLengthDelimited {
|
|
137
140
|
public:
|
|
138
141
|
explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {}
|
|
139
142
|
std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_); }
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Decode the length-delimited data into an existing ProtoMessage instance.
|
|
146
|
+
*
|
|
147
|
+
* This method allows decoding without templates, enabling use in contexts
|
|
148
|
+
* where the message type is not known at compile time. The ProtoMessage's
|
|
149
|
+
* decode() method will be called with the raw data and length.
|
|
150
|
+
*
|
|
151
|
+
* @param msg The ProtoMessage instance to decode into
|
|
152
|
+
*/
|
|
153
|
+
void decode_to_message(ProtoMessage &msg) const;
|
|
145
154
|
|
|
146
155
|
protected:
|
|
147
156
|
const uint8_t *const value_;
|
|
@@ -263,9 +272,6 @@ class ProtoWriteBuffer {
|
|
|
263
272
|
this->write((value >> 48) & 0xFF);
|
|
264
273
|
this->write((value >> 56) & 0xFF);
|
|
265
274
|
}
|
|
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
275
|
void encode_float(uint32_t field_id, float value, bool force = false) {
|
|
270
276
|
if (value == 0.0f && !force)
|
|
271
277
|
return;
|
|
@@ -306,18 +312,7 @@ class ProtoWriteBuffer {
|
|
|
306
312
|
}
|
|
307
313
|
this->encode_uint64(field_id, uvalue, force);
|
|
308
314
|
}
|
|
309
|
-
|
|
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
|
-
}
|
|
315
|
+
void encode_message(uint32_t field_id, const ProtoMessage &value, bool force = false);
|
|
321
316
|
std::vector<uint8_t> *get_buffer() const { return buffer_; }
|
|
322
317
|
|
|
323
318
|
protected:
|
|
@@ -345,6 +340,494 @@ class ProtoMessage {
|
|
|
345
340
|
virtual bool decode_64bit(uint32_t field_id, Proto64Bit value) { return false; }
|
|
346
341
|
};
|
|
347
342
|
|
|
343
|
+
class ProtoSize {
|
|
344
|
+
public:
|
|
345
|
+
/**
|
|
346
|
+
* @brief ProtoSize class for Protocol Buffer serialization size calculation
|
|
347
|
+
*
|
|
348
|
+
* This class provides static methods to calculate the exact byte counts needed
|
|
349
|
+
* for encoding various Protocol Buffer field types. All methods are designed to be
|
|
350
|
+
* efficient for the common case where many fields have default values.
|
|
351
|
+
*
|
|
352
|
+
* Implements Protocol Buffer encoding size calculation according to:
|
|
353
|
+
* https://protobuf.dev/programming-guides/encoding/
|
|
354
|
+
*
|
|
355
|
+
* Key features:
|
|
356
|
+
* - Early-return optimization for zero/default values
|
|
357
|
+
* - Direct total_size updates to avoid unnecessary additions
|
|
358
|
+
* - Specialized handling for different field types according to protobuf spec
|
|
359
|
+
* - Templated helpers for repeated fields and messages
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @brief Calculates the size in bytes needed to encode a uint32_t value as a varint
|
|
364
|
+
*
|
|
365
|
+
* @param value The uint32_t value to calculate size for
|
|
366
|
+
* @return The number of bytes needed to encode the value
|
|
367
|
+
*/
|
|
368
|
+
static inline uint32_t varint(uint32_t value) {
|
|
369
|
+
// Optimized varint size calculation using leading zeros
|
|
370
|
+
// Each 7 bits requires one byte in the varint encoding
|
|
371
|
+
if (value < 128)
|
|
372
|
+
return 1; // 7 bits, common case for small values
|
|
373
|
+
|
|
374
|
+
// For larger values, count bytes needed based on the position of the highest bit set
|
|
375
|
+
if (value < 16384) {
|
|
376
|
+
return 2; // 14 bits
|
|
377
|
+
} else if (value < 2097152) {
|
|
378
|
+
return 3; // 21 bits
|
|
379
|
+
} else if (value < 268435456) {
|
|
380
|
+
return 4; // 28 bits
|
|
381
|
+
} else {
|
|
382
|
+
return 5; // 32 bits (maximum for uint32_t)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @brief Calculates the size in bytes needed to encode a uint64_t value as a varint
|
|
388
|
+
*
|
|
389
|
+
* @param value The uint64_t value to calculate size for
|
|
390
|
+
* @return The number of bytes needed to encode the value
|
|
391
|
+
*/
|
|
392
|
+
static inline uint32_t varint(uint64_t value) {
|
|
393
|
+
// Handle common case of values fitting in uint32_t (vast majority of use cases)
|
|
394
|
+
if (value <= UINT32_MAX) {
|
|
395
|
+
return varint(static_cast<uint32_t>(value));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// For larger values, determine size based on highest bit position
|
|
399
|
+
if (value < (1ULL << 35)) {
|
|
400
|
+
return 5; // 35 bits
|
|
401
|
+
} else if (value < (1ULL << 42)) {
|
|
402
|
+
return 6; // 42 bits
|
|
403
|
+
} else if (value < (1ULL << 49)) {
|
|
404
|
+
return 7; // 49 bits
|
|
405
|
+
} else if (value < (1ULL << 56)) {
|
|
406
|
+
return 8; // 56 bits
|
|
407
|
+
} else if (value < (1ULL << 63)) {
|
|
408
|
+
return 9; // 63 bits
|
|
409
|
+
} else {
|
|
410
|
+
return 10; // 64 bits (maximum for uint64_t)
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* @brief Calculates the size in bytes needed to encode an int32_t value as a varint
|
|
416
|
+
*
|
|
417
|
+
* Special handling is needed for negative values, which are sign-extended to 64 bits
|
|
418
|
+
* in Protocol Buffers, resulting in a 10-byte varint.
|
|
419
|
+
*
|
|
420
|
+
* @param value The int32_t value to calculate size for
|
|
421
|
+
* @return The number of bytes needed to encode the value
|
|
422
|
+
*/
|
|
423
|
+
static inline uint32_t varint(int32_t value) {
|
|
424
|
+
// Negative values are sign-extended to 64 bits in protocol buffers,
|
|
425
|
+
// which always results in a 10-byte varint for negative int32
|
|
426
|
+
if (value < 0) {
|
|
427
|
+
return 10; // Negative int32 is always 10 bytes long
|
|
428
|
+
}
|
|
429
|
+
// For non-negative values, use the uint32_t implementation
|
|
430
|
+
return varint(static_cast<uint32_t>(value));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* @brief Calculates the size in bytes needed to encode an int64_t value as a varint
|
|
435
|
+
*
|
|
436
|
+
* @param value The int64_t value to calculate size for
|
|
437
|
+
* @return The number of bytes needed to encode the value
|
|
438
|
+
*/
|
|
439
|
+
static inline uint32_t varint(int64_t value) {
|
|
440
|
+
// For int64_t, we convert to uint64_t and calculate the size
|
|
441
|
+
// This works because the bit pattern determines the encoding size,
|
|
442
|
+
// and we've handled negative int32 values as a special case above
|
|
443
|
+
return varint(static_cast<uint64_t>(value));
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* @brief Calculates the size in bytes needed to encode a field ID and wire type
|
|
448
|
+
*
|
|
449
|
+
* @param field_id The field identifier
|
|
450
|
+
* @param type The wire type value (from the WireType enum in the protobuf spec)
|
|
451
|
+
* @return The number of bytes needed to encode the field ID and wire type
|
|
452
|
+
*/
|
|
453
|
+
static inline uint32_t field(uint32_t field_id, uint32_t type) {
|
|
454
|
+
uint32_t tag = (field_id << 3) | (type & 0b111);
|
|
455
|
+
return varint(tag);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @brief Common parameters for all add_*_field methods
|
|
460
|
+
*
|
|
461
|
+
* All add_*_field methods follow these common patterns:
|
|
462
|
+
*
|
|
463
|
+
* @param total_size Reference to the total message size to update
|
|
464
|
+
* @param field_id_size Pre-calculated size of the field ID in bytes
|
|
465
|
+
* @param value The value to calculate size for (type varies)
|
|
466
|
+
* @param force Whether to calculate size even if the value is default/zero/empty
|
|
467
|
+
*
|
|
468
|
+
* Each method follows this implementation pattern:
|
|
469
|
+
* 1. Skip calculation if value is default (0, false, empty) and not forced
|
|
470
|
+
* 2. Calculate the size based on the field's encoding rules
|
|
471
|
+
* 3. Add the field_id_size + calculated value size to total_size
|
|
472
|
+
*/
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* @brief Calculates and adds the size of an int32 field to the total message size
|
|
476
|
+
*/
|
|
477
|
+
static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
|
478
|
+
// Skip calculation if value is zero
|
|
479
|
+
if (value == 0) {
|
|
480
|
+
return; // No need to update total_size
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Calculate and directly add to total_size
|
|
484
|
+
if (value < 0) {
|
|
485
|
+
// Negative values are encoded as 10-byte varints in protobuf
|
|
486
|
+
total_size += field_id_size + 10;
|
|
487
|
+
} else {
|
|
488
|
+
// For non-negative values, use the standard varint size
|
|
489
|
+
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* @brief Calculates and adds the size of an int32 field to the total message size (repeated field version)
|
|
495
|
+
*/
|
|
496
|
+
static inline void add_int32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
|
497
|
+
// Always calculate size for repeated fields
|
|
498
|
+
if (value < 0) {
|
|
499
|
+
// Negative values are encoded as 10-byte varints in protobuf
|
|
500
|
+
total_size += field_id_size + 10;
|
|
501
|
+
} else {
|
|
502
|
+
// For non-negative values, use the standard varint size
|
|
503
|
+
total_size += field_id_size + varint(static_cast<uint32_t>(value));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* @brief Calculates and adds the size of a uint32 field to the total message size
|
|
509
|
+
*/
|
|
510
|
+
static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
|
511
|
+
// Skip calculation if value is zero
|
|
512
|
+
if (value == 0) {
|
|
513
|
+
return; // No need to update total_size
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Calculate and directly add to total_size
|
|
517
|
+
total_size += field_id_size + varint(value);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @brief Calculates and adds the size of a uint32 field to the total message size (repeated field version)
|
|
522
|
+
*/
|
|
523
|
+
static inline void add_uint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
|
524
|
+
// Always calculate size for repeated fields
|
|
525
|
+
total_size += field_id_size + varint(value);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* @brief Calculates and adds the size of a boolean field to the total message size
|
|
530
|
+
*/
|
|
531
|
+
static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
|
532
|
+
// Skip calculation if value is false
|
|
533
|
+
if (!value) {
|
|
534
|
+
return; // No need to update total_size
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Boolean fields always use 1 byte when true
|
|
538
|
+
total_size += field_id_size + 1;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* @brief Calculates and adds the size of a boolean field to the total message size (repeated field version)
|
|
543
|
+
*/
|
|
544
|
+
static inline void add_bool_field_repeated(uint32_t &total_size, uint32_t field_id_size, bool value) {
|
|
545
|
+
// Always calculate size for repeated fields
|
|
546
|
+
// Boolean fields always use 1 byte
|
|
547
|
+
total_size += field_id_size + 1;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* @brief Calculates and adds the size of a fixed field to the total message size
|
|
552
|
+
*
|
|
553
|
+
* Fixed fields always take exactly N bytes (4 for fixed32/float, 8 for fixed64/double).
|
|
554
|
+
*
|
|
555
|
+
* @tparam NumBytes The number of bytes for this fixed field (4 or 8)
|
|
556
|
+
* @param is_nonzero Whether the value is non-zero
|
|
557
|
+
*/
|
|
558
|
+
template<uint32_t NumBytes>
|
|
559
|
+
static inline void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero) {
|
|
560
|
+
// Skip calculation if value is zero
|
|
561
|
+
if (!is_nonzero) {
|
|
562
|
+
return; // No need to update total_size
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Fixed fields always take exactly NumBytes
|
|
566
|
+
total_size += field_id_size + NumBytes;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* @brief Calculates and adds the size of an enum field to the total message size
|
|
571
|
+
*
|
|
572
|
+
* Enum fields are encoded as uint32 varints.
|
|
573
|
+
*/
|
|
574
|
+
static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
|
575
|
+
// Skip calculation if value is zero
|
|
576
|
+
if (value == 0) {
|
|
577
|
+
return; // No need to update total_size
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Enums are encoded as uint32
|
|
581
|
+
total_size += field_id_size + varint(value);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* @brief Calculates and adds the size of an enum field to the total message size (repeated field version)
|
|
586
|
+
*
|
|
587
|
+
* Enum fields are encoded as uint32 varints.
|
|
588
|
+
*/
|
|
589
|
+
static inline void add_enum_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) {
|
|
590
|
+
// Always calculate size for repeated fields
|
|
591
|
+
// Enums are encoded as uint32
|
|
592
|
+
total_size += field_id_size + varint(value);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* @brief Calculates and adds the size of a sint32 field to the total message size
|
|
597
|
+
*
|
|
598
|
+
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
|
599
|
+
*/
|
|
600
|
+
static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
|
601
|
+
// Skip calculation if value is zero
|
|
602
|
+
if (value == 0) {
|
|
603
|
+
return; // No need to update total_size
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
|
607
|
+
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
|
608
|
+
total_size += field_id_size + varint(zigzag);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* @brief Calculates and adds the size of a sint32 field to the total message size (repeated field version)
|
|
613
|
+
*
|
|
614
|
+
* Sint32 fields use ZigZag encoding, which is more efficient for negative values.
|
|
615
|
+
*/
|
|
616
|
+
static inline void add_sint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) {
|
|
617
|
+
// Always calculate size for repeated fields
|
|
618
|
+
// ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
|
|
619
|
+
uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
|
|
620
|
+
total_size += field_id_size + varint(zigzag);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* @brief Calculates and adds the size of an int64 field to the total message size
|
|
625
|
+
*/
|
|
626
|
+
static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
|
627
|
+
// Skip calculation if value is zero
|
|
628
|
+
if (value == 0) {
|
|
629
|
+
return; // No need to update total_size
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Calculate and directly add to total_size
|
|
633
|
+
total_size += field_id_size + varint(value);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* @brief Calculates and adds the size of an int64 field to the total message size (repeated field version)
|
|
638
|
+
*/
|
|
639
|
+
static inline void add_int64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
|
640
|
+
// Always calculate size for repeated fields
|
|
641
|
+
total_size += field_id_size + varint(value);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* @brief Calculates and adds the size of a uint64 field to the total message size
|
|
646
|
+
*/
|
|
647
|
+
static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
|
648
|
+
// Skip calculation if value is zero
|
|
649
|
+
if (value == 0) {
|
|
650
|
+
return; // No need to update total_size
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Calculate and directly add to total_size
|
|
654
|
+
total_size += field_id_size + varint(value);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* @brief Calculates and adds the size of a uint64 field to the total message size (repeated field version)
|
|
659
|
+
*/
|
|
660
|
+
static inline void add_uint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint64_t value) {
|
|
661
|
+
// Always calculate size for repeated fields
|
|
662
|
+
total_size += field_id_size + varint(value);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* @brief Calculates and adds the size of a sint64 field to the total message size
|
|
667
|
+
*
|
|
668
|
+
* Sint64 fields use ZigZag encoding, which is more efficient for negative values.
|
|
669
|
+
*/
|
|
670
|
+
static inline void add_sint64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
|
671
|
+
// Skip calculation if value is zero
|
|
672
|
+
if (value == 0) {
|
|
673
|
+
return; // No need to update total_size
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// ZigZag encoding for sint64: (n << 1) ^ (n >> 63)
|
|
677
|
+
uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63));
|
|
678
|
+
total_size += field_id_size + varint(zigzag);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* @brief Calculates and adds the size of a sint64 field to the total message size (repeated field version)
|
|
683
|
+
*
|
|
684
|
+
* Sint64 fields use ZigZag encoding, which is more efficient for negative values.
|
|
685
|
+
*/
|
|
686
|
+
static inline void add_sint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) {
|
|
687
|
+
// Always calculate size for repeated fields
|
|
688
|
+
// ZigZag encoding for sint64: (n << 1) ^ (n >> 63)
|
|
689
|
+
uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63));
|
|
690
|
+
total_size += field_id_size + varint(zigzag);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* @brief Calculates and adds the size of a string/bytes field to the total message size
|
|
695
|
+
*/
|
|
696
|
+
static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str) {
|
|
697
|
+
// Skip calculation if string is empty
|
|
698
|
+
if (str.empty()) {
|
|
699
|
+
return; // No need to update total_size
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Calculate and directly add to total_size
|
|
703
|
+
const uint32_t str_size = static_cast<uint32_t>(str.size());
|
|
704
|
+
total_size += field_id_size + varint(str_size) + str_size;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* @brief Calculates and adds the size of a string/bytes field to the total message size (repeated field version)
|
|
709
|
+
*/
|
|
710
|
+
static inline void add_string_field_repeated(uint32_t &total_size, uint32_t field_id_size, const std::string &str) {
|
|
711
|
+
// Always calculate size for repeated fields
|
|
712
|
+
const uint32_t str_size = static_cast<uint32_t>(str.size());
|
|
713
|
+
total_size += field_id_size + varint(str_size) + str_size;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* @brief Calculates and adds the size of a nested message field to the total message size
|
|
718
|
+
*
|
|
719
|
+
* This helper function directly updates the total_size reference if the nested size
|
|
720
|
+
* is greater than zero.
|
|
721
|
+
*
|
|
722
|
+
* @param nested_size The pre-calculated size of the nested message
|
|
723
|
+
*/
|
|
724
|
+
static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
|
725
|
+
// Skip calculation if nested message is empty
|
|
726
|
+
if (nested_size == 0) {
|
|
727
|
+
return; // No need to update total_size
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// Calculate and directly add to total_size
|
|
731
|
+
// Field ID + length varint + nested message content
|
|
732
|
+
total_size += field_id_size + varint(nested_size) + nested_size;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
|
737
|
+
*
|
|
738
|
+
* @param nested_size The pre-calculated size of the nested message
|
|
739
|
+
*/
|
|
740
|
+
static inline void add_message_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) {
|
|
741
|
+
// Always calculate size for repeated fields
|
|
742
|
+
// Field ID + length varint + nested message content
|
|
743
|
+
total_size += field_id_size + varint(nested_size) + nested_size;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* @brief Calculates and adds the size of a nested message field to the total message size
|
|
748
|
+
*
|
|
749
|
+
* This version takes a ProtoMessage object, calculates its size internally,
|
|
750
|
+
* and updates the total_size reference. This eliminates the need for a temporary variable
|
|
751
|
+
* at the call site.
|
|
752
|
+
*
|
|
753
|
+
* @param message The nested message object
|
|
754
|
+
*/
|
|
755
|
+
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message) {
|
|
756
|
+
uint32_t nested_size = 0;
|
|
757
|
+
message.calculate_size(nested_size);
|
|
758
|
+
|
|
759
|
+
// Use the base implementation with the calculated nested_size
|
|
760
|
+
add_message_field(total_size, field_id_size, nested_size);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* @brief Calculates and adds the size of a nested message field to the total message size (repeated field version)
|
|
765
|
+
*
|
|
766
|
+
* @param message The nested message object
|
|
767
|
+
*/
|
|
768
|
+
static inline void add_message_object_repeated(uint32_t &total_size, uint32_t field_id_size,
|
|
769
|
+
const ProtoMessage &message) {
|
|
770
|
+
uint32_t nested_size = 0;
|
|
771
|
+
message.calculate_size(nested_size);
|
|
772
|
+
|
|
773
|
+
// Use the base implementation with the calculated nested_size
|
|
774
|
+
add_message_field_repeated(total_size, field_id_size, nested_size);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* @brief Calculates and adds the sizes of all messages in a repeated field to the total message size
|
|
779
|
+
*
|
|
780
|
+
* This helper processes a vector of message objects, calculating the size for each message
|
|
781
|
+
* and adding it to the total size.
|
|
782
|
+
*
|
|
783
|
+
* @tparam MessageType The type of the nested messages in the vector
|
|
784
|
+
* @param messages Vector of message objects
|
|
785
|
+
*/
|
|
786
|
+
template<typename MessageType>
|
|
787
|
+
static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size,
|
|
788
|
+
const std::vector<MessageType> &messages) {
|
|
789
|
+
// Skip if the vector is empty
|
|
790
|
+
if (messages.empty()) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Use the repeated field version for all messages
|
|
795
|
+
for (const auto &message : messages) {
|
|
796
|
+
add_message_object_repeated(total_size, field_id_size, message);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
// Implementation of encode_message - must be after ProtoMessage is defined
|
|
802
|
+
inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessage &value, bool force) {
|
|
803
|
+
this->encode_field_raw(field_id, 2); // type 2: Length-delimited message
|
|
804
|
+
|
|
805
|
+
// Calculate the message size first
|
|
806
|
+
uint32_t msg_length_bytes = 0;
|
|
807
|
+
value.calculate_size(msg_length_bytes);
|
|
808
|
+
|
|
809
|
+
// Calculate how many bytes the length varint needs
|
|
810
|
+
uint32_t varint_length_bytes = ProtoSize::varint(msg_length_bytes);
|
|
811
|
+
|
|
812
|
+
// Reserve exact space for the length varint
|
|
813
|
+
size_t begin = this->buffer_->size();
|
|
814
|
+
this->buffer_->resize(this->buffer_->size() + varint_length_bytes);
|
|
815
|
+
|
|
816
|
+
// Write the length varint directly
|
|
817
|
+
ProtoVarInt(msg_length_bytes).encode_to_buffer_unchecked(this->buffer_->data() + begin, varint_length_bytes);
|
|
818
|
+
|
|
819
|
+
// Now encode the message content - it will append to the buffer
|
|
820
|
+
value.encode(*this);
|
|
821
|
+
|
|
822
|
+
// Verify that the encoded size matches what we calculated
|
|
823
|
+
assert(this->buffer_->size() == begin + varint_length_bytes + msg_length_bytes);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Implementation of decode_to_message - must be after ProtoMessage is defined
|
|
827
|
+
inline void ProtoLengthDelimited::decode_to_message(ProtoMessage &msg) const {
|
|
828
|
+
msg.decode(this->value_, this->length_);
|
|
829
|
+
}
|
|
830
|
+
|
|
348
831
|
template<typename T> const char *proto_enum_to_string(T value);
|
|
349
832
|
|
|
350
833
|
class ProtoService {
|
|
@@ -363,11 +846,11 @@ class ProtoService {
|
|
|
363
846
|
* @return A ProtoWriteBuffer object with the reserved size.
|
|
364
847
|
*/
|
|
365
848
|
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
|
|
366
|
-
virtual bool send_buffer(ProtoWriteBuffer buffer,
|
|
849
|
+
virtual bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) = 0;
|
|
367
850
|
virtual void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
|
|
368
851
|
|
|
369
852
|
// Optimized method that pre-allocates buffer based on message size
|
|
370
|
-
bool send_message_(const ProtoMessage &msg,
|
|
853
|
+
bool send_message_(const ProtoMessage &msg, uint8_t message_type) {
|
|
371
854
|
uint32_t msg_size = 0;
|
|
372
855
|
msg.calculate_size(msg_size);
|
|
373
856
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include "esphome/core/automation.h"
|
|
8
8
|
#include "api_pb2.h"
|
|
9
9
|
|
|
10
|
+
#ifdef USE_API_SERVICES
|
|
10
11
|
namespace esphome {
|
|
11
12
|
namespace api {
|
|
12
13
|
|
|
@@ -73,3 +74,4 @@ template<typename... Ts> class UserServiceTrigger : public UserServiceBase<Ts...
|
|
|
73
74
|
|
|
74
75
|
} // namespace api
|
|
75
76
|
} // namespace esphome
|
|
77
|
+
#endif // USE_API_SERVICES
|
|
@@ -53,6 +53,7 @@ void DebugComponent::on_shutdown() {
|
|
|
53
53
|
auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
|
|
54
54
|
if (component != nullptr) {
|
|
55
55
|
strncpy(buffer, component->get_component_source(), REBOOT_MAX_LEN - 1);
|
|
56
|
+
buffer[REBOOT_MAX_LEN - 1] = '\0';
|
|
56
57
|
}
|
|
57
58
|
ESP_LOGD(TAG, "Storing reboot source: %s", buffer);
|
|
58
59
|
pref.save(&buffer);
|
|
@@ -68,6 +69,7 @@ std::string DebugComponent::get_reset_reason_() {
|
|
|
68
69
|
auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
|
|
69
70
|
char buffer[REBOOT_MAX_LEN]{};
|
|
70
71
|
if (pref.load(&buffer)) {
|
|
72
|
+
buffer[REBOOT_MAX_LEN - 1] = '\0';
|
|
71
73
|
reset_reason = "Reboot request from " + std::string(buffer);
|
|
72
74
|
}
|
|
73
75
|
}
|
|
@@ -707,6 +707,7 @@ async def to_code(config):
|
|
|
707
707
|
cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[config[CONF_VARIANT]])
|
|
708
708
|
|
|
709
709
|
cg.add_platformio_option("lib_ldf_mode", "off")
|
|
710
|
+
cg.add_platformio_option("lib_compat_mode", "strict")
|
|
710
711
|
|
|
711
712
|
framework_ver: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]
|
|
712
713
|
|
|
@@ -308,7 +308,7 @@ async def to_code(config):
|
|
|
308
308
|
cg.add(var.set_frame_buffer_count(config[CONF_FRAME_BUFFER_COUNT]))
|
|
309
309
|
cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
|
|
310
310
|
|
|
311
|
-
cg.add_define("
|
|
311
|
+
cg.add_define("USE_CAMERA")
|
|
312
312
|
|
|
313
313
|
if CORE.using_esp_idf:
|
|
314
314
|
add_idf_component(name="espressif/esp32-camera", ref="2.0.15")
|
|
@@ -109,6 +109,7 @@ void ESP32TouchComponent::loop() {
|
|
|
109
109
|
|
|
110
110
|
// Only publish if state changed - this filters out repeated events
|
|
111
111
|
if (new_state != child->last_state_) {
|
|
112
|
+
child->initial_state_published_ = true;
|
|
112
113
|
child->last_state_ = new_state;
|
|
113
114
|
child->publish_state(new_state);
|
|
114
115
|
// Original ESP32: ISR only fires when touched, release is detected by timeout
|
|
@@ -175,6 +176,9 @@ void ESP32TouchComponent::on_shutdown() {
|
|
|
175
176
|
void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|
176
177
|
ESP32TouchComponent *component = static_cast<ESP32TouchComponent *>(arg);
|
|
177
178
|
|
|
179
|
+
uint32_t mask = 0;
|
|
180
|
+
touch_ll_read_trigger_status_mask(&mask);
|
|
181
|
+
touch_ll_clear_trigger_status_mask();
|
|
178
182
|
touch_pad_clear_status();
|
|
179
183
|
|
|
180
184
|
// INTERRUPT BEHAVIOR: On ESP32 v1 hardware, the interrupt fires when ANY configured
|
|
@@ -184,6 +188,11 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|
|
184
188
|
// as any pad remains touched. This allows us to detect both new touches and
|
|
185
189
|
// continued touches, but releases must be detected by timeout in the main loop.
|
|
186
190
|
|
|
191
|
+
// IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2!
|
|
192
|
+
// ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE
|
|
193
|
+
// Therefore: touched = (value < threshold)
|
|
194
|
+
// This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold)
|
|
195
|
+
|
|
187
196
|
// Process all configured pads to check their current state
|
|
188
197
|
// Note: ESP32 v1 doesn't tell us which specific pad triggered the interrupt,
|
|
189
198
|
// so we must scan all configured pads to find which ones were touched
|
|
@@ -201,19 +210,12 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|
|
201
210
|
value = touch_ll_read_raw_data(pad);
|
|
202
211
|
}
|
|
203
212
|
|
|
204
|
-
// Skip pads
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (value == 0) {
|
|
213
|
+
// Skip pads that aren’t in the trigger mask
|
|
214
|
+
bool is_touched = (mask >> pad) & 1;
|
|
215
|
+
if (!is_touched) {
|
|
208
216
|
continue;
|
|
209
217
|
}
|
|
210
218
|
|
|
211
|
-
// IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2!
|
|
212
|
-
// ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE
|
|
213
|
-
// Therefore: touched = (value < threshold)
|
|
214
|
-
// This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold)
|
|
215
|
-
bool is_touched = value < child->get_threshold();
|
|
216
|
-
|
|
217
219
|
// Always send the current state - the main loop will filter for changes
|
|
218
220
|
// We send both touched and untouched states because the ISR doesn't
|
|
219
221
|
// track previous state (to keep ISR fast and simple)
|
|
@@ -180,6 +180,7 @@ async def to_code(config):
|
|
|
180
180
|
cg.add(esp8266_ns.setup_preferences())
|
|
181
181
|
|
|
182
182
|
cg.add_platformio_option("lib_ldf_mode", "off")
|
|
183
|
+
cg.add_platformio_option("lib_compat_mode", "strict")
|
|
183
184
|
|
|
184
185
|
cg.add_platformio_option("board", config[CONF_BOARD])
|
|
185
186
|
cg.add_build_flag("-DUSE_ESP8266")
|