mirror of
https://github.com/esphome/esphome.git
synced 2026-05-20 01:16:26 +08:00
[rp2040] Update arduino-pico to 5.5.1 and fix WiFi AP fallback (#14500)
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
b97e16a84153b2a4cfc51137cd6121db3c32374504b2bea55144413b3e573052
|
||||
b6f8c16c1ddd222134bf4a71910b4c832e764e23caf49f9bce3280b079955fcf
|
||||
|
||||
@@ -91,7 +91,7 @@ def _parse_platform_version(value):
|
||||
# The default/recommended arduino framework version
|
||||
# - https://github.com/earlephilhower/arduino-pico/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico
|
||||
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(5, 5, 0)
|
||||
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(5, 5, 1)
|
||||
|
||||
# The raspberrypi platform version to use for arduino frameworks
|
||||
# - https://github.com/maxgerhardt/platform-raspberrypi/tags
|
||||
@@ -101,8 +101,8 @@ RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.4.0-gcc14-arduinopico460"
|
||||
def _arduino_check_versions(value):
|
||||
value = value.copy()
|
||||
lookups = {
|
||||
"dev": (cv.Version(5, 5, 0), "https://github.com/earlephilhower/arduino-pico"),
|
||||
"latest": (cv.Version(5, 5, 0), None),
|
||||
"dev": (cv.Version(5, 5, 1), "https://github.com/earlephilhower/arduino-pico"),
|
||||
"latest": (cv.Version(5, 5, 1), None),
|
||||
"recommended": (RECOMMENDED_ARDUINO_FRAMEWORK_VERSION, None),
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,13 @@ WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend(
|
||||
def wifi_network_ap(value):
|
||||
if value is None:
|
||||
value = {}
|
||||
return WIFI_NETWORK_AP(value)
|
||||
config = WIFI_NETWORK_AP(value)
|
||||
if CONF_MANUAL_IP in config and CORE.is_rp2040:
|
||||
raise cv.Invalid(
|
||||
"Manual AP IP configuration is not supported on RP2040. "
|
||||
"The AP uses the default IP 192.168.4.1"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend(
|
||||
|
||||
@@ -18,6 +18,25 @@ namespace esphome::wifi {
|
||||
|
||||
static const char *const TAG = "wifi_pico_w";
|
||||
|
||||
// Check if STA is fully connected (WiFi joined + has IP address).
|
||||
// Do NOT use WiFi.status() or WiFi.connected() for this — in AP-only mode they
|
||||
// unconditionally return true regardless of STA state, causing false positives
|
||||
// when the fallback AP is active.
|
||||
static bool wifi_sta_connected() {
|
||||
int link = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
IPAddress local = WiFi.localIP();
|
||||
if (link == CYW43_LINK_JOIN && local.isSet()) {
|
||||
// Verify the IP is a real STA IP, not the AP's IP leaking through
|
||||
IPAddress ap_ip = WiFi.softAPIP();
|
||||
if (local == ap_ip) {
|
||||
ESP_LOGV(TAG, "wifi_sta_connected: localIP %s matches AP IP, ignoring", local.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Track previous state for detecting changes
|
||||
static bool s_sta_was_connected = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static bool s_sta_had_ip = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
@@ -27,17 +46,21 @@ bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
|
||||
if (sta.has_value()) {
|
||||
if (sta.value()) {
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE);
|
||||
} else {
|
||||
// Leave the STA network so the radio is free for scanning.
|
||||
// Use cyw43_wifi_leave directly to avoid corrupting Arduino framework state.
|
||||
cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA);
|
||||
}
|
||||
}
|
||||
|
||||
bool ap_state = false;
|
||||
if (ap.has_value()) {
|
||||
if (ap.value()) {
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, CYW43_COUNTRY_WORLDWIDE);
|
||||
ap_state = true;
|
||||
} else {
|
||||
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, false, CYW43_COUNTRY_WORLDWIDE);
|
||||
}
|
||||
this->ap_started_ = ap.value();
|
||||
}
|
||||
this->ap_started_ = ap_state;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -129,8 +152,8 @@ WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() const {
|
||||
int status = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||
switch (status) {
|
||||
case CYW43_LINK_JOIN:
|
||||
// WiFi joined, check if we have an IP address via the Arduino framework's WiFi class
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
// WiFi joined, check if STA has an IP address via wifi_sta_connected()
|
||||
if (wifi_sta_connected()) {
|
||||
return WiFiSTAConnectStatus::CONNECTED;
|
||||
}
|
||||
return WiFiSTAConnectStatus::CONNECTING;
|
||||
@@ -188,19 +211,9 @@ bool WiFiComponent::wifi_scan_start_(bool passive) {
|
||||
|
||||
#ifdef USE_WIFI_AP
|
||||
bool WiFiComponent::wifi_ap_ip_config_(const optional<ManualIP> &manual_ip) {
|
||||
esphome::network::IPAddress ip_address, gateway, subnet, dns;
|
||||
if (manual_ip.has_value()) {
|
||||
ip_address = manual_ip->static_ip;
|
||||
gateway = manual_ip->gateway;
|
||||
subnet = manual_ip->subnet;
|
||||
dns = manual_ip->static_ip;
|
||||
} else {
|
||||
ip_address = network::IPAddress(192, 168, 4, 1);
|
||||
gateway = network::IPAddress(192, 168, 4, 1);
|
||||
subnet = network::IPAddress(255, 255, 255, 0);
|
||||
dns = network::IPAddress(192, 168, 4, 1);
|
||||
}
|
||||
WiFi.config(ip_address, dns, gateway, subnet);
|
||||
// AP IP is configured by WiFi.beginAP() internally using defaults (192.168.4.1).
|
||||
// Manual AP IP has never worked on RP2040 — WiFi.config() configures the STA
|
||||
// interface, not the AP. This is now rejected at config validation time.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -219,18 +232,25 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
|
||||
}
|
||||
#endif
|
||||
|
||||
WiFi.beginAP(ap.ssid_.c_str(), ap.password_.c_str(), ap.has_channel() ? ap.get_channel() : 1);
|
||||
// Pass nullptr for empty password — CYW43 uses the password pointer (not length)
|
||||
// to choose between OPEN and WPA2 auth mode.
|
||||
const char *ap_password = ap.password_.empty() ? nullptr : ap.password_.c_str();
|
||||
WiFi.beginAP(ap.ssid_.c_str(), ap_password, ap.has_channel() ? ap.get_channel() : 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.localIP()}; }
|
||||
network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.softAPIP()}; }
|
||||
#endif // USE_WIFI_AP
|
||||
|
||||
bool WiFiComponent::wifi_disconnect_() {
|
||||
// Use Arduino WiFi.disconnect() instead of raw cyw43_wifi_leave() to properly
|
||||
// clean up the lwIP netif, DHCP client, and internal Arduino state.
|
||||
WiFi.disconnect();
|
||||
// Use cyw43_wifi_leave() directly instead of WiFi.disconnect().
|
||||
// WiFi.disconnect() sets _wifiHWInitted=false in the Arduino framework. beginAP()
|
||||
// uses _wifiHWInitted to determine AP+STA vs AP-only mode — with it false,
|
||||
// beginAP() enters AP-only mode (IP 192.168.42.1) instead of AP_STA mode
|
||||
// (IP 192.168.4.1). In AP-only mode, _beginInternal() redirects all subsequent
|
||||
// STA connect attempts to beginAP(), creating an infinite loop.
|
||||
cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -251,14 +271,21 @@ const char *WiFiComponent::wifi_ssid_to(std::span<char, SSID_BUFFER_SIZE> buffer
|
||||
buffer[len] = '\0';
|
||||
return buffer.data();
|
||||
}
|
||||
int8_t WiFiComponent::wifi_rssi() { return WiFi.status() == WL_CONNECTED ? WiFi.RSSI() : WIFI_RSSI_DISCONNECTED; }
|
||||
int8_t WiFiComponent::wifi_rssi() { return this->is_connected_() ? WiFi.RSSI() : WIFI_RSSI_DISCONNECTED; }
|
||||
int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); }
|
||||
|
||||
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
|
||||
network::IPAddresses addresses;
|
||||
uint8_t index = 0;
|
||||
// Filter out AP interface addresses — addrList includes all lwIP netifs.
|
||||
// The AP netif IP lingers even after the AP radio is disabled.
|
||||
IPAddress ap_ip = WiFi.softAPIP();
|
||||
for (auto addr : addrList) {
|
||||
addresses[index++] = addr.ipFromNetifNum();
|
||||
IPAddress ip(addr.ipFromNetifNum());
|
||||
if (ip == ap_ip) {
|
||||
continue;
|
||||
}
|
||||
addresses[index++] = ip;
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
@@ -288,9 +315,7 @@ void WiFiComponent::wifi_loop_() {
|
||||
// Poll for connection state changes
|
||||
// The arduino-pico WiFi library doesn't have event callbacks like ESP8266/ESP32,
|
||||
// so we need to poll the link status to detect state changes.
|
||||
// Use WiFi.connected() which checks both the WiFi link and IP address via the
|
||||
// Arduino framework's own netif (not the SDK's uninitialized one).
|
||||
bool is_connected = WiFi.connected();
|
||||
bool is_connected = wifi_sta_connected();
|
||||
|
||||
// Detect connection state change
|
||||
if (is_connected && !s_sta_was_connected) {
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ board_build.filesystem_size = 0.5m
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.4.0-gcc14-arduinopico460
|
||||
platform_packages =
|
||||
; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted
|
||||
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/5.5.0/rp2040-5.5.0.zip
|
||||
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/5.5.1/rp2040-5.5.1.zip
|
||||
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
|
||||
Reference in New Issue
Block a user