From 2cc933fe4c03c502f91714dd247c47aa3ae6da1f Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 21 Oct 2026 06:28:00 -0700 Subject: [PATCH 1/3] raspberrypi: return an empty string for wifi.Network.country The raw qstr number was cast straight to an object, so Python saw the integer 0 instead of a str. Co-Authored-By: Claude Opus 5.5 (1M context) --- ports/raspberrypi/common-hal/wifi/Network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/wifi/Network.c b/ports/raspberrypi/common-hal/wifi/Network.c index dd3e4d0f2f1..a323276003c 100644 --- a/ports/raspberrypi/common-hal/wifi/Network.c +++ b/ports/raspberrypi/common-hal/wifi/Network.c @@ -31,7 +31,7 @@ mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self) { } mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self) { - return (mp_obj_t)MP_QSTR_; + return MP_OBJ_NEW_QSTR(MP_QSTR_); } mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self) { From 570c5cedfd65682437ec7a154767339e0f917a5b Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 21 Oct 2026 06:27:48 -0700 Subject: [PATCH 2/3] raspberrypi: clear the old DHCP address when leaving a network After stop_station() the netif kept its DHCP address while the link was down. connect() to another network then saw the link come up with an address already set and returned before DHCP had run, still holding the previous network's address. Clear the address instead. DHCP keeps its lease and asks for it again when the link returns, so the same network re-acknowledges it and a different one refuses it and assigns a new one. Co-Authored-By: Claude Opus 5.5 (1M context) --- ports/raspberrypi/common-hal/wifi/Radio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 876941cab4d..2176f1d96bd 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -193,6 +193,12 @@ void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self) { break; } } + // Drop the DHCP address so the next connect() waits for a lease from the new network. + MICROPY_PY_LWIP_ENTER + if (dhcp_supplied_address(NETIF_STA)) { + netif_set_ipaddr(NETIF_STA, IP4_ADDR_ANY4); + } + MICROPY_PY_LWIP_EXIT bindings_cyw43_wifi_enforce_pm(); } From 8a7414500044738456041b3bf4d02c112d7ee1fc Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 21 Oct 2026 05:49:12 -0700 Subject: [PATCH 3/3] raspberrypi: implement wifi.radio.ap_info Return the connected network instead of raising NotImplementedError. SSID comes from the connect() call, channel, RSSI and BSSID from the CYW43. Security reflects how connect() joined: open, or WPA2 with a password. Returns None when the station link is not up. Fixes #11030, fixes #9323. Co-Authored-By: Claude Opus 5.5 (1M context) --- ports/raspberrypi/common-hal/wifi/Radio.c | 36 ++++++++++++++++++++--- ports/raspberrypi/common-hal/wifi/Radio.h | 1 + 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 2176f1d96bd..9e4090f2638 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -353,7 +353,10 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t // disconnect common_hal_wifi_radio_stop_station(self); - // connect + // connect. Record the network now: the join carries on after a timeout. + memcpy(self->connected_ssid, ssid, ssid_len); + self->connected_ssid_len = ssid_len; + self->connected_with_password = password_len != 0; int auth_mode = password_len ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN; cyw43_arch_wifi_connect_async((const char *)ssid, (const char *)password, auth_mode); // TODO: Implement authmode check like in espressif @@ -368,8 +371,6 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t switch (result) { case CYW43_LINK_UP: - memcpy(self->connected_ssid, ssid, ssid_len); - self->connected_ssid_len = ssid_len; bindings_cyw43_wifi_enforce_pm(); return WIFI_RADIO_ERROR_NONE; case CYW43_LINK_FAIL: @@ -390,7 +391,34 @@ bool common_hal_wifi_radio_get_connected(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { - mp_raise_NotImplementedError(NULL); + if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_UP) { + return mp_const_none; + } + + cyw43_ev_scan_result_t record = {0}; + memcpy(record.ssid, self->connected_ssid, self->connected_ssid_len); + record.ssid_len = self->connected_ssid_len; + + // channel_info_t: hardware channel, target channel, scan channel + uint32_t channel_info[3]; + if (cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_CHANNEL, sizeof(channel_info), (uint8_t *)channel_info, CYW43_ITF_STA) == 0) { + record.channel = channel_info[0]; + } + + int32_t rssi; + if (cyw43_wifi_get_rssi(&cyw43_state, &rssi) == 0) { + record.rssi = rssi; + } + + cyw43_wifi_get_bssid(&cyw43_state, record.bssid); + + // connect() joins with either CYW43_AUTH_OPEN or CYW43_AUTH_WPA2_AES_PSK. + // Encode that with the scan result bits from cyw43_ll.c: 1 is privacy, 4 is WPA2. + record.auth_mode = self->connected_with_password ? (1 | 4) : 0; + + wifi_network_obj_t *ap_info = mp_obj_malloc(wifi_network_obj_t, &wifi_network_type); + ap_info->record = record; + return MP_OBJ_FROM_PTR(ap_info); } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { diff --git a/ports/raspberrypi/common-hal/wifi/Radio.h b/ports/raspberrypi/common-hal/wifi/Radio.h index 53b6cd8f92f..6dbaa9ea174 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.h +++ b/ports/raspberrypi/common-hal/wifi/Radio.h @@ -17,6 +17,7 @@ typedef struct { wifi_scannednetworks_obj_t *current_scan; uint8_t connected_ssid[32]; uint8_t connected_ssid_len; + bool connected_with_password; bool enabled; } wifi_radio_obj_t;