ESPHome 2025.8.0b1
Loading...
Searching...
No Matches
wifi_component.h
Go to the documentation of this file.
1#pragma once
2
4#ifdef USE_WIFI
9
10#include <string>
11#include <vector>
12
13#ifdef USE_ESP32_FRAMEWORK_ARDUINO
14#include <WiFi.h>
15#include <WiFiType.h>
16#include <esp_wifi.h>
17#endif
18
19#ifdef USE_LIBRETINY
20#include <WiFi.h>
21#endif
22
23#if defined(USE_ESP_IDF) && defined(USE_WIFI_WPA2_EAP)
24#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1)
25#include <esp_eap_client.h>
26#else
27#include <esp_wpa2.h>
28#endif
29#endif
30
31#ifdef USE_ESP8266
32#include <ESP8266WiFi.h>
33#include <ESP8266WiFiType.h>
34
35#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE < VERSION_CODE(2, 4, 0)
36extern "C" {
37#include <user_interface.h>
38};
39#endif
40#endif
41
42#ifdef USE_RP2040
43extern "C" {
44#include "cyw43.h"
45#include "cyw43_country.h"
46#include "pico/cyw43_arch.h"
47}
48
49#include <WiFi.h>
50#endif
51
52namespace esphome {
53namespace wifi {
54
56 char ssid[33];
57 char password[65];
58} PACKED; // NOLINT
59
61 uint8_t bssid[6];
62 uint8_t channel;
63 int8_t ap_index;
64} PACKED; // NOLINT
65
88
96
105
106#ifdef USE_WIFI_WPA2_EAP
107struct EAPAuth {
108 std::string identity; // required for all auth types
109 std::string username;
110 std::string password;
111 const char *ca_cert; // optionally verify authentication server
112 // used for EAP-TLS
113 const char *client_cert;
114 const char *client_key;
115// used for EAP-TTLS
116#ifdef USE_ESP_IDF
117 esp_eap_ttls_phase2_types ttls_phase_2;
118#endif
119};
120#endif // USE_WIFI_WPA2_EAP
121
122using bssid_t = std::array<uint8_t, 6>;
123
124class WiFiAP {
125 public:
126 void set_ssid(const std::string &ssid);
127 void set_bssid(bssid_t bssid);
128 void set_bssid(optional<bssid_t> bssid);
129 void set_password(const std::string &password);
130#ifdef USE_WIFI_WPA2_EAP
131 void set_eap(optional<EAPAuth> eap_auth);
132#endif // USE_WIFI_WPA2_EAP
133 void set_channel(optional<uint8_t> channel);
135 void set_manual_ip(optional<ManualIP> manual_ip);
136 void set_hidden(bool hidden);
137 const std::string &get_ssid() const;
138 const optional<bssid_t> &get_bssid() const;
139 const std::string &get_password() const;
140#ifdef USE_WIFI_WPA2_EAP
141 const optional<EAPAuth> &get_eap() const;
142#endif // USE_WIFI_WPA2_EAP
143 const optional<uint8_t> &get_channel() const;
144 float get_priority() const { return priority_; }
145 const optional<ManualIP> &get_manual_ip() const;
146 bool get_hidden() const;
147
148 protected:
149 std::string ssid_;
150 std::string password_;
152#ifdef USE_WIFI_WPA2_EAP
154#endif // USE_WIFI_WPA2_EAP
156 float priority_{0};
158 bool hidden_{false};
159};
160
162 public:
163 WiFiScanResult(const bssid_t &bssid, std::string ssid, uint8_t channel, int8_t rssi, bool with_auth, bool is_hidden);
164
165 bool matches(const WiFiAP &config);
166
167 bool get_matches() const;
168 void set_matches(bool matches);
169 const bssid_t &get_bssid() const;
170 const std::string &get_ssid() const;
171 uint8_t get_channel() const;
172 int8_t get_rssi() const;
173 bool get_with_auth() const;
174 bool get_is_hidden() const;
175 float get_priority() const { return priority_; }
177
178 bool operator==(const WiFiScanResult &rhs) const;
179
180 protected:
182 std::string ssid_;
183 float priority_{0.0f};
184 uint8_t channel_;
185 int8_t rssi_;
186 bool matches_{false};
189};
190
195
201
202#ifdef USE_ESP_IDF
203struct IDFWiFiEvent;
204#endif
205
207class WiFiComponent : public Component {
208 public:
211
212 void set_sta(const WiFiAP &ap);
213 WiFiAP get_sta() { return this->selected_ap_; }
214 void add_sta(const WiFiAP &ap);
215 void clear_sta();
216
217#ifdef USE_WIFI_AP
225 void set_ap(const WiFiAP &ap);
226 WiFiAP get_ap() { return this->ap_; }
227#endif // USE_WIFI_AP
228
229 void enable();
230 void disable();
231 bool is_disabled();
232 void start_scanning();
234 void start_connecting(const WiFiAP &ap, bool two);
235 void set_fast_connect(bool fast_connect);
236 void set_ap_timeout(uint32_t ap_timeout) { ap_timeout_ = ap_timeout; }
237
239
240 void retry_connect();
241
242 bool can_proceed() override;
243
244 void set_reboot_timeout(uint32_t reboot_timeout);
245
246 bool is_connected();
247
248 void set_power_save_mode(WiFiPowerSaveMode power_save);
249 void set_output_power(float output_power) { output_power_ = output_power; }
250
251 void set_passive_scan(bool passive);
252
253 void save_wifi_sta(const std::string &ssid, const std::string &password);
254 // ========== INTERNAL METHODS ==========
255 // (In most use cases you won't need these)
257 void setup() override;
258 void start();
259 void dump_config() override;
260 void restart_adapter();
262 float get_setup_priority() const override;
263 float get_loop_priority() const override;
264
266 void loop() override;
267
268 bool has_sta() const;
269 bool has_ap() const;
270
271#ifdef USE_WIFI_11KV_SUPPORT
272 void set_btm(bool btm);
273 void set_rrm(bool rrm);
274#endif
275
278 std::string get_use_address() const;
279 void set_use_address(const std::string &use_address);
280
281 const std::vector<WiFiScanResult> &get_scan_result() const { return scan_result_; }
282
284
285 bool has_sta_priority(const bssid_t &bssid) {
286 for (auto &it : this->sta_priorities_) {
287 if (it.bssid == bssid)
288 return true;
289 }
290 return false;
291 }
292 float get_sta_priority(const bssid_t bssid) {
293 for (auto &it : this->sta_priorities_) {
294 if (it.bssid == bssid)
295 return it.priority;
296 }
297 return 0.0f;
298 }
299 void set_sta_priority(const bssid_t bssid, float priority) {
300 for (auto &it : this->sta_priorities_) {
301 if (it.bssid == bssid) {
302 it.priority = priority;
303 return;
304 }
305 }
306 this->sta_priorities_.push_back(WiFiSTAPriority{
307 .bssid = bssid,
308 .priority = priority,
309 });
310 }
311
313 std::string wifi_ssid();
315
316 int8_t wifi_rssi();
317
318 void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
319
322
323 int32_t get_wifi_channel();
324
325 protected:
326#ifdef USE_WIFI_AP
327 void setup_ap_config_();
328#endif // USE_WIFI_AP
329
331
332 void wifi_loop_();
334 bool wifi_sta_pre_setup_();
335 bool wifi_apply_output_power_(float output_power);
339 bool wifi_sta_connect_(const WiFiAP &ap);
340 void wifi_pre_setup_();
342 bool wifi_scan_start_(bool passive);
343
344#ifdef USE_WIFI_AP
346 bool wifi_start_ap_(const WiFiAP &ap);
347#endif // USE_WIFI_AP
348
349 bool wifi_disconnect_();
350
354
357
360
361#ifdef USE_ESP8266
362 static void wifi_event_callback(System_Event_t *event);
363 void wifi_scan_done_callback_(void *arg, STATUS status);
364 static void s_wifi_scan_done_callback(void *arg, STATUS status);
365#endif
366
367#ifdef USE_ESP32_FRAMEWORK_ARDUINO
368 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
370#endif
371#ifdef USE_ESP_IDF
372 void wifi_process_event_(IDFWiFiEvent *data);
373#endif
374
375#ifdef USE_RP2040
376 static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
377 void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
378#endif
379
380#ifdef USE_LIBRETINY
381 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
383#endif
384
385 std::string use_address_;
386 std::vector<WiFiAP> sta_;
387 std::vector<WiFiSTAPriority> sta_priorities_;
388 std::vector<WiFiScanResult> scan_result_;
394
395 // Group all 32-bit integers together
397 uint32_t last_connected_{0};
398 uint32_t reboot_timeout_{};
399 uint32_t ap_timeout_{};
400
401 // Group all 8-bit values together
404 uint8_t num_retried_{0};
405 uint8_t ap_index_{0};
406#if USE_NETWORK_IPV6
408#endif /* USE_NETWORK_IPV6 */
409
410 // Group all boolean values together
411 bool fast_connect_{false};
412 bool trying_loaded_ap_{false};
413 bool retry_hidden_{false};
414 bool has_ap_{false};
417 bool scan_done_{false};
418 bool ap_setup_{false};
419 bool passive_scan_{false};
421#ifdef USE_WIFI_11KV_SUPPORT
422 bool btm_{false};
423 bool rrm_{false};
424#endif
426 bool got_ipv4_address_{false};
427
428 // Pointers at the end (naturally aligned)
431};
432
433extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
434
435template<typename... Ts> class WiFiConnectedCondition : public Condition<Ts...> {
436 public:
437 bool check(Ts... x) override { return global_wifi_component->is_connected(); }
438};
439
440template<typename... Ts> class WiFiEnabledCondition : public Condition<Ts...> {
441 public:
442 bool check(Ts... x) override { return !global_wifi_component->is_disabled(); }
443};
444
445template<typename... Ts> class WiFiEnableAction : public Action<Ts...> {
446 public:
447 void play(Ts... x) override { global_wifi_component->enable(); }
448};
449
450template<typename... Ts> class WiFiDisableAction : public Action<Ts...> {
451 public:
452 void play(Ts... x) override { global_wifi_component->disable(); }
453};
454
455template<typename... Ts> class WiFiConfigureAction : public Action<Ts...>, public Component {
456 public:
457 TEMPLATABLE_VALUE(std::string, ssid)
458 TEMPLATABLE_VALUE(std::string, password)
459 TEMPLATABLE_VALUE(bool, save)
460 TEMPLATABLE_VALUE(uint32_t, connection_timeout)
461
462 void play(Ts... x) override {
463 auto ssid = this->ssid_.value(x...);
464 auto password = this->password_.value(x...);
465 // Avoid multiple calls
466 if (this->connecting_)
467 return;
468 // If already connected to the same AP, do nothing
469 if (global_wifi_component->wifi_ssid() == ssid) {
470 // Callback to notify the user that the connection was successful
471 this->connect_trigger_->trigger();
472 return;
473 }
474 // Create a new WiFiAP object with the new SSID and password
475 this->new_sta_.set_ssid(ssid);
476 this->new_sta_.set_password(password);
477 // Save the current STA
478 this->old_sta_ = global_wifi_component->get_sta();
479 // Disable WiFi
481 // Set the state to connecting
482 this->connecting_ = true;
483 // Store the new STA so once the WiFi is enabled, it will connect to it
484 // This is necessary because the WiFiComponent will raise an error and fallback to the saved STA
485 // if trying to connect to a new STA while already connected to another one
486 if (this->save_.value(x...)) {
487 global_wifi_component->save_wifi_sta(new_sta_.get_ssid(), new_sta_.get_password());
488 } else {
490 }
491 // Enable WiFi
493 // Set timeout for the connection
494 this->set_timeout("wifi-connect-timeout", this->connection_timeout_.value(x...), [this, x...]() {
495 // If the timeout is reached, stop connecting and revert to the old AP
496 global_wifi_component->disable();
497 global_wifi_component->save_wifi_sta(old_sta_.get_ssid(), old_sta_.get_password());
498 global_wifi_component->enable();
499 // Start a timeout for the fallback if the connection to the old AP fails
500 this->set_timeout("wifi-fallback-timeout", this->connection_timeout_.value(x...), [this]() {
501 this->connecting_ = false;
502 this->error_trigger_->trigger();
503 });
504 });
505 }
506
507 Trigger<> *get_connect_trigger() const { return this->connect_trigger_; }
508 Trigger<> *get_error_trigger() const { return this->error_trigger_; }
509
510 void loop() override {
511 if (!this->connecting_)
512 return;
514 // The WiFi is connected, stop the timeout and reset the connecting flag
515 this->cancel_timeout("wifi-connect-timeout");
516 this->cancel_timeout("wifi-fallback-timeout");
517 this->connecting_ = false;
518 if (global_wifi_component->wifi_ssid() == this->new_sta_.get_ssid()) {
519 // Callback to notify the user that the connection was successful
520 this->connect_trigger_->trigger();
521 } else {
522 // Callback to notify the user that the connection failed
523 this->error_trigger_->trigger();
524 }
525 }
526 }
527
528 protected:
529 bool connecting_{false};
532 Trigger<> *connect_trigger_{new Trigger<>()};
533 Trigger<> *error_trigger_{new Trigger<>()};
534};
535
536} // namespace wifi
537} // namespace esphome
538#endif
virtual void play(Ts... x)=0
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Base class for all automation conditions.
Definition automation.h:124
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:145
void set_priority(float priority)
const optional< bssid_t > & get_bssid() const
const std::string & get_ssid() const
void set_ssid(const std::string &ssid)
const optional< uint8_t > & get_channel() const
const optional< EAPAuth > & get_eap() const
void set_channel(optional< uint8_t > channel)
const std::string & get_password() const
void set_bssid(bssid_t bssid)
optional< uint8_t > channel_
optional< EAPAuth > eap_
optional< bssid_t > bssid_
optional< ManualIP > manual_ip_
void set_eap(optional< EAPAuth > eap_auth)
void set_password(const std::string &password)
void set_manual_ip(optional< ManualIP > manual_ip)
float get_priority() const
const optional< ManualIP > & get_manual_ip() const
void set_hidden(bool hidden)
This component is responsible for managing the ESP WiFi interface.
Trigger * get_connect_trigger() const
void add_sta(const WiFiAP &ap)
void set_ap(const WiFiAP &ap)
Setup an Access Point that should be created if no connection to a station can be made.
void set_sta(const WiFiAP &ap)
bool has_sta_priority(const bssid_t &bssid)
std::string get_use_address() const
void save_wifi_sta(const std::string &ssid, const std::string &password)
void loop() override
Reconnect WiFi if required.
bool wifi_sta_ip_config_(optional< ManualIP > manual_ip)
void set_enable_on_boot(bool enable_on_boot)
float get_sta_priority(const bssid_t bssid)
static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
network::IPAddress get_dns_address(int num)
static void wifi_event_callback(System_Event_t *event)
WiFiComponent()
Construct a WiFiComponent.
std::vector< WiFiScanResult > scan_result_
void wifi_process_event_(IDFWiFiEvent *data)
std::vector< WiFiSTAPriority > sta_priorities_
bool wifi_ap_ip_config_(optional< ManualIP > manual_ip)
void start_connecting(const WiFiAP &ap, bool two)
void set_passive_scan(bool passive)
void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info)
const std::vector< WiFiScanResult > & get_scan_result() const
static void s_wifi_scan_done_callback(void *arg, STATUS status)
void set_power_save_mode(WiFiPowerSaveMode power_save)
void set_use_address(const std::string &use_address)
ESPPreferenceObject fast_connect_pref_
void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
float get_loop_priority() const override
network::IPAddresses get_ip_addresses()
std::vector< WiFiAP > sta_
float get_setup_priority() const override
WIFI setup_priority.
void set_output_power(float output_power)
Trigger * get_disconnect_trigger() const
optional< float > output_power_
void set_ap_timeout(uint32_t ap_timeout)
void set_sta_priority(const bssid_t bssid, float priority)
void set_fast_connect(bool fast_connect)
bool wifi_apply_output_power_(float output_power)
bool wifi_mode_(optional< bool > sta, optional< bool > ap)
void set_reboot_timeout(uint32_t reboot_timeout)
void setup() override
Setup WiFi interface.
TEMPLATABLE_VALUE(std::string, ssid) TEMPLATABLE_VALUE(std WiFiAP new_sta_
void play(Ts... x) override
const std::string & get_ssid() const
void set_priority(float priority)
const bssid_t & get_bssid() const
WiFiScanResult(const bssid_t &bssid, std::string ssid, uint8_t channel, int8_t rssi, bool with_auth, bool is_hidden)
bool matches(const WiFiAP &config)
bool operator==(const WiFiScanResult &rhs) const
uint8_t priority
void loop()
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:144
std::array< uint8_t, 6 > bssid_t
struct esphome::wifi::SavedWifiSettings PACKED
WiFiComponent * global_wifi_component
@ WIFI_COMPONENT_STATE_DISABLED
WiFi is disabled.
@ WIFI_COMPONENT_STATE_AP
WiFi is in AP-only mode and internal AP is already enabled.
@ WIFI_COMPONENT_STATE_STA_CONNECTING
WiFi is in STA(+AP) mode and currently connecting to an AP.
@ WIFI_COMPONENT_STATE_OFF
Nothing has been initialized yet.
@ WIFI_COMPONENT_STATE_STA_SCANNING
WiFi is in STA-only mode and currently scanning for APs.
@ WIFI_COMPONENT_STATE_STA_CONNECTING_2
WiFi is in STA(+AP) mode and currently connecting to an AP a second time.
@ WIFI_COMPONENT_STATE_COOLDOWN
WiFi is in cooldown mode because something went wrong, scanning will begin after a short period of ti...
@ WIFI_COMPONENT_STATE_STA_CONNECTED
WiFi is in STA(+AP) mode and successfully connected.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
esp_eap_ttls_phase2_types ttls_phase_2
Struct for setting static IPs in WiFiComponent.
network::IPAddress static_ip
network::IPAddress dns1
The first DNS server. 0.0.0.0 for default.
network::IPAddress gateway
network::IPAddress dns2
The second DNS server. 0.0.0.0 for default.
network::IPAddress subnet
uint16_t x
Definition tt21100.cpp:5