ESPHome 2025.12.5
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_ESP32) && 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
52#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
53#include <freertos/FreeRTOS.h>
54#include <freertos/semphr.h>
55#endif
56
57namespace esphome::wifi {
58
60static constexpr int8_t WIFI_RSSI_DISCONNECTED = -127;
61
63 char ssid[33];
64 char password[65];
65} PACKED; // NOLINT
66
68 uint8_t bssid[6];
69 uint8_t channel;
70 int8_t ap_index;
71} PACKED; // NOLINT
72
89
97
99enum class WiFiRetryPhase : uint8_t {
102#ifdef USE_WIFI_FAST_CONNECT
105#endif
114};
115
124
125#ifdef USE_WIFI_WPA2_EAP
126struct EAPAuth {
127 std::string identity; // required for all auth types
128 std::string username;
129 std::string password;
130 const char *ca_cert; // optionally verify authentication server
131 // used for EAP-TLS
132 const char *client_cert;
133 const char *client_key;
134// used for EAP-TTLS
135#ifdef USE_ESP32
136 esp_eap_ttls_phase2_types ttls_phase_2;
137#endif
138};
139#endif // USE_WIFI_WPA2_EAP
140
141using bssid_t = std::array<uint8_t, 6>;
142
143// Use std::vector for RP2040 since scan count is unknown (callback-based)
144// Use FixedVector for other platforms where count is queried first
145#ifdef USE_RP2040
146template<typename T> using wifi_scan_vector_t = std::vector<T>;
147#else
148template<typename T> using wifi_scan_vector_t = FixedVector<T>;
149#endif
150
151class WiFiAP {
152 public:
153 void set_ssid(const std::string &ssid);
154 void set_bssid(bssid_t bssid);
155 void set_bssid(optional<bssid_t> bssid);
156 void set_password(const std::string &password);
157#ifdef USE_WIFI_WPA2_EAP
158 void set_eap(optional<EAPAuth> eap_auth);
159#endif // USE_WIFI_WPA2_EAP
160 void set_channel(optional<uint8_t> channel);
162#ifdef USE_WIFI_MANUAL_IP
163 void set_manual_ip(optional<ManualIP> manual_ip);
164#endif
165 void set_hidden(bool hidden);
166 const std::string &get_ssid() const;
167 const optional<bssid_t> &get_bssid() const;
168 const std::string &get_password() const;
169#ifdef USE_WIFI_WPA2_EAP
170 const optional<EAPAuth> &get_eap() const;
171#endif // USE_WIFI_WPA2_EAP
172 const optional<uint8_t> &get_channel() const;
173 int8_t get_priority() const { return priority_; }
174#ifdef USE_WIFI_MANUAL_IP
175 const optional<ManualIP> &get_manual_ip() const;
176#endif
177 bool get_hidden() const;
178
179 protected:
180 std::string ssid_;
181 std::string password_;
183#ifdef USE_WIFI_WPA2_EAP
185#endif // USE_WIFI_WPA2_EAP
186#ifdef USE_WIFI_MANUAL_IP
188#endif
190 int8_t priority_{0};
191 bool hidden_{false};
192};
193
195 public:
196 WiFiScanResult(const bssid_t &bssid, std::string ssid, uint8_t channel, int8_t rssi, bool with_auth, bool is_hidden);
197
198 bool matches(const WiFiAP &config) const;
199
200 bool get_matches() const;
201 void set_matches(bool matches);
202 const bssid_t &get_bssid() const;
203 const std::string &get_ssid() const;
204 uint8_t get_channel() const;
205 int8_t get_rssi() const;
206 bool get_with_auth() const;
207 bool get_is_hidden() const;
208 int8_t get_priority() const { return priority_; }
210
211 bool operator==(const WiFiScanResult &rhs) const;
212
213 protected:
215 uint8_t channel_;
216 int8_t rssi_;
217 std::string ssid_;
218 int8_t priority_{0};
219 bool matches_{false};
222};
223
228
234
240
241#ifdef USE_ESP32
242struct IDFWiFiEvent;
243#endif
244
251 public:
252 virtual void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
253 const network::IPAddress &dns2) = 0;
254};
255
262 public:
264};
265
272 public:
273 virtual void on_wifi_connect_state(const std::string &ssid, const bssid_t &bssid) = 0;
274};
275
282 public:
284};
285
287class WiFiComponent : public Component {
288 public:
291
292 void set_sta(const WiFiAP &ap);
293 // Returns a copy of the currently selected AP configuration
294 WiFiAP get_sta() const;
295 void init_sta(size_t count);
296 void add_sta(const WiFiAP &ap);
297 void clear_sta() {
298 this->sta_.clear();
299 this->selected_sta_index_ = -1;
300 }
301
302#ifdef USE_WIFI_AP
310 void set_ap(const WiFiAP &ap);
311 WiFiAP get_ap() { return this->ap_; }
312 void set_ap_timeout(uint32_t ap_timeout) { ap_timeout_ = ap_timeout; }
313#endif // USE_WIFI_AP
314
315 void enable();
316 void disable();
317 bool is_disabled();
318 void start_scanning();
320 void start_connecting(const WiFiAP &ap);
321 // Backward compatibility overload - ignores 'two' parameter
322 void start_connecting(const WiFiAP &ap, bool /* two */) { this->start_connecting(ap); }
323
325
326 void retry_connect();
327
328#ifdef USE_RP2040
329 bool can_proceed() override;
330#endif
331
332 void set_reboot_timeout(uint32_t reboot_timeout);
333
334 bool is_connected();
335
336 void set_power_save_mode(WiFiPowerSaveMode power_save);
337 void set_min_auth_mode(WifiMinAuthMode min_auth_mode) { min_auth_mode_ = min_auth_mode; }
338 void set_output_power(float output_power) { output_power_ = output_power; }
339
340 void set_passive_scan(bool passive);
341
342 void save_wifi_sta(const std::string &ssid, const std::string &password);
343
344 // ========== INTERNAL METHODS ==========
345 // (In most use cases you won't need these)
347 void setup() override;
348 void start();
349 void dump_config() override;
350 void restart_adapter();
352 float get_setup_priority() const override;
353 float get_loop_priority() const override;
354
356 void loop() override;
357
358 bool has_sta() const;
359 bool has_ap() const;
360 bool is_ap_active() const;
361
362#ifdef USE_WIFI_11KV_SUPPORT
363 void set_btm(bool btm);
364 void set_rrm(bool rrm);
365#endif
366
369 const char *get_use_address() const;
370 void set_use_address(const char *use_address);
371
373
375
376 bool has_sta_priority(const bssid_t &bssid) {
377 for (auto &it : this->sta_priorities_) {
378 if (it.bssid == bssid)
379 return true;
380 }
381 return false;
382 }
383 int8_t get_sta_priority(const bssid_t bssid) {
384 for (auto &it : this->sta_priorities_) {
385 if (it.bssid == bssid)
386 return it.priority;
387 }
388 return 0;
389 }
390 void set_sta_priority(const bssid_t bssid, int8_t priority) {
391 for (auto &it : this->sta_priorities_) {
392 if (it.bssid == bssid) {
393 it.priority = priority;
394 return;
395 }
396 }
397 this->sta_priorities_.push_back(WiFiSTAPriority{
398 .bssid = bssid,
399 .priority = priority,
400 });
401 }
402
404 std::string wifi_ssid();
406
407 int8_t wifi_rssi();
408
409 void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
410 void set_keep_scan_results(bool keep_scan_results) { this->keep_scan_results_ = keep_scan_results; }
411
414
415 int32_t get_wifi_channel();
416
417#ifdef USE_WIFI_LISTENERS
421 void add_ip_state_listener(WiFiIPStateListener *listener) { this->ip_state_listeners_.push_back(listener); }
424 this->scan_results_listeners_.push_back(listener);
425 }
430 this->connect_state_listeners_.push_back(listener);
431 }
435 void add_power_save_listener(WiFiPowerSaveListener *listener) { this->power_save_listeners_.push_back(listener); }
436#endif // USE_WIFI_LISTENERS
437
438#ifdef USE_WIFI_RUNTIME_POWER_SAVE
454
467#endif // USE_WIFI_RUNTIME_POWER_SAVE
468
469 protected:
470#ifdef USE_WIFI_AP
471 void setup_ap_config_();
472#endif // USE_WIFI_AP
473
476
481 bool transition_to_phase_(WiFiRetryPhase new_phase);
484 bool needs_scan_results_() const;
490 int8_t find_first_non_hidden_index_() const;
493 bool ssid_was_seen_in_scan_(const std::string &ssid) const;
497 int8_t find_next_hidden_sta_(int8_t start_index);
507 const WiFiAP *get_selected_sta_() const {
508 if (this->selected_sta_index_ >= 0 && static_cast<size_t>(this->selected_sta_index_) < this->sta_.size()) {
509 return &this->sta_[this->selected_sta_index_];
510 }
511 return nullptr;
512 }
513
515 if (this->selected_sta_index_ < 0 || static_cast<size_t>(this->selected_sta_index_) >= this->sta_.size()) {
516 this->selected_sta_index_ = this->sta_.empty() ? -1 : 0;
517 }
518 }
519
520 bool all_networks_hidden_() const {
521 if (this->sta_.empty())
522 return false;
523 for (const auto &ap : this->sta_) {
524 if (!ap.get_hidden())
525 return false;
526 }
527 return true;
528 }
529
530 void connect_soon_();
531
532 void wifi_loop_();
534 bool wifi_sta_pre_setup_();
535 bool wifi_apply_output_power_(float output_power);
537 bool wifi_sta_ip_config_(const optional<ManualIP> &manual_ip);
539 bool wifi_sta_connect_(const WiFiAP &ap);
540 void wifi_pre_setup_();
542 bool wifi_scan_start_(bool passive);
543
544#ifdef USE_WIFI_AP
545 bool wifi_ap_ip_config_(const optional<ManualIP> &manual_ip);
546 bool wifi_start_ap_(const WiFiAP &ap);
547#endif // USE_WIFI_AP
548
549 bool wifi_disconnect_();
550
554
557
558#ifdef USE_WIFI_FAST_CONNECT
561#endif
562
563#ifdef USE_ESP8266
564 static void wifi_event_callback(System_Event_t *event);
565 void wifi_scan_done_callback_(void *arg, STATUS status);
566 static void s_wifi_scan_done_callback(void *arg, STATUS status);
567#endif
568
569#ifdef USE_ESP32_FRAMEWORK_ARDUINO
570 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
572#endif
573#ifdef USE_ESP32
574 void wifi_process_event_(IDFWiFiEvent *data);
575#endif
576
577#ifdef USE_RP2040
578 static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
579 void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
580#endif
581
582#ifdef USE_LIBRETINY
583 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
585#endif
586
588 std::vector<WiFiSTAPriority> sta_priorities_;
590#ifdef USE_WIFI_AP
592#endif
594#ifdef USE_WIFI_LISTENERS
595 std::vector<WiFiIPStateListener *> ip_state_listeners_;
596 std::vector<WiFiScanResultsListener *> scan_results_listeners_;
597 std::vector<WiFiConnectStateListener *> connect_state_listeners_;
598 std::vector<WiFiPowerSaveListener *> power_save_listeners_;
599#endif // USE_WIFI_LISTENERS
601#ifdef USE_WIFI_FAST_CONNECT
603#endif
604
605 // Group all 32-bit integers together
607 uint32_t last_connected_{0};
608 uint32_t reboot_timeout_{};
609#ifdef USE_WIFI_AP
610 uint32_t ap_timeout_{};
611#endif
612
613 // Group all 8-bit values together
618 uint8_t num_retried_{0};
619 // Index into sta_ array for the currently selected AP configuration (-1 = none selected)
620 // Used to access password, manual_ip, priority, EAP settings, and hidden flag
621 // int8_t limits to 127 APs (enforced in __init__.py via MAX_WIFI_NETWORKS)
623
624#if USE_NETWORK_IPV6
626#endif /* USE_NETWORK_IPV6 */
627
628 // Group all boolean values together
629 bool has_ap_{false};
632 bool scan_done_{false};
633 bool ap_setup_{false};
634 bool ap_started_{false};
635 bool passive_scan_{false};
637#ifdef USE_WIFI_11KV_SUPPORT
638 bool btm_{false};
639 bool rrm_{false};
640#endif
641 bool enable_on_boot_{true};
642 bool got_ipv4_address_{false};
646#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
649
650 SemaphoreHandle_t high_performance_semaphore_{nullptr};
651#endif
652
653 // Pointers at the end (naturally aligned)
656
657 private:
658 // Stores a pointer to a string literal (static storage duration).
659 // ONLY set from Python-generated code with string literals - never dynamic strings.
660 const char *use_address_{""};
661};
662
663extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
664
665} // namespace esphome::wifi
666#endif
BedjetMode mode
BedJet operating mode.
Fixed-capacity vector - allocates once at runtime, never reallocates This avoids std::vector template...
Definition helpers.h:184
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)
const optional< ManualIP > & get_manual_ip() const
int8_t get_priority() const
void set_hidden(bool hidden)
void set_priority(int8_t priority)
This component is responsible for managing the ESP WiFi interface.
Trigger * get_connect_trigger() const
void add_sta(const WiFiAP &ap)
bool load_fast_connect_settings_(WiFiAP &params)
void add_connect_state_listener(WiFiConnectStateListener *listener)
Add a listener for WiFi connection state changes.
void set_ap(const WiFiAP &ap)
Setup an Access Point that should be created if no connection to a station can be made.
bool request_high_performance()
Request high-performance mode (no power saving) for improved WiFi latency.
void set_sta(const WiFiAP &ap)
std::vector< WiFiIPStateListener * > ip_state_listeners_
bool has_sta_priority(const bssid_t &bssid)
const WiFiAP * get_selected_sta_() const
int8_t get_sta_priority(const bssid_t bssid)
void log_and_adjust_priority_for_failed_connect_()
Log failed connection and decrease BSSID priority to avoid repeated attempts.
std::vector< WiFiScanResultsListener * > scan_results_listeners_
void save_wifi_sta(const std::string &ssid, const std::string &password)
wifi_scan_vector_t< WiFiScanResult > scan_result_
WiFiPowerSaveMode configured_power_save_
void set_sta_priority(const bssid_t bssid, int8_t priority)
void loop() override
Reconnect WiFi if required.
void start_connecting(const WiFiAP &ap)
void set_enable_on_boot(bool enable_on_boot)
void advance_to_next_target_or_increment_retry_()
Advance to next target (AP/SSID) within current phase, or increment retry counter Called when staying...
void add_power_save_listener(WiFiPowerSaveListener *listener)
Add a listener for WiFi power save mode changes.
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)
SemaphoreHandle_t high_performance_semaphore_
network::IPAddress get_dns_address(int num)
static void wifi_event_callback(System_Event_t *event)
WiFiComponent()
Construct a WiFiComponent.
void wifi_process_event_(IDFWiFiEvent *data)
std::vector< WiFiSTAPriority > sta_priorities_
void set_min_auth_mode(WifiMinAuthMode min_auth_mode)
void start_connecting(const WiFiAP &ap, bool)
void set_passive_scan(bool passive)
void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info)
static void s_wifi_scan_done_callback(void *arg, STATUS status)
void set_power_save_mode(WiFiPowerSaveMode power_save)
int8_t find_next_hidden_sta_(int8_t start_index)
Find next SSID that wasn't in scan results (might be hidden) Returns index of next potentially hidden...
void add_ip_state_listener(WiFiIPStateListener *listener)
Add a listener for IP state changes.
ESPPreferenceObject fast_connect_pref_
void clear_priorities_if_all_min_()
Clear BSSID priority tracking if all priorities are at minimum (saves memory)
void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
WiFiRetryPhase determine_next_phase_()
Determine next retry phase based on current state and failure conditions.
network::IPAddress wifi_dns_ip_(int num)
float get_loop_priority() const override
network::IPAddresses get_ip_addresses()
float get_setup_priority() const override
WIFI setup_priority.
void set_output_power(float output_power)
FixedVector< WiFiAP > sta_
int8_t find_first_non_hidden_index_() const
Find the index of the first non-hidden network Returns where EXPLICIT_HIDDEN phase would have stopped...
bool ssid_was_seen_in_scan_(const std::string &ssid) const
Check if an SSID was seen in the most recent scan results Used to skip hidden mode for SSIDs we know ...
bool wifi_ap_ip_config_(const optional< ManualIP > &manual_ip)
bool needs_scan_results_() const
Check if we need valid scan results for the current phase but don't have any Returns true if the phas...
void add_scan_results_listener(WiFiScanResultsListener *listener)
Add a listener for WiFi scan results.
bool transition_to_phase_(WiFiRetryPhase new_phase)
Transition to a new retry phase with logging Returns true if a scan was started (caller should wait),...
Trigger * get_disconnect_trigger() const
optional< float > output_power_
void set_ap_timeout(uint32_t ap_timeout)
bool release_high_performance()
Release a high-performance mode request.
bool wifi_apply_output_power_(float output_power)
const char * get_use_address() const
WiFiSTAConnectStatus wifi_sta_connect_status_()
bool went_through_explicit_hidden_phase_() const
Check if we went through EXPLICIT_HIDDEN phase (first network is marked hidden) Used in RETRY_HIDDEN ...
bool wifi_mode_(optional< bool > sta, optional< bool > ap)
void set_reboot_timeout(uint32_t reboot_timeout)
network::IPAddresses wifi_sta_ip_addresses()
void set_keep_scan_results(bool keep_scan_results)
void start_initial_connection_()
Start initial connection - either scan or connect directly to hidden networks.
void setup() override
Setup WiFi interface.
void set_use_address(const char *use_address)
std::vector< WiFiConnectStateListener * > connect_state_listeners_
std::vector< WiFiPowerSaveListener * > power_save_listeners_
const wifi_scan_vector_t< WiFiScanResult > & get_scan_result() const
Listener interface for WiFi connection state changes.
virtual void on_wifi_connect_state(const std::string &ssid, const bssid_t &bssid)=0
Listener interface for WiFi IP state changes.
virtual void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1, const network::IPAddress &dns2)=0
Listener interface for WiFi power save mode changes.
virtual void on_wifi_power_save(WiFiPowerSaveMode mode)=0
const std::string & get_ssid() const
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) const
void set_priority(int8_t priority)
bool operator==(const WiFiScanResult &rhs) const
Listener interface for WiFi scan results.
virtual void on_wifi_scan_results(const wifi_scan_vector_t< WiFiScanResult > &results)=0
uint8_t priority
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:149
std::array< uint8_t, 6 > bssid_t
std::vector< T > wifi_scan_vector_t
struct esphome::wifi::SavedWifiSettings PACKED
WiFiRetryPhase
Tracks the current retry strategy/phase for WiFi connection attempts.
@ RETRY_HIDDEN
Retry networks not found in scan (might be hidden)
@ RESTARTING_ADAPTER
Restarting WiFi adapter to clear stuck state.
@ INITIAL_CONNECT
Initial connection attempt (varies based on fast_connect setting)
@ EXPLICIT_HIDDEN
Explicitly hidden networks (user marked as hidden, try before scanning)
@ FAST_CONNECT_CYCLING_APS
Fast connect mode: cycling through configured APs (config-only, no scan)
@ SCAN_CONNECTING
Scan-based: connecting to best AP from scan results.
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_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.
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