2024-05-20 17:50:13 -07:00

211 lines
5.0 KiB
C++

/// © MiroZ 2024
#include "Wifi.h"
#include "errors.h"
#include "Settings.h"
#include <WiFi.h>
#include <functional>
#include "utilities.h"
static const char *TAG = "Wifi";
#define IGNORE_SSID_MINS 20
using namespace std::placeholders;
Wifi::Wifi()
{
esp_log_level_set("wifi", ESP_LOG_WARN);
esp_log_level_set("wifi_init", ESP_LOG_INFO);
// memset(m_ignored, 0, SETTINGS_NUM_WIFI_ENTRIES);
WiFi.onEvent(std::bind(&Wifi::wifi_event, this, _1, _2));
// esp_timer_create_args_t timer;
// timer.arg = this;
// timer.callback = &timerCallback;
// timer.dispatch_method = ESP_TIMER_TASK;
// timer.skip_unhandled_events = true;
// timer.name = "wifi countdown timer";
// ESP_ERROR_CHECK(esp_timer_create(&timer, &m_timer));
// ESP_ERROR_CHECK(esp_timer_start_periodic(m_timer, 60000000)); // 1 min
// m_task = TASK_FACTORY.createTask(std::bind(&Wifi::wifiTask, this), "wifi task", 2048, 5, 0);
}
// void Wifi::timerCallback(void* arg)
// {
// for(int n = 0; n < SETTINGS_NUM_WIFI_ENTRIES; n++)
// {
// if(((Wifi*)arg)->m_ignored[n] > 0)
// ((Wifi*)arg)->m_ignored[n]--;
// }
// }
void Wifi::wifi_event(arduino_event_id_t event, arduino_event_info_t info)
{
ESP_LOGI(TAG, "event: %s (%d)", WiFi.eventName(event), (int)event);
if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED)
{
wifi_err_reason_t reason = (wifi_err_reason_t)info.wifi_sta_disconnected.reason;
ESP_LOGI(TAG, "reason: %s", WiFi.disconnectReasonName(reason));
}
}
// void Wifi::wifiTask()
// {
// while(true)
// {
// delay(1000);
// ESP_LOGI(TAG, "in wifi task!");
// }
// }
/// @brief Connect to provisioned wifi
/// @param index index of wifi in settings
/// @return ok/not connected
uint32_t Wifi::connectTo(int index)
{
IPAddress local_IP(192, 168, 1, 155);
IPAddress gateway(192, 168, 1, 100);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);
IPAddress secondaryDNS(8, 8, 4, 4);
ESP_LOGI(TAG, "Connecting to %s...", SETTINGS.wifi.entry[index].ssid);
WiFi.mode(WIFI_STA);
WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
WiFi.hostname("wellhub");
WiFi.begin(SETTINGS.wifi.entry[index].ssid, SETTINGS.wifi.entry[index].pwd);
int status = WiFi.waitForConnectResult(10000);
if(status == WL_CONNECTED)
{
ESP_LOGI(TAG, "Connected");
return WH_OK;
}
WiFi.disconnect();
ESP_LOGW(TAG, "Failed to connect");
return WH_ERR_WIFI_NOT_CONNECTED;
}
/// @brief Connects to wifi. Returns immediately if already connected.
/// @return WH_OK | WH_ERR_WIFI_NOT_PROVISIONED
uint32_t Wifi::start()
{
if(SETTINGS.wifi.num == 0)
{
ESP_LOGE(TAG, "Not provisioned!");
return WH_ERR_WIFI_NOT_PROVISIONED;
}
if(WiFi.isConnected())
return WH_OK;
// if only one network is provisioned
if(SETTINGS.wifi.num == 1)
{
SETTINGS.wifi.selected = 0;
for(int n = 0; n < 3; n++)
{
if(connectTo(SETTINGS.wifi.selected) == WH_OK)
return WH_OK;
WiFi.disconnect();
}
ESP_LOGW(TAG, "Cannot connect, need provisioning");
return WH_ERR_WIFI_NOT_PROVISIONED;
}
// multiple networks are provisioned. Use either specific network or scan for highest rssi
memset(m_ignored, 0, SETTINGS_NUM_WIFI_ENTRIES);
int ssid_ix = SETTINGS.wifi.selected;
if(SETTINGS.wifi.always_scan_before_connect || SETTINGS.wifi.selected >= SETTINGS.wifi.num)
ssid_ix = scan();
if(ssid_ix < 0)
return WH_ERR_WIFI_NOT_PROVISIONED;
if(connectTo(ssid_ix) == WH_OK)
{
SETTINGS.wifi.selected = ssid_ix;
return WH_OK;
}
// didn't work. go through them all giving priority to one with highest rssi
m_ignored[ssid_ix] = IGNORE_SSID_MINS;
do
{
ssid_ix = scan();
if(ssid_ix >= 0)
{
if(connectTo(ssid_ix) == WH_OK)
return WH_OK;
else
m_ignored[ssid_ix] = IGNORE_SSID_MINS;
}
else
break;
} while(true);
// that failed too, try them all again round-robin
for(int m = 0; m < 3; m++)
{
for(int n = 0; n < SETTINGS.wifi.num; n++)
{
if(connectTo(n) == WH_OK)
return WH_OK;
}
}
ESP_LOGW(TAG, "Cannot connect, need provisioning");
return WH_ERR_WIFI_NOT_PROVISIONED;
}
/// @brief Scans all visible ssid's and picks known ssid with highest rssi that is not ignored.
/// @return wifi index in Settings
int Wifi::scan()
{
ESP_LOGI(TAG, "Scanning wifi networks...");
int num_networks = WiFi.scanNetworks(false, false, false, 500);
ESP_LOGI(TAG, "found %d networks", num_networks);
int rssi = -500;
int selected_index = -1;
// crossref scanned and saved networks
for(int n = 0; n < num_networks; n++)
{
for(int p = 0; p < SETTINGS.wifi.num; p++)
{
if(strcmp(SETTINGS.wifi.entry[p].ssid, WiFi.SSID(n).c_str()) == 0)
{
// found saved network
ESP_LOGI(TAG, "Found provisioned network '%s' with RSSI %d dBm", SETTINGS.wifi.entry[p].ssid, WiFi.RSSI(n));
if(WiFi.RSSI(n) > rssi && m_ignored[p] == 0)
{
rssi = WiFi.RSSI(n);
selected_index = p;
}
}
}
}
if(selected_index >= 0)
ESP_LOGI(TAG, "Chosen network '%s'", SETTINGS.wifi.entry[selected_index].ssid);
else
ESP_LOGI(TAG, "No suitable networks found at this time");
return selected_index;
}