11#include <esp_wifi_types.h>
12#include <freertos/FreeRTOS.h>
13#include <freertos/event_groups.h>
14#include <freertos/task.h>
20#ifdef USE_WIFI_WPA2_EAP
21#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
22#include <esp_eap_client.h>
33#include "dhcpserver/dhcpserver.h"
36#ifdef USE_CAPTIVE_PORTAL
40#include "lwip/apps/sntp.h"
43#ifdef USE_WIFI_LEASE_CACHE
44#include <esp_netif_net_stack.h>
45#include <esp_rtc_time.h>
47#include "lwip/netif.h"
60static EventGroupHandle_t s_wifi_event_group;
65static bool s_sta_connected =
false;
66static bool s_sta_connect_not_found =
false;
67static bool s_sta_connect_error =
false;
68static bool s_sta_connecting =
false;
69static bool s_wifi_started =
false;
74static void copy_terminated(
char *dst,
const uint8_t *
src,
size_t len) {
81 esp_event_base_t event_base;
84 wifi_event_sta_scan_done_t sta_scan_done;
85 wifi_event_sta_connected_t sta_connected;
86 wifi_event_sta_disconnected_t sta_disconnected;
87 wifi_event_sta_authmode_change_t sta_authmode_change;
88 wifi_event_ap_staconnected_t ap_staconnected;
89 wifi_event_ap_stadisconnected_t ap_stadisconnected;
90 wifi_event_ap_probe_req_rx_t ap_probe_req_rx;
91 wifi_event_bss_rssi_low_t bss_rssi_low;
93 SavedWifiSettings *dpp_credentials;
94 wifi_event_dpp_failed_t dpp_failed;
96 ip_event_got_ip_t ip_got_ip;
98 ip_event_got_ip6_t ip_got_ip6;
100#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
101 ip_event_assigned_ip_to_client_t ip_assigned_ip_to_client;
103 ip_event_ap_staipassigned_t ip_ap_staipassigned;
110void event_handler(
void *arg, esp_event_base_t event_base, int32_t
event_id,
void *event_data) {
112 memset(&event, 0,
sizeof(IDFWiFiEvent));
113 event.event_base = event_base;
115 if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_START) {
117 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_STOP) {
119 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) {
120 memcpy(&event.data.sta_authmode_change, event_data,
sizeof(wifi_event_sta_authmode_change_t));
121 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_CONNECTED) {
122 memcpy(&event.data.sta_connected, event_data,
sizeof(wifi_event_sta_connected_t));
123 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_DISCONNECTED) {
124 memcpy(&event.data.sta_disconnected, event_data,
sizeof(wifi_event_sta_disconnected_t));
125 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_STA_GOT_IP) {
126 memcpy(&event.data.ip_got_ip, event_data,
sizeof(ip_event_got_ip_t));
128 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_GOT_IP6) {
129 memcpy(&event.data.ip_got_ip6, event_data,
sizeof(ip_event_got_ip6_t));
131#if defined(USE_WIFI_AP_WISP) && !defined(USE_WIFI_AP_WISP_STATIC_DNS)
132 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_ETH_GOT_IP) {
135 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_STA_LOST_IP) {
137 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_SCAN_DONE) {
138 memcpy(&event.data.sta_scan_done, event_data,
sizeof(wifi_event_sta_scan_done_t));
139 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_AP_START) {
141 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_AP_STOP) {
143 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
144 memcpy(&event.data.ap_probe_req_rx, event_data,
sizeof(wifi_event_ap_probe_req_rx_t));
145 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_AP_STACONNECTED) {
146 memcpy(&event.data.ap_staconnected, event_data,
sizeof(wifi_event_ap_staconnected_t));
147 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_AP_STADISCONNECTED) {
148 memcpy(&event.data.ap_stadisconnected, event_data,
sizeof(wifi_event_ap_stadisconnected_t));
150 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_DPP_URI_READY) {
152 const auto *uri =
static_cast<const wifi_event_dpp_uri_ready_t *
>(event_data);
153 const size_t len = strnlen(uri->uri, uri->uri_data_len);
154 auto copy = std::make_unique<char[]>(
len + 1);
155 copy_terminated(copy.get(),
reinterpret_cast<const uint8_t *
>(uri->uri),
len);
157 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_DPP_CFG_RECVD) {
158 const auto &sta =
static_cast<const wifi_event_dpp_config_received_t *
>(event_data)->wifi_cfg.sta;
159 auto *credentials =
new SavedWifiSettings;
160 copy_terminated(credentials->ssid, sta.ssid,
sizeof(sta.ssid));
161 copy_terminated(credentials->password, sta.password,
sizeof(sta.password));
162 event.data.dpp_credentials = credentials;
163 }
else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_DPP_FAILED) {
164 memcpy(&event.data.dpp_failed, event_data,
sizeof(wifi_event_dpp_failed_t));
166#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
167 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_ASSIGNED_IP_TO_CLIENT) {
168 memcpy(&event.data.ip_assigned_ip_to_client, event_data,
sizeof(ip_event_assigned_ip_to_client_t));
170 }
else if (event_base == IP_EVENT &&
event_id == IP_EVENT_AP_STAIPASSIGNED) {
171 memcpy(&event.data.ip_ap_staipassigned, event_data,
sizeof(ip_event_ap_staipassigned_t));
179 auto *to_send =
new IDFWiFiEvent;
180 memcpy(to_send, &event,
sizeof(IDFWiFiEvent));
183 if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_DPP_CFG_RECVD)
184 delete to_send->data.dpp_credentials;
192 s_wifi_event_group = xEventGroupCreate();
193 if (s_wifi_event_group ==
nullptr) {
194 ESP_LOGE(TAG,
"xEventGroupCreate failed");
197 esp_event_handler_instance_t instance_wifi_id, instance_ip_id;
199 esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &
event_handler,
nullptr, &instance_wifi_id);
201 ESP_LOGE(TAG,
"esp_event_handler_instance_register failed: %s",
esp_err_to_name(err));
204 err = esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, &
event_handler,
nullptr, &instance_ip_id);
206 ESP_LOGE(TAG,
"esp_event_handler_instance_register failed: %s",
esp_err_to_name(err));
223 if (s_sta_netif ==
nullptr)
224 s_sta_netif = esp_netif_create_default_wifi_sta();
225 if (s_sta_netif ==
nullptr) {
227 ESP_LOGE(TAG,
"esp_netif_create_default_wifi_sta failed");
232 if (s_ap_netif ==
nullptr)
233 s_ap_netif = esp_netif_create_default_wifi_ap();
249 if (esp_wifi_get_mode(&
mode) == ESP_OK) {
250 ESP_LOGD(TAG,
"WiFi driver already started without STA netif; restarting to bind it");
258 err = esp_wifi_set_storage(WIFI_STORAGE_RAM);
260 ESP_LOGW(TAG,
"esp_wifi_set_storage failed: %s",
esp_err_to_name(err));
262 err = esp_wifi_start();
267 s_wifi_started =
true;
275 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
277 ESP_LOGW(TAG,
"starting wifi without nvs");
278 cfg.nvs_enable =
false;
285 err = esp_wifi_set_storage(WIFI_STORAGE_RAM);
287 ESP_LOGE(TAG,
"esp_wifi_set_storage failed: %s",
esp_err_to_name(err));
300#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
303 esp_err_t err = esp_supp_dpp_init(
nullptr);
306 ESP_LOGW(TAG,
"%s failed: %s", LOG_STR_LITERAL(
"esp_supp_dpp_init"),
esp_err_to_name(err));
311 ESP_LOGW(TAG,
"%s failed: %s", LOG_STR_LITERAL(
"esp_supp_dpp_bootstrap_gen"),
esp_err_to_name(err));
318 wifi_mode_t current_mode = WIFI_MODE_NULL;
319 if (s_wifi_started) {
320 err = esp_wifi_get_mode(¤t_mode);
326 bool current_sta = current_mode == WIFI_MODE_STA || current_mode == WIFI_MODE_APSTA;
327 bool current_ap = current_mode == WIFI_MODE_AP || current_mode == WIFI_MODE_APSTA;
329 bool set_sta = sta.value_or(current_sta);
330 bool set_ap = ap.value_or(current_ap);
332 wifi_mode_t set_mode;
334 set_mode = WIFI_MODE_APSTA;
336 set_mode = WIFI_MODE_STA;
338 set_mode = WIFI_MODE_AP;
340 set_mode = WIFI_MODE_NULL;
343 if (current_mode == set_mode)
347 ESP_LOGV(TAG,
"Enabling STA");
348 }
else if (!
set_sta && current_sta) {
349 ESP_LOGV(TAG,
"Disabling STA");
351 if (
set_ap && !current_ap) {
352 ESP_LOGV(TAG,
"Enabling AP");
353 }
else if (!
set_ap && current_ap) {
354 ESP_LOGV(TAG,
"Disabling AP");
357 if (set_mode == WIFI_MODE_NULL && s_wifi_started) {
358 err = esp_wifi_stop();
363 s_wifi_started =
false;
367 err = esp_wifi_set_mode(set_mode);
373 if (set_mode != WIFI_MODE_NULL && !s_wifi_started) {
374 err = esp_wifi_start();
379 s_wifi_started =
true;
388 int8_t
val =
static_cast<int8_t
>(output_power * 4);
389 return esp_wifi_set_max_tx_power(
val) == ESP_OK;
393 wifi_ps_type_t power_save;
396 power_save = WIFI_PS_MIN_MODEM;
399 power_save = WIFI_PS_MAX_MODEM;
403 power_save = WIFI_PS_NONE;
406 bool success = esp_wifi_set_ps(power_save) == ESP_OK;
407#ifdef USE_WIFI_POWER_SAVE_LISTENERS
417#ifdef SOC_WIFI_SUPPORT_5G
432 memset(&conf, 0,
sizeof(conf));
433 if (ap.ssid_.size() >
sizeof(conf.sta.ssid)) {
434 ESP_LOGE(TAG,
"SSID too long");
437 if (ap.password_.size() >
sizeof(conf.sta.password)) {
438 ESP_LOGE(TAG,
"Password too long");
441 memcpy(
reinterpret_cast<char *
>(conf.sta.ssid), ap.ssid_.c_str(), ap.ssid_.size());
442 memcpy(
reinterpret_cast<char *
>(conf.sta.password), ap.password_.c_str(), ap.password_.size());
445 if (ap.password_.empty()) {
446 conf.sta.threshold.authmode = WIFI_AUTH_OPEN;
451 conf.sta.threshold.authmode = WIFI_AUTH_WPA_PSK;
454 conf.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
457 conf.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK;
462#ifdef USE_WIFI_WPA2_EAP
463 if (ap.get_eap().has_value()) {
464 conf.sta.threshold.authmode = WIFI_AUTH_WPA2_ENTERPRISE;
468#ifdef USE_WIFI_11KV_SUPPORT
469 conf.sta.btm_enabled = this->
btm_;
470 conf.sta.rm_enabled = this->
rrm_;
473 if (ap.has_bssid()) {
474 conf.sta.bssid_set =
true;
475 memcpy(conf.sta.bssid, ap.get_bssid().data(), 6);
477 conf.sta.bssid_set =
false;
479 if (ap.has_channel()) {
480 conf.sta.channel = ap.get_channel();
481 conf.sta.scan_method = WIFI_FAST_SCAN;
483 conf.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
487 conf.sta.listen_interval = 0;
491 conf.sta.pmf_cfg.capable =
true;
492 conf.sta.pmf_cfg.required =
false;
496 conf.sta.threshold.rssi = -127;
498 wifi_config_t current_conf;
500 err = esp_wifi_get_config(WIFI_IF_STA, ¤t_conf);
506 if (memcmp(¤t_conf, &conf,
sizeof(wifi_config_t)) != 0) {
507 err = esp_wifi_disconnect();
514 err = esp_wifi_set_config(WIFI_IF_STA, &conf);
520#ifdef USE_WIFI_MANUAL_IP
531#ifdef USE_WIFI_WPA2_EAP
532 const auto &eap_opt = ap.get_eap();
533 if (eap_opt.has_value()) {
535 const EAPAuth &eap = *eap_opt;
536#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
537 err = esp_eap_client_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length());
539 err = esp_wifi_sta_wpa2_ent_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length());
542 ESP_LOGV(TAG,
"set_identity failed %d", err);
544 int ca_cert_len = strlen(eap.ca_cert);
545 int client_cert_len = strlen(eap.client_cert);
546 int client_key_len = strlen(eap.client_key);
548#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
549 err = esp_eap_client_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1);
551 err = esp_wifi_sta_wpa2_ent_set_ca_cert((uint8_t *) eap.ca_cert, ca_cert_len + 1);
554 ESP_LOGV(TAG,
"set_ca_cert failed %d", err);
559 if (client_cert_len && client_key_len) {
561#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
562 err = esp_eap_client_set_certificate_and_key((uint8_t *) eap.client_cert, client_cert_len + 1,
563 (uint8_t *) eap.client_key, client_key_len + 1,
564 (uint8_t *) eap.password.c_str(), eap.password.length());
566 err = esp_wifi_sta_wpa2_ent_set_cert_key((uint8_t *) eap.client_cert, client_cert_len + 1,
567 (uint8_t *) eap.client_key, client_key_len + 1,
568 (uint8_t *) eap.password.c_str(), eap.password.length());
571 ESP_LOGV(TAG,
"set_cert_key failed %d", err);
575#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
576 err = esp_eap_client_set_username((uint8_t *) eap.username.c_str(), eap.username.length());
578 err = esp_wifi_sta_wpa2_ent_set_username((uint8_t *) eap.username.c_str(), eap.username.length());
581 ESP_LOGV(TAG,
"set_username failed %d", err);
583#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
584 err = esp_eap_client_set_password((uint8_t *) eap.password.c_str(), eap.password.length());
586 err = esp_wifi_sta_wpa2_ent_set_password((uint8_t *) eap.password.c_str(), eap.password.length());
589 ESP_LOGV(TAG,
"set_password failed %d", err);
592#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
593 err = esp_eap_client_set_ttls_phase2_method(eap.ttls_phase_2);
595 err = esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(eap.ttls_phase_2);
598 ESP_LOGV(TAG,
"set_ttls_phase2_method failed %d", err);
601#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
602 err = esp_wifi_sta_enterprise_enable();
604 err = esp_wifi_sta_wpa2_ent_enable();
607 ESP_LOGV(TAG,
"enterprise_enable failed %d", err);
614 s_sta_connecting =
true;
615 s_sta_connected =
false;
616 s_sta_connect_error =
false;
617 s_sta_connect_not_found =
false;
625 err = esp_wifi_connect();
635static void disable_dhcp_sntp() {
636#if SNTP_GET_SERVERS_FROM_DHCP || SNTP_GET_SERVERS_FROM_DHCPV6
639 sntp_servermode_dhcp(
false);
642#ifdef USE_WIFI_LEASE_CACHE
644static constexpr uint32_t LEASE_APPLY_MARGIN_SECS = 60;
647static uint32_t lease_cache_age_secs(
const SavedWifiLeaseSettings &lease) {
649 return now >= lease.saved_at ? now - lease.saved_at : UINT32_MAX;
653static uint32_t lease_renew_at_secs(
const SavedWifiLeaseSettings &lease) {
655 if (renew_at == 0 || renew_at >= lease.lease_secs)
656 renew_at = lease.lease_secs / 2;
662 ESP_LOGI(TAG,
"Cached lease renew deadline reached; re-acquiring the address over DHCP, connections may drop");
666 esp_err_t err = esp_netif_dhcpc_start(s_sta_netif);
668 ESP_LOGW(TAG,
"Lease renew: starting DHCP client failed: %s, retrying in 60 s",
esp_err_to_name(err));
675 if (lease.version != SAVED_WIFI_LEASE_VERSION || this->selected_sta_index_ < 0 ||
676 lease.ap_index != this->selected_sta_index_)
679 esp_reset_reason_t reason = esp_reset_reason();
680 if (reason != ESP_RST_DEEPSLEEP && reason != ESP_RST_SW)
682 uint32_t age = lease_cache_age_secs(lease);
683 if (age == UINT32_MAX)
688 if (age >= lease_renew_at_secs(lease))
691 uint32_t margin = std::max<uint32_t>(LEASE_APPLY_MARGIN_SECS, lease.lease_secs / 16);
692 return lease.lease_secs > age + margin;
702 if (s_sta_netif ==
nullptr) {
703 ESP_LOGW(TAG,
"STA interface not initialized");
707 esp_netif_dhcp_status_t dhcp_status;
708 esp_err_t err = esp_netif_dhcpc_get_status(s_sta_netif, &dhcp_status);
710 ESP_LOGV(TAG,
"esp_netif_dhcpc_get_status failed: %s",
esp_err_to_name(err));
714#ifdef USE_WIFI_LEASE_CACHE
716 optional<ManualIP> effective_ip = manual_ip;
719 if (!effective_ip.has_value() && this->lease_valid_for_apply_()) {
721 esp_ip4_addr_t ip4{lease.ip}, mask4{lease.netmask}, gw4{lease.gateway}, dns1_4{lease.dns1}, dns2_4{lease.dns2};
723 cached.static_ip = network::IPAddress(&ip4);
724 cached.gateway = network::IPAddress(&gw4);
725 cached.subnet = network::IPAddress(&mask4);
726 cached.dns1 = network::IPAddress(&dns1_4);
727 cached.dns2 = network::IPAddress(&dns2_4);
728 effective_ip = cached;
731 uint32_t age = lease_cache_age_secs(lease);
732 uint32_t remaining = lease.lease_secs > age ? lease.lease_secs - age : 0;
733 ESP_LOGI(TAG,
"Applying cached lease " IPSTR
", ~%" PRIu32
"s left, skipping DHCP", IP2STR(&ip4), remaining);
736 uint32_t renew_in = lease_renew_at_secs(lease) - age;
739 static_cast<uint32_t>(std::min<uint64_t>(
static_cast<uint64_t
>(renew_in) * 1000ULL, UINT32_MAX - 1));
743 const optional<ManualIP> &effective_ip = manual_ip;
746 if (!effective_ip.has_value()) {
753 if (dhcp_status != ESP_NETIF_DHCP_STARTED) {
754 err = esp_netif_dhcpc_start(s_sta_netif);
756 ESP_LOGV(TAG,
"Starting DHCP client failed: %d", err);
758 return err == ESP_OK;
763 esp_netif_ip_info_t info;
764 info.ip = effective_ip->static_ip;
765 info.gw = effective_ip->gateway;
766 info.netmask = effective_ip->subnet;
767 err = esp_netif_dhcpc_stop(s_sta_netif);
768 if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
769 ESP_LOGV(TAG,
"Stopping DHCP client failed: %s",
esp_err_to_name(err));
772 err = esp_netif_set_ip_info(s_sta_netif, &info);
774 ESP_LOGV(TAG,
"Setting manual IP info failed: %s",
esp_err_to_name(err));
777 esp_netif_dns_info_t dns;
778 if (effective_ip->dns1.is_set()) {
779 dns.ip = effective_ip->dns1;
780 esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_MAIN, &dns);
782 if (effective_ip->dns2.is_set()) {
783 dns.ip = effective_ip->dns2;
784 esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_BACKUP, &dns);
790#ifdef USE_WIFI_LEASE_CACHE
796#ifdef USE_WIFI_MANUAL_IP
801 esp_netif_ip_info_t info;
802 if (esp_netif_get_ip_info(s_sta_netif, &info) != ESP_OK || info.ip.addr == 0)
805 SavedWifiLeaseSettings lease{};
806 lease.version = SAVED_WIFI_LEASE_VERSION;
808 lease.ip = info.ip.addr;
809 lease.netmask = info.netmask.addr;
810 lease.gateway = info.gw.addr;
812 esp_netif_dns_info_t dns;
813 if (esp_netif_get_dns_info(s_sta_netif, ESP_NETIF_DNS_MAIN, &dns) == ESP_OK && dns.ip.type == ESP_IPADDR_TYPE_V4) {
814 lease.dns1 = dns.ip.u_addr.ip4.addr;
816 if (esp_netif_get_dns_info(s_sta_netif, ESP_NETIF_DNS_BACKUP, &dns) == ESP_OK && dns.ip.type == ESP_IPADDR_TYPE_V4) {
817 lease.dns2 = dns.ip.u_addr.ip4.addr;
821 bool have_timing =
false;
822 if (
auto *impl =
static_cast<struct netif *
>(esp_netif_get_netif_impl(s_sta_netif))) {
824 if (
struct dhcp *d = netif_dhcp_data(impl)) {
825 lease.lease_secs = d->offered_t0_lease;
826 lease.t1_renew = d->offered_t1_renew;
833 lease.saved_at =
static_cast<uint32_t>(esp_rtc_get_time_us() / 1000000ULL);
837#ifdef USE_WIFI_LEASE_CACHE_IN_FLASH
838 constexpr size_t compare_len = offsetof(SavedWifiLeaseSettings, saved_at);
840 constexpr size_t compare_len =
sizeof(SavedWifiLeaseSettings);
842 const SavedWifiLeaseSettings &previous = this->
cached_lease_;
843 if (previous.saved_at <= lease.saved_at && memcmp(&previous, &lease, compare_len) == 0)
849 ESP_LOGD(TAG,
"Lease cache: saved " IPSTR
" (network %d, lease %" PRIu32
"s)", IP2STR(&info.ip), lease.ap_index,
860 esp_netif_ip_info_t ip;
861 esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip);
863 ESP_LOGV(TAG,
"esp_netif_get_ip_info failed: %s",
esp_err_to_name(err));
867 addresses[0] = network::IPAddress(&ip.ip);
885 case WIFI_AUTH_WPA_PSK:
887 case WIFI_AUTH_WPA2_PSK:
889 case WIFI_AUTH_WPA_WPA2_PSK:
890 return "WPA/WPA2 PSK";
891 case WIFI_AUTH_WPA2_ENTERPRISE:
892 return "WPA2 Enterprise";
893 case WIFI_AUTH_WPA3_PSK:
895 case WIFI_AUTH_WPA2_WPA3_PSK:
896 return "WPA2/WPA3 PSK";
897 case WIFI_AUTH_WAPI_PSK:
906 case WIFI_REASON_AUTH_EXPIRE:
907 return "Auth Expired";
908 case WIFI_REASON_AUTH_LEAVE:
910#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
911 case WIFI_REASON_DISASSOC_DUE_TO_INACTIVITY:
912 return "Disassociated Due to Inactivity";
914 case WIFI_REASON_ASSOC_EXPIRE:
915 return "Association Expired";
917 case WIFI_REASON_ASSOC_TOOMANY:
918 return "Too Many Associations";
919#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
920 case WIFI_REASON_CLASS2_FRAME_FROM_NONAUTH_STA:
921 return "Class 2 Frame from Non-Authenticated STA";
922 case WIFI_REASON_CLASS3_FRAME_FROM_NONASSOC_STA:
923 return "Class 3 Frame from Non-Associated STA";
925 case WIFI_REASON_NOT_AUTHED:
926 return "Not Authenticated";
927 case WIFI_REASON_NOT_ASSOCED:
928 return "Not Associated";
930 case WIFI_REASON_ASSOC_LEAVE:
931 return "Association Leave";
932 case WIFI_REASON_ASSOC_NOT_AUTHED:
933 return "Association not Authenticated";
934 case WIFI_REASON_DISASSOC_PWRCAP_BAD:
935 return "Disassociate Power Cap Bad";
936 case WIFI_REASON_DISASSOC_SUPCHAN_BAD:
937 return "Disassociate Supported Channel Bad";
938 case WIFI_REASON_IE_INVALID:
940 case WIFI_REASON_MIC_FAILURE:
941 return "Mic Failure";
942 case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
943 return "4-Way Handshake Timeout";
944 case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT:
945 return "Group Key Update Timeout";
946 case WIFI_REASON_IE_IN_4WAY_DIFFERS:
947 return "IE In 4-Way Handshake Differs";
948 case WIFI_REASON_GROUP_CIPHER_INVALID:
949 return "Group Cipher Invalid";
950 case WIFI_REASON_PAIRWISE_CIPHER_INVALID:
951 return "Pairwise Cipher Invalid";
952 case WIFI_REASON_AKMP_INVALID:
953 return "AKMP Invalid";
954 case WIFI_REASON_UNSUPP_RSN_IE_VERSION:
955 return "Unsupported RSN IE version";
956 case WIFI_REASON_INVALID_RSN_IE_CAP:
957 return "Invalid RSN IE Cap";
958 case WIFI_REASON_802_1X_AUTH_FAILED:
959 return "802.1x Authentication Failed";
960 case WIFI_REASON_CIPHER_SUITE_REJECTED:
961 return "Cipher Suite Rejected";
962 case WIFI_REASON_BEACON_TIMEOUT:
963 return "Beacon Timeout";
964 case WIFI_REASON_NO_AP_FOUND:
965 return "AP Not Found";
966 case WIFI_REASON_AUTH_FAIL:
967 return "Authentication Failed";
968 case WIFI_REASON_ASSOC_FAIL:
969 return "Association Failed";
970 case WIFI_REASON_HANDSHAKE_TIMEOUT:
971 return "Handshake Failed";
972 case WIFI_REASON_CONNECTION_FAIL:
973 return "Connection Failed";
974 case WIFI_REASON_AP_TSF_RESET:
975 return "AP TSF reset";
976 case WIFI_REASON_ROAMING:
977 return "Station Roaming";
978 case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG:
979 return "Association comeback time too long";
980 case WIFI_REASON_SA_QUERY_TIMEOUT:
981 return "SA query timeout";
982#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
983 case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY:
984 return "No AP found with compatible security";
985 case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD:
986 return "No AP found in auth mode threshold";
987 case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD:
988 return "No AP found in RSSI threshold";
990 case WIFI_REASON_UNSPECIFIED:
992 return "Unspecified";
998static void read_ap_clients(uint8_t &
count) {
999 wifi_sta_list_t sta_list;
1000 if (esp_wifi_ap_get_sta_list(&sta_list) == ESP_OK)
1001 count = sta_list.num;
1009 if (data ==
nullptr)
1021 ESP_LOGW(TAG,
"Dropped %u WiFi events due to buffer overflow", dropped);
1035 if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_STA_START) {
1036 ESP_LOGV(TAG,
"STA start");
1039 if (err != ERR_OK) {
1040 ESP_LOGW(TAG,
"esp_netif_set_hostname failed: %s",
esp_err_to_name(err));
1045#ifdef SOC_WIFI_SUPPORT_5G
1049 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_STA_STOP) {
1050 ESP_LOGV(TAG,
"STA stop");
1051 s_sta_connecting =
false;
1053 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) {
1054 const auto &it =
data->data.sta_authmode_change;
1057 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_STA_CONNECTED) {
1058 const auto &it =
data->data.sta_connected;
1059#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
1060 char bssid_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1062 ESP_LOGV(TAG,
"Connected ssid='%.*s' bssid=" LOG_SECRET(
"%s")
" channel=%u, authmode=%s", it.ssid_len,
1065 s_sta_connected =
true;
1068 if (esp_err_t ll_err = esp_netif_create_ip6_linklocal(s_sta_netif); ll_err != ESP_OK) {
1069 ESP_LOGW(TAG,
"esp_netif_create_ip6_linklocal failed: %s",
esp_err_to_name(ll_err));
1075#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO
1076 char roam_bssid_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1078 ESP_LOGI(TAG,
"Roamed ssid='%.*s' bssid=" LOG_SECRET(
"%s")
" channel=%u", it.ssid_len, (
const char *) it.ssid,
1079 roam_bssid_s, it.channel);
1082 std::copy(it.bssid, it.bssid + 6, roam_bssid.begin());
1085#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
1088 this->
pending_.connect_state =
true;
1091#if defined(USE_WIFI_IP_STATE_LISTENERS) && (defined(USE_WIFI_MANUAL_IP) || defined(USE_WIFI_LEASE_CACHE))
1092 bool static_ip =
false;
1093#ifdef USE_WIFI_MANUAL_IP
1095 static_ip = config && config->get_manual_ip().has_value();
1097#ifdef USE_WIFI_LEASE_CACHE
1105 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_STA_DISCONNECTED) {
1106 const auto &it =
data->data.sta_disconnected;
1107 if (it.reason == WIFI_REASON_NO_AP_FOUND) {
1108 ESP_LOGW(TAG,
"Disconnected ssid='%.*s' reason='Probe Request Unsuccessful'", it.ssid_len,
1109 (
const char *) it.ssid);
1110 s_sta_connect_not_found =
true;
1111 }
else if (it.reason == WIFI_REASON_ROAMING) {
1112 ESP_LOGI(TAG,
"Disconnected ssid='%.*s' reason='Station Roaming'", it.ssid_len, (
const char *) it.ssid);
1115 char bssid_s[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1117 ESP_LOGW(TAG,
"Disconnected ssid='%.*s' bssid=" LOG_SECRET(
"%s")
" reason='%s'", it.ssid_len,
1119 s_sta_connect_error =
true;
1121 s_sta_connected =
false;
1122 s_sta_connecting =
false;
1126#ifdef USE_WIFI_CONNECT_STATE_LISTENERS
1130#if defined(USE_WIFI_AP_WISP) && !defined(USE_WIFI_AP_WISP_STATIC_DNS)
1131 }
else if (data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_ETH_GOT_IP) {
1134 }
else if (data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_STA_GOT_IP) {
1135 const auto &it =
data->data.ip_got_ip;
1136 ESP_LOGV(TAG,
"static_ip=" IPSTR
" gateway=" IPSTR, IP2STR(&it.ip_info.ip), IP2STR(&it.ip_info.gw));
1138#if defined(USE_WIFI_AP_WISP) && !defined(USE_WIFI_AP_WISP_STATIC_DNS)
1141#ifdef USE_WIFI_LEASE_CACHE
1144#ifdef USE_WIFI_IP_STATE_LISTENERS
1149 }
else if (data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_GOT_IP6) {
1150 const auto &it =
data->data.ip_got_ip6;
1151 ESP_LOGV(TAG,
"IPv6 address=" IPV6STR, IPV62STR(it.ip6_info.ip));
1153#ifdef USE_WIFI_IP_STATE_LISTENERS
1158 }
else if (data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_STA_LOST_IP) {
1159 ESP_LOGV(TAG,
"Lost IP");
1162 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_SCAN_DONE) {
1163 const auto &it =
data->data.sta_scan_done;
1164 ESP_LOGV(TAG,
"Scan done: status=%" PRIu32
" number=%u scan_id=%u", it.status, it.number, it.scan_id);
1166 uint16_t number = it.number;
1175 if (it.status != 0) {
1185 const size_t wanted = filtered ? std::min<size_t>(number, WIFI_SCAN_RESULT_BOUND) : number;
1188 if (this->
scan_result_.capacity() < wanted && !this->scan_result_.try_init(wanted)) {
1189 esp_wifi_clear_ap_list();
1190 ESP_LOGW(TAG,
"No memory for %zu scan results", wanted);
1194#ifdef USE_ESP32_HOSTED
1198 static constexpr size_t SCAN_RECORD_STACK_COUNT = 3904 /
sizeof(wifi_ap_record_t);
1199 SmallBufferWithHeapFallback<SCAN_RECORD_STACK_COUNT, wifi_ap_record_t> records(number);
1200 err = esp_wifi_scan_get_ap_records(&number, records.get());
1201 if (err != ESP_OK) {
1202 esp_wifi_clear_ap_list();
1203 ESP_LOGW(TAG,
"esp_wifi_scan_get_ap_records failed: %s",
esp_err_to_name(err));
1206 for (uint16_t i = 0; i < number; i++) {
1207 wifi_ap_record_t &record = records.get()[i];
1210 for (uint16_t i = 0; i < number; i++) {
1211 wifi_ap_record_t record;
1212 err = esp_wifi_scan_get_ap_record(&record);
1213 if (err != ESP_OK) {
1214 ESP_LOGW(TAG,
"esp_wifi_scan_get_ap_record failed: %s",
esp_err_to_name(err));
1215 esp_wifi_clear_ap_list();
1220 const char *ssid_cstr =
reinterpret_cast<const char *
>(record.ssid);
1226 std::copy(record.bssid, record.bssid + 6, bssid.begin());
1228 this->
scan_result_.emplace_back(bssid, ssid_cstr, strlen(ssid_cstr), record.primary, record.rssi,
1229 record.authmode != WIFI_AUTH_OPEN, ssid_cstr[0] ==
'\0');
1237 if (res.get_rssi() < weakest->get_rssi())
1240 if (record.rssi <= weakest->get_rssi()) {
1245 weakest->~WiFiScanResult();
1246 new (weakest) WiFiScanResult(bssid, ssid_cstr, strlen(ssid_cstr), record.primary, record.rssi,
1247 record.authmode != WIFI_AUTH_OPEN, ssid_cstr[0] ==
'\0');
1250 ESP_LOGV(TAG,
"Scan complete: %u found, %zu stored%s", number, this->scan_result_.size(),
1251 filtered ? LOG_STR_LITERAL(
" (driver filtered)") : LOG_STR_LITERAL(
""));
1252#ifdef USE_WIFI_SCAN_RESULTS_LISTENERS
1256 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_AP_START) {
1257 ESP_LOGV(TAG,
"AP start");
1259#ifdef USE_WIFI_AP_WISP
1262 if (esp_err_t err = esp_netif_napt_enable(s_ap_netif); err != ESP_OK) {
1268 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_AP_STOP) {
1269 ESP_LOGV(TAG,
"AP stop");
1272 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
1273#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
1274 const auto &it =
data->data.ap_probe_req_rx;
1275 char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1277 ESP_LOGVV(TAG,
"AP receive Probe Request MAC=%s RSSI=%d", mac_buf, it.rssi);
1280 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_AP_STACONNECTED) {
1284#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
1285 const auto &it =
data->data.ap_staconnected;
1286 char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1288 ESP_LOGV(TAG,
"AP client connected MAC=%s", mac_buf);
1291 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_AP_STADISCONNECTED) {
1295#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
1296 const auto &it =
data->data.ap_stadisconnected;
1297 char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
1299 ESP_LOGV(TAG,
"AP client disconnected MAC=%s", mac_buf);
1303 }
else if (
data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_DPP_URI_READY) {
1304 ESP_LOGD(TAG,
"DPP URI: %s", this->
dpp_uri_.get());
1305#ifdef USE_WIFI_DPP_URI_TRIGGER
1309 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_DPP_CFG_RECVD) {
1310 const std::unique_ptr<SavedWifiSettings> credentials(
data->data.dpp_credentials);
1312 ESP_LOGI(TAG,
"DPP configured network " LOG_SECRET(
"'%s'"), credentials->ssid);
1316 this->
save_wifi_sta(credentials->ssid, credentials->password);
1322 }
else if (data->event_base == WIFI_EVENT &&
data->event_id == WIFI_EVENT_DPP_FAILED) {
1327#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
1328 }
else if (
data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_ASSIGNED_IP_TO_CLIENT) {
1329 const auto &it =
data->data.ip_assigned_ip_to_client;
1331 }
else if (
data->event_base == IP_EVENT &&
data->event_id == IP_EVENT_AP_STAIPASSIGNED) {
1332 const auto &it =
data->data.ip_ap_staipassigned;
1334 ESP_LOGV(TAG,
"AP client assigned IP " IPSTR, IP2STR(&it.ip));
1340#if USE_NETWORK_IPV6 && (USE_NETWORK_MIN_IPV6_ADDR_COUNT > 0)
1348 if (s_sta_connect_error) {
1351 if (s_sta_connect_not_found) {
1354 if (s_sta_connecting) {
1364 wifi_scan_config_t config{};
1365 config.ssid =
nullptr;
1366 config.bssid =
nullptr;
1367#ifndef USE_WIFI_MULTI_SSID
1374 config.ssid =
const_cast<uint8_t *
>(
reinterpret_cast<const uint8_t *
>(this->
sta_[0].get_ssid().c_str()));
1378 config.show_hidden =
true;
1379 config.scan_type = passive ? WIFI_SCAN_TYPE_PASSIVE : WIFI_SCAN_TYPE_ACTIVE;
1381 config.scan_time.passive = 300;
1383 config.scan_time.active.min = 100;
1384 config.scan_time.active.max = 300;
1388#ifdef CONFIG_SOC_WIFI_SUPPORTED
1390 config.coex_background_scan =
true;
1394 esp_err_t err = esp_wifi_scan_start(&config,
false);
1395 if (err != ESP_OK) {
1396 ESP_LOGV(TAG,
"esp_wifi_scan_start failed: %s",
esp_err_to_name(err));
1409 if (s_ap_netif ==
nullptr) {
1410 ESP_LOGW(TAG,
"AP interface not initialized");
1414 esp_netif_ip_info_t info;
1415 if (manual_ip.has_value()) {
1416 info.ip = manual_ip->static_ip;
1417 info.gw = manual_ip->gateway;
1418 info.netmask = manual_ip->subnet;
1420 info.ip = network::IPAddress(192, 168, 4, 1);
1421 info.gw = network::IPAddress(192, 168, 4, 1);
1422 info.netmask = network::IPAddress(255, 255, 255, 0);
1425 err = esp_netif_dhcps_stop(s_ap_netif);
1426 if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
1427 ESP_LOGE(TAG,
"esp_netif_dhcps_stop failed: %s",
esp_err_to_name(err));
1431 err = esp_netif_set_ip_info(s_ap_netif, &info);
1432 if (err != ESP_OK) {
1433 ESP_LOGE(TAG,
"esp_netif_set_ip_info failed: %d", err);
1437 dhcps_lease_t lease;
1438 lease.enable =
true;
1439 network::IPAddress start_address = network::IPAddress(&info.ip);
1440 start_address += 99;
1441 lease.start_ip = start_address;
1442#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
1443 char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
1445 ESP_LOGV(TAG,
"DHCP server IP lease start: %s", start_address.str_to(ip_buf));
1446 start_address += 10;
1447 lease.end_ip = start_address;
1448 ESP_LOGV(TAG,
"DHCP server IP lease end: %s", start_address.str_to(ip_buf));
1449 err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease,
sizeof(lease));
1451 if (err != ESP_OK) {
1452 ESP_LOGE(TAG,
"esp_netif_dhcps_option failed: %d", err);
1456#if (defined(USE_CAPTIVE_PORTAL) || defined(USE_WEBSERVER_CAPTIVE)) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
1459 static char captive_portal_uri[24];
1460 memcpy(captive_portal_uri,
"http://", 7);
1461 network::IPAddress(&info.ip).str_to(captive_portal_uri + 7);
1462 err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captive_portal_uri,
1463 strlen(captive_portal_uri));
1464 if (err != ESP_OK) {
1465 ESP_LOGV(TAG,
"Failed to set DHCP captive portal URI: %s",
esp_err_to_name(err));
1467 ESP_LOGV(TAG,
"DHCP Captive Portal URI set to: %s", captive_portal_uri);
1471#ifdef USE_WIFI_AP_WISP
1474 uint8_t dns_offer = 1;
1476 esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dns_offer,
sizeof(dns_offer));
1477 if (err != ESP_OK) {
1478 ESP_LOGE(TAG,
"Failed to enable DHCP DNS option: %s",
esp_err_to_name(err));
1484 err = esp_netif_dhcps_start(s_ap_netif);
1486 if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_IF_NOT_READY) {
1487 ESP_LOGE(TAG,
"esp_netif_dhcps_start failed: %d", err);
1497#ifdef USE_WIFI_MANUAL_IP
1502 ESP_LOGE(TAG,
"wifi_ap_ip_config_ failed:");
1511 memset(&conf, 0,
sizeof(conf));
1512 if (ap.ssid_.size() >
sizeof(conf.ap.ssid)) {
1513 ESP_LOGE(TAG,
"AP SSID too long");
1516 memcpy(
reinterpret_cast<char *
>(conf.ap.ssid), ap.ssid_.c_str(), ap.ssid_.size());
1517 conf.ap.channel = ap.has_channel() ? ap.get_channel() : 1;
1518 conf.ap.ssid_hidden = ap.get_hidden();
1519 conf.ap.max_connection = 5;
1520 conf.ap.beacon_interval = 100;
1522 if (ap.password_.empty()) {
1523 conf.ap.authmode = WIFI_AUTH_OPEN;
1524 *conf.ap.password = 0;
1526 conf.ap.authmode = WIFI_AUTH_WPA2_PSK;
1527 if (ap.password_.size() >
sizeof(conf.ap.password)) {
1528 ESP_LOGE(TAG,
"AP password too long");
1531 memcpy(
reinterpret_cast<char *
>(conf.ap.password), ap.password_.c_str(), ap.password_.size());
1535 conf.ap.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP;
1537 esp_err_t err = esp_wifi_set_config(WIFI_IF_AP, &conf);
1538 if (err != ESP_OK) {
1539 ESP_LOGE(TAG,
"esp_wifi_set_config failed: %d", err);
1546 esp_netif_ip_info_t ip;
1547 esp_netif_get_ip_info(s_ap_netif, &ip);
1548 return network::IPAddress(&ip.ip);
1554 esp_err_t err = esp_supp_dpp_start_listen();
1555 if (err != ESP_OK) {
1556 ESP_LOGW(TAG,
"%s failed: %s", LOG_STR_LITERAL(
"esp_supp_dpp_start_listen"),
esp_err_to_name(err));
1559 ESP_LOGD(TAG,
"DPP listening for a configurator");
1570 wifi_ap_record_t info;
1571 esp_err_t err = esp_wifi_sta_get_ap_info(&info);
1572 if (err != ESP_OK) {
1574 ESP_LOGVV(TAG,
"esp_wifi_sta_get_ap_info failed: %s",
esp_err_to_name(err));
1577 std::copy(info.bssid, info.bssid + 6, bssid.begin());
1581 wifi_ap_record_t info{};
1582 esp_err_t err = esp_wifi_sta_get_ap_info(&info);
1583 if (err != ESP_OK) {
1588 size_t len = strnlen(
reinterpret_cast<const char *
>(info.ssid), 32);
1594 wifi_ap_record_t info;
1595 esp_err_t err = esp_wifi_sta_get_ap_info(&info);
1596 if (err != ESP_OK) {
1598 ESP_LOGVV(TAG,
"esp_wifi_sta_get_ap_info failed: %s",
esp_err_to_name(err));
1599 return WIFI_RSSI_DISCONNECTED;
1605 wifi_second_chan_t
second;
1607 if (err != ESP_OK) {
1608 ESP_LOGW(TAG,
"esp_wifi_get_channel failed: %s",
esp_err_to_name(err));
1614 esp_netif_ip_info_t ip;
1615 esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip);
1616 if (err != ESP_OK) {
1617 ESP_LOGW(TAG,
"esp_netif_get_ip_info failed: %s",
esp_err_to_name(err));
1620 return network::IPAddress(&ip.netmask);
1623 esp_netif_ip_info_t ip;
1624 esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip);
1625 if (err != ESP_OK) {
1626 ESP_LOGW(TAG,
"esp_netif_get_ip_info failed: %s",
esp_err_to_name(err));
1629 return network::IPAddress(&ip.gw);
1632 const ip_addr_t *dns_ip = dns_getserver(num);
1633 return network::IPAddress(dns_ip);
1636#ifdef USE_WIFI_AP_WISP
1638#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
1639static constexpr size_t AP_DNS_COUNT = 2;
1641static constexpr size_t AP_DNS_COUNT = 1;
1643#ifdef USE_WIFI_AP_WISP_STATIC_DNS
1645static constexpr uint32_t AP_DNS[] = {
1647#ifdef WIFI_AP_WISP_DNS_1
1653static uint32_t ap_dns_to_offer(
size_t i) {
1654#ifdef USE_WIFI_AP_WISP_STATIC_DNS
1655 return i < std::size(AP_DNS) ? AP_DNS[i] : 0;
1657 return ip_addr_get_ip4_u32(dns_getserver(i));
1665 for (
size_t i = 0; i < AP_DNS_COUNT; i++) {
1666 const uint32_t addr = ap_dns_to_offer(i);
1669 esp_netif_dns_info_t info{};
1670 info.ip.type = ESP_IPADDR_TYPE_V4;
1671 info.ip.u_addr.ip4.addr = addr;
1672 esp_err_t err = esp_netif_set_dns_info(s_ap_netif,
static_cast<esp_netif_dns_type_t
>(i), &info);
1673 if (err != ESP_OK) {
1674 ESP_LOGW(TAG,
"Failed to set DHCP DNS server %u: %s", (
unsigned) i,
esp_err_to_name(err));
1677 ESP_LOGV(TAG,
"DHCP DNS server: " IPSTR, IP2STR(&info.ip.u_addr.ip4));
1683#ifndef USE_WIFI_AP_WISP_STATIC_DNS
1689 bool changed =
false;
1690 for (
size_t i = 0; i < AP_DNS_COUNT && !changed; i++) {
1691 const uint32_t addr = ap_dns_to_offer(i);
1692 esp_netif_dns_info_t current{};
1694 addr != 0 && (esp_netif_get_dns_info(s_ap_netif,
static_cast<esp_netif_dns_type_t
>(i), ¤t) != ESP_OK ||
1695 current.ip.u_addr.ip4.addr != addr);
1700#ifdef USE_WIFI_MANUAL_IP
BedjetMode mode
BedJet operating mode.
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
bool cancel_timeout(const char *name)
Cancel a timeout function.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
uint16_t get_and_reset_dropped_count()
constexpr const char * c_str() const
const optional< ManualIP > & get_manual_ip() const
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 error_from_callback_
bool wifi_apply_power_save_()
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)
WiFiPowerSaveMode power_save_
const WiFiAP * get_selected_sta_() const
WiFiSTAConnectStatus wifi_sta_connect_status_() const
void set_last_connected_(uint32_t now)
friend class ScanResultsLock
void save_wifi_sta(const std::string &ssid, const std::string &password)
bool wifi_dpp_start_listen_()
SavedWifiLeaseSettings cached_lease_
WiFiComponentState state_
wifi_scan_vector_t< WiFiScanResult > scan_result_
bool wifi_apply_band_mode_()
void notify_ip_state_listeners_()
Notify IP state listeners with current addresses.
bool is_scan_driver_filtered_() const
bool applied_cached_lease_
void start_connecting(const WiFiAP &ap)
ESPPreferenceObject lease_cache_pref_
bool wifi_sta_ip_config_(const optional< ManualIP > &manual_ip)
esp_netif_t * get_esp_netif_sta()
esp_netif handle of the station interface, used by network for default-route arbitration.
bool ap_dns_known_()
Whether there is an IPv4 resolver to offer AP clients: a configured one, or the station's.
void apply_ap_dns_()
Pass the station's resolvers on to AP clients when they changed.
wifi_band_mode_t band_mode_
void wifi_dpp_stop_listen_()
void wifi_process_event_(IDFWiFiEvent *data)
bool lease_valid_for_apply_() const
int8_t selected_sta_index_
void notify_disconnect_state_listeners_()
Notify connect state listeners of disconnection.
friend void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
bool wifi_start_ap_(const WiFiAP &ap)
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)
int32_t get_wifi_channel()
const char * wifi_ssid_to(std::span< char, SSID_BUFFER_SIZE > buffer)
Write SSID to buffer without heap allocation.
network::IPAddress wifi_subnet_mask_()
void save_lease_settings_()
network::IPAddress wifi_soft_ap_ip()
CallbackManager< void(const char *)> dpp_uri_callback_
network::IPAddress wifi_gateway_ip_()
bool is_roaming_scan_active() const
True while a post-connect roaming scan holds the radio off-channel.
bool scan_driver_filtered_
network::IPAddress wifi_dns_ip_(int num)
bool wifi_apply_hostname_()
bool wifi_sta_pre_setup_()
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_
const char * dpp_device_info_
FixedVector< WiFiAP > sta_
const char * dpp_channels_
bool wifi_ap_ip_config_(const optional< ManualIP > &manual_ip)
void update_connected_state_()
uint32_t lease_cache_max_age_
bool needs_full_scan_results_() const
Check if full scan results are needed (captive portal active, improv, listeners)
LockFreeQueue< IDFWiFiEvent, 17 > event_queue_
StaticVector< WiFiPowerSaveListener *, ESPHOME_WIFI_POWER_SAVE_LISTENERS > power_save_listeners_
WifiMinAuthMode min_auth_mode_
bool wifi_apply_output_power_(float output_power)
bool wifi_sta_connect_(const WiFiAP &ap)
bool wifi_mode_(optional< bool > sta, optional< bool > ap)
network::IPAddresses wifi_sta_ip_addresses()
uint8_t num_ipv6_addresses_
std::unique_ptr< char[]> dpp_uri_
void renew_cached_lease_()
bool wifi_scan_start_(bool passive)
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.
const char * esp_err_to_name(esp_err_t err)
std::span< const uint8_t > data
std::array< IPAddress, 5 > IPAddresses
void fill_ip6_addresses(esp_netif_t *netif, IPAddresses &addresses)
Copies the IPv6 addresses of an esp_netif into addresses[1..], warning once when some do not fit.
std::array< uint8_t, 6 > bssid_t
const LogString * get_auth_mode_str(uint8_t mode)
ESPHOME_LOG_TAG(TAG, "wifi")
const LogString * get_disconnect_reason_str(uint8_t reason)
@ WIFI_MIN_AUTH_MODE_WPA2
@ WIFI_MIN_AUTH_MODE_WPA3
@ ERROR_NETWORK_NOT_FOUND
WiFiComponent * global_wifi_component
@ WIFI_COMPONENT_STATE_AP
WiFi is in AP-only mode and internal AP is already enabled.
@ WIFI_COMPONENT_STATE_OFF
Nothing has been initialized yet.
@ WIFI_COMPONENT_STATE_STA_CONNECTED
WiFi is in STA(+AP) mode and successfully connected.
ESPPreferences * global_preferences
Application App
Global storage of Application pointer - only one Application can exist.
char * format_mac_addr_upper(const uint8_t *mac, char *output)
Format MAC address as XX:XX:XX:XX:XX:XX (uppercase, colon separators)
struct esp_netif_obj esp_netif_t