When multiple ble_client RSSI sensors were configured, they all reported
the same RSSI value because the GAP event handler did not filter by
remote device address. Add an address check so each sensor only processes
RSSI events matching its parent client's device.
Fixes https://github.com/esphome/esphome/issues/14898
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The sds011 component handles update_interval via its own
set_update_interval_min method. Pop it from config before
register_component to prevent generating a set_update_interval
call on the Component base class.
Remove the virtual keyword from set_update_interval and inline the
trivial setter in the header. No component in the tree actually
overrides this on PollingComponent — the only apparent override was
in sds011 which extends Component (not PollingComponent), so it was
just a name-hiding no-op that is also removed here.
This allows the compiler to inline the setter at all 8 call sites
generated by register_component, eliminating function call overhead
and removing a vtable entry.
Move set_gate_move_threshold_number and set_gate_still_threshold_number
definitions into the header. These are single-line array assignments
called 14 times each (once per gate), and inlining them eliminates
function call overhead, saving ~52 bytes of flash.
Replace floating-point comparison (value != 0.0f) with integer bit-pattern
check via a shared float_to_raw() helper in both encode_float() and
calc_float(). This avoids software float library calls on platforms without
hardware FPU (ESP8266, some LibreTiny chips) and ensures both functions
use identical zero-check logic so size calculation always matches encoding.
Callback::create() can store callables inline (no heap allocation)
when they fit in sizeof(void*) — i.e., a single [this] capture on
32-bit platforms. Many automation triggers captured [this, parent]
in their callback lambdas, doubling the capture size and forcing
heap allocation.
Store the parent/state pointer as a class member and capture only
[this] in the lambda. This trades 4 bytes of member storage for
avoiding a permanent heap allocation per callback registration.
Components changed: cover, valve, lock, fan, media_player, datetime,
display_menu_base, graphical_display_menu, esp32_improv, mqtt_fan.
The notify_state_deferred_ lambda captured [this, state, progress, error]
(16 bytes on 32-bit), exceeding std::function SBO and forcing a heap
allocation on every OTA progress update.
Pack the three values into a single uint32_t:
- state (8 bits) + error (8 bits) + progress as fixed-point (16 bits)
The lambda now captures [this, packed] (8 bytes), fitting in SBO.
Progress resolution of 0.01% is more than adequate for OTA reporting.
The set_timeout lambda captured a psk_t (std::array<uint8_t, 32>) by
value, making the lambda 36 bytes — well beyond the std::function
small buffer optimization threshold, forcing a heap allocation.
Re-read the PSK from preferences inside the timeout callback instead.
The PSK was just saved to flash moments before the timeout was
scheduled, so re-reading it is reliable and avoids the large capture.
Extract load_and_apply_noise_psk_() helper to deduplicate the
load-from-preferences-and-apply pattern used in both setup() and
the timeout callback.