RAMAllocator with default flags is stateless — it's just a dispatch
wrapper over heap_caps_malloc/realloc/free. Remove the stored member
from SpiRamAllocator, using stack-local instances at each call site.
Also make RAMAllocator constructors constexpr so the compiler can
fully evaluate flag logic at compile time.
Note: SpiRamAllocator was initialized with RAMAllocator::NONE (0),
which is equivalent to default construction since the constructor
preserves the default ALLOC_INTERNAL | ALLOC_EXTERNAL flags when
no valid allocation flags are provided.
Co-Authored-By: J. Nick Koston <nick@koston.org>
RAMAllocator with default flags is stateless — it's just a dispatch
wrapper over heap_caps_malloc/realloc/free. There's no need to store
it as a class member. Use stack-local instances at each call site
instead, matching the pattern used in audio_transfer_buffer and
ring_buffer.
Co-Authored-By: J. Nick Koston <nick@koston.org>
RAMAllocator with default flags is stateless — it's just a dispatch
wrapper over heap_caps_malloc/realloc/free. There's no need to store
it as a class member. Use stack-local instances at each call site
instead, matching the pattern used in audio_transfer_buffer and
ring_buffer.
Co-Authored-By: J. Nick Koston <nick@koston.org>
RAMAllocator is stateless when using default flags — it's just a
dispatch wrapper over heap_caps_malloc/realloc/free. There's no need
to store it as a class member. Use stack-local instances at each call
site instead, matching the pattern used in audio_transfer_buffer and
ring_buffer.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Cannot confirm wifi_station_disconnect() synchronously clears the
lwIP netif LINK_UP flag on ESP8266 NONOS SDK. The comment doesn't
need to make claims about link state since the fix is simply that
the hostname never changes at runtime, making dhcp_renew() pointless.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dhcp_renew() loop was cargo-culted from Arduino ESP8266's
WiFi.hostname() which was designed for changing the hostname on
an already-connected system with multiple interfaces (WiFi+Ethernet).
In ESPHome, wifi_apply_hostname_() is only called from:
- setup_() — before WiFi connects (link never up)
- wifi_sta_connect_() — after wifi_disconnect_() (link always down)
The hostname is fixed at compile time and never changes at runtime.
Setting intf->hostname is sufficient — lwIP automatically includes
it in DHCP DISCOVER/REQUEST packets via LWIP_NETIF_HOSTNAME.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DHCP_STATE_BOUND alone is insufficient — during reconnection, DHCP
can remain BOUND from a previous connection while the link is down
(wifi_disconnect_() doesn't stop DHCP). Both conditions are needed:
DHCP must be BOUND and the interface must have link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
netif_is_link_up() is insufficient — if wifi_station_connect()
completes quickly (e.g. fast_connect), the setup() call at line 710
could reach dhcp_renew() with link up but DHCP still in SELECTING
or REQUESTING state, causing the same state corruption.
Check dhcp->state == DHCP_STATE_BOUND directly to ensure dhcp_renew()
is only called when there is an actual lease to renew.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
wifi_apply_hostname_() calls dhcp_renew() on all interfaces with DHCP
data, including when WiFi is not yet connected. lwIP's dhcp_renew()
unconditionally sets the DHCP state to RENEWING (line 1159 in dhcp.c)
before attempting to send, and never rolls back the state on failure.
This corrupts the DHCP state machine: when WiFi later connects and
dhcp_network_changed() is called, it sees RENEWING state and calls
dhcp_reboot() instead of dhcp_discover(). dhcp_reboot() sends a
broadcast DHCP REQUEST for IP 0.0.0.0 (since no lease was ever
obtained), which can put some routers into a persistent bad state
that requires a router restart to clear.
This bug has existed since commit 072b2c445c (Dec 2019, "Add ESP8266
core v2.6.2") and affects every ESP8266 WiFi connection attempt. Most
routers handle the bogus DHCP REQUEST gracefully (NAK then fallback
to DISCOVER), but affected routers get stuck and refuse connections
from the device until restarted.
Fix: guard the dhcp_renew() call with netif_is_link_up() so it only
runs when the interface actually has an active link. The hostname is
still set on the netif regardless, so it will be included in DHCP
packets when the connection is established normally.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace heap-allocated std::vector constants with static constexpr
std::array in MIFARE Classic and Ultralight write operations across
pn532, pn7150, and pn7160 components.
Changes:
- Convert write_mifare_classic_block_ and write_mifare_ultralight_page_
signatures from std::vector<uint8_t>& to const uint8_t*/size_t
- Replace 24 constant 16-byte vectors in format functions with
static constexpr std::array (data now lives in flash/rodata)
- Replace 3 constant 4-byte blank_data vectors with static constexpr
std::array
- Eliminate per-iteration vector copies in write_tag loops by passing
pointers directly into the encoded buffer
Replace std::string with StringRef (non-owning string view) for
user service string arguments in YAML-generated services. This
avoids unnecessary heap allocation when the protobuf decode buffer
already contains the string data.
Key changes:
- Frame helpers reserve +1 byte in rx_buf_ so string fields can be
safely null-terminated in-place after decode
- Add (null_terminate) protobuf field option to target only fields
that need it (ExecuteServiceArgument.string_ and
HomeAssistantStateResponse.state)
- Add StringRef template specializations for get_execute_arg_value
and to_service_arg_type
- Python codegen uses StringRef for string service args, with
automatic std::string fallback when deferred actions (delay,
wait_until, script.wait) are present in the action chain
- Add deferred flag to action registry for detecting actions that
store trigger args for later execution
- Simplify HomeAssistantStateResponse handler by removing
SmallBufferWithHeapFallback copy (state is null-terminated
in-place)
- Add compare() method to StringRef for external component
compatibility
Saves ~240 bytes of flash on ESP8266 by eliminating std::string
template instantiations for user service string arguments.