mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'encode_perf' into integration
This commit is contained in:
		| @@ -5,7 +5,6 @@ | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "proto.h" | ||||
| #include "api_pb2_size.h" | ||||
| #include <cstring> | ||||
| #include <cinttypes> | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| // This file was automatically generated with a tool. | ||||
| // See script/api_protobuf/api_protobuf.py | ||||
| #include "api_pb2.h" | ||||
| #include "api_pb2_size.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| #include "esphome/core/defines.h" | ||||
|  | ||||
| #include "proto.h" | ||||
| #include "api_pb2_size.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace api { | ||||
|   | ||||
| @@ -1,469 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "proto.h" | ||||
| #include <cstdint> | ||||
| #include <string> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace api { | ||||
|  | ||||
| class ProtoSize { | ||||
|  public: | ||||
|   /** | ||||
|    * @brief ProtoSize class for Protocol Buffer serialization size calculation | ||||
|    * | ||||
|    * This class provides static methods to calculate the exact byte counts needed | ||||
|    * for encoding various Protocol Buffer field types. All methods are designed to be | ||||
|    * efficient for the common case where many fields have default values. | ||||
|    * | ||||
|    * Implements Protocol Buffer encoding size calculation according to: | ||||
|    * https://protobuf.dev/programming-guides/encoding/ | ||||
|    * | ||||
|    * Key features: | ||||
|    * - Early-return optimization for zero/default values | ||||
|    * - Direct total_size updates to avoid unnecessary additions | ||||
|    * - Specialized handling for different field types according to protobuf spec | ||||
|    * - Templated helpers for repeated fields and messages | ||||
|    */ | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a uint32_t value as a varint | ||||
|    * | ||||
|    * @param value The uint32_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(uint32_t value) { | ||||
|     // Optimized varint size calculation using leading zeros | ||||
|     // Each 7 bits requires one byte in the varint encoding | ||||
|     if (value < 128) | ||||
|       return 1;  // 7 bits, common case for small values | ||||
|  | ||||
|     // For larger values, count bytes needed based on the position of the highest bit set | ||||
|     if (value < 16384) { | ||||
|       return 2;  // 14 bits | ||||
|     } else if (value < 2097152) { | ||||
|       return 3;  // 21 bits | ||||
|     } else if (value < 268435456) { | ||||
|       return 4;  // 28 bits | ||||
|     } else { | ||||
|       return 5;  // 32 bits (maximum for uint32_t) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a uint64_t value as a varint | ||||
|    * | ||||
|    * @param value The uint64_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(uint64_t value) { | ||||
|     // Handle common case of values fitting in uint32_t (vast majority of use cases) | ||||
|     if (value <= UINT32_MAX) { | ||||
|       return varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|  | ||||
|     // For larger values, determine size based on highest bit position | ||||
|     if (value < (1ULL << 35)) { | ||||
|       return 5;  // 35 bits | ||||
|     } else if (value < (1ULL << 42)) { | ||||
|       return 6;  // 42 bits | ||||
|     } else if (value < (1ULL << 49)) { | ||||
|       return 7;  // 49 bits | ||||
|     } else if (value < (1ULL << 56)) { | ||||
|       return 8;  // 56 bits | ||||
|     } else if (value < (1ULL << 63)) { | ||||
|       return 9;  // 63 bits | ||||
|     } else { | ||||
|       return 10;  // 64 bits (maximum for uint64_t) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode an int32_t value as a varint | ||||
|    * | ||||
|    * Special handling is needed for negative values, which are sign-extended to 64 bits | ||||
|    * in Protocol Buffers, resulting in a 10-byte varint. | ||||
|    * | ||||
|    * @param value The int32_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(int32_t value) { | ||||
|     // Negative values are sign-extended to 64 bits in protocol buffers, | ||||
|     // which always results in a 10-byte varint for negative int32 | ||||
|     if (value < 0) { | ||||
|       return 10;  // Negative int32 is always 10 bytes long | ||||
|     } | ||||
|     // For non-negative values, use the uint32_t implementation | ||||
|     return varint(static_cast<uint32_t>(value)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode an int64_t value as a varint | ||||
|    * | ||||
|    * @param value The int64_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(int64_t value) { | ||||
|     // For int64_t, we convert to uint64_t and calculate the size | ||||
|     // This works because the bit pattern determines the encoding size, | ||||
|     // and we've handled negative int32 values as a special case above | ||||
|     return varint(static_cast<uint64_t>(value)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a field ID and wire type | ||||
|    * | ||||
|    * @param field_id The field identifier | ||||
|    * @param type The wire type value (from the WireType enum in the protobuf spec) | ||||
|    * @return The number of bytes needed to encode the field ID and wire type | ||||
|    */ | ||||
|   static inline uint32_t field(uint32_t field_id, uint32_t type) { | ||||
|     uint32_t tag = (field_id << 3) | (type & 0b111); | ||||
|     return varint(tag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Common parameters for all add_*_field methods | ||||
|    * | ||||
|    * All add_*_field methods follow these common patterns: | ||||
|    * | ||||
|    * @param total_size Reference to the total message size to update | ||||
|    * @param field_id_size Pre-calculated size of the field ID in bytes | ||||
|    * @param value The value to calculate size for (type varies) | ||||
|    * @param force Whether to calculate size even if the value is default/zero/empty | ||||
|    * | ||||
|    * Each method follows this implementation pattern: | ||||
|    * 1. Skip calculation if value is default (0, false, empty) and not forced | ||||
|    * 2. Calculate the size based on the field's encoding rules | ||||
|    * 3. Add the field_id_size + calculated value size to total_size | ||||
|    */ | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int32 field to the total message size | ||||
|    */ | ||||
|   static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     if (value < 0) { | ||||
|       // Negative values are encoded as 10-byte varints in protobuf | ||||
|       total_size += field_id_size + 10; | ||||
|     } else { | ||||
|       // For non-negative values, use the standard varint size | ||||
|       total_size += field_id_size + varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int32 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_int32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     if (value < 0) { | ||||
|       // Negative values are encoded as 10-byte varints in protobuf | ||||
|       total_size += field_id_size + 10; | ||||
|     } else { | ||||
|       // For non-negative values, use the standard varint size | ||||
|       total_size += field_id_size + varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint32 field to the total message size | ||||
|    */ | ||||
|   static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint32 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_uint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a boolean field to the total message size | ||||
|    */ | ||||
|   static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value) { | ||||
|     // Skip calculation if value is false | ||||
|     if (!value) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Boolean fields always use 1 byte when true | ||||
|     total_size += field_id_size + 1; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a boolean field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_bool_field_repeated(uint32_t &total_size, uint32_t field_id_size, bool value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Boolean fields always use 1 byte | ||||
|     total_size += field_id_size + 1; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a fixed field to the total message size | ||||
|    * | ||||
|    * Fixed fields always take exactly N bytes (4 for fixed32/float, 8 for fixed64/double). | ||||
|    * | ||||
|    * @tparam NumBytes The number of bytes for this fixed field (4 or 8) | ||||
|    * @param is_nonzero Whether the value is non-zero | ||||
|    */ | ||||
|   template<uint32_t NumBytes> | ||||
|   static inline void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (!is_nonzero) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Fixed fields always take exactly NumBytes | ||||
|     total_size += field_id_size + NumBytes; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an enum field to the total message size | ||||
|    * | ||||
|    * Enum fields are encoded as uint32 varints. | ||||
|    */ | ||||
|   static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Enums are encoded as uint32 | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an enum field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Enum fields are encoded as uint32 varints. | ||||
|    */ | ||||
|   static inline void add_enum_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Enums are encoded as uint32 | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint32 field to the total message size | ||||
|    * | ||||
|    * Sint32 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // ZigZag encoding for sint32: (n << 1) ^ (n >> 31) | ||||
|     uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint32 field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Sint32 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // ZigZag encoding for sint32: (n << 1) ^ (n >> 31) | ||||
|     uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int64 field to the total message size | ||||
|    */ | ||||
|   static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int64 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_int64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint64 field to the total message size | ||||
|    */ | ||||
|   static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint64 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_uint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint64 field to the total message size | ||||
|    * | ||||
|    * Sint64 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // ZigZag encoding for sint64: (n << 1) ^ (n >> 63) | ||||
|     uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint64 field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Sint64 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // ZigZag encoding for sint64: (n << 1) ^ (n >> 63) | ||||
|     uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a string/bytes field to the total message size | ||||
|    */ | ||||
|   static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str) { | ||||
|     // Skip calculation if string is empty | ||||
|     if (str.empty()) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     const uint32_t str_size = static_cast<uint32_t>(str.size()); | ||||
|     total_size += field_id_size + varint(str_size) + str_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a string/bytes field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_string_field_repeated(uint32_t &total_size, uint32_t field_id_size, const std::string &str) { | ||||
|     // Always calculate size for repeated fields | ||||
|     const uint32_t str_size = static_cast<uint32_t>(str.size()); | ||||
|     total_size += field_id_size + varint(str_size) + str_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size | ||||
|    * | ||||
|    * This helper function directly updates the total_size reference if the nested size | ||||
|    * is greater than zero. | ||||
|    * | ||||
|    * @param nested_size The pre-calculated size of the nested message | ||||
|    */ | ||||
|   static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) { | ||||
|     // Skip calculation if nested message is empty | ||||
|     if (nested_size == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     // Field ID + length varint + nested message content | ||||
|     total_size += field_id_size + varint(nested_size) + nested_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size (repeated field version) | ||||
|    * | ||||
|    * @param nested_size The pre-calculated size of the nested message | ||||
|    */ | ||||
|   static inline void add_message_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Field ID + length varint + nested message content | ||||
|     total_size += field_id_size + varint(nested_size) + nested_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size | ||||
|    * | ||||
|    * This version takes a ProtoMessage object, calculates its size internally, | ||||
|    * and updates the total_size reference. This eliminates the need for a temporary variable | ||||
|    * at the call site. | ||||
|    * | ||||
|    * @param message The nested message object | ||||
|    */ | ||||
|   static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message) { | ||||
|     uint32_t nested_size = 0; | ||||
|     message.calculate_size(nested_size); | ||||
|  | ||||
|     // Use the base implementation with the calculated nested_size | ||||
|     add_message_field(total_size, field_id_size, nested_size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size (repeated field version) | ||||
|    * | ||||
|    * @param message The nested message object | ||||
|    */ | ||||
|   static inline void add_message_object_repeated(uint32_t &total_size, uint32_t field_id_size, | ||||
|                                                  const ProtoMessage &message) { | ||||
|     uint32_t nested_size = 0; | ||||
|     message.calculate_size(nested_size); | ||||
|  | ||||
|     // Use the base implementation with the calculated nested_size | ||||
|     add_message_field_repeated(total_size, field_id_size, nested_size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the sizes of all messages in a repeated field to the total message size | ||||
|    * | ||||
|    * This helper processes a vector of message objects, calculating the size for each message | ||||
|    * and adding it to the total size. | ||||
|    * | ||||
|    * @tparam MessageType The type of the nested messages in the vector | ||||
|    * @param messages Vector of message objects | ||||
|    */ | ||||
|   template<typename MessageType> | ||||
|   static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size, | ||||
|                                           const std::vector<MessageType> &messages) { | ||||
|     // Skip if the vector is empty | ||||
|     if (messages.empty()) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     // Use the repeated field version for all messages | ||||
|     for (const auto &message : messages) { | ||||
|       add_message_object_repeated(total_size, field_id_size, message); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace api | ||||
| }  // namespace esphome | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| #include <cassert> | ||||
| #include <vector> | ||||
|  | ||||
| #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE | ||||
| @@ -339,18 +340,487 @@ class ProtoMessage { | ||||
|   virtual bool decode_64bit(uint32_t field_id, Proto64Bit value) { return false; } | ||||
| }; | ||||
|  | ||||
| class ProtoSize { | ||||
|  public: | ||||
|   /** | ||||
|    * @brief ProtoSize class for Protocol Buffer serialization size calculation | ||||
|    * | ||||
|    * This class provides static methods to calculate the exact byte counts needed | ||||
|    * for encoding various Protocol Buffer field types. All methods are designed to be | ||||
|    * efficient for the common case where many fields have default values. | ||||
|    * | ||||
|    * Implements Protocol Buffer encoding size calculation according to: | ||||
|    * https://protobuf.dev/programming-guides/encoding/ | ||||
|    * | ||||
|    * Key features: | ||||
|    * - Early-return optimization for zero/default values | ||||
|    * - Direct total_size updates to avoid unnecessary additions | ||||
|    * - Specialized handling for different field types according to protobuf spec | ||||
|    * - Templated helpers for repeated fields and messages | ||||
|    */ | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a uint32_t value as a varint | ||||
|    * | ||||
|    * @param value The uint32_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(uint32_t value) { | ||||
|     // Optimized varint size calculation using leading zeros | ||||
|     // Each 7 bits requires one byte in the varint encoding | ||||
|     if (value < 128) | ||||
|       return 1;  // 7 bits, common case for small values | ||||
|  | ||||
|     // For larger values, count bytes needed based on the position of the highest bit set | ||||
|     if (value < 16384) { | ||||
|       return 2;  // 14 bits | ||||
|     } else if (value < 2097152) { | ||||
|       return 3;  // 21 bits | ||||
|     } else if (value < 268435456) { | ||||
|       return 4;  // 28 bits | ||||
|     } else { | ||||
|       return 5;  // 32 bits (maximum for uint32_t) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a uint64_t value as a varint | ||||
|    * | ||||
|    * @param value The uint64_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(uint64_t value) { | ||||
|     // Handle common case of values fitting in uint32_t (vast majority of use cases) | ||||
|     if (value <= UINT32_MAX) { | ||||
|       return varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|  | ||||
|     // For larger values, determine size based on highest bit position | ||||
|     if (value < (1ULL << 35)) { | ||||
|       return 5;  // 35 bits | ||||
|     } else if (value < (1ULL << 42)) { | ||||
|       return 6;  // 42 bits | ||||
|     } else if (value < (1ULL << 49)) { | ||||
|       return 7;  // 49 bits | ||||
|     } else if (value < (1ULL << 56)) { | ||||
|       return 8;  // 56 bits | ||||
|     } else if (value < (1ULL << 63)) { | ||||
|       return 9;  // 63 bits | ||||
|     } else { | ||||
|       return 10;  // 64 bits (maximum for uint64_t) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode an int32_t value as a varint | ||||
|    * | ||||
|    * Special handling is needed for negative values, which are sign-extended to 64 bits | ||||
|    * in Protocol Buffers, resulting in a 10-byte varint. | ||||
|    * | ||||
|    * @param value The int32_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(int32_t value) { | ||||
|     // Negative values are sign-extended to 64 bits in protocol buffers, | ||||
|     // which always results in a 10-byte varint for negative int32 | ||||
|     if (value < 0) { | ||||
|       return 10;  // Negative int32 is always 10 bytes long | ||||
|     } | ||||
|     // For non-negative values, use the uint32_t implementation | ||||
|     return varint(static_cast<uint32_t>(value)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode an int64_t value as a varint | ||||
|    * | ||||
|    * @param value The int64_t value to calculate size for | ||||
|    * @return The number of bytes needed to encode the value | ||||
|    */ | ||||
|   static inline uint32_t varint(int64_t value) { | ||||
|     // For int64_t, we convert to uint64_t and calculate the size | ||||
|     // This works because the bit pattern determines the encoding size, | ||||
|     // and we've handled negative int32 values as a special case above | ||||
|     return varint(static_cast<uint64_t>(value)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates the size in bytes needed to encode a field ID and wire type | ||||
|    * | ||||
|    * @param field_id The field identifier | ||||
|    * @param type The wire type value (from the WireType enum in the protobuf spec) | ||||
|    * @return The number of bytes needed to encode the field ID and wire type | ||||
|    */ | ||||
|   static inline uint32_t field(uint32_t field_id, uint32_t type) { | ||||
|     uint32_t tag = (field_id << 3) | (type & 0b111); | ||||
|     return varint(tag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Common parameters for all add_*_field methods | ||||
|    * | ||||
|    * All add_*_field methods follow these common patterns: | ||||
|    * | ||||
|    * @param total_size Reference to the total message size to update | ||||
|    * @param field_id_size Pre-calculated size of the field ID in bytes | ||||
|    * @param value The value to calculate size for (type varies) | ||||
|    * @param force Whether to calculate size even if the value is default/zero/empty | ||||
|    * | ||||
|    * Each method follows this implementation pattern: | ||||
|    * 1. Skip calculation if value is default (0, false, empty) and not forced | ||||
|    * 2. Calculate the size based on the field's encoding rules | ||||
|    * 3. Add the field_id_size + calculated value size to total_size | ||||
|    */ | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int32 field to the total message size | ||||
|    */ | ||||
|   static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     if (value < 0) { | ||||
|       // Negative values are encoded as 10-byte varints in protobuf | ||||
|       total_size += field_id_size + 10; | ||||
|     } else { | ||||
|       // For non-negative values, use the standard varint size | ||||
|       total_size += field_id_size + varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int32 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_int32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     if (value < 0) { | ||||
|       // Negative values are encoded as 10-byte varints in protobuf | ||||
|       total_size += field_id_size + 10; | ||||
|     } else { | ||||
|       // For non-negative values, use the standard varint size | ||||
|       total_size += field_id_size + varint(static_cast<uint32_t>(value)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint32 field to the total message size | ||||
|    */ | ||||
|   static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint32 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_uint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a boolean field to the total message size | ||||
|    */ | ||||
|   static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value) { | ||||
|     // Skip calculation if value is false | ||||
|     if (!value) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Boolean fields always use 1 byte when true | ||||
|     total_size += field_id_size + 1; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a boolean field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_bool_field_repeated(uint32_t &total_size, uint32_t field_id_size, bool value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Boolean fields always use 1 byte | ||||
|     total_size += field_id_size + 1; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a fixed field to the total message size | ||||
|    * | ||||
|    * Fixed fields always take exactly N bytes (4 for fixed32/float, 8 for fixed64/double). | ||||
|    * | ||||
|    * @tparam NumBytes The number of bytes for this fixed field (4 or 8) | ||||
|    * @param is_nonzero Whether the value is non-zero | ||||
|    */ | ||||
|   template<uint32_t NumBytes> | ||||
|   static inline void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (!is_nonzero) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Fixed fields always take exactly NumBytes | ||||
|     total_size += field_id_size + NumBytes; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an enum field to the total message size | ||||
|    * | ||||
|    * Enum fields are encoded as uint32 varints. | ||||
|    */ | ||||
|   static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Enums are encoded as uint32 | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an enum field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Enum fields are encoded as uint32 varints. | ||||
|    */ | ||||
|   static inline void add_enum_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Enums are encoded as uint32 | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint32 field to the total message size | ||||
|    * | ||||
|    * Sint32 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // ZigZag encoding for sint32: (n << 1) ^ (n >> 31) | ||||
|     uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint32 field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Sint32 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint32_field_repeated(uint32_t &total_size, uint32_t field_id_size, int32_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // ZigZag encoding for sint32: (n << 1) ^ (n >> 31) | ||||
|     uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int64 field to the total message size | ||||
|    */ | ||||
|   static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of an int64 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_int64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint64 field to the total message size | ||||
|    */ | ||||
|   static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a uint64 field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_uint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     total_size += field_id_size + varint(value); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint64 field to the total message size | ||||
|    * | ||||
|    * Sint64 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Skip calculation if value is zero | ||||
|     if (value == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // ZigZag encoding for sint64: (n << 1) ^ (n >> 63) | ||||
|     uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a sint64 field to the total message size (repeated field version) | ||||
|    * | ||||
|    * Sint64 fields use ZigZag encoding, which is more efficient for negative values. | ||||
|    */ | ||||
|   static inline void add_sint64_field_repeated(uint32_t &total_size, uint32_t field_id_size, int64_t value) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // ZigZag encoding for sint64: (n << 1) ^ (n >> 63) | ||||
|     uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63)); | ||||
|     total_size += field_id_size + varint(zigzag); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a string/bytes field to the total message size | ||||
|    */ | ||||
|   static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str) { | ||||
|     // Skip calculation if string is empty | ||||
|     if (str.empty()) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     const uint32_t str_size = static_cast<uint32_t>(str.size()); | ||||
|     total_size += field_id_size + varint(str_size) + str_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a string/bytes field to the total message size (repeated field version) | ||||
|    */ | ||||
|   static inline void add_string_field_repeated(uint32_t &total_size, uint32_t field_id_size, const std::string &str) { | ||||
|     // Always calculate size for repeated fields | ||||
|     const uint32_t str_size = static_cast<uint32_t>(str.size()); | ||||
|     total_size += field_id_size + varint(str_size) + str_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size | ||||
|    * | ||||
|    * This helper function directly updates the total_size reference if the nested size | ||||
|    * is greater than zero. | ||||
|    * | ||||
|    * @param nested_size The pre-calculated size of the nested message | ||||
|    */ | ||||
|   static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) { | ||||
|     // Skip calculation if nested message is empty | ||||
|     if (nested_size == 0) { | ||||
|       return;  // No need to update total_size | ||||
|     } | ||||
|  | ||||
|     // Calculate and directly add to total_size | ||||
|     // Field ID + length varint + nested message content | ||||
|     total_size += field_id_size + varint(nested_size) + nested_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size (repeated field version) | ||||
|    * | ||||
|    * @param nested_size The pre-calculated size of the nested message | ||||
|    */ | ||||
|   static inline void add_message_field_repeated(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size) { | ||||
|     // Always calculate size for repeated fields | ||||
|     // Field ID + length varint + nested message content | ||||
|     total_size += field_id_size + varint(nested_size) + nested_size; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size | ||||
|    * | ||||
|    * This version takes a ProtoMessage object, calculates its size internally, | ||||
|    * and updates the total_size reference. This eliminates the need for a temporary variable | ||||
|    * at the call site. | ||||
|    * | ||||
|    * @param message The nested message object | ||||
|    */ | ||||
|   static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message) { | ||||
|     uint32_t nested_size = 0; | ||||
|     message.calculate_size(nested_size); | ||||
|  | ||||
|     // Use the base implementation with the calculated nested_size | ||||
|     add_message_field(total_size, field_id_size, nested_size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the size of a nested message field to the total message size (repeated field version) | ||||
|    * | ||||
|    * @param message The nested message object | ||||
|    */ | ||||
|   static inline void add_message_object_repeated(uint32_t &total_size, uint32_t field_id_size, | ||||
|                                                  const ProtoMessage &message) { | ||||
|     uint32_t nested_size = 0; | ||||
|     message.calculate_size(nested_size); | ||||
|  | ||||
|     // Use the base implementation with the calculated nested_size | ||||
|     add_message_field_repeated(total_size, field_id_size, nested_size); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * @brief Calculates and adds the sizes of all messages in a repeated field to the total message size | ||||
|    * | ||||
|    * This helper processes a vector of message objects, calculating the size for each message | ||||
|    * and adding it to the total size. | ||||
|    * | ||||
|    * @tparam MessageType The type of the nested messages in the vector | ||||
|    * @param messages Vector of message objects | ||||
|    */ | ||||
|   template<typename MessageType> | ||||
|   static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size, | ||||
|                                           const std::vector<MessageType> &messages) { | ||||
|     // Skip if the vector is empty | ||||
|     if (messages.empty()) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     // Use the repeated field version for all messages | ||||
|     for (const auto &message : messages) { | ||||
|       add_message_object_repeated(total_size, field_id_size, message); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Implementation of encode_message - must be after ProtoMessage is defined | ||||
| inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessage &value, bool force) { | ||||
|   this->encode_field_raw(field_id, 2);  // type 2: Length-delimited message | ||||
|   size_t begin = this->buffer_->size(); | ||||
|  | ||||
|   // Calculate the message size first | ||||
|   uint32_t msg_length_bytes = 0; | ||||
|   value.calculate_size(msg_length_bytes); | ||||
|  | ||||
|   // Calculate how many bytes the length varint needs | ||||
|   uint32_t varint_length_bytes = ProtoSize::varint(msg_length_bytes); | ||||
|  | ||||
|   // Reserve exact space for the length varint | ||||
|   size_t begin = this->buffer_->size(); | ||||
|   this->buffer_->resize(this->buffer_->size() + varint_length_bytes); | ||||
|  | ||||
|   // Write the length varint directly | ||||
|   ProtoVarInt(msg_length_bytes).encode_to_buffer_unchecked(this->buffer_->data() + begin, varint_length_bytes); | ||||
|  | ||||
|   // Now encode the message content - it will append to the buffer | ||||
|   value.encode(*this); | ||||
|  | ||||
|   const uint32_t nested_length = this->buffer_->size() - begin; | ||||
|   // add size varint | ||||
|   std::vector<uint8_t> var; | ||||
|   ProtoVarInt(nested_length).encode(var); | ||||
|   this->buffer_->insert(this->buffer_->begin() + begin, var.begin(), var.end()); | ||||
|   // Verify that the encoded size matches what we calculated | ||||
|   assert(this->buffer_->size() == begin + varint_length_bytes + msg_length_bytes); | ||||
| } | ||||
|  | ||||
| // Implementation of decode_to_message - must be after ProtoMessage is defined | ||||
|   | ||||
| @@ -314,6 +314,9 @@ void PacketTransport::send_data_(bool all) { | ||||
| } | ||||
|  | ||||
| void PacketTransport::update() { | ||||
|   if (!this->ping_pong_enable_) { | ||||
|     return; | ||||
|   } | ||||
|   auto now = millis() / 1000; | ||||
|   if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) { | ||||
|     this->resend_ping_key_ = this->ping_pong_enable_; | ||||
|   | ||||
| @@ -167,8 +167,8 @@ def validate_config(config): | ||||
|     if config[CONF_MODULATION] == "LORA": | ||||
|         if config[CONF_BANDWIDTH] not in lora_bws: | ||||
|             raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA") | ||||
|         if config[CONF_PREAMBLE_SIZE] > 0 and config[CONF_PREAMBLE_SIZE] < 6: | ||||
|             raise cv.Invalid("Minimum preamble size is 6 with LORA") | ||||
|         if config[CONF_PREAMBLE_SIZE] < 6: | ||||
|             raise cv.Invalid("Minimum 'preamble_size' is 6 with LORA") | ||||
|         if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0: | ||||
|             raise cv.Invalid("Payload length must be set when spreading factor is 6") | ||||
|     else: | ||||
| @@ -200,7 +200,7 @@ CONFIG_SCHEMA = ( | ||||
|             cv.Optional(CONF_PA_RAMP, default="40us"): cv.enum(RAMP), | ||||
|             cv.Optional(CONF_PAYLOAD_LENGTH, default=0): cv.int_range(min=0, max=256), | ||||
|             cv.Optional(CONF_PREAMBLE_DETECT, default=2): cv.int_range(min=0, max=4), | ||||
|             cv.Required(CONF_PREAMBLE_SIZE): cv.int_range(min=1, max=65535), | ||||
|             cv.Optional(CONF_PREAMBLE_SIZE, default=8): cv.int_range(min=1, max=65535), | ||||
|             cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema, | ||||
|             cv.Optional(CONF_RX_START, default=True): cv.boolean, | ||||
|             cv.Required(CONF_RF_SWITCH): cv.boolean, | ||||
|   | ||||
| @@ -164,8 +164,8 @@ def validate_config(config): | ||||
|             raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA") | ||||
|         if CONF_DIO0_PIN not in config: | ||||
|             raise cv.Invalid("Cannot use LoRa without dio0_pin") | ||||
|         if 0 < config[CONF_PREAMBLE_SIZE] < 6: | ||||
|             raise cv.Invalid("Minimum preamble size is 6 with LORA") | ||||
|         if config[CONF_PREAMBLE_SIZE] < 6: | ||||
|             raise cv.Invalid("Minimum 'preamble_size' is 6 with LORA") | ||||
|         if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0: | ||||
|             raise cv.Invalid("Payload length must be set when spreading factor is 6") | ||||
|     else: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user