diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 8d5e02943a9..e0a4e03189e 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -27,6 +27,8 @@ constexpr uint8_t WIRE_TYPE_MASK = 0b111; // Mask to extract wire type // Reinterpret float bits as uint32_t without floating-point comparison. // Used by both encode_float() and calc_float() to ensure identical zero checks. +// Uses union type-punning which is a GCC/Clang extension (not standard C++), +// but bit_cast/memcpy don't optimize to a no-op on xtensa-gcc (ESP8266). inline uint32_t float_to_raw(float value) { union { float f; @@ -456,14 +458,10 @@ class ProtoEncode { // is needed in the future, the necessary encoding/decoding functions must be added. static inline void encode_float(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, float value, bool force = false) { - if (value == 0.0f && !force) + uint32_t raw = float_to_raw(value); + if (raw == 0 && !force) return; - union { - float value; - uint32_t raw; - } val{}; - val.value = value; - encode_fixed32(pos PROTO_ENCODE_DEBUG_ARG, field_id, val.raw); + encode_fixed32(pos PROTO_ENCODE_DEBUG_ARG, field_id, raw); } static inline void encode_int32(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM, uint32_t field_id, int32_t value, bool force = false) {