Wi Fi - mriksman/esp-idf-homekit GitHub Wiki
Wi-Fi
NVS
Wi-Fi configuration is stored to NVS when CONFIG_ESP8266_WIFI_NVS_ENABLED
is defined. So previously configured (even if not successful connecting) is stored to NVS. You can retrieve the values by;
esp_wifi_get_config(ESP_IF_WIFI_AP, &wifi_cfg);
esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg)
Note; you must call esp_wifi_set_mode()
before setting the configuration.
esp_wifi_set_mode(WIFI_MODE_APSTA);
esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_ap_config);
Migrate From tcpip_adapter_init() to esp_netif_init()
As of ESP-IDF v4.1, ESP-NETIF
is to be used.
Legacy Wi-Fi/LwIP initialisation phase;
- The main task calls
tcpip_adapter_init()
to create an LwIP core task and initialize LwIP-related work. - The main task calls
esp_event_loop_init()
to create a system Event task and initialize an application event's callback function. In the scenario above, the application event's callback function does nothing but relaying the event to the application task. - The main task calls
esp_wifi_init()
to create the Wi-Fi driver task and initialize the Wi-Fi driver. - The main task calls OS API to create the application task.
Using the new esp_netif_init()
- The main task calls
esp_netif_init()
to create an LwIP core task and initialize LwIP-related work. - The main task calls
esp_event_loop_init()
to create a system Event task and initialize an application event's callback function. In the scenario above, the application event's callback function does nothing but relaying the event to the application task. - The main task calls
esp_netif_create_default_wifi_ap()
and/oresp_netif_create_default_wifi_sta()
to create default network interface instance binding station or AP with TCP/IP stack. - The main task calls
esp_wifi_init()
to create the Wi-Fi driver task and initialize the Wi-Fi driver. - The main task calls OS API to create the application task.
Disconnect Event and Connection Retries
When esp_wifi_connect()
is called, then the Wi-Fi driver will try to scan the configured AP first. This is the same as
esp_wifi_scan_start()
'Scan for a Specific AP In All Channels', except that no WIFI_EVENT_SCAN_DONE
event will be generated when the scan is completed. If the target AP is found, then the Wi-Fi driver will start the Wi-Fi connection; otherwise, WIFI_EVENT_STA_DISCONNECTED
will be generated.
It is up to the user what to do when the WIFI_EVENT_STA_DISCONNECTED
is generated. In ESP8266 RTOS SDK, it will automatically retry. In ESP-IDF, it will not -- you need to explicitly call esp_wifi_connect()
again. The automatic retry will occur every ~2 seconds (the time it takes to perform a scan). In order to delay this time, you can use a
timer or kick off a task and use vTaskDelay
.
You can't use esp_timer_start_once()
timer to kick off another connection attempt within the WIFI_EVENT_STA_DISCONNECTED
event. If esp_wifi_scan_start()
starts and then the timer expires and calls for an esp_wifi_connect()
, it will not be able to take the Mutex and will abort the attempt. Thus, the WIFI_EVENT_STA_DISCONNECTED event will *never* reoccur, and a reconnection will not be reattempted. So instead, kick off a periodic timer with
esp_timer_start_periodic()` at the same time as starting the Soft AP. When you no longer need the
reconnect attempts, simply stop the timer.
} else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
} else {
wifi_mode_t wifi_mode;
esp_wifi_get_mode(&wifi_mode);
if (wifi_mode != WIFI_MODE_APSTA) {
ESP_LOGI(TAG, "Failed to connect to AP. Start softAP Provisioning");
// Currently not in softAP (APSTA) mode. Start it.
start_ap_prov();
// Keep trying to connect to existing AP (perhaps AP was restarted)
esp_timer_start_periodic(s_wifi_reconnect_timer, 10000000);
}
}
} else if (event_base == IP_EVENT) {
if (event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR "\n", IP2STR(&event->ip_info.ip));
s_retry_num = 0;
// Got IP - do not need softAP anymore
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// Stop periodic connection retry attempts
esp_timer_stop(s_wifi_reconnect_timer);
}
}
Unfortunately, using the esp-timer
library caused stack faults. Alternatively -- used a simple Task. Replace;
esp_timer_start_periodic(s_wifi_reconnect_timer, 10000000);
with
xTaskCreate(&retry_connect_task, "retry_connect", 1024, NULL, tskIDLE_PRIORITY, &retry_connect_task_handle);
and
esp_timer_stop(s_wifi_reconnect_timer);
with
if (retry_connect_task_handle != NULL) {
vTaskDelete(retry_connect_task_handle);
retry_connect_task_handle = NULL;
}
Really important to check if the task handle is not NULL
. If it is NULL
, it will delete the currently executing task (which for me was the System Event task loop…)
Then create a simple task retry_connect_task
that calls the esp_wifi_connect
and then vTaskDelay
for 10 seconds.
Connect and Scan Contention
A common use-case would be; if a connection to the previous AP (station) cannot be made, then start up a Soft AP to allow a user to connect to the ESP and reconfigure. But at the same time, the ESP should continue to retry connecting to the previous AP, in case it comes online again (maybe it was powered off for a period).
When a user initiates a scan, it is possible for one of the connection retries to be attempted -- causing the scan to end prematurely. As such -- a Mutex should be employed to manage access to this resource. ESP SDK offers a few ways to approach this. See https://github.com/mriksman/esp-idf-homekit/wiki/Events,-Queues,-Tasks
LwIP Assert Bug ESP8266 RTOS SDK
Occasionally an assert would occur in the LwIP code;
assertion "netconn marked closed" failed: file "C:/VSCode/SDK/esp8266/ESP8266_RTOS_SDK/components/lwip/lwip/src/api/api_msg.c", line 860, function: netconn_drain
abort() was called at PC 0x4025a868 on core 0
This was flagged over in the ESP-IDF issues, and apparently fixed with commit 076270e
, on March 9th 2020. ESP8266 RTOS SDK was still linked to commit c9e3b53
from December 10th 2019.
To update the submodule being used, open the ESP8266 RTOS SDK folder in VSCode, and go to 'Source Control'. Click on c9e3b53
and select branch 2.1.2-esp
(or any later version).