Defense-in-depth: validate device class strings don't exceed the
48-byte PROGMEM buffer limit (47 chars + null), matching the same
pattern used for icon strings.
Same treatment as icons in #14437. Device class strings were in
.rodata (RAM on ESP8266). Now stored as individual PROGMEM char arrays.
- Add get_device_class_to(std::span<char, MAX_DEVICE_CLASS_LENGTH>)
buffer API matching get_icon_to() pattern
- Add fill_and_encode_entity_info_with_device_class() wrapper to
deduplicate buffer handling across 10 API entity types
- Centralize MQTT device_class in send_discovery_() lambda where
buffer lifetime outlives ArduinoJson serialization
- Deprecate get_device_class_ref()/get_device_class() on non-ESP8266
- static_assert error on ESP8266 directing to get_device_class_to()
- Update all callers: api, mqtt, web_server, log helper
- When USE_ENTITY_ICON is disabled, return "" directly without
calling through the lookup table
- When enabled, ensure the empty-string fallback (index 0 / out of
range) is a PROGMEM char array so strncpy_P on ESP8266 is safe
The switch from cyw43_tcpip_link_status to cyw43_wifi_link_status
was intended for 2026.3.0 alongside the arduino-pico 5.5.0 framework
update but was accidentally included in 2026.2.3.
With the old framework (3.9.4), cyw43_wifi_link_status never returns
CYW43_LINK_UP, so the CONNECTED state is unreachable. The device
connects to WiFi but the status stays at CONNECTING until timeout,
causing a connect/disconnect loop.
Fixes https://github.com/esphome/esphome/issues/14422
Move trivial component_state_ accessors from out-of-line definitions
in component.cpp to inline definitions in the header. This allows the
compiler to inline these single-expression field accesses at call sites,
eliminating function call overhead. Most notably, get_component_state()
is called per-component per-loop iteration in Application::loop().
Inlined: get_component_state(), is_in_loop_state(), is_idle(),
is_failed(), status_has_warning(), status_has_error()
Kept out-of-line: is_ready() (3-way OR, larger body)
Move is_high_frequency() from out-of-line definition in helpers.cpp
to inline in the header. This allows the compiler to inline the
trivial check (num_requests > 0) at the call site in
Application::loop(), avoiding a function call every loop iteration.
Explicitly checkout the base branch SHA for consistency and to
ensure the shared codeowners.js script is always loaded from
trusted code, not the PR head.
- Actually filter bot reviews (not just comment about it)
- Use core.setFailed() instead of silently swallowing errors
- Remove unused getEffectiveOwners import from detectors.js
pull_request_review checks out the PR merge commit by default,
which means require() would load the PR author's version of
shared scripts. Explicitly checkout the base branch SHA instead.