1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-30 22:53:59 +00:00

Merge remote-tracking branch 'upstream/dev' into integration

This commit is contained in:
J. Nick Koston
2025-07-17 12:23:10 -10:00
23 changed files with 899 additions and 13 deletions

View File

@@ -1,4 +1,5 @@
#include "esphome/core/helpers.h"
#include "esphome/core/defines.h"
#ifdef USE_ESP32
@@ -36,7 +37,15 @@ IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
LwIPLock::LwIPLock() {
#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING
// Only lock if we're not already in the TCPIP thread
// When CONFIG_LWIP_TCPIP_CORE_LOCKING is enabled, lwIP uses a global mutex to protect
// its internal state. Any thread can take this lock to safely access lwIP APIs.
//
// sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER) returns true if the current thread
// already holds the lwIP core lock. This prevents recursive locking attempts and
// allows nested LwIPLock instances to work correctly.
//
// If we don't already hold the lock, acquire it. This will block until the lock
// is available if another thread currently holds it.
if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) {
LOCK_TCPIP_CORE();
}
@@ -45,7 +54,16 @@ LwIPLock::LwIPLock() {
LwIPLock::~LwIPLock() {
#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING
// Only unlock if we hold the lock
// Only release the lwIP core lock if this thread currently holds it.
//
// sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER) queries lwIP's internal lock
// ownership tracking. It returns true only if the current thread is registered
// as the lock holder.
//
// This check is essential because:
// 1. We may not have acquired the lock in the constructor (if we already held it)
// 2. The lock might have been released by other means between constructor and destructor
// 3. Calling UNLOCK_TCPIP_CORE() without holding the lock causes undefined behavior
if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) {
UNLOCK_TCPIP_CORE();
}

View File

@@ -22,6 +22,10 @@ void Mutex::unlock() {}
IRAM_ATTR InterruptLock::InterruptLock() { state_ = xt_rsil(15); }
IRAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(state_); }
// ESP8266 doesn't support lwIP core locking, so this is a no-op
LwIPLock::LwIPLock() {}
LwIPLock::~LwIPLock() {}
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
wifi_get_macaddr(STATION_IF, mac);
}

View File

@@ -26,6 +26,10 @@ void Mutex::unlock() { xSemaphoreGive(this->handle_); }
IRAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); }
IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
// LibreTiny doesn't support lwIP core locking, so this is a no-op
LwIPLock::LwIPLock() {}
LwIPLock::~LwIPLock() {}
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
WiFi.macAddress(mac);
}

View File

@@ -204,7 +204,7 @@ def add_pio_file(component: str, key: str, data: str):
cv.validate_id_name(key)
except cv.Invalid as e:
raise EsphomeError(
f"[{component}] Invalid PIO key: {key}. Allowed characters: [{ascii_letters}{digits}_]\nPlease report an issue https://github.com/esphome/issues"
f"[{component}] Invalid PIO key: {key}. Allowed characters: [{ascii_letters}{digits}_]\nPlease report an issue https://github.com/esphome/esphome/issues"
) from e
CORE.data[KEY_RP2040][KEY_PIO_FILES][key] = data

View File

@@ -44,6 +44,10 @@ void Mutex::unlock() {}
IRAM_ATTR InterruptLock::InterruptLock() { state_ = save_and_disable_interrupts(); }
IRAM_ATTR InterruptLock::~InterruptLock() { restore_interrupts(state_); }
// RP2040 doesn't support lwIP core locking, so this is a no-op
LwIPLock::LwIPLock() {}
LwIPLock::~LwIPLock() {}
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
#ifdef USE_WIFI
WiFi.macAddress(mac);

View File

@@ -317,3 +317,15 @@ async def to_code(config):
if (sorting_group_config := config.get(CONF_SORTING_GROUPS)) is not None:
cg.add_define("USE_WEBSERVER_SORTING")
add_sorting_groups(var, sorting_group_config)
def FILTER_SOURCE_FILES() -> list[str]:
"""Filter out web_server_v1.cpp when version is not 1."""
files_to_filter: list[str] = []
# web_server_v1.cpp is only needed when version is 1
config = CORE.config.get("web_server", {})
if config.get(CONF_VERSION, 2) != 1:
files_to_filter.append("web_server_v1.cpp")
return files_to_filter

View File

@@ -1620,7 +1620,9 @@ void WebServer::handle_event_request(AsyncWebServerRequest *request, const UrlMa
request->send(404);
}
static std::string get_event_type(event::Event *event) { return event->last_event_type ? *event->last_event_type : ""; }
static std::string get_event_type(event::Event *event) {
return (event && event->last_event_type) ? *event->last_event_type : "";
}
std::string WebServer::event_state_json_generator(WebServer *web_server, void *source) {
auto *event = static_cast<event::Event *>(source);

View File

@@ -54,6 +54,10 @@ void Mutex::unlock() { k_mutex_unlock(static_cast<k_mutex *>(this->handle_)); }
IRAM_ATTR InterruptLock::InterruptLock() { state_ = irq_lock(); }
IRAM_ATTR InterruptLock::~InterruptLock() { irq_unlock(state_); }
// Zephyr doesn't support lwIP core locking, so this is a no-op
LwIPLock::LwIPLock() {}
LwIPLock::~LwIPLock() {}
uint32_t random_uint32() { return rand(); } // NOLINT(cert-msc30-c, cert-msc50-cpp)
bool random_bytes(uint8_t *data, size_t len) {
sys_rand_get(data, len);

View File

@@ -695,6 +695,10 @@ class LwIPLock {
public:
LwIPLock();
~LwIPLock();
// Delete copy constructor and copy assignment operator to prevent accidental copying
LwIPLock(const LwIPLock &) = delete;
LwIPLock &operator=(const LwIPLock &) = delete;
};
/** Helper class to request `loop()` to be called as fast as possible.