Files
squeezelite-esp32/components/wifi-manager/network_wifi.cpp
2025-03-18 17:38:34 -04:00

806 lines
31 KiB
C++

#ifdef NETWORK_WIFI_LOG_LEVEL
#define LOG_LOCAL_LEVEL NETWORK_WIFI_LOG_LEVEL
#endif
#include "network_wifi.h"
#include "Config.h"
#include "WifiList.h"
#include "accessors.h"
#include "bootstate.h"
#include "cJSON.h"
#include "dns_server.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "lwip/sockets.h"
#include "messaging.h"
#include "network_status.h"
#include "platform_esp32.h"
#include "tools.h"
#include "trace.h"
#include <string.h>
#include "esp_sntp.h"
WifiList* wifi_config_aps;
EXT_RAM_ATTR WifiList scan_results_aps("scan_results");
static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data);
static const char* get_disconnect_code_desc(uint8_t reason);
esp_err_t network_wifi_get_blob(void* target, size_t size, const char* key);
static const char TAG[] = "network_wifi";
esp_netif_t* wifi_netif;
esp_netif_t* wifi_ap_netif;
extern sys_status_data status;
static void time_sync_notification_cb(struct timeval *tv)
{
ESP_LOGI(TAG, "Notification of a time synchronization event");
wifi_config_aps->UpdateFromClock();
scan_results_aps.UpdateFromClock();
}
static bool is_initialized() { return (platform != NULL) && platform->has_net; }
// void network_wifi_update_connected() {
// wifi_config_t config;
// esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &config);
// if (err != ESP_OK) {
// ESP_LOGE(TAG, "Unable to update connected STA: %s", esp_err_to_name(err));
// return;
// }
// auto sta = wifi_config_aps->AddUpdate(&config.sta);
// ESP_LOGD(TAG, "Added/Updated STA %s to credentials list, password: %s", sta.ssid, sta.password);
// wifi_config_aps->PrintWifiSTAEntry(sta);
// if (sys_status_obj.Lock()) {
// sta.connected = true;
// auto status = sys_status_obj.get();
// status.has_net = true;
// status.net.has_wifi = true;
// memcpy(&status.net.wifi.connected_sta, &sta, sizeof(status.net.wifi.connected_sta));
// status.net.wifi.has_connected_sta = true;
// sys_status_obj.Unlock();
// }
// config_raise_changed(false);
// }
size_t network_wifi_get_known_count() {
size_t result = 0;
if (!is_initialized()) {
ESP_LOGE(TAG, "Config not initialized");
return 0;
}
result = wifi_config_aps->GetCount();
ESP_LOGD(TAG, "SSID Count from config: %d", result);
return result;
}
const wifi_sta_config_t* network_wifi_get_active_config() {
static wifi_config_t config;
esp_err_t err = ESP_OK;
memset(&config, 0x00, sizeof(config));
if ((err = esp_wifi_get_config(WIFI_IF_STA, &config)) == ESP_OK) {
return &config.sta;
} else {
ESP_LOGD(TAG, "Could not get wifi STA config: %s", esp_err_to_name(err));
}
return nullptr;
}
bool network_wifi_is_known_ap(const char* ssid) { return wifi_config_aps->Exists(ssid); }
esp_netif_t* network_wifi_get_interface() { return wifi_netif; }
esp_netif_t* network_wifi_get_ap_interface() { return wifi_ap_netif; }
esp_err_t network_wifi_set_sta_mode() {
if (!wifi_netif) {
ESP_LOGE(TAG, "Wifi not initialized. Cannot set sta mode");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGD(TAG, "Set Mode to STA");
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error setting mode to STA: %s", esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "Starting wifi");
err = esp_wifi_start();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error starting wifi: %s", esp_err_to_name(err));
}
}
ESP_LOGD(TAG,"Done setting wifi mode to STA");
return err;
}
esp_netif_t* network_wifi_start() {
esp_err_t err = ESP_OK;
if (!wifi_netif) {
wifi_netif = esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
err = esp_wifi_init(&cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error initializing wifi: %s", esp_err_to_name(err));
return wifi_netif;
}
// network_wifi_register_handlers();
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &network_wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_wifi_set_storage(WIFI_STORAGE_RAM));
}
network_wifi_set_sta_mode();
network_set_hostname(wifi_netif);
return wifi_netif;
}
void destroy_network_wifi() {}
bool network_wifi_sta_config_changed() { return wifi_config_aps->Update(network_wifi_get_active_config()); }
esp_err_t network_wifi_set_connected(bool connected) {
wifi_config_t config;
bool state_changed = false;
bool config_changed = false;
ESP_LOGD(TAG, "Resetting connected list");
if (wifi_config_aps->Lock()) {
wifi_config_aps->ResetConnected();
wifi_config_aps->Unlock();
}
ESP_LOGD(TAG, "Erasing connected sta object");
if (sys_status_obj.get()->net.wifi.has_connected_sta && sys_status_obj.Lock()) {
pb_release(&sys_net_wifi_entry_msg, &sys_status_obj.get()->net.wifi.connected_sta);
sys_status_obj.get()->net.has_wifi = true;
sys_status_obj.get()->has_net = true;
sys_status_obj.get()->net.wifi.has_connected_sta = false;
sys_status_obj.Unlock();
}
if (stateWrapper.get()->has_connected_sta && stateWrapper.Lock()) {
pb_release(&sys_net_wifi_entry_msg, stateWrapper.get());
stateWrapper.get()->has_connected_sta = false;
stateWrapper.Unlock();
state_changed = true;
}
esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error retrieving wifi config");
} else {
if (!connected) {
ESP_LOGI(TAG, "Connected list was reset");
} else {
ESP_LOGI(TAG, "Updating connected sta to %s", WifiList::GetSSID(&config.sta).c_str());
ESP_LOGD(TAG, "Locking credentials manager");
if (wifi_config_aps->Lock()) {
ESP_LOGD(TAG, "Adding/updating credentials");
wifi_config_aps->AddUpdate(&config.sta).connected = true;
ESP_LOGD(TAG, "Unlocking credentials manager");
config_changed = true;
wifi_config_aps->Unlock();
}
}
}
if (config_changed) {
ESP_LOGD(TAG, "Raising changed event on the config wrapper object");
configWrapper.RaiseChangedAsync();
}
if (state_changed) {
ESP_LOGD(TAG, "Raising changed event on the state wrapper object");
stateWrapper.RaiseChangedAsync();
}
return err;
}
static void network_wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base != WIFI_EVENT) return;
switch (event_id) {
case WIFI_EVENT_WIFI_READY:
ESP_LOGD(TAG, "WIFI_EVENT_WIFI_READY");
break;
case WIFI_EVENT_SCAN_DONE:
ESP_LOGD(TAG, "WIFI_EVENT_SCAN_DONE");
network_async_scan_done();
break;
case WIFI_EVENT_STA_AUTHMODE_CHANGE:
ESP_LOGD(TAG, "WIFI_EVENT_STA_AUTHMODE_CHANGE");
break;
case WIFI_EVENT_AP_START:
ESP_LOGD(TAG, "WIFI_EVENT_AP_START");
break;
case WIFI_EVENT_AP_STOP:
ESP_LOGD(TAG, "WIFI_EVENT_AP_STOP");
break;
case WIFI_EVENT_AP_PROBEREQRECVED: {
wifi_event_ap_probe_req_rx_t* s = (wifi_event_ap_probe_req_rx_t*)event_data;
char* mac = alloc_get_formatted_mac_string(s->mac);
if (mac) {
ESP_LOGD(TAG, "WIFI_EVENT_AP_PROBEREQRECVED. RSSI: %d, MAC: %s", s->rssi, STR_OR_BLANK(mac));
}
FREE_AND_NULL(mac);
} break;
case WIFI_EVENT_STA_WPS_ER_SUCCESS:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
break;
case WIFI_EVENT_STA_WPS_ER_FAILED:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");
break;
case WIFI_EVENT_STA_WPS_ER_TIMEOUT:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT");
break;
case WIFI_EVENT_STA_WPS_ER_PIN:
ESP_LOGD(TAG, "WIFI_EVENT_STA_WPS_ER_PIN");
break;
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t* stac = (wifi_event_ap_staconnected_t*)event_data;
char* mac = alloc_get_formatted_mac_string(stac->mac);
if (mac) {
ESP_LOGD(TAG, "WIFI_EVENT_AP_STACONNECTED. aid: %d, mac: %s", stac->aid, STR_OR_BLANK(mac));
}
FREE_AND_NULL(mac);
} break;
case WIFI_EVENT_AP_STADISCONNECTED:
ESP_LOGD(TAG, "WIFI_EVENT_AP_STADISCONNECTED");
break;
case WIFI_EVENT_STA_START:
ESP_LOGD(TAG, "WIFI_EVENT_STA_START");
break;
case WIFI_EVENT_STA_STOP:
ESP_LOGD(TAG, "WIFI_EVENT_STA_STOP");
break;
case WIFI_EVENT_STA_CONNECTED: {
ESP_LOGD(TAG, "WIFI_EVENT_STA_CONNECTED. ");
network_async(EN_CONNECTED);
} break;
case WIFI_EVENT_STA_DISCONNECTED: {
if (is_restarting()) {
ESP_LOGD(TAG, "Disconnect event ignored while restarting");
return;
}
wifi_event_sta_disconnected_t* s = (wifi_event_sta_disconnected_t*)event_data;
char* bssid = alloc_get_formatted_mac_string(s->bssid);
ESP_LOGW(TAG, "WIFI_EVENT_STA_DISCONNECTED. From BSSID: %s, reason code: %d (%s)", STR_OR_BLANK(bssid), s->reason,
get_disconnect_code_desc(s->reason));
FREE_AND_NULL(bssid);
if (s->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "WiFi Roaming to new access point");
} else {
network_async_lost_connection((wifi_event_sta_disconnected_t*)event_data);
network_wifi_set_connected(false);
}
} break;
default:
break;
}
}
void network_wifi_global_init() {
ESP_LOGD(TAG, "running network_wifi_global_init");
assert(platform != nullptr);
wifi_config_aps = reinterpret_cast<WifiList*>(platform->net.credentials);
assert(wifi_config_aps != nullptr);
sys_status_obj.get()->has_net = true;
sys_status_obj.get()->net.has_wifi = true;
sys_status_obj.get()->net.wifi.scan_result = reinterpret_cast<sys_net_wifi_entry*>(&scan_results_aps);
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
}
esp_netif_t* network_wifi_config_ap() {
esp_netif_ip_info_t info;
esp_err_t err = ESP_OK;
wifi_config_t ap_config;
memset(&ap_config, 0x00, sizeof(ap_config));
ESP_LOGI(TAG, "Configuring Access Point.");
if (!wifi_ap_netif) {
wifi_ap_netif = esp_netif_create_default_wifi_ap();
}
if (!is_initialized()) {
ESP_LOGE(TAG, "Config not initialized");
return wifi_ap_netif;
}
if (platform->has_net && platform->net.has_ap && platform->net.ap.has_ip) {
inet_pton(AF_INET, platform->net.ap.ip.ip, (ip4_addr_t*)&info.ip); /* access point is on a static IP */
inet_pton(AF_INET, platform->net.ap.ip.gw, (ip4_addr_t*)&info.gw); /* access point is on a static IP */
inet_pton(AF_INET, platform->net.ap.ip.netmask, (ip4_addr_t*)&info.netmask); /* access point is on a static IP */
} else {
ESP_LOGE(TAG, "Access point not configured. Bailing out");
return nullptr;
}
ap_config.ap.max_connection = platform->net.ap.max_connection > 0 ? platform->net.ap.max_connection : 4;
ap_config.ap.beacon_interval = platform->net.ap.beacon_interval > 0 ? platform->net.ap.beacon_interval : 100;
ap_config.ap.ssid_hidden = platform->net.ap.hidden;
ap_config.ap.authmode = WifiList::GetESPAuthMode(platform->net.ap.auth_mode);
ap_config.ap.channel = platform->net.ap.channel;
/* In order to change the IP info structure, we have to first stop
* the DHCP server on the new interface
*/
network_start_stop_dhcps(wifi_ap_netif, false);
ESP_LOGD(TAG, "Setting tcp_ip info for access point");
if ((err = esp_netif_set_ip_info(wifi_ap_netif, &info)) != ESP_OK) {
ESP_LOGE(TAG, "Setting tcp_ip info for interface TCPIP_ADAPTER_IF_AP. Error %s", esp_err_to_name(err));
return wifi_ap_netif;
}
network_start_stop_dhcps(wifi_ap_netif, true);
strlcpy((char*)ap_config.ap.ssid, platform->names.wifi_ap_name, sizeof(ap_config.ap.ssid));
strlcpy((char*)ap_config.ap.password, STR_OR_BLANK(platform->net.ap.password), sizeof(ap_config.ap.password));
ESP_LOGI(TAG, "AP SSID: %s, PASSWORD: %s Auth Mode: %d SSID: %s Max Connections: %d Beacon interval: %d", (char*)ap_config.ap.ssid,
(char*)ap_config.ap.password, ap_config.ap.authmode, ap_config.ap.ssid_hidden ? "HIDDEN" : "VISIBLE", ap_config.ap.max_connection,
ap_config.ap.beacon_interval);
const char* msg = "Setting wifi mode as WIFI_MODE_APSTA";
ESP_LOGD(TAG, "%s", msg);
if ((err = esp_wifi_set_mode(WIFI_MODE_APSTA)) != ESP_OK) {
ESP_LOGE(TAG, "%s. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi AP configuration for WIFI_IF_AP";
ESP_LOGD(TAG, "%s", msg);
if ((err = esp_wifi_set_config(WIFI_IF_AP, &ap_config)) != ESP_OK) /* stop AP DHCP server */
{
ESP_LOGE(TAG, "%s . Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi bandwidth";
ESP_LOGD(TAG, "%s (%d)", msg, DEFAULT_AP_BANDWIDTH);
if ((err = esp_wifi_set_bandwidth(WIFI_IF_AP, DEFAULT_AP_BANDWIDTH)) != ESP_OK) /* stop AP
DHCP server */
{
ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
msg = "Setting wifi power save";
ESP_LOGD(TAG, "%s (%s)", msg, sys_net_config_ps_types_name(platform->net.power_save_mode));
if ((err = esp_wifi_set_ps((wifi_ps_type_t)platform->net.power_save_mode)) != ESP_OK) /* stop AP DHCP server */
{
ESP_LOGE(TAG, "%s failed. Error %s", msg, esp_err_to_name(err));
return wifi_ap_netif;
}
ESP_LOGD(TAG, "Done configuring Soft Access Point");
return wifi_ap_netif;
}
void network_wifi_filter_unique(wifi_ap_record_t* aplist, uint16_t* aps) {
int total_unique;
wifi_ap_record_t* first_free;
total_unique = *aps;
first_free = NULL;
for (int i = 0; i < *aps - 1; i++) {
wifi_ap_record_t* ap = &aplist[i];
/* skip the previously removed APs */
if (ap->ssid[0] == 0) continue;
/* remove the identical SSID+authmodes */
for (int j = i + 1; j < *aps; j++) {
wifi_ap_record_t* ap1 = &aplist[j];
if ((strcmp((const char*)ap->ssid, (const char*)ap1->ssid) == 0) &&
(ap->authmode == ap1->authmode)) { /* same SSID, different auth mode is skipped */
/* save the rssi for the display */
if ((ap1->rssi) > (ap->rssi)) ap->rssi = ap1->rssi;
/* clearing the record */
memset(ap1, 0, sizeof(wifi_ap_record_t));
}
}
}
/* reorder the list so APs follow each other in the list */
for (int i = 0; i < *aps; i++) {
wifi_ap_record_t* ap = &aplist[i];
/* skipping all that has no name */
if (ap->ssid[0] == 0) {
/* mark the first free slot */
if (first_free == NULL) first_free = ap;
total_unique--;
continue;
}
if (first_free != NULL) {
memcpy(first_free, ap, sizeof(wifi_ap_record_t));
memset(ap, 0, sizeof(wifi_ap_record_t));
/* find the next free slot */
for (int j = 0; j < *aps; j++) {
if (aplist[j].ssid[0] == 0) {
first_free = &aplist[j];
break;
}
}
}
}
/* update the length of the list */
*aps = total_unique;
}
bool network_wifi_update_scan_list(wifi_ap_record_t* accessp_records, uint16_t count) {
bool changed = false;
// reset RSSI values. This will help when choosing the
// strongest signal to connect to
wifi_config_aps->ResetRSSI();
// clear current access point list
scan_results_aps.Clear();
if (count > 0) {
WifiList::PrintWifiSTAEntryTitle();
ESP_LOGD(TAG, "Found %d AP(s) during scan:",count);
for (int i = 0; i < count; i++) {
auto& entry = scan_results_aps.AddUpdate(&accessp_records[i]);
scan_results_aps.UpdateLastSeen(&accessp_records[i]);
if (wifi_config_aps->Exists(&accessp_records[i]) && configWrapper.Lock()) {
ESP_LOGD(TAG,"AP with known password. updating last seen");
changed = wifi_config_aps->Update(&accessp_records[i]) || changed;
changed = wifi_config_aps->UpdateLastSeen(&accessp_records[i]) || changed;
configWrapper.Unlock();
}
ESP_LOGV(TAG,"Address of entry is %p", static_cast<void*>(&entry));
if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
WifiList::PrintWifiSTAEntry(entry);
}
}
} else {
ESP_LOGI(TAG, "No nearby access point found");
}
if (changed) {
config_raise_changed(false);
}
return true;
}
esp_err_t wifi_scan_done() {
esp_err_t err = ESP_OK;
wifi_ap_record_t* accessp_records = NULL;
ESP_LOGD(TAG, "Getting AP list records");
uint16_t ap_num = platform->net.max_ap_num;
if ((err = esp_wifi_scan_get_ap_num(&ap_num)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to retrieve scan results count. Error %s", esp_err_to_name(err));
return err;
}
if (ap_num <= 0) {
ESP_LOGI(TAG, "No AP found during scan");
return err;
}
accessp_records = (wifi_ap_record_t*)malloc_init_external(sizeof(wifi_ap_record_t) * ap_num);
if (!accessp_records) {
ESP_LOGE(TAG, "Alloc failed for scan results");
return ESP_FAIL;
}
if ((err = esp_wifi_scan_get_ap_records(&ap_num, accessp_records)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to retrieve scan results list. Error %s", esp_err_to_name(err));
} else {
/* make sure the http server isn't trying to access the list while it gets refreshed */
ESP_LOGD(TAG, "Retrieving scan list");
/* Will remove the duplicate SSIDs from the list and update ap_num */
network_wifi_filter_unique(accessp_records, &ap_num);
if (!network_wifi_update_scan_list(accessp_records, ap_num)) {
ESP_LOGE(TAG, "could not get access to json mutex in wifi_scan");
err = ESP_FAIL;
}
ESP_LOGD(TAG, "Done retrieving scan list");
}
free(accessp_records);
return err;
}
bool is_wifi_up() { return wifi_netif != NULL; }
esp_err_t network_wifi_start_scan() {
wifi_scan_config_t scan_config = {.ssid = 0, .bssid = 0, .channel = 0, .show_hidden = true, .scan_type = WIFI_SCAN_TYPE_ACTIVE};
esp_err_t err = ESP_OK;
ESP_LOGI(TAG, "Initiating wifi network scan");
if (!is_wifi_up()) {
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot scan");
return ESP_FAIL;
}
/* if a scan is already in progress this message is simply ignored thanks to the
* WIFI_MANAGER_SCAN_BIT uxBit */
if ((err = esp_wifi_scan_start(&scan_config, false)) != ESP_OK) {
ESP_LOGW(TAG, "Unable to start scan; %s ", esp_err_to_name(err));
// set_status_message(WARNING, "Wifi Connecting. Cannot start scan.");
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Scanning failed: %s", esp_err_to_name(err));
}
return err;
}
bool network_wifi_is_ap_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_AP;
}
bool network_wifi_is_sta_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_STA;
}
bool network_wifi_is_ap_sta_mode() {
wifi_mode_t mode;
/* update config to latest and attempt connection */
return esp_wifi_get_mode(&mode) == ESP_OK && mode == WIFI_MODE_APSTA;
}
esp_err_t network_wifi_connect(const char* ssid, const char* password) {
esp_err_t err = ESP_OK;
wifi_config_t config;
bool changed = false;
memset(&config, 0x00, sizeof(config));
ESP_LOGD(TAG, "network_wifi_connect");
network_wifi_set_connected(false);
if (!is_wifi_up()) {
messaging_post_message(MESSAGING_WARNING, MESSAGING_CLASS_SYSTEM, "Wifi not started. Cannot connect");
return ESP_FAIL;
}
if (!ssid || !password || strlen(ssid) == 0) {
ESP_LOGE(TAG, "Cannot connect wifi. wifi config is null!");
return ESP_ERR_INVALID_ARG;
}
wifi_mode_t wifi_mode;
err = esp_wifi_get_mode(&wifi_mode);
if (err == ESP_ERR_WIFI_NOT_INIT) {
ESP_LOGW(TAG, "Wifi not initialized. Attempting to start sta mode");
network_wifi_start();
} else if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not retrieve wifi mode : %s", esp_err_to_name(err));
} else if (wifi_mode != WIFI_MODE_STA && wifi_mode != WIFI_MODE_APSTA) {
ESP_LOGD(TAG, "Changing wifi mode to STA");
err = network_wifi_set_sta_mode();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Could not set mode to STA. Cannot connect to SSID %s", ssid);
return err;
}
}
// copy configuration and connect
strlcpy((char*)config.sta.ssid, ssid, sizeof(config.sta.ssid));
if (password) {
strlcpy((char*)config.sta.password, password, sizeof(config.sta.password));
}
config.sta.scan_method = platform->net.wifi_connect_fast_scan ? WIFI_FAST_SCAN : WIFI_ALL_CHANNEL_SCAN;
auto existing = wifi_config_aps->Get(&config.sta);
if (existing != nullptr) {
if (existing->channel > 0 && existing->channel <= 13) {
ESP_LOGD(TAG, "Trying to connect on channel %d", existing->channel);
config.sta.channel = existing->channel;
} else {
ESP_LOGD(TAG, "Access point known, but no channel defined. Scanning");
}
}
// First Disconnect
esp_wifi_disconnect();
config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
if ((err = esp_wifi_set_config(WIFI_IF_STA, &config)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set STA configuration. Error %s", esp_err_to_name(err));
}
if (err == ESP_OK) {
ESP_LOGI(TAG, "Wifi Connecting to %s...", ssid);
if ((err = esp_wifi_connect()) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initiate wifi connection. Error %s", esp_err_to_name(err));
} else {
if (wifi_config_aps->Lock()) {
ESP_LOGD(TAG, "Storing/updating credentials entry");
if (wifi_config_aps->Exists(&config.sta)) {
ESP_LOGD(TAG, "Existing entry. Updating it");
changed = wifi_config_aps->Update(&config.sta);
} else {
ESP_LOGD(TAG, "New entry. Adding it");
wifi_config_aps->AddUpdate(&config.sta);
}
auto entry = wifi_config_aps->Get(&config.sta);
if (entry != nullptr) {
wifi_config_aps->UpdateLastTry(&config.sta);
WifiList::PrintWifiSTAEntryTitle();
WifiList::PrintWifiSTAEntry(*entry);
}
wifi_config_aps->Unlock();
}
if (changed) {
configWrapper.RaiseChangedAsync();
}
}
}
return err;
}
esp_err_t network_wifi_connect_ssid(const char* ssid) {
sys_net_wifi_entry* item = wifi_config_aps->Get(std::string(ssid));
if (item != nullptr) {
return network_wifi_connect(item->ssid, item->password);
} else {
ESP_LOGE(TAG, "Attempting to connect to an unknown ssid: %s", ssid);
}
return ESP_FAIL;
}
esp_err_t network_wifi_connect_active_ssid() {
sys_net_wifi_entry* connected = NULL;
if (sys_state->has_connected_sta && strlen(sys_state->connected_sta.ssid) > 0) {
connected = &sys_state->connected_sta;
if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) {
ESP_LOGI(TAG, "Connecting to active access point");
WifiList::PrintWifiSTAEntryTitle();
WifiList::PrintWifiSTAEntry(sys_state->connected_sta);
}
return network_wifi_connect(connected->ssid, connected->password);
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t network_wifi_add_ssid(const char* ssid, const char* password) {
bool changed = false;
auto conn = wifi_config_aps->Get(ssid);
if (conn != nullptr) {
ESP_LOGW(TAG, "Existing ssid %s. Updating password", ssid);
if (strcmp(conn->password, password) != 0) {
strncpy(conn->password, password, sizeof(conn->password));
changed = true;
} else {
ESP_LOGI(TAG, "No change to ssid %s", password);
}
} else {
ESP_LOGI(TAG, "Adding new ssid %s with password %s to credentials", ssid, STR_OR_BLANK(password));
auto seen = scan_results_aps.Get(ssid);
if (seen) {
ESP_LOGD(TAG,"Adding with extra info from scan");
wifi_config_aps->AddUpdate(seen, STR_OR_BLANK(password));
changed = true;
} else {
ESP_LOGD(TAG,"Adding without extra info from scan");
wifi_config_aps->AddUpdate(ssid, STR_OR_BLANK(password));
changed = true;
}
}
if (changed) {
config_raise_changed(false);
}
return ESP_OK;
}
esp_err_t network_wifi_remove_ssid(const char* ssid) {
wifi_config_t config;
esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error retrieving wifi config");
}
if ((network_wifi_is_sta_mode() || network_wifi_is_ap_sta_mode()) && WifiList::GetSSID(&config.sta) == ssid) {
ESP_LOGI(TAG, "Disconnecting from deleted ssid: %s", ssid);
esp_wifi_disconnect();
}
if (wifi_config_aps->RemoveCredential(std::string(ssid))) {
ESP_LOGI(TAG, "SSID %s was removed", ssid);
config_raise_changed(false);
} else {
ESP_LOGI(TAG, "SSID %s could not be removed", ssid);
}
return ESP_OK;
}
void network_wifi_activate_strongest_ssid() {
sys_state->has_connected_sta = true;
auto strongest = wifi_config_aps->GetStrongestSTA();
if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
ESP_LOGD(TAG, "Setting strongest AP as active");
WifiList::PrintWifiSTAEntryTitle();
WifiList::PrintWifiSTAEntry(strongest);
}
WifiList::Update(sys_state->connected_sta, strongest);
}
void network_wifi_clear_config() {
/* erase configuration */
wifi_config_aps->RemoveCredential(network_wifi_get_active_config());
esp_err_t err = ESP_OK;
if ((err = esp_wifi_disconnect()) != ESP_OK) {
ESP_LOGW(TAG, "Could not disconnect from deleted network : %s", esp_err_to_name(err));
}
}
void print_wifi_ap_status(const wifi_sta_config_t* ap_status) {
if (ap_status == NULL) {
printf("AP status is NULL\n");
return;
}
printf("SSID: %s\n", ap_status->ssid);
printf("Password: %s\n", ap_status->password);
const char* scan_method = (ap_status->scan_method == WIFI_FAST_SCAN) ? "Fast Scan" : "All Channel Scan";
printf("Scan Method: %s\n", scan_method);
printf("BSSID Set: %s\n", ap_status->bssid_set ? "Yes" : "No");
printf("BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", ap_status->bssid[0], ap_status->bssid[1], ap_status->bssid[2], ap_status->bssid[3],
ap_status->bssid[4], ap_status->bssid[5]);
printf("Channel: %d\n", ap_status->channel);
printf("Listen Interval: %d\n", ap_status->listen_interval);
const char* sort_method = (ap_status->sort_method == WIFI_CONNECT_AP_BY_SIGNAL) ? "By Signal" : "By Security";
printf("Sort Method: %s\n", sort_method);
printf("RSSI Threshold: %d\n", ap_status->threshold.rssi);
printf("Auth Mode Threshold: %d\n", ap_status->threshold.authmode);
printf("PMF Capable: %s\n", ap_status->pmf_cfg.capable ? "Yes" : "No");
printf("PMF Required: %s\n", ap_status->pmf_cfg.required ? "Yes" : "No");
// Add other fields as needed
}
void network_wifi_get_status() {
wifi_config_t config;
esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &config);
if (err == ESP_OK) {
print_wifi_ap_status(&config.sta);
} else {
ESP_LOGE(TAG, "Error getting wifi status: %s", esp_err_to_name(err));
}
if (wifi_config_aps->GetCount() > 0 || scan_results_aps.GetCount() > 0) {
WifiList::PrintWifiSTAEntryTitle();
}
ESP_LOGI(TAG, "Known access points:");
for (int i = 0; i < wifi_config_aps->GetCount(); i++) {
const auto entry = wifi_config_aps->GetIndex(i);
if (entry != nullptr) {
WifiList::PrintWifiSTAEntry(*entry);
}
}
if (scan_results_aps.GetCount() > 0) {
ESP_LOGI(TAG, "List of nearby access points");
for (int i = 0; i < scan_results_aps.GetCount(); i++) {
const auto entry = scan_results_aps.GetIndex(i);
if (entry != nullptr) {
WifiList::PrintWifiSTAEntry(*entry);
}
}
}
}
const char* get_disconnect_code_desc(uint8_t reason) {
switch (reason) {
ENUM_TO_STRING(WIFI_REASON_UNSPECIFIED);
ENUM_TO_STRING(WIFI_REASON_AUTH_EXPIRE);
ENUM_TO_STRING(WIFI_REASON_AUTH_LEAVE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_EXPIRE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_TOOMANY);
ENUM_TO_STRING(WIFI_REASON_NOT_AUTHED);
ENUM_TO_STRING(WIFI_REASON_NOT_ASSOCED);
ENUM_TO_STRING(WIFI_REASON_ASSOC_LEAVE);
ENUM_TO_STRING(WIFI_REASON_ASSOC_NOT_AUTHED);
ENUM_TO_STRING(WIFI_REASON_DISASSOC_PWRCAP_BAD);
ENUM_TO_STRING(WIFI_REASON_DISASSOC_SUPCHAN_BAD);
ENUM_TO_STRING(WIFI_REASON_IE_INVALID);
ENUM_TO_STRING(WIFI_REASON_MIC_FAILURE);
ENUM_TO_STRING(WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_IE_IN_4WAY_DIFFERS);
ENUM_TO_STRING(WIFI_REASON_GROUP_CIPHER_INVALID);
ENUM_TO_STRING(WIFI_REASON_PAIRWISE_CIPHER_INVALID);
ENUM_TO_STRING(WIFI_REASON_AKMP_INVALID);
ENUM_TO_STRING(WIFI_REASON_UNSUPP_RSN_IE_VERSION);
ENUM_TO_STRING(WIFI_REASON_INVALID_RSN_IE_CAP);
ENUM_TO_STRING(WIFI_REASON_802_1X_AUTH_FAILED);
ENUM_TO_STRING(WIFI_REASON_CIPHER_SUITE_REJECTED);
ENUM_TO_STRING(WIFI_REASON_INVALID_PMKID);
ENUM_TO_STRING(WIFI_REASON_BEACON_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_NO_AP_FOUND);
ENUM_TO_STRING(WIFI_REASON_AUTH_FAIL);
ENUM_TO_STRING(WIFI_REASON_ASSOC_FAIL);
ENUM_TO_STRING(WIFI_REASON_HANDSHAKE_TIMEOUT);
ENUM_TO_STRING(WIFI_REASON_CONNECTION_FAIL);
ENUM_TO_STRING(WIFI_REASON_AP_TSF_RESET);
ENUM_TO_STRING(WIFI_REASON_ROAMING);
}
return "";
}