ESPHome 2025.5.0
Loading...
Searching...
No Matches
wifi_component.cpp
Go to the documentation of this file.
1#include "wifi_component.h"
2#ifdef USE_WIFI
3#include <cinttypes>
4#include <map>
5
6#ifdef USE_ESP_IDF
7#if (ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1)
8#include <esp_eap_client.h>
9#else
10#include <esp_wpa2.h>
11#endif
12#endif
13
14#if defined(USE_ESP32) || defined(USE_ESP_IDF)
15#include <esp_wifi.h>
16#endif
17#ifdef USE_ESP8266
18#include <user_interface.h>
19#endif
20
21#include <algorithm>
22#include <utility>
23#include "lwip/dns.h"
24#include "lwip/err.h"
25
27#include "esphome/core/hal.h"
29#include "esphome/core/log.h"
30#include "esphome/core/util.h"
31
32#ifdef USE_CAPTIVE_PORTAL
34#endif
35
36#ifdef USE_IMPROV
38#endif
39
40namespace esphome {
41namespace wifi {
42
43static const char *const TAG = "wifi";
44
46
48 ESP_LOGCONFIG(TAG, "Setting up WiFi...");
49 this->wifi_pre_setup_();
50 if (this->enable_on_boot_) {
51 this->start();
52 } else {
53#ifdef USE_ESP32
54 esp_netif_init();
55#endif
57 }
58}
59
61 ESP_LOGCONFIG(TAG, "Starting WiFi...");
62 ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str());
63 this->last_connected_ = millis();
64
65 uint32_t hash = this->has_sta() ? fnv1_hash(App.get_compilation_time()) : 88491487UL;
66
68 if (this->fast_connect_) {
70 }
71
72 SavedWifiSettings save{};
73 if (this->pref_.load(&save)) {
74 ESP_LOGD(TAG, "Loaded saved wifi settings: %s", save.ssid);
75
76 WiFiAP sta{};
77 sta.set_ssid(save.ssid);
78 sta.set_password(save.password);
79 this->set_sta(sta);
80 }
81
82 if (this->has_sta()) {
83 this->wifi_sta_pre_setup_();
84 if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
85 ESP_LOGV(TAG, "Setting Output Power Option failed!");
86 }
87
88 if (!this->wifi_apply_power_save_()) {
89 ESP_LOGV(TAG, "Setting Power Save Option failed!");
90 }
91
92 if (this->fast_connect_) {
93 this->selected_ap_ = this->sta_[0];
95 this->start_connecting(this->selected_ap_, false);
96 } else {
97 this->start_scanning();
98 }
99#ifdef USE_WIFI_AP
100 } else if (this->has_ap()) {
101 this->setup_ap_config_();
102 if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
103 ESP_LOGV(TAG, "Setting Output Power Option failed!");
104 }
105#ifdef USE_CAPTIVE_PORTAL
107 this->wifi_sta_pre_setup_();
108 this->start_scanning();
110 }
111#endif
112#endif // USE_WIFI_AP
113 }
114#ifdef USE_IMPROV
115 if (!this->has_sta() && esp32_improv::global_improv_component != nullptr) {
116 if (this->wifi_mode_(true, {}))
118 }
119#endif
120 this->wifi_apply_hostname_();
121}
122
124 this->wifi_loop_();
125 const uint32_t now = millis();
126
127 if (this->has_sta()) {
128 if (this->is_connected() != this->handled_connected_state_) {
129 if (this->handled_connected_state_) {
131 } else {
132 this->connect_trigger_->trigger();
133 }
135 }
136
137 switch (this->state_) {
139 this->status_set_warning("waiting to reconnect");
140 if (millis() - this->action_started_ > 5000) {
141 if (this->fast_connect_ || this->retry_hidden_) {
142 this->start_connecting(this->sta_[0], false);
143 } else {
144 this->start_scanning();
145 }
146 }
147 break;
148 }
150 this->status_set_warning("scanning for networks");
152 break;
153 }
156 this->status_set_warning("associating to network");
158 break;
159 }
160
162 if (!this->is_connected()) {
163 ESP_LOGW(TAG, "WiFi Connection lost... Reconnecting...");
165 this->retry_connect();
166 } else {
167 this->status_clear_warning();
168 this->last_connected_ = now;
169 }
170 break;
171 }
174 break;
176 return;
177 }
178
179#ifdef USE_WIFI_AP
180 if (this->has_ap() && !this->ap_setup_) {
181 if (this->ap_timeout_ != 0 && (now - this->last_connected_ > this->ap_timeout_)) {
182 ESP_LOGI(TAG, "Starting fallback AP!");
183 this->setup_ap_config_();
184#ifdef USE_CAPTIVE_PORTAL
187#endif
188 }
189 }
190#endif // USE_WIFI_AP
191
192#ifdef USE_IMPROV
194 if (now - this->last_connected_ > esp32_improv::global_improv_component->get_wifi_timeout()) {
195 if (this->wifi_mode_(true, {}))
197 }
198 }
199
200#endif
201
202 if (!this->has_ap() && this->reboot_timeout_ != 0) {
203 if (now - this->last_connected_ > this->reboot_timeout_) {
204 ESP_LOGE(TAG, "Can't connect to WiFi, rebooting...");
205 App.reboot();
206 }
207 }
208 }
209}
210
212
213bool WiFiComponent::has_ap() const { return this->has_ap_; }
214bool WiFiComponent::has_sta() const { return !this->sta_.empty(); }
215void WiFiComponent::set_fast_connect(bool fast_connect) { this->fast_connect_ = fast_connect; }
216#ifdef USE_WIFI_11KV_SUPPORT
217void WiFiComponent::set_btm(bool btm) { this->btm_ = btm; }
218void WiFiComponent::set_rrm(bool rrm) { this->rrm_ = rrm; }
219#endif
221 if (this->has_sta())
222 return this->wifi_sta_ip_addresses();
223
224#ifdef USE_WIFI_AP
225 if (this->has_ap())
226 return {this->wifi_soft_ap_ip()};
227#endif // USE_WIFI_AP
228
229 return {};
230}
232 if (this->has_sta())
233 return this->wifi_dns_ip_(num);
234 return {};
235}
237 if (this->use_address_.empty()) {
238 return App.get_name() + ".local";
239 }
240 return this->use_address_;
241}
242void WiFiComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
243
244#ifdef USE_WIFI_AP
246 this->wifi_mode_({}, true);
247
248 if (this->ap_setup_)
249 return;
250
251 if (this->ap_.get_ssid().empty()) {
252 std::string name = App.get_name();
253 if (name.length() > 32) {
255 name.erase(name.begin() + 25, name.end() - 7); // Remove characters between 25 and the mac address
256 } else {
257 name = name.substr(0, 32);
258 }
259 }
260 this->ap_.set_ssid(name);
261 }
262
263 ESP_LOGCONFIG(TAG, "Setting up AP...");
264
265 ESP_LOGCONFIG(TAG, " AP SSID: '%s'", this->ap_.get_ssid().c_str());
266 ESP_LOGCONFIG(TAG, " AP Password: '%s'", this->ap_.get_password().c_str());
267 if (this->ap_.get_manual_ip().has_value()) {
268 auto manual = *this->ap_.get_manual_ip();
269 ESP_LOGCONFIG(TAG, " AP Static IP: '%s'", manual.static_ip.str().c_str());
270 ESP_LOGCONFIG(TAG, " AP Gateway: '%s'", manual.gateway.str().c_str());
271 ESP_LOGCONFIG(TAG, " AP Subnet: '%s'", manual.subnet.str().c_str());
272 }
273
274 this->ap_setup_ = this->wifi_start_ap_(this->ap_);
275 ESP_LOGCONFIG(TAG, " IP Address: %s", this->wifi_soft_ap_ip().str().c_str());
276
277 if (!this->has_sta()) {
279 }
280}
281
283 this->ap_ = ap;
284 this->has_ap_ = true;
285}
286#endif // USE_WIFI_AP
287
289 return 10.0f; // before other loop components
290}
291
292void WiFiComponent::add_sta(const WiFiAP &ap) { this->sta_.push_back(ap); }
294 this->clear_sta();
295 this->add_sta(ap);
296}
297void WiFiComponent::clear_sta() { this->sta_.clear(); }
298void WiFiComponent::save_wifi_sta(const std::string &ssid, const std::string &password) {
299 SavedWifiSettings save{};
300 snprintf(save.ssid, sizeof(save.ssid), "%s", ssid.c_str());
301 snprintf(save.password, sizeof(save.password), "%s", password.c_str());
302 this->pref_.save(&save);
303 // ensure it's written immediately
305
306 WiFiAP sta{};
307 sta.set_ssid(ssid);
308 sta.set_password(password);
309 this->set_sta(sta);
310}
311
312void WiFiComponent::start_connecting(const WiFiAP &ap, bool two) {
313 ESP_LOGI(TAG, "WiFi Connecting to '%s'...", ap.get_ssid().c_str());
314#ifdef ESPHOME_LOG_HAS_VERBOSE
315 ESP_LOGV(TAG, "Connection Params:");
316 ESP_LOGV(TAG, " SSID: '%s'", ap.get_ssid().c_str());
317 if (ap.get_bssid().has_value()) {
318 bssid_t b = *ap.get_bssid();
319 ESP_LOGV(TAG, " BSSID: %02X:%02X:%02X:%02X:%02X:%02X", b[0], b[1], b[2], b[3], b[4], b[5]);
320 } else {
321 ESP_LOGV(TAG, " BSSID: Not Set");
322 }
323
324#ifdef USE_WIFI_WPA2_EAP
325 if (ap.get_eap().has_value()) {
326 ESP_LOGV(TAG, " WPA2 Enterprise authentication configured:");
327 EAPAuth eap_config = ap.get_eap().value();
328 ESP_LOGV(TAG, " Identity: " LOG_SECRET("'%s'"), eap_config.identity.c_str());
329 ESP_LOGV(TAG, " Username: " LOG_SECRET("'%s'"), eap_config.username.c_str());
330 ESP_LOGV(TAG, " Password: " LOG_SECRET("'%s'"), eap_config.password.c_str());
331#ifdef USE_ESP_IDF
332#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
333 std::map<esp_eap_ttls_phase2_types, std::string> phase2types = {{ESP_EAP_TTLS_PHASE2_PAP, "pap"},
334 {ESP_EAP_TTLS_PHASE2_CHAP, "chap"},
335 {ESP_EAP_TTLS_PHASE2_MSCHAP, "mschap"},
336 {ESP_EAP_TTLS_PHASE2_MSCHAPV2, "mschapv2"},
337 {ESP_EAP_TTLS_PHASE2_EAP, "eap"}};
338 ESP_LOGV(TAG, " TTLS Phase 2: " LOG_SECRET("'%s'"), phase2types[eap_config.ttls_phase_2].c_str());
339#endif
340#endif
341 bool ca_cert_present = eap_config.ca_cert != nullptr && strlen(eap_config.ca_cert);
342 bool client_cert_present = eap_config.client_cert != nullptr && strlen(eap_config.client_cert);
343 bool client_key_present = eap_config.client_key != nullptr && strlen(eap_config.client_key);
344 ESP_LOGV(TAG, " CA Cert: %s", ca_cert_present ? "present" : "not present");
345 ESP_LOGV(TAG, " Client Cert: %s", client_cert_present ? "present" : "not present");
346 ESP_LOGV(TAG, " Client Key: %s", client_key_present ? "present" : "not present");
347 } else {
348#endif
349 ESP_LOGV(TAG, " Password: " LOG_SECRET("'%s'"), ap.get_password().c_str());
350#ifdef USE_WIFI_WPA2_EAP
351 }
352#endif
353 if (ap.get_channel().has_value()) {
354 ESP_LOGV(TAG, " Channel: %u", *ap.get_channel());
355 } else {
356 ESP_LOGV(TAG, " Channel: Not Set");
357 }
358 if (ap.get_manual_ip().has_value()) {
359 ManualIP m = *ap.get_manual_ip();
360 ESP_LOGV(TAG, " Manual IP: Static IP=%s Gateway=%s Subnet=%s DNS1=%s DNS2=%s", m.static_ip.str().c_str(),
361 m.gateway.str().c_str(), m.subnet.str().c_str(), m.dns1.str().c_str(), m.dns2.str().c_str());
362 } else {
363 ESP_LOGV(TAG, " Using DHCP IP");
364 }
365 ESP_LOGV(TAG, " Hidden: %s", YESNO(ap.get_hidden()));
366#endif
367
368 if (!this->wifi_sta_connect_(ap)) {
369 ESP_LOGE(TAG, "wifi_sta_connect_ failed!");
370 this->retry_connect();
371 return;
372 }
373
374 if (!two) {
376 } else {
378 }
379 this->action_started_ = millis();
380}
381
382const LogString *get_signal_bars(int8_t rssi) {
383 // LOWER ONE QUARTER BLOCK
384 // Unicode: U+2582, UTF-8: E2 96 82
385 // LOWER HALF BLOCK
386 // Unicode: U+2584, UTF-8: E2 96 84
387 // LOWER THREE QUARTERS BLOCK
388 // Unicode: U+2586, UTF-8: E2 96 86
389 // FULL BLOCK
390 // Unicode: U+2588, UTF-8: E2 96 88
391 if (rssi >= -50) {
392 return LOG_STR("\033[0;32m" // green
393 "\xe2\x96\x82"
394 "\xe2\x96\x84"
395 "\xe2\x96\x86"
396 "\xe2\x96\x88"
397 "\033[0m");
398 } else if (rssi >= -65) {
399 return LOG_STR("\033[0;33m" // yellow
400 "\xe2\x96\x82"
401 "\xe2\x96\x84"
402 "\xe2\x96\x86"
403 "\033[0;37m"
404 "\xe2\x96\x88"
405 "\033[0m");
406 } else if (rssi >= -85) {
407 return LOG_STR("\033[0;33m" // yellow
408 "\xe2\x96\x82"
409 "\xe2\x96\x84"
410 "\033[0;37m"
411 "\xe2\x96\x86"
412 "\xe2\x96\x88"
413 "\033[0m");
414 } else {
415 return LOG_STR("\033[0;31m" // red
416 "\xe2\x96\x82"
417 "\033[0;37m"
418 "\xe2\x96\x84"
419 "\xe2\x96\x86"
420 "\xe2\x96\x88"
421 "\033[0m");
422 }
423}
424
426 bssid_t bssid = wifi_bssid();
427
428 ESP_LOGCONFIG(TAG, " Local MAC: %s", get_mac_address_pretty().c_str());
429 if (this->is_disabled()) {
430 ESP_LOGCONFIG(TAG, " WiFi is disabled!");
431 return;
432 }
433 ESP_LOGCONFIG(TAG, " SSID: " LOG_SECRET("'%s'"), wifi_ssid().c_str());
434 for (auto &ip : wifi_sta_ip_addresses()) {
435 if (ip.is_set()) {
436 ESP_LOGCONFIG(TAG, " IP Address: %s", ip.str().c_str());
437 }
438 }
439 ESP_LOGCONFIG(TAG, " BSSID: " LOG_SECRET("%02X:%02X:%02X:%02X:%02X:%02X"), bssid[0], bssid[1], bssid[2], bssid[3],
440 bssid[4], bssid[5]);
441 ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());
442 int8_t rssi = wifi_rssi();
443 ESP_LOGCONFIG(TAG, " Signal strength: %d dB %s", rssi, LOG_STR_ARG(get_signal_bars(rssi)));
444 if (this->selected_ap_.get_bssid().has_value()) {
445 ESP_LOGV(TAG, " Priority: %.1f", this->get_sta_priority(*this->selected_ap_.get_bssid()));
446 }
447 ESP_LOGCONFIG(TAG, " Channel: %" PRId32, get_wifi_channel());
448 ESP_LOGCONFIG(TAG, " Subnet: %s", wifi_subnet_mask_().str().c_str());
449 ESP_LOGCONFIG(TAG, " Gateway: %s", wifi_gateway_ip_().str().c_str());
450 ESP_LOGCONFIG(TAG, " DNS1: %s", wifi_dns_ip_(0).str().c_str());
451 ESP_LOGCONFIG(TAG, " DNS2: %s", wifi_dns_ip_(1).str().c_str());
452#ifdef USE_WIFI_11KV_SUPPORT
453 ESP_LOGCONFIG(TAG, " BTM: %s", this->btm_ ? "enabled" : "disabled");
454 ESP_LOGCONFIG(TAG, " RRM: %s", this->rrm_ ? "enabled" : "disabled");
455#endif
456}
457
460 return;
461
462 ESP_LOGD(TAG, "Enabling WIFI...");
463 this->error_from_callback_ = false;
465 this->start();
466}
467
470 return;
471
472 ESP_LOGD(TAG, "Disabling WIFI...");
474 this->wifi_disconnect_();
475 this->wifi_mode_(false, false);
476}
477
479
481 this->action_started_ = millis();
482 ESP_LOGD(TAG, "Starting scan...");
483 this->wifi_scan_start_(this->passive_scan_);
485}
486
488 if (!this->scan_done_) {
489 if (millis() - this->action_started_ > 30000) {
490 ESP_LOGE(TAG, "Scan timeout!");
491 this->retry_connect();
492 }
493 return;
494 }
495 this->scan_done_ = false;
496
497 ESP_LOGD(TAG, "Found networks:");
498 if (this->scan_result_.empty()) {
499 ESP_LOGD(TAG, " No network found!");
500 this->retry_connect();
501 return;
502 }
503
504 for (auto &res : this->scan_result_) {
505 for (auto &ap : this->sta_) {
506 if (res.matches(ap)) {
507 res.set_matches(true);
508 if (!this->has_sta_priority(res.get_bssid())) {
509 this->set_sta_priority(res.get_bssid(), ap.get_priority());
510 }
511 res.set_priority(this->get_sta_priority(res.get_bssid()));
512 break;
513 }
514 }
515 }
516
517 std::stable_sort(this->scan_result_.begin(), this->scan_result_.end(),
518 [](const WiFiScanResult &a, const WiFiScanResult &b) {
519 // return true if a is better than b
520 if (a.get_matches() && !b.get_matches())
521 return true;
522 if (!a.get_matches() && b.get_matches())
523 return false;
524
525 if (a.get_matches() && b.get_matches()) {
526 // if both match, check priority
527 if (a.get_priority() != b.get_priority())
528 return a.get_priority() > b.get_priority();
529 }
530
531 return a.get_rssi() > b.get_rssi();
532 });
533
534 for (auto &res : this->scan_result_) {
535 char bssid_s[18];
536 auto bssid = res.get_bssid();
537 sprintf(bssid_s, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
538
539 if (res.get_matches()) {
540 ESP_LOGI(TAG, "- '%s' %s" LOG_SECRET("(%s) ") "%s", res.get_ssid().c_str(),
541 res.get_is_hidden() ? "(HIDDEN) " : "", bssid_s, LOG_STR_ARG(get_signal_bars(res.get_rssi())));
542 ESP_LOGD(TAG, " Channel: %u", res.get_channel());
543 ESP_LOGD(TAG, " RSSI: %d dB", res.get_rssi());
544 } else {
545 ESP_LOGD(TAG, "- " LOG_SECRET("'%s'") " " LOG_SECRET("(%s) ") "%s", res.get_ssid().c_str(), bssid_s,
546 LOG_STR_ARG(get_signal_bars(res.get_rssi())));
547 }
548 }
549
550 if (!this->scan_result_[0].get_matches()) {
551 ESP_LOGW(TAG, "No matching network found!");
552 this->retry_connect();
553 return;
554 }
555
556 WiFiAP connect_params;
557 WiFiScanResult scan_res = this->scan_result_[0];
558 for (auto &config : this->sta_) {
559 // search for matching STA config, at least one will match (from checks before)
560 if (!scan_res.matches(config)) {
561 continue;
562 }
563
564 if (config.get_hidden()) {
565 // selected network is hidden, we use the data from the config
566 connect_params.set_hidden(true);
567 connect_params.set_ssid(config.get_ssid());
568 // don't set BSSID and channel, there might be multiple hidden networks
569 // but we can't know which one is the correct one. Rely on probe-req with just SSID.
570 } else {
571 // selected network is visible, we use the data from the scan
572 // limit the connect params to only connect to exactly this network
573 // (network selection is done during scan phase).
574 connect_params.set_hidden(false);
575 connect_params.set_ssid(scan_res.get_ssid());
576 connect_params.set_channel(scan_res.get_channel());
577 connect_params.set_bssid(scan_res.get_bssid());
578 }
579 // copy manual IP (if set)
580 connect_params.set_manual_ip(config.get_manual_ip());
581
582#ifdef USE_WIFI_WPA2_EAP
583 // copy EAP parameters (if set)
584 connect_params.set_eap(config.get_eap());
585#endif
586
587 // copy password (if set)
588 connect_params.set_password(config.get_password());
589
590 break;
591 }
592
593 yield();
594
595 this->selected_ap_ = connect_params;
596 this->start_connecting(connect_params, false);
597}
598
599void WiFiComponent::dump_config() {
600 ESP_LOGCONFIG(TAG, "WiFi:");
601 this->print_connect_params_();
602}
603
604void WiFiComponent::check_connecting_finished() {
605 auto status = this->wifi_sta_connect_status_();
606
607 if (status == WiFiSTAConnectStatus::CONNECTED) {
608 if (wifi_ssid().empty()) {
609 ESP_LOGW(TAG, "Incomplete connection.");
610 this->retry_connect();
611 return;
612 }
613
614 // We won't retry hidden networks unless a reconnect fails more than three times again
615 this->retry_hidden_ = false;
616
617 ESP_LOGI(TAG, "WiFi Connected!");
618 this->print_connect_params_();
619
620 if (this->has_ap()) {
621#ifdef USE_CAPTIVE_PORTAL
622 if (this->is_captive_portal_active_()) {
624 }
625#endif
626 ESP_LOGD(TAG, "Disabling AP...");
627 this->wifi_mode_({}, false);
628 }
629#ifdef USE_IMPROV
630 if (this->is_esp32_improv_active_()) {
632 }
633#endif
634
636 this->num_retried_ = 0;
637
638 if (this->fast_connect_) {
639 this->save_fast_connect_settings_();
640 }
641
642 return;
643 }
644
645 uint32_t now = millis();
646 if (now - this->action_started_ > 30000) {
647 ESP_LOGW(TAG, "Timeout while connecting to WiFi.");
648 this->retry_connect();
649 return;
650 }
651
652 if (this->error_from_callback_) {
653 ESP_LOGW(TAG, "Error while connecting to network.");
654 this->retry_connect();
655 return;
656 }
657
658 if (status == WiFiSTAConnectStatus::CONNECTING) {
659 return;
660 }
661
662 if (status == WiFiSTAConnectStatus::ERROR_NETWORK_NOT_FOUND) {
663 ESP_LOGW(TAG, "WiFi network can not be found anymore.");
664 this->retry_connect();
665 return;
666 }
667
668 if (status == WiFiSTAConnectStatus::ERROR_CONNECT_FAILED) {
669 ESP_LOGW(TAG, "Connecting to WiFi network failed. Are the credentials wrong?");
670 this->retry_connect();
671 return;
672 }
673
674 ESP_LOGW(TAG, "WiFi Unknown connection status %d", (int) status);
675 this->retry_connect();
676}
677
678void WiFiComponent::retry_connect() {
679 if (this->selected_ap_.get_bssid()) {
680 auto bssid = *this->selected_ap_.get_bssid();
681 float priority = this->get_sta_priority(bssid);
682 this->set_sta_priority(bssid, priority - 1.0f);
683 }
684
685 delay(10);
686 if (!this->is_captive_portal_active_() && !this->is_esp32_improv_active_() &&
687 (this->num_retried_ > 3 || this->error_from_callback_)) {
688 if (this->num_retried_ > 5) {
689 // If retry failed for more than 5 times, let's restart STA
690 ESP_LOGW(TAG, "Restarting WiFi adapter...");
691 this->wifi_mode_(false, {});
692 delay(100); // NOLINT
693 this->num_retried_ = 0;
694 this->retry_hidden_ = false;
695 } else {
696 // Try hidden networks after 3 failed retries
697 ESP_LOGD(TAG, "Retrying with hidden networks...");
698 this->retry_hidden_ = true;
699 this->num_retried_++;
700 }
701 } else {
702 this->num_retried_++;
703 }
704 this->error_from_callback_ = false;
705 if (this->state_ == WIFI_COMPONENT_STATE_STA_CONNECTING) {
706 yield();
708 this->start_connecting(this->selected_ap_, true);
709 return;
710 }
711
712 this->state_ = WIFI_COMPONENT_STATE_COOLDOWN;
713 this->action_started_ = millis();
714}
715
716bool WiFiComponent::can_proceed() {
717 if (!this->has_sta() || this->state_ == WIFI_COMPONENT_STATE_DISABLED || this->ap_setup_) {
718 return true;
719 }
720 return this->is_connected();
721}
722void WiFiComponent::set_reboot_timeout(uint32_t reboot_timeout) { this->reboot_timeout_ = reboot_timeout; }
723bool WiFiComponent::is_connected() {
724 return this->state_ == WIFI_COMPONENT_STATE_STA_CONNECTED &&
725 this->wifi_sta_connect_status_() == WiFiSTAConnectStatus::CONNECTED && !this->error_from_callback_;
726}
727void WiFiComponent::set_power_save_mode(WiFiPowerSaveMode power_save) { this->power_save_ = power_save; }
728
729void WiFiComponent::set_passive_scan(bool passive) { this->passive_scan_ = passive; }
730
731std::string WiFiComponent::format_mac_addr(const uint8_t *mac) {
732 char buf[20];
733 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
734 return buf;
735}
736bool WiFiComponent::is_captive_portal_active_() {
737#ifdef USE_CAPTIVE_PORTAL
739#else
740 return false;
741#endif
742}
743bool WiFiComponent::is_esp32_improv_active_() {
744#ifdef USE_IMPROV
746#else
747 return false;
748#endif
749}
750
751void WiFiComponent::load_fast_connect_settings_() {
752 SavedWifiFastConnectSettings fast_connect_save{};
753
754 if (this->fast_connect_pref_.load(&fast_connect_save)) {
755 bssid_t bssid{};
756 std::copy(fast_connect_save.bssid, fast_connect_save.bssid + 6, bssid.begin());
757 this->selected_ap_.set_bssid(bssid);
758 this->selected_ap_.set_channel(fast_connect_save.channel);
759
760 ESP_LOGD(TAG, "Loaded saved fast_connect wifi settings");
761 }
762}
763
764void WiFiComponent::save_fast_connect_settings_() {
765 bssid_t bssid = wifi_bssid();
766 uint8_t channel = get_wifi_channel();
767
768 if (bssid != this->selected_ap_.get_bssid() || channel != this->selected_ap_.get_channel()) {
769 SavedWifiFastConnectSettings fast_connect_save{};
770
771 memcpy(fast_connect_save.bssid, bssid.data(), 6);
772 fast_connect_save.channel = channel;
773
774 this->fast_connect_pref_.save(&fast_connect_save);
775
776 ESP_LOGD(TAG, "Saved fast_connect wifi settings");
777 }
778}
779
780void WiFiAP::set_ssid(const std::string &ssid) { this->ssid_ = ssid; }
781void WiFiAP::set_bssid(bssid_t bssid) { this->bssid_ = bssid; }
782void WiFiAP::set_bssid(optional<bssid_t> bssid) { this->bssid_ = bssid; }
783void WiFiAP::set_password(const std::string &password) { this->password_ = password; }
784#ifdef USE_WIFI_WPA2_EAP
785void WiFiAP::set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); }
786#endif
787void WiFiAP::set_channel(optional<uint8_t> channel) { this->channel_ = channel; }
788void WiFiAP::set_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; }
789void WiFiAP::set_hidden(bool hidden) { this->hidden_ = hidden; }
790const std::string &WiFiAP::get_ssid() const { return this->ssid_; }
791const optional<bssid_t> &WiFiAP::get_bssid() const { return this->bssid_; }
792const std::string &WiFiAP::get_password() const { return this->password_; }
793#ifdef USE_WIFI_WPA2_EAP
794const optional<EAPAuth> &WiFiAP::get_eap() const { return this->eap_; }
795#endif
796const optional<uint8_t> &WiFiAP::get_channel() const { return this->channel_; }
797const optional<ManualIP> &WiFiAP::get_manual_ip() const { return this->manual_ip_; }
798bool WiFiAP::get_hidden() const { return this->hidden_; }
799
800WiFiScanResult::WiFiScanResult(const bssid_t &bssid, std::string ssid, uint8_t channel, int8_t rssi, bool with_auth,
801 bool is_hidden)
802 : bssid_(bssid),
803 ssid_(std::move(ssid)),
804 channel_(channel),
805 rssi_(rssi),
806 with_auth_(with_auth),
807 is_hidden_(is_hidden) {}
808bool WiFiScanResult::matches(const WiFiAP &config) {
809 if (config.get_hidden()) {
810 // User configured a hidden network, only match actually hidden networks
811 // don't match SSID
812 if (!this->is_hidden_)
813 return false;
814 } else if (!config.get_ssid().empty()) {
815 // check if SSID matches
816 if (config.get_ssid() != this->ssid_)
817 return false;
818 } else {
819 // network is configured without SSID - match other settings
820 }
821 // If BSSID configured, only match for correct BSSIDs
822 if (config.get_bssid().has_value() && *config.get_bssid() != this->bssid_)
823 return false;
824
825#ifdef USE_WIFI_WPA2_EAP
826 // BSSID requires auth but no PSK or EAP credentials given
827 if (this->with_auth_ && (config.get_password().empty() && !config.get_eap().has_value()))
828 return false;
829
830 // BSSID does not require auth, but PSK or EAP credentials given
831 if (!this->with_auth_ && (!config.get_password().empty() || config.get_eap().has_value()))
832 return false;
833#else
834 // If PSK given, only match for networks with auth (and vice versa)
835 if (config.get_password().empty() == this->with_auth_)
836 return false;
837#endif
838
839 // If channel configured, only match networks on that channel.
840 if (config.get_channel().has_value() && *config.get_channel() != this->channel_) {
841 return false;
842 }
843 return true;
844}
845bool WiFiScanResult::get_matches() const { return this->matches_; }
846void WiFiScanResult::set_matches(bool matches) { this->matches_ = matches; }
847const bssid_t &WiFiScanResult::get_bssid() const { return this->bssid_; }
848const std::string &WiFiScanResult::get_ssid() const { return this->ssid_; }
849uint8_t WiFiScanResult::get_channel() const { return this->channel_; }
850int8_t WiFiScanResult::get_rssi() const { return this->rssi_; }
851bool WiFiScanResult::get_with_auth() const { return this->with_auth_; }
852bool WiFiScanResult::get_is_hidden() const { return this->is_hidden_; }
853
854bool WiFiScanResult::operator==(const WiFiScanResult &rhs) const { return this->bssid_ == rhs.bssid_; }
855
856WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
857
858} // namespace wifi
859} // namespace esphome
860#endif
uint8_t m
Definition bl0906.h:1
uint8_t status
Definition bl0942.h:8
std::string get_compilation_time() const
bool is_name_add_mac_suffix_enabled() const
const std::string & get_name() const
Get the name of this Application set by pre_setup().
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
bool save(const T *src)
Definition preferences.h:21
virtual bool sync()=0
Commit pending writes to flash.
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
void trigger(Ts... x)
Inform the parent automation that the event has triggered.
Definition automation.h:96
bool has_value() const
Definition optional.h:87
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
const std::string & get_password() const
const optional< ManualIP > & get_manual_ip() const
This component is responsible for managing the ESP WiFi interface.
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.
float get_sta_priority(const bssid_t bssid)
network::IPAddress get_dns_address(int num)
WiFiComponent()
Construct a WiFiComponent.
std::vector< WiFiScanResult > scan_result_
void start_connecting(const WiFiAP &ap, bool two)
void set_use_address(const std::string &use_address)
ESPPreferenceObject fast_connect_pref_
float get_loop_priority() const override
network::IPAddresses get_ip_addresses()
std::vector< WiFiAP > sta_
float get_setup_priority() const override
WIFI setup_priority.
optional< float > output_power_
void set_sta_priority(const bssid_t bssid, float priority)
void set_fast_connect(bool fast_connect)
bool wifi_mode_(optional< bool > sta, optional< bool > ap)
void setup() override
Setup WiFi interface.
const std::string & get_ssid() const
const bssid_t & get_bssid() const
bool matches(const WiFiAP &config)
bool operator==(const WiFiScanResult &rhs) const
uint8_t priority
CaptivePortal * global_captive_portal
ESP32ImprovComponent * global_improv_component
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:143
std::array< uint8_t, 6 > bssid_t
const LogString * get_signal_bars(int8_t rssi)
@ 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.
WiFiComponent * global_wifi_component
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint32_t fnv1_hash(const std::string &str)
Calculate a FNV-1 hash of str.
Definition helpers.cpp:186
ESPPreferences * global_preferences
std::string get_mac_address_pretty()
Get the device MAC address as a string, in colon-separated uppercase hex notation.
Definition helpers.cpp:732
void IRAM_ATTR HOT yield()
Definition core.cpp:26
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
Application App
Global storage of Application pointer - only one Application can exist.
esp_eap_ttls_phase2_types ttls_phase_2
Struct for setting static IPs in WiFiComponent.