Commit Graph
25443 Commits
Author SHA1 Message Date
J. Nick Koston 5e5079ec56 Merge remote-tracking branch 'upstream/remove-noinline-encode-fixed32' into integration 2026-03-21 00:07:05 -10:00
J. Nick Koston d8d5619ba7 [api] Use write_tag_and_fixed32 and extract calculate_tag helper
- Combine tag byte + fixed32 value into single write_tag_and_fixed32()
  method: pos[0] = tag, memcpy(pos+1, &value, 4), pos += 5
- Extract calculate_tag() from duplicated computation in
  calculate_field_id_size() and encode_content
2026-03-21 00:05:53 -10:00
J. Nick Koston 2a379490e8 Merge remote-tracking branch 'upstream/remove-noinline-encode-fixed32' into integration 2026-03-20 23:57:37 -10:00
J. Nick Koston 225c770b1b [api] Use write_tag_and_fixed32 and extract calculate_tag helper
- Combine tag byte + fixed32 value into single write_tag_and_fixed32()
  method: pos[0] = tag, memcpy(pos+1, &value, 4), pos += 5
- Extract calculate_tag() from duplicated computation in
  calculate_field_id_size() and encode_content
2026-03-20 23:45:23 -10:00
J. Nick Koston 21725983fd [api] Emit raw tag+value writes for force=true fixed32 fields
Instead of ALWAYS_INLINE on encode_field_raw (which bloated all
callers), have the code generator precompute the tag byte and emit
write_raw_byte(tag) + write_fixed32_raw(value) directly.

This gives the same tight codegen (single byte store + memcpy) for
key fields without inflating encode_bool/encode_uint32/etc.

+108 bytes flash vs baseline, -48 bytes vs the ALWAYS_INLINE approach.
2026-03-20 23:28:19 -10:00
J. Nick Koston 7ce24edabb [api] Force-inline encode_fixed32 and add force=true to all key fields
- Add ESPHOME_ALWAYS_INLINE to encode_fixed32 so the compiler inlines it
  on hot paths despite -Os heuristics (removing noinline alone was not
  enough — gcc still chose not to inline at 51 call sites)
- Mark all fixed32 key fields in api.proto with [(force) = true] since
  entity keys are FNV hashes and never zero, eliminating the zero-check
  branch and making calculate_size() use constants

+96 bytes flash (555167 → 555263) on ESP32 — negligible for removing
branch + call overhead on every sensor state encode.
2026-03-20 23:17:11 -10:00
J. Nick Koston 21929eb157 [api] Remove noinline from encode_fixed32
Profiling showed the noinline call overhead dominated hot paths like
SensorStateResponse encoding, where encode_fixed32 is called twice
per message (once for key, once via encode_float for state).

The function body is trivial (tag byte + 4-byte memcpy), so the
function call prologue/epilogue cost exceeded the actual work.

Despite 51 call sites, removing noinline shows no measurable flash
size increase (555167 bytes before and after on ESP32).
2026-03-20 23:07:12 -10:00
J. Nick Koston 0761170514 Merge remote-tracking branch 'upstream/fix-esp32-efuse-mac-validation' into integration 2026-03-20 22:14:39 -10:00
J. Nick Koston b08de20e6d Merge remote-tracking branch 'upstream/fix-constant-brightness-gamma' into integration 2026-03-20 22:14:36 -10:00
J. Nick Koston 935ab42b1e [esp32] Validate eFuse MAC reads and reject garbage MACs
On some ESP32 boards (especially cheap clones), the eFuse custom MAC
area contains random garbage that passes the existing all-zeros/all-ones
validation. Additionally, esp_efuse_mac_get_default() can fail with CRC
errors, but the return value was being ignored, causing garbage MAC
addresses to be advertised via mDNS.

This caused Home Assistant to report false "MAC address changed" device
conflicts on every boot.

Two fixes:
- Check return values from eFuse MAC read functions and add a fallback
  chain: custom MAC -> default MAC -> raw eFuse bytes -> zeroed MAC.
- Reject multicast MACs (bit 0 of first byte set) in mac_address_is_valid()
  since device MACs must always be unicast.

Closes https://github.com/esphome/esphome/issues/14501
2026-03-20 22:13:01 -10:00
J. Nick KostonandCopilot 4ae1043c2e Update esphome/components/light/light_color_values.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-20 22:06:11 -10:00
J. Nick KostonandCopilot 4d805e2d30 Update tests/integration/test_light_constant_brightness.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-20 22:06:03 -10:00
J. Nick Koston f50720a3c5 [light] Add integration tests for constant_brightness with gamma
Regression tests for #15040 using a single compiled binary with two
cwww lights to verify:
- constant_brightness: true maintains constant total CW+WW power
  output across all color temperatures with gamma correction
- constant_brightness: false correctly varies total power (higher
  at mid-range where both channels contribute)
2026-03-20 22:00:44 -10:00
J. Nick Koston 22c338c724 [light] Fix constant_brightness broken by gamma LUT refactor
The gamma LUT refactor (#14123) moved gamma correction to after
the constant_brightness balancing formula (max/sum ratio). This
broke constant_brightness because gamma is nonlinear and does not
commute with the ratio calculation, causing a severe brightness
dip at mid-range color temperatures.

Fix by applying gamma to individual CW/WW/brightness values
before the constant_brightness formula, restoring the original
behavior where total power output remains constant across all
color temperatures.

Closes #15040
2026-03-20 21:46:03 -10:00
J. Nick Koston 7c1b30f37f Merge remote-tracking branch 'upstream/devirtualize-api-dispatch' into integration 2026-03-20 21:31:54 -10:00
J. Nick Koston 1d191d2461 [api] Fix review comments and add USE_API guards
- Update comments to reflect that ProtoService methods moved to
  APIConnection, not APIServerConnectionBase
- Fix comment referring to read_message as "override"
- Wrap #include "api_connection.h" and read_message_ implementation
  in #ifdef USE_API guards
2026-03-20 21:29:42 -10:00
J. Nick Koston 7d8eba85c6 Merge remote-tracking branch 'upstream/devirtualize-api-dispatch' into integration 2026-03-20 21:21:56 -10:00
J. Nick Koston 20d3e7c13a [api] Remove virtual destructor and rename read_message to read_message_
The virtual destructor was unnecessary since APIConnection is only
stored as unique_ptr<APIConnection>, never via a base class pointer.
Removing it eliminates the vtable entirely.

Rename read_message to read_message_ per clang-tidy naming convention
for protected methods.
2026-03-20 21:21:09 -10:00
J. Nick Koston e1f37675da Merge remote-tracking branch 'upstream/devirtualize-api-dispatch' into integration 2026-03-20 21:15:06 -10:00
J. Nick Koston 2067053adb [api] Remove ProtoService base class
ProtoService was an abstract interface with 6 pure virtual methods,
but APIConnection was the only concrete implementation. Move all
functionality directly into APIConnection and remove the unnecessary
virtual dispatch and vtable overhead.
2026-03-20 21:14:45 -10:00
J. Nick Koston da0acc0b11 Merge remote-tracking branch 'upstream/devirtualize-api-dispatch' into integration 2026-03-20 21:11:11 -10:00
J. Nick Koston e9d25645cb [api] Move auth check helpers from ProtoService to APIConnection
check_connection_setup_() and check_authenticated_() call virtual
methods (is_connection_setup, on_no_setup_connection). When defined
in ProtoService, the compiler cannot devirtualize these calls.
Moving them to APIConnection (final) enables devirtualization.
2026-03-20 21:10:41 -10:00
J. Nick Koston 77d2e378e2 Merge remote-tracking branch 'upstream/devirtualize-api-dispatch' into integration 2026-03-20 21:06:22 -10:00
J. Nick Koston 9583a6a921 [api] Restore override on is_authenticated (ProtoService virtual) 2026-03-20 21:05:03 -10:00
J. Nick Koston 391ad05d45 [api] Devirtualize API command dispatch
Move read_message() from APIServerConnectionBase into APIConnection
and drop the virtual keyword from all 64 on_* handler declarations.

Since APIConnection is final and the only subclass, the virtual
dispatch was unnecessary. With read_message and the on_* handlers
in the same class, the compiler can devirtualize the calls and
inline small handlers directly into the switch cases.
2026-03-20 20:58:54 -10:00
J. Nick Koston 1d08f4087d Merge remote-tracking branch 'upstream/inline-application-loop' into integration 2026-03-20 20:42:40 -10:00
J. Nick Koston aa2c7fd834 [core] Restore race condition comments in before_loop_tasks_ 2026-03-20 20:41:08 -10:00
J. Nick Koston 5050a82a85 [core] Inline before_loop_tasks_() to reduce scheduler call depth
Move before_loop_tasks_() to application.h as always_inline.
This removes one stack frame between the main loop and
scheduler.call(), which matters for timer callbacks that
trigger deeply nested operations.
2026-03-20 20:40:46 -10:00
J. Nick Koston baf1c0c9f1 Merge remote-tracking branch 'origin/inline-application-loop' into integration 2026-03-20 19:24:10 -10:00
J. Nick Koston 71c95d76fc [core] Move runtime_stats include to top of application.h
Eliminates the namespace close/reopen that was needed when the
include was between the two inline definitions.
2026-03-20 19:23:39 -10:00
J. Nick Koston ed77c547cc Merge remote-tracking branch 'origin/reduce-automation-call-stack' into integration 2026-03-20 19:20:24 -10:00
J. Nick Koston fcaaa46bd9 [core] Use ESPHOME_ALWAYS_INLINE macro for consistency 2026-03-20 19:20:02 -10:00
J. Nick Koston 846b7f6a1f Merge remote-tracking branch 'origin/inline-application-loop' into integration 2026-03-20 19:14:29 -10:00
J. Nick Koston 41a2531d45 Merge remote-tracking branch 'origin/reduce-automation-call-stack' into integration 2026-03-20 19:14:01 -10:00
J. Nick Koston 60df1b436e [socket] Add NOLINT for socket_delay forward declaration
Suppress readability-redundant-declaration warning triggered by the
forward declaration added in application.h for inline yield_with_select_.
2026-03-20 19:14:00 -10:00
J. Nick Koston 3be2b57c15 Merge remote-tracking branch 'upstream/inline-application-loop' into integration 2026-03-20 19:05:34 -10:00
J. Nick Koston 1918e17c21 [core] Inline yield_with_select_ on all embedded platforms
Inline yield_with_select_ for ESP8266/RP2040 (socket_delay) and
no-socket (delay) paths in addition to the LWIP_FAST_SELECT path.
Only the select() fallback (host platform) remains in the .cpp.

This ensures yield_with_select_ is inlined into the loop on all
embedded platforms, not just ESP32/LibreTiny.
2026-03-20 19:05:01 -10:00
J. Nick Koston bfa446a28e [core] Switch to always_inline only, drop play_complex overrides
The play_complex overrides cost flash per template instantiation
across every automation. The always_inline on the forwarding chain
(Trigger::trigger, Automation::trigger, ActionList::play) is a
fixed cost that collapses 3 frames into 1.
2026-03-20 18:59:45 -10:00
J. Nick Koston 9227d8f2dd [core] Restore play_complex overrides for LambdaAction and ContinuationAction
The +384 flash was from the always_inline attributes (already removed),
not from the play_complex overrides.
2026-03-20 18:52:48 -10:00
J. Nick Koston aacc7e54d2 [core] Limit play_complex override to StatelessLambdaAction only
LambdaAction and ContinuationAction overrides caused flash bloat
by replacing shared base class play_complex instantiations with
per-class copies. StatelessLambdaAction is the most common
automation action and its no-args variant is only 24 bytes.
2026-03-20 18:52:12 -10:00
J. Nick Koston 884db8060a [core] Use qualified calls and add comments explaining overrides 2026-03-20 18:48:51 -10:00
J. Nick Koston 536093acfa [core] Drop always_inline attributes to avoid flash bloat
The always_inline on Trigger::trigger(), ActionList::play(), and
Automation::trigger() duplicates code at every trigger call site,
adding ~384 bytes of flash. Revert to compiler-managed inlining
and keep only the play_complex overrides (phase 2).
2026-03-20 18:46:46 -10:00
J. Nick Koston 998d61f434 [core] Inline yield_with_select_ fast path for LWIP_FAST_SELECT
When USE_LWIP_FAST_SELECT is defined (ESP32/LibreTiny), move the
yield_with_select_ implementation to application.h as always_inline.
This eliminates another stack frame from the hot loop path on these
platforms. The fallback select()/delay() paths for other platforms
remain in application.cpp.
2026-03-20 18:42:55 -10:00
J. Nick Koston 34345b86fa [core] Reduce automation call chain stack depth
Force-inline the Trigger→Automation→ActionList forwarding chain
and override play_complex() in leaf action classes to skip the
virtual play() dispatch, reducing the button→lambda call stack
from 8 frames to ~4.
2026-03-20 18:36:07 -10:00
J. Nick Koston e15782844e [core] Inline after_loop_tasks_() into header
Trivial one-liner (single assignment) called from the inlined loop()
and setup(). Eliminates another unnecessary function call.
2026-03-20 18:34:55 -10:00
J. Nick Koston ae4e2aebb9 Merge remote-tracking branch 'origin/inline-application-loop' into integration 2026-03-20 18:29:57 -10:00
J. Nick Koston 9d2d4f2243 [core] Inline Application::loop() to eliminate stack frame
Move Application::loop() from application.cpp to application.h as
inline ESPHOME_ALWAYS_INLINE so the compiler can inline it at all
call sites. On ESP32, loop_task() now calls App.loop() directly
instead of going through the generated loop() wrapper.

This eliminates one stack frame from the main loop call chain on
all platforms, producing cleaner crash backtraces and reducing
function call overhead on every loop iteration.
2026-03-20 18:27:24 -10:00
J. Nick Koston d203a46ef8 [api] Enable HAVE_WEAK_SYMBOLS and HAVE_INLINE_ASM for libsodium (#15038) 2026-03-21 04:17:37 +00:00
J. Nick Koston 7b6312a819 Merge remote-tracking branch 'upstream/libsodium-enable-weak-symbols' into integration 2026-03-20 18:02:29 -10:00
J. Nick Koston 98d3520e2d Merge branch 'dev' into libsodium-enable-weak-symbols 2026-03-20 17:46:22 -10:00