Commit Graph
27734 Commits
Author SHA1 Message Date
J. Nick Koston 57d9e508ea merge 2026-04-14 08:09:00 -10:00
J. Nick Koston f4f56cfaaa Merge remote-tracking branch 'upstream/dev' into optimize-value-accuracy
# Conflicts:
#	esphome/core/helpers.h
#	tests/components/core/test_helpers.cpp
2026-04-14 08:07:44 -10:00
Alexey SpirkovandAlexey Spirkov 9f5ed938e5 [i2s_audio] Add PDM mics support for ESP32-P4 (#15333)
Co-authored-by: Alexey Spirkov <dev@alsp.net>
2026-04-14 14:07:16 -04:00
J. Nick Koston 4729efbd04 [light] Deduplicate color_uncorrect channel math via shared helper (#15727) 2026-04-14 07:50:28 -10:00
J. Nick Koston da9fbb8044 [core] Fix app_state_ status bits clobbered for non-looping components (#15658) 2026-04-14 07:50:11 -10:00
J. Nick Koston cf01163c8c [core] Add uint32_to_str helper and use in preferences (#15597) 2026-04-14 07:49:44 -10:00
J. Nick Koston 5ba8c644e4 [ld24xx] Replace heap-allocated SensorWithDedup with inline SensorWithDedup (#15676) 2026-04-14 07:49:27 -10:00
Kevin AhrendtandCopilot c833ff4a84 [audio] Add/configure microDecoder library in preparation for use in future PRs (#15679)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-14 13:49:18 -04:00
J. Nick Koston 2a530a4bf4 [core] Optimize format_hex_internal by splitting separator loop (#15594) 2026-04-14 07:48:33 -10:00
J. Nick Koston 6b4b653462 [globals] Fix TemplatableFn deprecation warning for globals.set (#15733) 2026-04-14 09:18:38 -04:00
J. Nick Koston 651e37dcdc Merge branch 'light-addressable-gamma-transition-stall' into integration 2026-04-13 22:57:50 -10:00
J. Nick Koston 111e2cc9ed cleanups 2026-04-13 22:56:32 -10:00
J. Nick Koston a60631a599 Merge remote-tracking branch 'upstream/light-addressable-gamma-transition-stall' into integration 2026-04-13 22:42:36 -10:00
J. Nick Koston c7b4ee5c60 fix when on_boot at 800 2026-04-13 22:40:17 -10:00
J. Nick Koston 8255afaa60 Merge remote-tracking branch 'origin/globals-set-lambda-return-type' into integration 2026-04-13 22:21:25 -10:00
J. Nick Koston 503e299d15 [globals] Use value_type alias instead of stashing type in CORE.data 2026-04-13 22:10:24 -10:00
J. Nick Koston a325df98da [globals] Emit globals.set value lambda with declared global type
Pass the global's declared C++ type as the lambda return type so
TemplatableFn stores a direct function pointer instead of hitting the
deprecated converting trampoline when the value expression deduces to a
different type (e.g. an int literal or int-returning lambda assigned to
a float global).
2026-04-13 21:59:54 -10:00
J. Nick Koston fa1391ac54 Merge branch 'light-force-inline-set-flag' into integration 2026-04-13 17:27:22 -10:00
J. Nick Koston a0286616f7 [light] Force-inline LightCall::set_flag_/clear_flag_
Both are trivial bit operations on a uint16_t (one or/and on flags_),
but without ESPHOME_ALWAYS_INLINE each call costs a call0/call8 plus
the return/register-window rotation — more work than the body itself.
validate_() invokes these ~8 times and transform_parameters_() adds
more, so runtime benchmarks should reflect the elimination of the
call overhead.

Note: a previous attempt at this (#15402) was closed based on flash
size deltas alone. This reopens the question with CodSpeed in-loop
to measure actual runtime impact.
2026-04-13 17:16:49 -10:00
J. Nick Koston bd97a3ef85 Merge remote-tracking branch 'origin/light-gamma-uncorrect-outline' into integration 2026-04-13 17:03:36 -10:00
J. Nick Koston 1ee28e210a Merge remote-tracking branch 'upstream-ssh/light-validate-clamp-loop' into integration 2026-04-13 17:03:20 -10:00
J. Nick Koston c9b6253d24 [light] Fix stale comments on float_out_of_unit_range / clamp_unit_float 2026-04-13 17:01:11 -10:00
J. Nick KostonandCopilot Autofix powered by AI edb16a27d3 [esphome] Skip missing extra flash images in upload_using_esptool (#15723)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-04-13 16:58:48 -10:00
J. Nick Koston 674fb1d3f6 [light] Drop redundant is_standard_layout asserts (offsetof no longer used)
Since validate_() now accesses unit_fields_[] directly via the union
alias, there's no offsetof arithmetic to guard. The FieldFlags bit
layout assert is all that's needed.
2026-04-13 16:57:58 -10:00
J. Nick Koston 58885c2090 [light] Rename log_value_out_of_range_ to drop trailing underscore (clang-tidy) 2026-04-13 16:55:25 -10:00
J. Nick Koston 6491072a77 [light] Alias clamp fields via anonymous-union float[8] to eliminate pointer UB
Replaces the previous `float *p = &this->brightness_; p[bit]` pattern
(flagged by Copilot as pointer-into-scalar UB) with a shared anonymous
union that exposes brightness_..warm_white_ as unit_fields_[8] in both
LightCall and LightColorValues. validate_() now indexes the real array
directly — defined behavior — while the named members stay accessible
to getters/setters. Code generation is unchanged.

The union is declared once via ESPHOME_LIGHT_UNIT_FIELDS_UNION() in
light_color_values.h and expanded in both structs. The per-field
offsetof static_asserts collapse to a single FieldFlags bit-layout
assert since the union guarantees member ↔ array-index alignment.

Caught by Copilot on PR review.
2026-04-13 16:54:43 -10:00
J. Nick Koston 8ef1057674 [light] Treat -0.0f as in range in float_out_of_unit_range
-0.0f has bit pattern 0x80000000 which exceeds ONE_F_BITS as unsigned,
so the check previously flagged it and emitted a spurious out-of-range
warning. Add an explicit compare against NEG_ZERO_F_BITS (declared as
a named constexpr for readability) so -0.0f takes the in-range fast
path. clamp_unit_float() already returned 0.0f for it via the sign-bit
branch, so behavior on clamp is unchanged.

Caught by Copilot on PR review.
2026-04-13 16:48:00 -10:00
J. Nick Koston bdd1c413de [light] Eliminate static-local guard variables by hoisting names to PROGMEM_STRING_TABLE
The PROGMEM_STRING_TABLE expansion is entirely constexpr-initialized, so it doesn't require the per-static thread-safe-init guard variables that the previous `static const LogString *const FIELD_NAMES[8] PROGMEM = { LOG_STR(...) }` form emitted inside validate_() (LOG_STR contains a GCC statement-expression, which is not a constant expression, so GCC fell back to dynamic init with an 8-byte guard).

Combined the 8 clamp-field names and "Color temperature" into a single ValidateFieldNames table; index 8 is reserved for CT. log_value_out_of_range_() now takes the resolved `const LogString *` directly, so the helper no longer needs its internal progmem_read_ptr dereference.

Impact vs. prior commit (isolated light build):

  ESP8266 .irom0.text: 267912 -> 267784  (-128 B)

  ESP8266 .bss guard vars on light symbols: 16 -> 0 (-16 B RAM)

  ESP32-IDF .flash.text: 136988 -> 136996 (+8 B, marginal)
2026-04-13 16:38:44 -10:00
J. Nick Koston de44b8e859 [light] Tighten comments in validate_ clamp loop and LightColorValues helpers 2026-04-13 16:31:50 -10:00
J. Nick Koston 8eb8b3dc0f [light] Promote bit-pattern clamp to LightColorValues setters and add layout asserts
Move `float_out_of_unit_range()` / add `clamp_unit_float()` to
light_color_values.h so the nine `set_*(float)` setters can use the
unsigned bit-pattern clamp instead of `std::clamp(x, 0.0f, 1.0f)`.
`std::clamp` expands to two soft-float `__ltsf2`/`__gtsf2` calls per
invocation on ESP8266 — replacing it with a single unsigned compare
saves code across every caller of these setters (StrobeLightEffect,
the 11-arg LightColorValues constructor, external components).

Split the cold-path helper: `log_value_out_of_range_()` now only logs,
and each caller applies the clamp strategy appropriate to its range
(`clamp_unit_float` for the 8-field loop, `std::clamp` for color
temperature's runtime-variable range).

Add layout/format assertions:
- std::is_standard_layout_v on LightCall and LightColorValues so the
  offsetof arithmetic in the clamp loop is well-defined.
- sizeof(float) == 4 and is_iec559 so the bit-pattern trick is valid.
  A direct __builtin_bit_cast check would be cleaner but is not
  available on the ESP8266 xtensa toolchain.

Text-section delta vs. prior commit (isolated light build):
  ESP32-IDF: .flash.text  137760 -> 136988 (-772 B)
  ESP8266:   .irom0.text  268440 -> 267912 (-528 B)
2026-04-13 16:27:09 -10:00
J. Nick Koston 36881166a8 [light] Replace soft-float range check with union bit-cast + unsigned compare
The inlined `value < 0.0f || value > 1.0f` check in the clamp loop costs
~50 B per iteration on ESP8266 (two libgcc soft-float calls with register
spills). IEEE 754 floats in [0.0f, 1.0f] have bit patterns in
[0x00000000, 0x3F800000]; anything out of range — values > 1.0f, negatives
(sign bit set → huge unsigned interpretation), NaN, Infinity — has a
strictly larger unsigned interpretation. A single `pun.u > 0x3F800000u`
covers every case.

Using a union for the type-pun rather than memcpy/bit_cast because those
don't optimize to a no-op on xtensa-gcc (same reason api/proto.h's
float_to_raw() uses a union).

The loop body is now two instructions for the range check:
  l32i a2, a9, 0    ; load raw u32
  bgeu a10, a2, ... ; compare against pre-hoisted 1.0f bits

Size delta vs. the prior float-compare form:
  ESP32-IDF: validate_ -16 B, net -12 B
  ESP8266:   validate_ -20 B, net -20 B

vs. dev baseline (isolated light build, matched funcs):
  ESP32-IDF: -103 B code, +32 B PROGMEM table = -71 B net
  ESP8266:    -42 B code, +32 B PROGMEM table = -10 B net
2026-04-13 16:16:44 -10:00
J. Nick Koston cdde0abec7 [light] Refine validate_ clamp loop: ctz iteration, per-field asserts, typed pointers
Follow-up to edb2145a addressing three points:

1. Hoist the in-range check out of the logging helper. The loop now tests
   `value < 0.0f || value > 1.0f` inline and only calls the out-of-line
   log_out_of_range_and_clamp_ helper on the cold path. Hot path (value in
   range) skips the call8 and the register spill/reload around it, which
   matters because HA automations can drive perform() at high frequency.

2. Iterate only set bits with __builtin_ctz + (active & active-1). Common
   calls with one or two flags set now exit the loop after one or two
   iterations instead of always scanning all eight slots.

3. Replace the uint8_t* pointer arithmetic with typed float arrays aliasing
   &brightness_ in each struct. Per-field static_asserts (expanded via a
   local macro) now catch reorders of any single member in either struct,
   not just reorders at the endpoints. Compiles to the same machine code as
   the uint8_t* version.

Size delta vs. prior commit (isolated light build):
  ESP32-IDF: validate_ +60 B, helper -29 B, net +31 B
  ESP8266:   validate_ +72 B, helper -42 B, net +30 B
Still a net win vs. dev on both targets (ESP32-IDF -91 B, ESP8266 -22 B).
2026-04-13 16:07:34 -10:00
J. Nick Koston edb2145aca [light] Collapse 8 clamp-and-copy blocks in LightCall::validate_ into a loop
Reorder FieldFlags so the eight [0.0, 1.0]-clamped float fields occupy
bits 0-7 in the same order as they appear in LightCall and
LightColorValues, and move color_temperature_ to the end of both
structs. Under that layout the LightCall offset for clamp field i is
`offsetof(LightCall, brightness_) + i * 4`, and the LightColorValues
offset is exactly 12 bytes lower for every field. validate_() now
iterates the active clamp bits in a small loop that computes these
offsets from the bit position instead of expanding eight nearly
identical inline blocks via macro.

The field-name PROGMEM pointer is passed to clamp_and_log_if_invalid as
`const LogString *const *`; progmem_read_ptr only runs on the cold
(out-of-range) path, so the hot path performs no flash reads for the
name. The eight invariants the loop relies on (flag-bit layout,
field contiguity, and the constant 12-byte delta) are enforced by
static_asserts so any future reshuffle fails loudly at compile time.

Size deltas for the isolated light component build (vs dev):
  ESP32-IDF:  -118 B code, +32 B PROGMEM name table = -86 B net
  ESP8266:     -56 B code, +32 B PROGMEM name table = -24 B net
0 B RAM impact on both targets.
2026-04-13 15:55:50 -10:00
J. Nick Koston 76c8eeede9 [light] Fix uint16_t overflow in color_uncorrect_channel_
When max_brightness and local_brightness_ are small but non-zero, the
intermediate (uncorrected / max_brightness) * 255 can exceed 65535
before the std::min(255) clamp runs, producing an incorrect low result.
Widen intermediates to uint32_t. Copilot review catch on #15727.
2026-04-13 15:08:36 -10:00
J. Nick Koston 10412ac2c5 Merge remote-tracking branch 'origin/light-gamma-uncorrect-outline' into integration 2026-04-13 15:04:11 -10:00
J. Nick Koston 4696d70b8a Merge remote-tracking branch 'origin/light-addressable-gamma-transition-stall' into integration 2026-04-13 15:04:07 -10:00
J. Nick Koston 12b55f176f [light] Clearer uniformity scan + note edge case in uniform path 2026-04-13 14:56:48 -10:00
J. Nick Koston b324630f8e [light] Type-annotate to_code in mock_addressable_light 2026-04-13 14:56:02 -10:00
J. Nick Koston 8da24fd1d9 [light] Use existing integration test helpers in transition test 2026-04-13 14:54:39 -10:00
J. Nick Koston 32130e1cb1 [light] Address Copilot review feedback on PR #15726
- mock_addressable_light.h: add direct <memory>/<cstdint>/<cstddef> includes
- test: use asyncio.get_running_loop() instead of deprecated get_event_loop()
- test: rebase timing to command-issue time (not first-nonzero) and use
  absolute progress for assertion 2, so late-transition check can't skew
  when the first nonzero sample happens to land near the assertion-1 limit
2026-04-13 14:53:17 -10:00
J. Nick Koston 827afb0e98 [light] Move gamma uncorrect math out-of-line, drop ALWAYS_INLINE hints
The color_uncorrect_red/green/blue/white helpers each contain two 16-bit
divides and a call into the out-of-line gamma_uncorrect_ LUT search. They
were marked ESPHOME_ALWAYS_INLINE, a hint inherited from the original 2019
C++ port when the gamma math was a single powf() call and the methods were
trivially small.

Since the 16-bit gamma LUT landed (#14123, Feb 2026) the bodies grew enough
that forcing inlining at every call site duplicates two 16-bit div routines
(~90 bytes on ESP8266 Xtensa, no fast 16-bit hw div) across every addressable
effect, range op, and transition step that reads a pixel back through the
gamma curve. Move the four channel methods and the Color wrapper to the .cpp
and drop the ALWAYS_INLINE hints on the forward direction too so the
compiler picks per call site.
2026-04-13 14:47:11 -10:00
J. Nick Koston 93893e02a7 Revert: raw-byte uniformity check (didn't help inlining) 2026-04-13 14:35:23 -10:00
J. Nick Koston 6edadaa33b [light] Use raw byte compare for uniformity scan to keep apply() hot path inlinable 2026-04-13 14:31:42 -10:00
J. Nick Koston 4e8f98e767 [light] Collapse uniform-start flag+Color into optional<Color> 2026-04-13 14:22:13 -10:00
J. Nick Koston 3f56e0255a [light] Avoid addressable transition stall at low gamma-corrected values
When a uniform-colored addressable strip transitions from one color to
another, interpolate math-only against a cached start color instead of
reading each LED's current value back through the 8-bit stored byte.

The old algorithm used led.get_red()/etc. every step as the source for
the delta, which round-tripped through gamma uncorrect/correct and the
8-bit stored byte. At gamma 2.8, any pre-gamma value below ~27 rounds
to stored byte 0, so small early-transition steps produced stored 0 and
the next step read back 0, stalling progress until ~90% of the transition
before a single step produced a large-enough pre-gamma value to clear
the gamma threshold. Result: dark for the first 9s of a 10s fade, then
jump on in the final 1s.

Detect uniform start state in start() and take a cheap math-only lerp
path when true, so the stored byte advances through each gamma threshold
as smoothed_progress crosses it. Falls back to the existing per-LED
read-back algorithm when the buffer is non-uniform (e.g. when
transitioning out of an addressable effect).
2026-04-13 14:17:21 -10:00
J. Nick Koston 21df5d9bf6 [web_server] Reset OTA backend on new upload to avoid brick after interrupted OTA (#15720) 2026-04-13 13:59:45 -10:00
J. Nick Koston 73c972a604 [adc] Place ADC oneshot control functions in IRAM for cache safety (#15717) 2026-04-13 13:59:32 -10:00
J. Nick Koston 4dfdcfc46d Merge remote-tracking branch 'upstream/adc-iram-safety' into integration 2026-04-13 13:51:21 -10:00
J. Nick Koston ddf5ab6d1c Merge remote-tracking branch 'upstream/esptool-skip-missing-flash-images' into integration 2026-04-13 13:51:03 -10:00
J. Nick Koston 5f76b78cfa [esphome] Skip missing extra flash images in upload_using_esptool
PlatformIO's idedata may list flash images that do not exist on disk
(e.g. a tasmota tinyuf2.bin referenced by the adafruit_qtpy_esp32s3_n4r2
board). Previously the CLI passed every entry straight to esptool, which
aborted the entire flash with "No such file or directory". The dashboard
path is unaffected because it flashes the pre-merged firmware.factory.bin
produced by the post-build step, which already tolerates missing inputs.

Filter non-existent extra_flash_images with a warning so a stale or
incorrect platform-declared image no longer breaks esphome run.

Fixes https://github.com/esphome/esphome/issues/15634
2026-04-13 13:37:29 -10:00