ESPHome 2025.12.1
Loading...
Searching...
No Matches
wifi_component_pico_w.cpp
Go to the documentation of this file.
1#include "wifi_component.h"
2
3#ifdef USE_WIFI
4#ifdef USE_RP2040
5
6#include "lwip/dns.h"
7#include "lwip/err.h"
8#include "lwip/netif.h"
9#include <AddrList.h>
10
12#include "esphome/core/hal.h"
14#include "esphome/core/log.h"
15#include "esphome/core/util.h"
16
17namespace esphome::wifi {
18
19static const char *const TAG = "wifi_pico_w";
20
21// Track previous state for detecting changes
22static bool s_sta_was_connected = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
23static bool s_sta_had_ip = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
24
25bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
26 if (sta.has_value()) {
27 if (sta.value()) {
28 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE);
29 }
30 }
31
32 bool ap_state = false;
33 if (ap.has_value()) {
34 if (ap.value()) {
35 cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_AP, true, CYW43_COUNTRY_WORLDWIDE);
36 ap_state = true;
37 }
38 }
39 this->ap_started_ = ap_state;
40 return true;
41}
42
44 uint32_t pm;
45 switch (this->power_save_) {
47 pm = CYW43_PERFORMANCE_PM;
48 break;
50 pm = CYW43_DEFAULT_PM;
51 break;
53 pm = CYW43_AGGRESSIVE_PM;
54 break;
55 }
56 int ret = cyw43_wifi_pm(&cyw43_state, pm);
57 bool success = ret == 0;
58#ifdef USE_WIFI_LISTENERS
59 if (success) {
60 for (auto *listener : this->power_save_listeners_) {
61 listener->on_wifi_power_save(this->power_save_);
62 }
63 }
64#endif
65 return success;
66}
67
68// TODO: The driver doesn't seem to have an API for this
69bool WiFiComponent::wifi_apply_output_power_(float output_power) { return true; }
70
71bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
72#ifdef USE_WIFI_MANUAL_IP
73 if (!this->wifi_sta_ip_config_(ap.get_manual_ip()))
74 return false;
75#else
76 if (!this->wifi_sta_ip_config_({}))
77 return false;
78#endif
79
80 auto ret = WiFi.begin(ap.get_ssid().c_str(), ap.get_password().c_str());
81 if (ret != WL_CONNECTED)
82 return false;
83
84 return true;
85}
86
87bool WiFiComponent::wifi_sta_pre_setup_() { return this->wifi_mode_(true, {}); }
88
89bool WiFiComponent::wifi_sta_ip_config_(const optional<ManualIP> &manual_ip) {
90 if (!manual_ip.has_value()) {
91 return true;
92 }
93
94 IPAddress ip_address = manual_ip->static_ip;
95 IPAddress gateway = manual_ip->gateway;
96 IPAddress subnet = manual_ip->subnet;
97
98 IPAddress dns = manual_ip->dns1;
99
100 WiFi.config(ip_address, dns, gateway, subnet);
101 return true;
102}
103
105 WiFi.setHostname(App.get_name().c_str());
106 return true;
107}
108const char *get_auth_mode_str(uint8_t mode) {
109 // TODO:
110 return "UNKNOWN";
111}
112const char *get_disconnect_reason_str(uint8_t reason) {
113 // TODO:
114 return "UNKNOWN";
115}
116
118 int status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
119 switch (status) {
120 case CYW43_LINK_JOIN:
121 case CYW43_LINK_NOIP:
123 case CYW43_LINK_UP:
125 case CYW43_LINK_FAIL:
126 case CYW43_LINK_BADAUTH:
128 case CYW43_LINK_NONET:
130 }
132}
133
134int WiFiComponent::s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result) {
136 return 0;
137}
138
139void WiFiComponent::wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result) {
140 bssid_t bssid;
141 std::copy(result->bssid, result->bssid + 6, bssid.begin());
142 std::string ssid(reinterpret_cast<const char *>(result->ssid));
143 WiFiScanResult res(bssid, ssid, result->channel, result->rssi, result->auth_mode != CYW43_AUTH_OPEN, ssid.empty());
144 if (std::find(this->scan_result_.begin(), this->scan_result_.end(), res) == this->scan_result_.end()) {
145 this->scan_result_.push_back(res);
146 }
147}
148
149bool WiFiComponent::wifi_scan_start_(bool passive) {
150 this->scan_result_.clear();
151 this->scan_done_ = false;
152 cyw43_wifi_scan_options_t scan_options = {0};
153 scan_options.scan_type = passive ? 1 : 0;
154 int err = cyw43_wifi_scan(&cyw43_state, &scan_options, nullptr, &s_wifi_scan_result);
155 if (err) {
156 ESP_LOGV(TAG, "cyw43_wifi_scan failed");
157 }
158 return err == 0;
159 return true;
160}
161
162#ifdef USE_WIFI_AP
163bool WiFiComponent::wifi_ap_ip_config_(const optional<ManualIP> &manual_ip) {
164 esphome::network::IPAddress ip_address, gateway, subnet, dns;
165 if (manual_ip.has_value()) {
166 ip_address = manual_ip->static_ip;
167 gateway = manual_ip->gateway;
168 subnet = manual_ip->subnet;
169 dns = manual_ip->static_ip;
170 } else {
171 ip_address = network::IPAddress(192, 168, 4, 1);
172 gateway = network::IPAddress(192, 168, 4, 1);
173 subnet = network::IPAddress(255, 255, 255, 0);
174 dns = network::IPAddress(192, 168, 4, 1);
175 }
176 WiFi.config(ip_address, dns, gateway, subnet);
177 return true;
178}
179
180bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
181 if (!this->wifi_mode_({}, true))
182 return false;
183#ifdef USE_WIFI_MANUAL_IP
184 if (!this->wifi_ap_ip_config_(ap.get_manual_ip())) {
185 ESP_LOGV(TAG, "wifi_ap_ip_config_ failed");
186 return false;
187 }
188#else
189 if (!this->wifi_ap_ip_config_({})) {
190 ESP_LOGV(TAG, "wifi_ap_ip_config_ failed");
191 return false;
192 }
193#endif
194
195 WiFi.beginAP(ap.get_ssid().c_str(), ap.get_password().c_str(), ap.get_channel().value_or(1));
196
197 return true;
198}
199
200network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {(const ip_addr_t *) WiFi.localIP()}; }
201#endif // USE_WIFI_AP
202
204 int err = cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA);
205 return err == 0;
206}
207
209 bssid_t bssid{};
210 uint8_t raw_bssid[6];
211 WiFi.BSSID(raw_bssid);
212 for (size_t i = 0; i < bssid.size(); i++)
213 bssid[i] = raw_bssid[i];
214 return bssid;
215}
216std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); }
217int8_t WiFiComponent::wifi_rssi() { return WiFi.status() == WL_CONNECTED ? WiFi.RSSI() : WIFI_RSSI_DISCONNECTED; }
218int32_t WiFiComponent::get_wifi_channel() { return WiFi.channel(); }
219
221 network::IPAddresses addresses;
222 uint8_t index = 0;
223 for (auto addr : addrList) {
224 addresses[index++] = addr.ipFromNetifNum();
225 }
226 return addresses;
227}
228network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; }
229network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; }
230network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {
231 const ip_addr_t *dns_ip = dns_getserver(num);
232 return network::IPAddress(dns_ip);
233}
234
236 // Handle scan completion
237 if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) {
238 this->scan_done_ = true;
239 ESP_LOGV(TAG, "Scan done");
240#ifdef USE_WIFI_LISTENERS
241 for (auto *listener : this->scan_results_listeners_) {
242 listener->on_wifi_scan_results(this->scan_result_);
243 }
244#endif
245 }
246
247 // Poll for connection state changes
248 // The arduino-pico WiFi library doesn't have event callbacks like ESP8266/ESP32,
249 // so we need to poll the link status to detect state changes
250 auto status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
251 bool is_connected = (status == CYW43_LINK_UP);
252
253 // Detect connection state change
254 if (is_connected && !s_sta_was_connected) {
255 // Just connected
256 s_sta_was_connected = true;
257 ESP_LOGV(TAG, "Connected");
258#ifdef USE_WIFI_LISTENERS
259 for (auto *listener : this->connect_state_listeners_) {
260 listener->on_wifi_connect_state(this->wifi_ssid(), this->wifi_bssid());
261 }
262#endif
263 } else if (!is_connected && s_sta_was_connected) {
264 // Just disconnected
265 s_sta_was_connected = false;
266 s_sta_had_ip = false;
267 ESP_LOGV(TAG, "Disconnected");
268#ifdef USE_WIFI_LISTENERS
269 for (auto *listener : this->connect_state_listeners_) {
270 listener->on_wifi_connect_state("", bssid_t({0, 0, 0, 0, 0, 0}));
271 }
272#endif
273 }
274
275 // Detect IP address changes (only when connected)
276 if (is_connected) {
277 bool has_ip = false;
278 // Check for any IP address (IPv4 or IPv6)
279 for (auto addr : addrList) {
280 has_ip = true;
281 break;
282 }
283
284 if (has_ip && !s_sta_had_ip) {
285 // Just got IP address
286 s_sta_had_ip = true;
287 ESP_LOGV(TAG, "Got IP address");
288#ifdef USE_WIFI_LISTENERS
289 for (auto *listener : this->ip_state_listeners_) {
290 listener->on_ip_state(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
291 }
292#endif
293 }
294 }
295}
296
298
299} // namespace esphome::wifi
300#endif
301#endif
BedjetMode mode
BedJet operating mode.
uint8_t status
Definition bl0942.h:8
const std::string & get_name() const
Get the name of this Application set by pre_setup().
std::vector< WiFiIPStateListener * > ip_state_listeners_
std::vector< WiFiScanResultsListener * > scan_results_listeners_
wifi_scan_vector_t< WiFiScanResult > scan_result_
bool wifi_sta_ip_config_(const optional< ManualIP > &manual_ip)
static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
network::IPAddress get_dns_address(int num)
void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
network::IPAddress wifi_dns_ip_(int num)
bool wifi_ap_ip_config_(const optional< ManualIP > &manual_ip)
bool wifi_apply_output_power_(float output_power)
WiFiSTAConnectStatus wifi_sta_connect_status_()
bool wifi_mode_(optional< bool > sta, optional< bool > ap)
network::IPAddresses wifi_sta_ip_addresses()
std::vector< WiFiConnectStateListener * > connect_state_listeners_
std::vector< WiFiPowerSaveListener * > power_save_listeners_
in_addr ip_addr_t
Definition ip_address.h:22
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:149
const char *const TAG
Definition spi.cpp:8
std::array< uint8_t, 6 > bssid_t
const LogString * get_auth_mode_str(uint8_t mode)
const LogString * get_disconnect_reason_str(uint8_t reason)
WiFiComponent * global_wifi_component
@ WIFI_COMPONENT_STATE_STA_SCANNING
WiFi is in STA-only mode and currently scanning for APs.
Application App
Global storage of Application pointer - only one Application can exist.