diff --git a/esphome/components/api/api_pb2_defines.h b/esphome/components/api/api_pb2_defines.h index 6f60f24f996..8ebd60fb5d1 100644 --- a/esphome/components/api/api_pb2_defines.h +++ b/esphome/components/api/api_pb2_defines.h @@ -4,5 +4,9 @@ #include "esphome/core/defines.h" #ifdef USE_BLUETOOTH_PROXY +#ifndef USE_API_VARINT64 #define USE_API_VARINT64 #endif +#endif + +namespace esphome::api {} // namespace esphome::api diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index ce3f9e18083..87fce485f1b 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -119,7 +119,7 @@ class ProtoVarInt { } // 32-bit phase: process remaining bytes with native 32-bit shifts. // Without USE_API_VARINT64: cover bytes 1-4 (shifts 7, 14, 21, 28) — the uint32_t - // shift at byte 4 truncates upper bits but those are always zero for valid uint32 values. + // shift at byte 4 (shift by 28) may lose bits 32-34, but those are always zero for valid uint32 values. // With USE_API_VARINT64: cover bytes 1-3 (shifts 7, 14, 21) so parse_wide handles // byte 4+ with full 64-bit arithmetic (avoids truncating values > UINT32_MAX). uint32_t result32 = buffer[0] & 0x7F; diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 5d3c61fcdaf..c862983fc4f 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -1929,6 +1929,9 @@ def get_varint64_ifdef( } if not ifdefs: return False, None + if None in ifdefs: + # At least one 64-bit varint field is unconditional, so the guard must be unconditional. + return True, None ifdefs.discard(None) return True, ifdefs.pop() if len(ifdefs) == 1 else None @@ -2603,10 +2606,14 @@ def main() -> None: defines_content += "#pragma once\n\n" defines_content += '#include "esphome/core/defines.h"\n' if has_varint64: - defines_content += "\n".join( - wrap_with_ifdef(["#define USE_API_VARINT64"], varint64_guard) - ) + lines = [ + "#ifndef USE_API_VARINT64", + "#define USE_API_VARINT64", + "#endif", + ] + defines_content += "\n".join(wrap_with_ifdef(lines, varint64_guard)) defines_content += "\n" + defines_content += "\nnamespace esphome::api {} // namespace esphome::api\n" with open(root / "api_pb2_defines.h", "w", encoding="utf-8") as f: f.write(defines_content)