Fix clang-tidy bugprone-unchecked-optional-access in speed fan,
speaker media player, and sprinkler components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store optional results in local variables before checking
and dereferencing to satisfy bugprone-unchecked-optional-access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move set_component_state_ from component.cpp to the header as
an inline method so it can be reused wherever Component state
needs to be updated. Replace the manual bit manipulation in
Application::enable_pending_loops_ with a call to the helper.
Co-Authored-By: J. Nick Koston <nick@koston.org>
get_state() requires callers to check has_state() first.
This is a documented precondition, not an unchecked access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The custom optional implementation (from optional-bare, 2017) predates
C++17. All ESPHome platforms now compile with gnu++20, making
std::optional available everywhere.
The custom implementation had several issues:
- No emplace() support
- Always default-constructs value_ (wasteful for non-trivial types)
- reset() only flips a bool without destroying the value
- No move semantics
- Requires T to be default constructible
Replace with using aliases (using std::optional, using std::nullopt,
etc.) so all existing code using esphome::optional continues to work.
Also fix ~30 unsafe .value() calls across climate IR components that
relied on the custom optional's behavior of returning a
default-constructed value when empty. With std::optional, accessing
an empty optional is UB. These are replaced with value_or() using
appropriate defaults (CLIMATE_FAN_AUTO, CLIMATE_PRESET_NONE).
The sen6x test YAML used identical sensor IDs (pm_1_0, pm_2_5,
pm_4_0, pm_10_0) as sen5x, causing ID redefinition errors when
both components are tested together in grouped builds. Prefix
the sen6x IDs with sen6x_ to make them unique.
Make set_mode(const char*, size_t) the real implementation using
ESPHOME_strncasecmp_P with length checks, instead of ignoring len
and delegating to the null-terminated overload.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Avoid implicit StringRef->std::string conversion when the protobuf
message fields are already StringRef. Use the (const char*, size_t)
overloads directly.
ESP-IDF SDK components reference fprintf(), printf(), and vprintf()
which pull in newlib's _vfprintf_r (~11 KB). This is a separate
implementation from _svfprintf_r (used by snprintf/vsnprintf) that
handles FILE* stream I/O with buffering and locking.
ESPHome replaces the ESP-IDF log handler via esp_log_set_vprintf_(),
so the SDK's vprintf() path is dead code at runtime. The fprintf()
and printf() calls in SDK components are only in debug/assert paths
that are either GC'd or never called.
These linker --wrap stubs redirect through vsnprintf() + fwrite(),
allowing the linker to dead-code eliminate _vfprintf_r.
An escape hatch is provided via enable_full_printf: true in the
esp32 advanced config section for external components that need
full FILE*-based fprintf.
These are only used in debug rollover logging. Guarding them avoids
unused variable warnings and unnecessary includes in normal builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>