Split the rarely-taken warning path into a separate noinline cold
function so the hot path (called every component every loop iteration)
is minimal. Also make WARN_IF_BLOCKING_OVER_MS constexpr so the
compiler uses an immediate compare instead of a memory load, and
merge the two ESP_LOGW calls into one.
finish() shrinks from 108 to 30 bytes. Total flash savings: -116 bytes.
When a preset is cleared, the field was omitted entirely from the JSON.
Since the frontend uses Object.assign to merge state updates, the old
preset value was never removed. Now we always send the field (empty
string when no preset is active) so the UI updates correctly.
Convert setup_priority floats, component state uint8_t constants, and
status LED constants from extern const (defined in component.cpp) to
inline constexpr in the header. This lets the compiler use immediate
values instead of memory loads across all translation units.
Also removes the dead HARDWARE_LATE declaration (declared extern but
never defined).
Saves ~364 bytes flash on ESP32-S3.
On 32-bit platforms (ESP32 Xtensa), 64-bit shifts in varint parsing
compile to __ashldi3 library calls. Since the vast majority of protobuf
varint fields (message types, sizes, enum values, sensor readings) fit
in 4 bytes, the 64-bit arithmetic is unnecessary overhead on the common
path.
Split parse() into two phases:
- Bytes 0-3: uint32_t loop with native 32-bit shifts (0, 7, 14, 21)
- Bytes 4-9: noinline parse_wide_() with uint64_t, only for BLE
addresses and other 64-bit fields
The code generator auto-detects which proto messages use int64/uint64/
sint64 fields and emits USE_API_VARINT64 conditionally. On non-BLE
configs, parse_wide_() and the 64-bit accessors (as_uint64, as_int64,
as_sint64) are compiled out entirely.
Saves ~40 bytes flash on non-BLE configs. Benchmark shows 25-50%
faster parsing for 1-4 byte varints (the common case).
The web server's handle_climate_request() parsed mode, fan_mode, and
swing_mode but did not parse preset, making it impossible to set climate
presets via the REST API or web UI.
Also fix the JSON response to always include the presets and
custom_presets arrays when the climate entity supports them, rather than
only when a preset is currently active. This matches how swing_modes is
already handled and ensures the frontend can render preset controls
before one is selected.
Reuse a single stack buffer for both name_id and legacy id
construction instead of two separate buffers. ArduinoJson
copies from char* before the buffer is overwritten.
Use .c_str() instead of passing StringRef directly to
ArduinoJson assignments, routing through the already-
instantiated set<const char*> template and eliminating
the 24-byte set<StringRef> wrapper from the binary.
std::list uses per-node heap allocation (one allocation per element)
and has poor cache locality. std::vector is contiguous and uses a
single allocation.
Changes:
- Replace std::list<Header> with std::vector<Header> in perform()
virtual method signature across all platforms (IDF, Arduino, Host)
- Update all start(), get(), post() overloads accordingly
- Add ESPDEPRECATED overloads for std::list<Header> callers
- Update online_image to use std::vector<Header>
- Clean up request_headers construction in play() using structured
bindings and reserve()
The sizes are known at Python codegen time, so use FixedVector with
init() for a single allocation and no reallocation machinery. This
eliminates _M_realloc_append template instantiations for these types.
The sizes are known at Python codegen time, so use FixedVector with
init() for a single allocation and no reallocation machinery. This
eliminates _M_realloc_append template instantiations for these types.
request_headers_ and json_ are populated at config time via
add_request_header()/add_json() and only iterated linearly at
runtime. std::map's red-black tree is unnecessary overhead for
these small collections. Drop the <map> include.
The template only existed to share a loop between set and vector
iterators. Instead, have the deprecated set overload forward to
the vector overload, and inline the loop there.
start() already lowercases all collect_headers via lowercase_headers(),
so pre-lowercasing at insertion time was redundant double work on
every request.
Both start() overloads now use a shared lowercase_headers() template
that does a single pass from any iterator range, avoiding the extra
vector copy that the set overload was doing.
The vector overload of start() was passing collect_headers directly
to perform() without lowercasing. This meant callers using get()/post()
with mixed-case header names (e.g. {"ETag"}) would fail to match
against the lowercased header names from the HTTP response.
The no-collect-headers start() overload calls perform() directly
instead of the vector start() overload to avoid ambiguity with
the deprecated std::set overload.
- Change get()/post() collect_headers param from std::set to std::vector
(initializer list callers like online_image work unchanged)
- Add ESPDEPRECATED on start() std::set overload with clear message
about the collect_headers parameter
Replace heavy STL containers with simple std::vector and linear scan
for response header collection. This eliminates red-black tree (_Rb_tree)
and hash table template instantiations that are unnecessary for the small
number of headers typically collected (1-5 elements).
Changes:
- response_headers_: std::map<string, list<string>> -> std::vector<Header>
- collect_headers_: std::set<string> -> std::vector<string>
- perform() signature: std::set -> std::vector
- Add should_collect_header() inline helper for linear scan
- Lowercase collect_headers at config/insertion time instead of per-request
- IDF UserData now holds references to container's vector instead of
owning a separate map that gets moved after the request
- Reuse existing Header struct instead of std::pair
Reduces stack usage in perform() and eliminates STL container overhead
on memory-constrained ESP devices.