Move the notify_*_update() method definitions from controller_registry.cpp
into controller_registry.h as inline functions. These are tiny loops over
1-2 controllers that each have a single call site in the entity's
notify_frontend_() method.
When defined in a separate TU, the compiler cannot inline them at the call
site without LTO, resulting in an unnecessary function-call frame on every
state publish. CodSpeed profiling of the CallbackManager container change
(#15272) showed this extra frame accounting for ~12% regression in text
sensor publish benchmarks.
controller_registry.h is only ever included from .cpp files (never from
other headers), so including controller.h after the class definition is
safe and introduces no circular dependencies.
Add a max_data_length field option to api_options.proto for string/bytes
fields. When max_data_length < 128 and force = true, the code generator
uses encode_short_string_force() — a single call that writes the tag
byte, 1-byte length varint, and raw string data with no branching. Size
calculation simplifies from calc_length(1, size) to 2 + size.
Annotate entity fields across all 25 ListEntities*Response messages:
- name and object_id: max_data_length = 120, force = true (50 fields)
- icon: max_data_length = 63 (25 fields)
The 120 and 63 values match NAME_MAX_LENGTH and ICON_MAX_LENGTH in
esphome/core/config.py, validated at config time.
Scan all enum definitions in api.proto at codegen time and automatically
populate max_value for enum-typed fields. This eliminates the need for
manual (max_value) annotations on every enum field.
When max_value < 128, the generated calculate_size uses constant-size
arithmetic instead of a function call:
- `calc_uint32(1, static_cast<uint32_t>(field))` → `field ? 2 : 0`
For repeated enum fields with constant element size, the per-element
loop is replaced with a multiply: `size += count * bytes_per_element`.
encode_float() already used union type-punning to convert a float to
its raw uint32_t bits for encoding. However, its zero check still used
a floating-point comparison (value == 0.0f), and calc_float() used
value != 0.0f with no type-punning at all.
Extract the existing union type-punning into a shared float_to_raw()
helper and use it in both places, so the zero check is a simple integer
comparison (raw == 0) in both encode_float() and calc_float(). This
ensures size calculation always matches encoding.
On platforms without hardware FPU (ESP8266, some LibreTiny chips),
value != 0.0f compiles to a software float library call (__nesf2 or
similar). The new code does a single integer comparison instead.