IfAction now takes a bool HasElse template parameter. When false (the
common case — most if actions have no else branch), the else_ ActionList
is replaced by an empty struct with [[no_unique_address]], saving 8
bytes per instance.
The codegen already knows at generation time whether an else branch
exists and passes the appropriate template argument.
Replace the inline optional<LightStateRTCState> (~44 bytes) with a
function pointer callback (4 bytes) that populates the initial state
during setup. The callback is a stateless lambda whose values live in
flash as code, not in the LightState object.
Saves ~40 bytes per LightState instance unconditionally — the optional
reserved space for the struct even when initial_state was not configured
(the common case).
Replace 14 TemplatableValue fields with a per-field union that stores
either a constant value or a callable pointer in the same 4 bytes
(on 32-bit targets). A 2-bit-per-field type tag in a uint32_t tracks
field state (unset/constant/stateless lambda/stateful lambda).
Reduces LightControlAction from 128 to 76 bytes per instance on ESP32.
For a config with 8 light actions, this saves 416 bytes of RAM and
476 bytes of flash (from eliminated TemplatableValue template
instantiations).
Replace 14 TemplatableValue fields with a per-field union that stores
either a constant value or a callable pointer in the same 4 bytes
(on 32-bit targets). A 2-bit-per-field type tag in a uint32_t tracks
field state (unset/constant/stateless lambda/stateful lambda).
Reduces LightControlAction from 128 to 76 bytes per instance on ESP32.
For a config with 8 light actions, this saves 416 bytes of RAM and
476 bytes of flash (from eliminated TemplatableValue template
instantiations).
Add support for the WIZnet W5100/W5100S SPI Ethernet controller
on RP2040 platforms, using the arduino-pico lwIP_w5100 library.
Tested on W5100S-EVB-Pico hardware.
The "Roam check skipped, signal good" message was at VERBOSE level,
making it invisible in normal logs. This made it unclear whether
roaming checks were happening after a successful roam. Promote to
DEBUG to match the "Roam scan" message level.
Split the RECONNECTING log message into two cases:
- "Reconnected after failed roam" when a specific roam target was
set but we ended up on a different AP
- "Reconnected after roam scan" when no roam target was set (the
disconnect was caused by going off-channel during the scan itself)
Split the RECONNECTING log message into two cases:
- "Reconnected after failed roam" when a specific roam target was
set but we ended up on a different AP
- "Reconnected after roam scan" when no roam target was set (the
disconnect was caused by going off-channel during the scan itself)
- Clear roaming_scan_end_ on successful reconnect to prevent grace
period from incorrectly applying to a second disconnect
- Log target BSSID in "Roam successful (via retry)" message
- Move bssid_t roaming_target_bssid_ to 1-byte section to avoid
2 bytes struct padding before ap_timeout_