ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
wifi_component.h
Go to the documentation of this file.
1#pragma once
2
4#ifdef USE_WIFI
9#ifdef USE_ESP32
11#endif
12#if defined(USE_LIBRETINY) && defined(ESPHOME_THREAD_MULTI_ATOMICS)
14#elif defined(USE_LIBRETINY) && defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
16#endif
18
19#include <algorithm>
20#include <atomic>
21#include <limits>
22#include <span>
23#include <memory>
24#include <string>
25#include <type_traits>
26#include <utility>
27#include <vector>
28
29#ifdef USE_LIBRETINY
30#include <WiFi.h>
31#endif
32
33#if defined(USE_ESP32) && defined(USE_WIFI_WPA2_EAP)
34#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
35#include <esp_eap_client.h>
36#else
37#include <esp_wpa2.h>
38#endif
39#endif
40
41#ifdef USE_ESP8266
42#include <ESP8266WiFi.h>
43#include <ESP8266WiFiType.h>
44
45#endif
46
47#ifdef USE_RP2
48extern "C" {
49#include "cyw43.h"
50#include "cyw43_country.h"
51#include "pico/cyw43_arch.h"
52}
53
54#include <WiFi.h>
55
56#ifdef USE_WIFI_AP
57// The linker routes the driver's firmware events here; wifi/__init__.py adds the wrap flag
58// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
59extern "C" void __wrap_cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev);
60// NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
61#endif
62#endif
63
64#if defined(USE_ESP32) && defined(SOC_WIFI_SUPPORT_5G)
65#include <esp_wifi_types.h>
66#endif
67
68#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
69#include <freertos/FreeRTOS.h>
70#include <freertos/semphr.h>
71#endif
72
73#ifdef USE_ESP32
74// Forward declaration matching esp_netif's own typedef; avoids pulling esp_netif.h
75// into this widely-included header.
76using esp_netif_t = struct esp_netif_obj;
77#endif
78
79namespace esphome::wifi {
80
82static constexpr int8_t WIFI_RSSI_DISCONNECTED = -127;
83
85static constexpr size_t SSID_BUFFER_SIZE = 33;
86
88 char ssid[33];
89 char password[65];
90} PACKED; // NOLINT
91
93 uint8_t bssid[6];
94 uint8_t channel;
95 int8_t ap_index;
96} PACKED; // NOLINT
97
98#ifdef USE_WIFI_LEASE_CACHE
99// Checked on load; a zeroed record (version 0) means no cached lease.
100static constexpr uint8_t SAVED_WIFI_LEASE_VERSION = 1;
101
102// Cached DHCP lease. IPv4 fields in network byte order, times in seconds.
115#endif
116
133
141
143enum class WiFiRetryPhase : uint8_t {
146#ifdef USE_WIFI_FAST_CONNECT
149#endif
158};
159
161enum class RoamingState : uint8_t {
163 IDLE,
165 SCANNING,
170};
171
173enum class RetryHiddenMode : uint8_t {
180};
181
190
191#ifdef USE_WIFI_WPA2_EAP
192struct EAPAuth {
193 std::string identity; // required for all auth types
194 std::string username;
195 std::string password;
196 const char *ca_cert; // optionally verify authentication server
197 // used for EAP-TLS
198 const char *client_cert;
199 const char *client_key;
200// used for EAP-TTLS
201#ifdef USE_ESP32
202 esp_eap_ttls_phase2_types ttls_phase_2;
203#endif
204};
205#endif // USE_WIFI_WPA2_EAP
206
207using bssid_t = std::array<uint8_t, 6>;
208
209// ESP32 with one configured network: the driver filters the scan by its SSID and only this many of
210// its BSSIDs are kept, the strongest ones
211static constexpr size_t WIFI_SCAN_RESULT_BOUND = 12;
212
213// RP2040's callback delivers results one at a time with no count, so it needs a growable vector
214#if defined(USE_RP2)
215template<typename T> using wifi_scan_vector_t = std::vector<T>;
216#else
217template<typename T> using wifi_scan_vector_t = FixedVector<T>;
218#endif
219
220// A consumer component (e.g. the captive portal) reads scan results from another
221// task; guard them with a real lock only on platforms that actually run multiple
222// threads. See ScanResultsLock below the WiFiComponent class.
223#if defined(USE_WIFI_SCAN_RESULTS_LOCK) && !defined(ESPHOME_THREAD_SINGLE)
224#define WIFI_SCAN_RESULTS_LOCK_ENABLED
225#endif
226
230 public:
231 static constexpr uint8_t MAX_LENGTH = 127;
232 static constexpr uint8_t INLINE_CAPACITY = 18; // 18 chars + null terminator fits in 19 bytes
233
234 CompactString() : length_(0), is_heap_(0) { this->storage_[0] = '\0'; }
235 CompactString(const char *str, size_t len);
236 CompactString(const CompactString &other);
237 CompactString(CompactString &&other) noexcept;
239 CompactString &operator=(CompactString &&other) noexcept;
241
242 const char *data() const { return this->is_heap_ ? this->get_heap_ptr_() : this->storage_; }
243 const char *c_str() const { return this->data(); } // Always null-terminated
244 size_t size() const { return this->length_; }
245 bool empty() const { return this->length_ == 0; }
246
248 StringRef ref() const { return StringRef(this->data(), this->size()); }
249
250 bool operator==(const CompactString &other) const;
251 bool operator!=(const CompactString &other) const { return !(*this == other); }
252 bool operator==(const StringRef &other) const;
253 bool operator!=(const StringRef &other) const { return !(*this == other); }
254 bool operator==(const char *other) const { return *this == StringRef(other); }
255 bool operator!=(const char *other) const { return !(*this == other); }
256
257 protected:
258 char *get_heap_ptr_() const {
259 char *ptr;
260 std::memcpy(&ptr, this->storage_, sizeof(ptr));
261 return ptr;
262 }
263 void set_heap_ptr_(char *ptr) { std::memcpy(this->storage_, &ptr, sizeof(ptr)); }
264
265 // Storage for string data. When is_heap_=0, contains the string directly (null-terminated).
266 // When is_heap_=1, first sizeof(char*) bytes contain pointer to heap allocation.
267 char storage_[INLINE_CAPACITY + 1]; // 19 bytes: 18 chars + null terminator
268 uint8_t length_ : 7; // String length (0-127)
269 uint8_t is_heap_ : 1; // 1 if using heap pointer, 0 if using inline storage
270 // Total size: 20 bytes (19 bytes storage + 1 byte bitfields)
271};
272
273static_assert(sizeof(CompactString) == 20, "CompactString must be exactly 20 bytes");
274// CompactString is not trivially copyable (non-trivial destructor/copy for heap case).
275// However, its layout has no self-referential pointers: storage_[] contains either inline
276// data or an external heap pointer — never a pointer to itself. This is unlike libstdc++
277// std::string SSO where _M_p points to _M_local_buf within the same object.
278// This property allows memcpy-based permutation sorting where each element ends up in
279// exactly one slot (no ownership duplication). These asserts document that layout property.
280static_assert(std::is_standard_layout<CompactString>::value, "CompactString must be standard layout");
281static_assert(!std::is_polymorphic<CompactString>::value, "CompactString must not have vtable");
282
283class WiFiAP {
284 friend class WiFiComponent;
285 friend class WiFiScanResult;
286
287 public:
288 void set_ssid(const std::string &ssid) { this->ssid_ = CompactString(ssid.c_str(), ssid.size()); }
289 void set_ssid(const char *ssid) { this->set_ssid(StringRef(ssid)); }
290 void set_ssid(StringRef ssid) { this->ssid_ = CompactString(ssid.c_str(), ssid.size()); }
291 void set_bssid(const bssid_t &bssid) { this->bssid_ = bssid; }
292 void clear_bssid() { this->bssid_ = {}; }
293 void set_password(const std::string &password) { this->password_ = CompactString(password.c_str(), password.size()); }
294 void set_password(const char *password) { this->set_password(StringRef(password)); }
295 void set_password(StringRef password) { this->password_ = CompactString(password.c_str(), password.size()); }
296#ifdef USE_WIFI_WPA2_EAP
297 void set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); }
298#endif // USE_WIFI_WPA2_EAP
299 void set_channel(uint8_t channel) { this->channel_ = channel; }
300 void clear_channel() { this->channel_ = 0; }
302#ifdef USE_WIFI_MANUAL_IP
303 void set_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; }
304#endif
305 void set_hidden(bool hidden) { this->hidden_ = hidden; }
306 StringRef get_ssid() const { return this->ssid_.ref(); }
307 StringRef get_password() const { return this->password_.ref(); }
308 const bssid_t &get_bssid() const { return this->bssid_; }
309 bool has_bssid() const { return this->bssid_ != bssid_t{}; }
310#ifdef USE_WIFI_WPA2_EAP
311 const optional<EAPAuth> &get_eap() const { return this->eap_; }
312#endif // USE_WIFI_WPA2_EAP
313 uint8_t get_channel() const { return this->channel_; }
314 bool has_channel() const { return this->channel_ != 0; }
315 int8_t get_priority() const { return priority_; }
316#ifdef USE_WIFI_MANUAL_IP
317 const optional<ManualIP> &get_manual_ip() const { return this->manual_ip_; }
318#endif
319 bool get_hidden() const { return this->hidden_; }
320
321 protected:
324#ifdef USE_WIFI_WPA2_EAP
325 optional<EAPAuth> eap_;
326#endif // USE_WIFI_WPA2_EAP
327#ifdef USE_WIFI_MANUAL_IP
328 optional<ManualIP> manual_ip_;
329#endif
330 // Group small types together to minimize padding
331 bssid_t bssid_{}; // 6 bytes, all zeros = any/not set
332 uint8_t channel_{0}; // 1 byte, 0 = auto/not set
333 int8_t priority_{0}; // 1 byte
334 bool hidden_{false}; // 1 byte; WiFiAP is byte aligned unless manual IP or EAP adds a 4 byte aligned member
335};
336
338 friend class WiFiComponent;
339
340 public:
341 WiFiScanResult(const bssid_t &bssid, const char *ssid, size_t ssid_len, uint8_t channel, int8_t rssi, bool with_auth,
342 bool is_hidden);
343
344 bool matches(const WiFiAP &config) const;
345
346 bool get_matches() const { return this->matches_; }
347 void set_matches(bool matches) { this->matches_ = matches; }
348 const bssid_t &get_bssid() const { return this->bssid_; }
349 StringRef get_ssid() const { return this->ssid_.ref(); }
350 uint8_t get_channel() const { return this->channel_; }
351 int8_t get_rssi() const { return this->rssi_; }
352 bool get_with_auth() const { return this->with_auth_; }
353 bool get_is_hidden() const { return this->is_hidden_; }
354 bool ssid_equals(const WiFiScanResult &other) const { return this->ssid_ == other.ssid_; }
355 int8_t get_priority() const { return priority_; }
357
358 bool operator==(const WiFiScanResult &rhs) const;
359
360 protected:
362 uint8_t channel_;
363 int8_t rssi_;
365 int8_t priority_{0};
366 bool matches_{false};
369};
370
375
381
387
388#ifdef USE_WIFI_PHY_MODE
389// Values 1-3 match ESP8266 SDK phy_mode_t (PHY_MODE_11B=1, PHY_MODE_11G=2, PHY_MODE_11N=3).
390// AUTO leaves the SDK at its default (no wifi_set_phy_mode() call).
397#endif
398
399#ifdef USE_ESP32
400struct IDFWiFiEvent;
401#endif
402
403#ifdef USE_LIBRETINY
404struct LTWiFiEvent;
405#endif
406
416 public:
417 virtual void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
418 const network::IPAddress &dns2) = 0;
419};
420
430 public:
432};
433
443 public:
444 virtual void on_wifi_connect_state(StringRef ssid, std::span<const uint8_t, 6> bssid) = 0;
445};
446
456 public:
458};
459
460// Scheduler ids
461static constexpr uint32_t AP_HANDOVER_TIMEOUT_ID = 0;
462static constexpr uint32_t LEASE_RENEW_TIMEOUT_ID = 1;
463
465class WiFiComponent final : public Component {
466 public:
469
470 void set_sta(const WiFiAP &ap);
471 // Returns a copy of the currently selected AP configuration
472 WiFiAP get_sta() const;
473 // init_sta/add_sta kept out of line: inlining them into the generated setup() grows flash
474 void init_sta(size_t count);
475 void add_sta(const WiFiAP &ap);
476 void clear_sta();
477
478#ifdef USE_WIFI_AP
486 void set_ap(const WiFiAP &ap);
487 WiFiAP get_ap() { return this->ap_; }
488 void set_ap_timeout(uint32_t ap_timeout) { ap_timeout_ = ap_timeout; }
489#endif // USE_WIFI_AP
490
491#ifdef USE_WIFI_DPP
492 // Code generation passes string literals that live in flash
493 void set_dpp_key(const char *key) { this->dpp_key_ = key; }
494 void set_dpp_device_info(const char *info) { this->dpp_device_info_ = info; }
495 void set_dpp_channels(const char *channels) { this->dpp_channels_ = channels; }
496 void set_dpp_timeout(uint32_t timeout) { this->dpp_timeout_ = timeout; }
497#ifdef USE_WIFI_DPP_URI_TRIGGER
498 template<typename F> void add_on_dpp_uri_callback(F &&callback) {
499 this->dpp_uri_callback_.add(std::forward<F>(callback));
500 }
501#endif
503 const char *get_dpp_uri() const { return this->dpp_uri_.get(); }
504#endif
505
506 void enable();
507 void disable();
509 void start_scanning();
511 void start_connecting(const WiFiAP &ap);
512 // Backward compatibility overload - ignores 'two' parameter
513 void start_connecting(const WiFiAP &ap, bool /* two */) { this->start_connecting(ap); }
514
516
517 void retry_connect();
518
519 void set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
520
521 bool is_connected() const { return this->connected_; }
522
525
528 bool is_roaming() const { return this->roaming_state_ != RoamingState::IDLE; }
529
530#ifdef USE_ESP32
534#endif
535
536 void set_power_save_mode(WiFiPowerSaveMode power_save);
537 void set_min_auth_mode(WifiMinAuthMode min_auth_mode) { min_auth_mode_ = min_auth_mode; }
538 void set_output_power(float output_power) { output_power_ = output_power; }
539#if defined(USE_ESP32) && defined(SOC_WIFI_SUPPORT_5G)
540 void set_band_mode(wifi_band_mode_t band_mode) { this->band_mode_ = band_mode; }
541#endif
542#ifdef USE_WIFI_PHY_MODE
543 void set_phy_mode(WiFi8266PhyMode phy_mode) { this->phy_mode_ = phy_mode; }
544#endif
545
546 void set_passive_scan(bool passive) { this->passive_scan_ = passive; }
547
548 void save_wifi_sta(const std::string &ssid, const std::string &password);
549 void save_wifi_sta(const char *ssid, const char *password);
550 void save_wifi_sta(StringRef ssid, StringRef password) { this->save_wifi_sta(ssid.c_str(), password.c_str()); }
551
552 // ========== INTERNAL METHODS ==========
553 // (In most use cases you won't need these)
555 void setup() override;
556#ifdef USE_LN882X
557 void on_powerdown() override;
558#endif
559 void start();
560 void dump_config() override;
561 void restart_adapter();
563 float get_setup_priority() const override { return setup_priority::WIFI; }
565 void loop() override;
566
567 bool has_sta() const { return !this->sta_.empty(); }
568 bool has_ap() const { return this->has_ap_; }
569 bool is_ap_active() const { return this->ap_started_; }
570
571#ifdef USE_WIFI_11KV_SUPPORT
572 void set_btm(bool btm) { this->btm_ = btm; }
573 void set_rrm(bool rrm) { this->rrm_ = rrm; }
574#endif
575
580 const char *get_use_address() const { return this->use_address_; }
581 void set_use_address(const char *use_address) { this->use_address_ = use_address; }
582
587
589
590 bool has_sta_priority(const bssid_t &bssid) {
591 for (auto &it : this->sta_priorities_) {
592 if (it.bssid == bssid)
593 return true;
594 }
595 return false;
596 }
597 int8_t get_sta_priority(const bssid_t bssid) {
598 for (auto &it : this->sta_priorities_) {
599 if (it.bssid == bssid)
600 return it.priority;
601 }
602 return 0;
603 }
604 void set_sta_priority(bssid_t bssid, int8_t priority);
605
609 const char *wifi_ssid_to(std::span<char, SSID_BUFFER_SIZE> buffer);
611
612 int8_t wifi_rssi();
613
614 void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
615#ifdef USE_WIFI_LEASE_CACHE
616 void set_lease_cache_max_age(uint32_t seconds) { this->lease_cache_max_age_ = seconds; }
617#endif
618 void set_keep_scan_results(bool keep_scan_results) { this->keep_scan_results_ = keep_scan_results; }
619 void set_post_connect_roaming(bool enabled) { this->post_connect_roaming_ = enabled; }
620
625 void force_roam_check();
626
627#ifdef USE_WIFI_CONNECT_TRIGGER
629#endif
630#ifdef USE_WIFI_DISCONNECT_TRIGGER
632#endif
633
634 int32_t get_wifi_channel();
635
636#ifdef USE_WIFI_IP_STATE_LISTENERS
640 void add_ip_state_listener(WiFiIPStateListener *listener) { this->ip_state_listeners_.push_back(listener); }
641#endif // USE_WIFI_IP_STATE_LISTENERS
642#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS
645 this->scan_results_listeners_.push_back(listener);
646 }
647#endif // USE_WIFI_SCAN_RESULTS_LISTENERS
648#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
653 this->connect_state_listeners_.push_back(listener);
654 }
655#endif // USE_WIFI_CONNECT_STATE_LISTENERS
656#ifdef USE_WIFI_POWER_SAVE_LISTENERS
660 void add_power_save_listener(WiFiPowerSaveListener *listener) { this->power_save_listeners_.push_back(listener); }
661#endif // USE_WIFI_POWER_SAVE_LISTENERS
662
663#ifdef USE_WIFI_RUNTIME_POWER_SAVE
679
692#endif // USE_WIFI_RUNTIME_POWER_SAVE
693
694#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_ROAMING_SUPPRESSION)
711 uint8_t current = this->roaming_suppression_count_.load(std::memory_order_relaxed);
712 // CAS loop: saturate at max instead of wrapping, so an excess of requests can't roll the
713 // counter back to zero and unintentionally re-enable roaming.
714 while (current < std::numeric_limits<uint8_t>::max() &&
715 !this->roaming_suppression_count_.compare_exchange_weak(current, current + 1, std::memory_order_relaxed)) {
716 }
717 }
718
728 uint8_t current = this->roaming_suppression_count_.load(std::memory_order_relaxed);
729 // CAS loop: decrement only if non-zero, so an unmatched release can't wrap the counter
730 // and permanently suppress roaming.
731 while (current > 0 &&
732 !this->roaming_suppression_count_.compare_exchange_weak(current, current - 1, std::memory_order_relaxed)) {
733 }
734 }
735#endif // USE_ESP32 && USE_WIFI_RUNTIME_ROAMING_SUPPRESSION
736
737 protected:
738#ifdef USE_WIFI_AP
739 void setup_ap_config_();
741 void disable_ap_();
742#ifdef USE_WIFI_AP_EXCLUSIVE
744 void pause_exclusive_ap_();
745#endif
746#endif // USE_WIFI_AP
747
748#ifdef USE_WIFI_AP_WISP
754 void fail_bridge_();
755#ifndef USE_WIFI_AP_WISP_STATIC_DNS
758#endif
759#endif
760
763
768 bool transition_to_phase_(WiFiRetryPhase new_phase);
771 bool needs_scan_results_() const;
777 int8_t find_first_non_hidden_index_() const;
780 bool ssid_was_seen_in_scan_(const CompactString &ssid) const;
782 bool needs_full_scan_results_() const;
785 bool matches_configured_network_(const char *ssid, const uint8_t *bssid) const;
787 void log_discarded_scan_result_(const char *ssid, const uint8_t *bssid, int8_t rssi, uint8_t channel);
791 int8_t find_next_hidden_sta_(int8_t start_index);
803 const WiFiAP *get_selected_sta_() const {
804 if (this->selected_sta_index_ >= 0 && static_cast<size_t>(this->selected_sta_index_) < this->sta_.size()) {
805 return &this->sta_[this->selected_sta_index_];
806 }
807 return nullptr;
808 }
809
811 if (this->selected_sta_index_ < 0 || static_cast<size_t>(this->selected_sta_index_) >= this->sta_.size()) {
812 this->selected_sta_index_ = this->sta_.empty() ? -1 : 0;
813 }
814 }
815
816 bool all_networks_hidden_() const {
817 return !this->sta_.empty() &&
818 std::all_of(this->sta_.begin(), this->sta_.end(), [](const WiFiAP &ap) { return ap.get_hidden(); });
819 }
820
821 bool wifi_loop_();
822#ifdef USE_ESP8266
824#endif
825 bool wifi_mode_(optional<bool> sta, optional<bool> ap);
826 bool wifi_sta_pre_setup_();
827 bool wifi_apply_output_power_(float output_power);
829#if defined(USE_ESP32) && defined(SOC_WIFI_SUPPORT_5G)
831#endif
832#ifdef USE_WIFI_PHY_MODE
834#endif
835 bool wifi_sta_ip_config_(const optional<ManualIP> &manual_ip);
837 bool wifi_sta_connect_(const WiFiAP &ap);
838 void wifi_pre_setup_();
839#ifdef USE_ESP32
840 // ESP-IDF only: defers esp_wifi_init() + netif creation (which allocate ~15-30KB of
841 // DMA-capable internal SRAM) until wifi actually needs to come up. Idempotent.
842 // Called from setup() only when enable_on_boot_=true, and from enable() on first use.
844#endif
851 bool wifi_scan_start_(bool passive);
852
853#ifdef USE_WIFI_AP
854 bool wifi_ap_ip_config_(const optional<ManualIP> &manual_ip);
855 bool wifi_start_ap_(const WiFiAP &ap);
856#endif // USE_WIFI_AP
857
858 bool wifi_disconnect_();
859
863
864#ifdef USE_WIFI_DPP
865 // Starts listening for a DPP configurator; the platform half reports whether the driver accepted
866 void start_dpp_listen_(uint32_t now);
867 void stop_dpp_listen_();
868#endif
870 void start_cooldown_();
871#ifdef USE_WIFI_DPP
875#endif
876 bool is_dpp_active_();
884 void start_ap_portal_();
885 void end_ap_portal_();
887
888#ifdef USE_WIFI_FAST_CONNECT
890 void save_fast_connect_settings_(const bssid_t &bssid, uint8_t channel);
891#endif
892
893#ifdef USE_WIFI_LEASE_CACHE
897 // Cached lease belongs to the selected network and is still provably valid.
900#endif
901
902 // Post-connect roaming methods
903 void check_roaming_(uint32_t now);
906#ifdef USE_ESP32
910 void handle_driver_roam_(const bssid_t &bssid, uint8_t channel);
911#endif
912
914 bool roaming_suppressed_() const {
915#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_ROAMING_SUPPRESSION)
916 return this->roaming_suppression_count_.load(std::memory_order_relaxed) != 0;
917#else
918 return false;
919#endif
920 }
921
924
925#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
930#endif
931#ifdef USE_WIFI_IP_STATE_LISTENERS
934#endif
935#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS
938#endif
939
940#ifdef USE_ESP8266
941 static void wifi_event_callback(System_Event_t *event);
942 void wifi_scan_done_callback_(void *arg, STATUS status);
943 static void s_wifi_scan_done_callback(void *arg, STATUS status);
944#endif
945
946#ifdef USE_ESP32
947 void wifi_process_event_(IDFWiFiEvent *data);
948 friend void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
949#endif
950
951 friend class ScanResultsLock;
952
953#ifdef USE_RP2
954 static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
955 void wifi_scan_result_(void *env, const cyw43_ev_scan_result_t *result);
956#ifdef USE_WIFI_AP
957 // NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
958 friend void ::__wrap_cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev);
959 // NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
960#endif
961#endif
962
963#ifdef USE_LIBRETINY
964 void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
965 void wifi_process_event_(LTWiFiEvent *event);
967#endif
968
969 // Large/pointer-aligned members first
971 std::vector<WiFiSTAPriority> sta_priorities_;
972 // Guarded by ScanResultsLock (see below this class)
974#ifdef WIFI_SCAN_RESULTS_LOCK_ENABLED
976#endif
977#ifdef USE_WIFI_IP_STATE_LISTENERS
979#endif
980#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS
982#endif
983#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
985#endif
986#ifdef USE_WIFI_POWER_SAVE_LISTENERS
988#endif
990#ifdef USE_WIFI_FAST_CONNECT
992#endif
993#ifdef USE_WIFI_LEASE_CACHE
996 // Current IP came from the cache (DHCP not run); suppresses saving until a real lease arrives.
999#endif
1000#ifdef USE_WIFI_CONNECT_TRIGGER
1002#endif
1003#ifdef USE_WIFI_DISCONNECT_TRIGGER
1005#endif
1006#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
1007 SemaphoreHandle_t high_performance_semaphore_{nullptr};
1008#endif
1009
1010 static constexpr uint8_t FIRST_5GHZ_CHANNEL = 36;
1011
1012 // Post-connect roaming constants
1013 static constexpr uint32_t ROAMING_CHECK_INTERVAL = 5 * 60 * 1000; // 5 minutes
1014 static constexpr int8_t ROAMING_MIN_IMPROVEMENT = 10; // dB
1015 static constexpr int8_t ROAMING_GOOD_RSSI = -49; // Skip scan if signal is excellent
1016 static constexpr uint8_t ROAMING_MAX_ATTEMPTS = 3;
1017 // Grace period after roaming scan completes. If WiFi disconnects within this
1018 // window (e.g., ESP8266 Beacon Timeout caused by going off-channel during scan),
1019 // the disconnect is treated as roaming-related and the attempts counter is preserved.
1020 static constexpr uint32_t ROAMING_SCAN_GRACE_PERIOD = 30 * 1000; // 30 seconds
1021
1023 this->last_connected_ = now;
1024#if defined(USE_WIFI_AP) && !defined(USE_WIFI_AP_EXCLUSIVE)
1025 this->ap_start_failures_ = 0;
1026#endif
1027 }
1028
1029 // 4-byte members
1030 float output_power_{NAN};
1033#if defined(USE_WIFI_AP_EXCLUSIVE) || defined(USE_WIFI_AP_WISP)
1034 uint32_t ap_changed_{0}; // When the AP was last started or paused
1035#endif
1036 uint32_t reboot_timeout_{900000}; // Keep in sync with DEFAULT_REBOOT_TIMEOUT in __init__.py
1038 uint32_t roaming_scan_end_{0}; // Timestamp when last roaming scan completed
1039#ifdef USE_WIFI_AP
1040 uint32_t ap_timeout_{90000}; // Keep in sync with DEFAULT_AP_TIMEOUT in __init__.py
1041 // WiFiAP is byte aligned unless manual IP or EAP is enabled; placed before the
1042 // 1-byte members so they pack into its trailing bytes instead of padding after it
1044#endif // USE_WIFI_AP
1045#ifdef USE_WIFI_DPP
1046 const char *dpp_key_{nullptr};
1047 const char *dpp_device_info_{nullptr};
1048 const char *dpp_channels_{nullptr};
1049 std::unique_ptr<char[]> dpp_uri_; // written by the event task before the URI event is queued
1050#ifdef USE_WIFI_DPP_URI_TRIGGER
1052#endif
1053 uint32_t dpp_timeout_{60000}; // Keep in sync with DEFAULT_DPP_TIMEOUT in __init__.py
1055#endif
1056
1057 // 1-byte enums and integers
1060#if defined(USE_ESP32) && defined(SOC_WIFI_SUPPORT_5G)
1061 wifi_band_mode_t band_mode_{WIFI_BAND_MODE_AUTO};
1062#endif
1063#ifdef USE_WIFI_PHY_MODE
1065#endif
1068 uint8_t num_retried_{0};
1069 // Index into sta_ array for the currently selected AP configuration (-1 = none selected)
1070 // Used to access password, manual_ip, priority, EAP settings, and hidden flag
1071 // int8_t limits to 127 APs (enforced in __init__.py via MAX_WIFI_NETWORKS)
1074#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_ROAMING_SUPPRESSION)
1075 // Count of active roaming-suppression requests. Incremented/decremented from any task
1076 // (e.g. audio playback), read in loop(). Roaming scans are paused while non-zero.
1077 // Relaxed ordering is sufficient: the count value is the only data shared across threads,
1078 // so no happens-before relationship with other memory needs to be established.
1079 std::atomic<uint8_t> roaming_suppression_count_{0};
1080#endif
1081#if USE_NETWORK_IPV6
1083#endif /* USE_NETWORK_IPV6 */
1085#if defined(USE_ESP32) && !defined(USE_WIFI_MULTI_SSID)
1088#else
1089 constexpr bool is_scan_driver_filtered_() const { return false; }
1090#endif
1091#if defined(USE_ESP8266) || defined(USE_LIBRETINY)
1092 // Platform-specific STA state enum, defined in platform cpp file.
1093 // On ESP8266, written from SDK system context (wifi_event_callback) —
1094 // uint8_t writes are atomic on Xtensa LX106 so no synchronization is needed.
1095 uint8_t sta_state_{0};
1096#endif
1097#ifdef USE_LIBRETINY
1098 // First attempt since STA-up (re-armed on every STA off->on); the
1099 // pre-attempt teardown is skipped then.
1101 // A self-inflicted disconnect from that teardown is pending; it must not
1102 // consume an ignored-disconnect slot.
1104#endif
1107 bssid_t roaming_target_bssid_{}; // BSSID of the AP we're trying to roam to
1108#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
1110#endif
1111
1112 // Bools and bitfields
1113 // Pending listener callbacks deferred from platform callbacks to main loop.
1114 // Empty when no listener needs deferring (e.g. ESP32 without connect state listeners)
1115 [[no_unique_address]] struct {
1116#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
1117 // Deferred until state machine reaches STA_CONNECTED so wifi.connected
1118 // condition returns true in listener automations.
1120#ifdef USE_ESP8266
1121 // ESP8266: also defer disconnect notification to main loop
1122 bool disconnect : 1;
1123#endif
1124#endif
1125#if defined(USE_ESP8266) && defined(USE_WIFI_IP_STATE_LISTENERS)
1126 bool got_ip : 1;
1127#endif
1128#if defined(USE_ESP8266) && defined(USE_WIFI_SCAN_RESULTS_LISTENERS)
1130#endif
1132 bool has_ap_{false};
1133#if defined(USE_WIFI_CONNECT_TRIGGER) || defined(USE_WIFI_DISCONNECT_TRIGGER)
1135#endif
1136 bool scan_done_{false};
1137 bool ap_setup_{false};
1138 bool ap_started_{false};
1139#ifdef USE_WIFI_DPP
1140 bool dpp_listening_{false};
1141#endif
1142#ifdef USE_WIFI_AP
1143 // Stations joined to the AP; they hold the reboot timeout and keep an exclusive AP from pausing.
1144 // Counted on the main loop on ESP32 and LibreTiny (queued events), in the SDK callback on ESP8266 and
1145 // in the driver's interrupt context on the Pico W. The main loop only reads the byte while the AP is up
1146 // and only writes it (a reset) while the AP is down, so no lock is needed.
1147 uint8_t ap_clients_{0};
1148#ifndef USE_WIFI_AP_EXCLUSIVE
1149 // Fallback AP starts that failed since the last connection; each one waits another ap_timeout
1151#endif
1152#endif
1153 bool passive_scan_{false};
1155#ifdef USE_WIFI_11KV_SUPPORT
1156 bool btm_{false};
1157 bool rrm_{false};
1158#endif
1160#ifdef USE_ESP32
1161 // Tracks whether esp_wifi_init() + netif creation has happened. Allows enable()
1162 // to be called at runtime without re-allocating, and ensures the heavy init is
1163 // skipped entirely when enable_on_boot_ is false until first enable().
1165#endif
1169 false}; // Tracks if we've completed a scan after captive portal started
1171 bool connected_{false};
1172 bool post_connect_roaming_{true}; // Enabled by default
1173#if defined(USE_ESP32) && defined(USE_WIFI_RUNTIME_POWER_SAVE)
1175#endif
1176
1177#ifdef USE_ESP32
1178 // Lock-free SPSC queue for WiFi events from ESP-IDF event handler.
1179 // 17 slots = 16 usable (ring buffer reserves one slot). WiFi events are rare.
1180 // Placed at end of class to avoid padding between smaller fields.
1182#endif
1183
1184#ifdef USE_LIBRETINY
1185 // Thread-safe queue for WiFi events from LibreTiny callback thread.
1186 // LockFreeQueue on platforms with hardware atomics (RTL87xx, LN882x),
1187 // FreeRTOSQueue on platforms without (BK72xx).
1188 static constexpr uint8_t LT_EVENT_QUEUE_SIZE = 16;
1189#ifdef ESPHOME_THREAD_MULTI_ATOMICS
1190 // Ring buffer reserves one slot, so +1 for 16 usable slots
1192#else
1194#endif
1195#endif
1196
1197 private:
1198 // Stores a pointer to a string literal (static storage duration).
1199 // ONLY set from Python-generated code with string literals - never dynamic strings.
1200 const char *use_address_{nullptr};
1201};
1202
1203extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1204
1214 public:
1215#ifdef WIFI_SCAN_RESULTS_LOCK_ENABLED
1216 ScanResultsLock(WiFiComponent *parent) : guard_(parent->scan_result_lock_) {}
1217
1218 private:
1219 LockGuard guard_;
1220#else
1222#endif
1223};
1224
1225} // namespace esphome::wifi
1226#endif
BedjetMode mode
BedJet operating mode.
Fixed-capacity vector - sized once through init() or try_init(); push_back never reallocates This avo...
Definition helpers.h:624
Helper class that wraps a mutex with a RAII-style API.
Definition helpers.h:2135
Mutex implementation, with API based on the unavailable std::mutex.
Definition helpers.h:2096
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:286
StringRef is a reference to a string owned by something else.
Definition string_ref.h:31
constexpr const char * c_str() const
Definition string_ref.h:78
constexpr size_type size() const
Definition string_ref.h:79
20-byte string: 18 chars inline + null, heap for longer.
const char * data() const
StringRef ref() const
Return a StringRef view of this string (zero-copy)
bool operator!=(const CompactString &other) const
CompactString & operator=(const CompactString &other)
bool operator==(const CompactString &other) const
static constexpr uint8_t INLINE_CAPACITY
bool operator==(const char *other) const
bool operator!=(const StringRef &other) const
const char * c_str() const
char storage_[INLINE_CAPACITY+1]
static constexpr uint8_t MAX_LENGTH
bool operator!=(const char *other) const
Guards WiFiComponent::scan_result_.
ScanResultsLock(WiFiComponent *parent)
void set_password(const char *password)
uint8_t get_channel() const
StringRef get_ssid() const
void set_ssid(const std::string &ssid)
void set_ssid(const char *ssid)
const optional< EAPAuth > & get_eap() const
void set_ssid(StringRef ssid)
void set_bssid(const bssid_t &bssid)
void set_channel(uint8_t channel)
optional< EAPAuth > eap_
StringRef get_password() const
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)
const bssid_t & get_bssid() const
void set_priority(int8_t priority)
void set_password(StringRef password)
This component is responsible for managing the ESP WiFi interface.
void notify_scan_results_listeners_()
Notify scan results listeners with current scan results.
void fail_bridge_()
Take the bridge down so loop() runs its setup again after ap_timeout.
bool is_provisioning_closed_()
The provisioning window has closed, so no new provisioning surface may start.
void add_sta(const WiFiAP &ap)
bool load_fast_connect_settings_(WiFiAP &params)
constexpr bool is_scan_driver_filtered_() const
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)
bool roaming_suppressed_() const
Returns true if a component has requested that roaming scans be suppressed (e.g. during audio playbac...
bool has_sta_priority(const bssid_t &bssid)
const WiFiAP * get_selected_sta_() const
WiFiSTAConnectStatus wifi_sta_connect_status_() const
void set_band_mode(wifi_band_mode_t band_mode)
int8_t get_sta_priority(const bssid_t bssid)
void set_last_connected_(uint32_t now)
void log_and_adjust_priority_for_failed_connect_()
Log failed connection and decrease BSSID priority to avoid repeated attempts.
void save_wifi_sta(const std::string &ssid, const std::string &password)
void notify_connect_state_listeners_()
Notify connect state listeners (called after state machine reaches STA_CONNECTED)
SavedWifiLeaseSettings cached_lease_
wifi_scan_vector_t< WiFiScanResult > scan_result_
void save_fast_connect_settings_(const bssid_t &bssid, uint8_t channel)
WiFiPowerSaveMode configured_power_save_
void wifi_scan_result_(void *env, const cyw43_ev_scan_result_t *result)
void set_sta_priority(bssid_t bssid, int8_t priority)
StaticVector< WiFiScanResultsListener *, ESPHOME_WIFI_SCAN_RESULTS_LISTENERS > scan_results_listeners_
void loop() override
Reconnect WiFi if required.
void notify_ip_state_listeners_()
Notify IP state listeners with current addresses.
void start_connecting(const WiFiAP &ap)
std::atomic< uint8_t > roaming_suppression_count_
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.
void set_dpp_channels(const char *channels)
ESPPreferenceObject lease_cache_pref_
bool wifi_sta_ip_config_(const optional< ManualIP > &manual_ip)
static constexpr uint32_t ROAMING_CHECK_INTERVAL
esp_netif_t * get_esp_netif_sta()
esp_netif handle of the station interface, used by network for default-route arbitration.
bool is_roaming() const
True while a post-connect roam is in progress (scanning off-channel, reassociating,...
void set_dpp_timeout(uint32_t timeout)
static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
SemaphoreHandle_t high_performance_semaphore_
bool ap_dns_known_()
Whether there is an IPv4 resolver to offer AP clients: a configured one, or the station's.
void start_cooldown_()
Wait before the next attempt; while a configurator is waited for, the wait is its listen window.
network::IPAddress get_dns_address(int num)
void pause_exclusive_ap_()
Drop the fallback AP so the networks can be tried; it comes back after ap_timeout.
static void wifi_event_callback(System_Event_t *event)
void apply_ap_dns_()
Pass the station's resolvers on to AP clients when they changed.
WiFiComponent()
Construct a WiFiComponent.
void wifi_process_event_(IDFWiFiEvent *data)
std::vector< WiFiSTAPriority > sta_priorities_
bool lease_valid_for_apply_() const
FreeRTOSQueue< LTWiFiEvent, LT_EVENT_QUEUE_SIZE > event_queue_
static constexpr int8_t ROAMING_GOOD_RSSI
void notify_disconnect_state_listeners_()
Notify connect state listeners of disconnection.
void set_min_auth_mode(WifiMinAuthMode min_auth_mode)
friend void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
StaticVector< WiFiConnectStateListener *, ESPHOME_WIFI_CONNECT_STATE_LISTENERS > connect_state_listeners_
void release_roaming_suppression()
Release a roaming suppression request.
void set_dpp_key(const char *key)
void log_discarded_scan_result_(const char *ssid, const uint8_t *bssid, int8_t rssi, uint8_t channel)
Log a discarded scan result at VERBOSE level (skipped during roaming scans to avoid log overflow)
const char * wifi_ssid_to(std::span< char, SSID_BUFFER_SIZE > buffer)
Write SSID to buffer without heap allocation.
void start_connecting(const WiFiAP &ap, bool)
static constexpr uint8_t ROAMING_MAX_ATTEMPTS
void set_passive_scan(bool passive)
void set_dpp_device_info(const char *info)
void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info)
CallbackManager< void(const char *)> dpp_uri_callback_
static void s_wifi_scan_done_callback(void *arg, STATUS status)
void set_power_save_mode(WiFiPowerSaveMode power_save)
bool is_roaming_scan_active() const
True while a post-connect roaming scan holds the radio off-channel.
LockFreeQueue< LTWiFiEvent, LT_EVENT_QUEUE_SIZE+1 > event_queue_
void set_phy_mode(WiFi8266PhyMode phy_mode)
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)
bool is_ap_portal_active_()
captive_portal or the web_server AP mode is serving a user on the access point
static constexpr uint32_t ROAMING_SCAN_GRACE_PERIOD
void set_lease_cache_max_age(uint32_t seconds)
WiFiRetryPhase determine_next_phase_()
Determine next retry phase based on current state and failure conditions.
network::IPAddress wifi_dns_ip_(int num)
network::IPAddresses get_ip_addresses()
static constexpr int8_t ROAMING_MIN_IMPROVEMENT
static constexpr uint8_t LT_EVENT_QUEUE_SIZE
bool matches_configured_network_(const char *ssid, const uint8_t *bssid) const
Check if network matches any configured network (for scan result filtering) Matches by SSID when conf...
struct esphome::wifi::WiFiComponent::@194 pending_
bool is_provisioning_active_()
A portal, improv or DPP is waiting for credentials, so the retry machine must not disturb the radio.
float get_setup_priority() const override
WIFI setup_priority.
void disable_ap_()
End the portals and turn the AP off.
void set_output_power(float output_power)
StaticVector< WiFiIPStateListener *, ESPHOME_WIFI_IP_STATE_LISTENERS > ip_state_listeners_
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...
void release_scan_results_()
Free scan results memory unless a component needs them.
void request_roaming_suppression()
Request that post-connect roaming scans be suppressed.
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),...
bool needs_full_scan_results_() const
Check if full scan results are needed (captive portal active, improv, listeners)
void start_dpp_listen_(uint32_t now)
static constexpr uint8_t FIRST_5GHZ_CHANNEL
LockFreeQueue< IDFWiFiEvent, 17 > event_queue_
void set_ap_timeout(uint32_t ap_timeout)
bool release_high_performance()
Release a high-performance mode request.
void add_on_dpp_uri_callback(F &&callback)
void force_roam_check()
Force an immediate post-connect roaming check, bypassing the periodic interval and the per-connection...
StaticVector< WiFiPowerSaveListener *, ESPHOME_WIFI_POWER_SAVE_LISTENERS > power_save_listeners_
bool wifi_apply_output_power_(float output_power)
void set_post_connect_roaming(bool enabled)
const char * get_use_address() const
Returns nullptr when no explicit use_address is configured and the address is derived at runtime from...
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 check_connecting_finished(uint32_t now)
void set_keep_scan_results(bool keep_scan_results)
std::unique_ptr< char[]> dpp_uri_
void start_initial_connection_()
Start initial connection - either scan or connect directly to hidden networks.
bool ssid_was_seen_in_scan_(const CompactString &ssid) const
Check if an SSID was seen in the most recent scan results Used to skip hidden mode for SSIDs we know ...
void save_wifi_sta(StringRef ssid, StringRef password)
void handle_driver_roam_(const bssid_t &bssid, uint8_t channel)
Redo post-connect bookkeeping after a driver-initiated roam (e.g.
bool write_ap_dns_()
Hand the AP DHCP server its resolvers; false when one could not be set.
void setup() override
Setup WiFi interface.
void clear_all_bssid_priorities_()
Clear all BSSID priority penalties after successful connection (stale after disconnect)
void set_use_address(const char *use_address)
const char * get_dpp_uri() const
The Easy Connect URI to show as a QR code, nullptr until the supplicant has generated it.
const wifi_scan_vector_t< WiFiScanResult > & get_scan_result() const
Main-loop callers may read this directly.
Listener interface for WiFi connection state changes.
virtual void on_wifi_connect_state(StringRef ssid, std::span< const uint8_t, 6 > 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
bool ssid_equals(const WiFiScanResult &other) const
WiFiScanResult(const bssid_t &bssid, const char *ssid, size_t ssid_len, uint8_t channel, int8_t rssi, bool with_auth, bool is_hidden)
const bssid_t & get_bssid() const
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
const char * key
unsigned count
Definition gif.cpp:51
uint32_t buffer
Definition gif.cpp:50
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:369
constexpr float WIFI
Definition component.h:50
std::array< uint8_t, 6 > bssid_t
struct esphome::wifi::SavedWifiSettings PACKED
RetryHiddenMode
Controls how RETRY_HIDDEN phase selects networks to try.
@ BLIND_RETRY
Blind retry mode: scanning disabled (captive portal/improv active), try ALL configured networks seque...
@ SCAN_BASED
Normal mode: scan completed, only try networks NOT visible in scan results (truly hidden networks tha...
std::vector< T > wifi_scan_vector_t
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
RoamingState
Tracks post-connect roaming state machine.
@ SCANNING
Scanning for better AP.
@ IDLE
Not roaming, waiting for next check interval.
@ RECONNECTING
Roam connection failed, reconnecting to any available AP.
@ 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.
const void size_t len
Definition hal.h:68
struct esp_netif_obj esp_netif_t
static void uint32_t
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
uint8_t event_id
Definition tt21100.cpp:3
void __wrap_cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev)