The CLOSE_EVT handler matches on conn_id_ to call set_idle_().
Resetting conn_id_ to UNSET_CONN_ID before CLOSE_EVT arrives
causes the event to be dropped, leaving the client stuck in
DISCONNECTING state permanently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When OPEN_EVT arrives with a failure status, the connection was never
established so no CLOSE_EVT may follow. Reset conn_id_ to prevent a
stale value from matching a future CLOSE_EVT.
Instead of a separate early-return for DISCONNECTING state, let the
failed OPEN_EVT fall through to the existing failed-status handler
which already transitions to IDLE.
When a connection fails to establish, the ESP-IDF stack sends
DISCONNECT_EVT followed by OPEN_EVT with a failure status (e.g. 133).
No CLOSE_EVT follows since no GATT connection was established.
Previously the OPEN_EVT in DISCONNECTING state was silently ignored,
leaving the client stuck in DISCONNECTING forever. Now we treat this
failed OPEN_EVT as the terminal event and transition to IDLE.
Replace division-based line number formatting in LogBuffer::write_header
with subtraction loops. The ESP8266 (Xtensa lx106) lacks a hardware
divider, so each division compiles to an expensive software function call.
Measured on real ESP8266 hardware (10000 iterations x 13 test values):
- Division: 213,029 us
- Subtraction: 118,503 us (1.8x faster)
Flash savings:
- ESP8266: -36 bytes (323 -> 287)
- ESP32: -23 bytes (326 -> 303)
sound_level and wireguard were getting automation.h transitively
through sensor/filter.h. Now that filter.h is conditionally compiled,
add the direct includes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bme680_bsec, haier, and kamstrup_kmp were getting <queue> transitively
through sensor/filter.h. Now that filter.h is conditionally compiled,
add the direct include.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no binary sensor filters are configured, the entire Filter class
hierarchy (filter.h/filter.cpp) is still compiled and linked into the
binary. This includes delayed_on, delayed_off, delayed_on_off, invert,
autorepeat, lambda, settle, and timeout filter classes.
Add USE_BINARY_SENSOR_FILTER define that is only emitted when at least
one binary sensor has filters configured. Wrap filter-related code
behind this define to eliminate dead code from the binary.
When no sensor filters are configured, the entire Filter class
hierarchy (filter.h/filter.cpp) is still compiled and linked into
the binary. This includes ~20 filter classes (sliding window, median,
quantile, exponential moving average, throttle, debounce, heartbeat,
delta, calibrate, clamp, NTC, streaming filters, etc.)
Add USE_SENSOR_FILTER define that is only emitted when at least one
sensor has filters configured. Wrap filter-related code behind this
define to eliminate dead code from the binary.
When no text sensor filters are configured, the entire Filter class
hierarchy (filter.h/filter.cpp) was still compiled and linked. This
pulled in std::string manipulation code (_M_mutate, _M_create,
_M_append, _M_replace, _M_assign, _M_dispose) that is only needed
for filter chain processing.
Add USE_TEXT_SENSOR_FILTER define that is only emitted when at least
one text sensor has filters configured. Wrap filter-related code
behind this define to eliminate dead code from the binary.
Saves ~340 bytes of flash on configs with filterless text sensors.
Water heater was the only entity type that directly called
encode_message_to_buffer() instead of fill_and_encode_entity_state().
This meant device_id was never set on WaterHeaterStateResponse,
causing entities with device_id to show as unknown in Home Assistant.
Expand the device_id integration test to cover all entity types:
cover, fan, lock, number, select, text, valve, water_heater,
alarm_control_panel, date, time, datetime, and event.
Closes https://github.com/esphome/esphome/issues/14206
ESP_GATTC_DISCONNECT_EVT only indicates that the link-layer disconnection
has started, not that the controller has fully freed resources (L2CAP
channels, ATT resources, HCI connection handle). Transitioning to IDLE
immediately allowed reconnection attempts before cleanup was complete,
causing the controller to reject new connections with status=133
(ESP_GATT_CONN_FAIL_ESTABLISH) or crash with ASSERT_PARAM in lld_evt.c.
This applies the same fix that was made for bluetooth_proxy in #10303
to the base BLEClientBase class, which is used by the ble_client
component.
Changes:
- DISCONNECT_EVT now transitions to DISCONNECTING instead of IDLE
- CLOSE_EVT (already existing) handles the final IDLE transition
- connect() now blocks while in DISCONNECTING state
- OPEN_EVT ignores events received during DISCONNECTING state