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