Files
SpotMicroESP32-Leika/esp32/lib/ESP32-sveltekit/wifi_service.cpp
T
2025-01-17 09:22:43 +01:00

213 lines
7.3 KiB
C++

#include <wifi_service.h>
WiFiService::WiFiService()
: endpoint(WiFiSettings::read, WiFiSettings::update, this),
_persistence(WiFiSettings::read, WiFiSettings::update, this, WIFI_SETTINGS_FILE) {
addUpdateHandler([&](const String &originId) { reconfigureWiFiConnection(); }, false);
}
WiFiService::~WiFiService() {}
void WiFiService::begin() {
WiFi.mode(WIFI_MODE_STA);
WiFi.persistent(false);
WiFi.setAutoReconnect(false);
WiFi.onEvent(std::bind(&WiFiService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
WiFi.onEvent(std::bind(&WiFiService::onStationModeStop, this, std::placeholders::_1, std::placeholders::_2),
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_STOP);
WiFi.onEvent(onStationModeGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
_persistence.readFromFS();
reconfigureWiFiConnection();
if (state().wifiSettings.size() == 1) {
configureNetwork(state().wifiSettings[0]);
delay(500);
}
}
void WiFiService::reconfigureWiFiConnection() {
_lastConnectionAttempt = 0;
if (WiFi.disconnect(true)) _stopping = true;
}
void WiFiService::loop() { EXECUTE_EVERY_N_MS(reconnectDelay, manageSTA()); }
esp_err_t WiFiService::handleScan(PsychicRequest *request) {
if (WiFi.scanComplete() != -1) {
WiFi.scanDelete();
WiFi.scanNetworks(true);
}
return request->reply(202);
}
esp_err_t WiFiService::getNetworks(PsychicRequest *request) {
int numNetworks = WiFi.scanComplete();
if (numNetworks == -1)
return request->reply(202);
else if (numNetworks < -1)
return handleScan(request);
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
getNetworks(root);
return response.send();
}
void WiFiService::setupMDNS(const char *hostname) {
MDNS.begin(state().hostname.c_str());
MDNS.setInstanceName(hostname);
MDNS.addService("http", "tcp", 80);
MDNS.addService("ws", "tcp", 80);
MDNS.addServiceTxt("http", "tcp", "Firmware Version", APP_VERSION);
}
void WiFiService::getNetworks(JsonObject &root) {
JsonArray networks = root["networks"].to<JsonArray>();
int numNetworks = WiFi.scanComplete();
for (int i = 0; i < numNetworks; i++) {
JsonObject network = networks.add<JsonObject>();
network["rssi"] = WiFi.RSSI(i);
network["ssid"] = WiFi.SSID(i);
network["bssid"] = WiFi.BSSIDstr(i);
network["channel"] = WiFi.channel(i);
network["encryption_type"] = (uint8_t)WiFi.encryptionType(i);
}
}
esp_err_t WiFiService::getNetworkStatus(PsychicRequest *request) {
PsychicJsonResponse response = PsychicJsonResponse(request, false);
JsonObject root = response.getRoot();
getNetworkStatus(root);
return response.send();
}
void WiFiService::getNetworkStatus(JsonObject &root) {
wl_status_t status = WiFi.status();
root["status"] = (uint8_t)status;
if (status == WL_CONNECTED) {
root["local_ip"] = WiFi.localIP().toString();
root["mac_address"] = WiFi.macAddress();
root["rssi"] = WiFi.RSSI();
root["ssid"] = WiFi.SSID();
root["bssid"] = WiFi.BSSIDstr();
root["channel"] = WiFi.channel();
root["subnet_mask"] = WiFi.subnetMask().toString();
root["gateway_ip"] = WiFi.gatewayIP().toString();
IPAddress dnsIP1 = WiFi.dnsIP(0);
IPAddress dnsIP2 = WiFi.dnsIP(1);
if (dnsIP1 != INADDR_NONE) {
root["dns_ip_1"] = dnsIP1.toString();
}
if (dnsIP2 != INADDR_NONE) {
root["dns_ip_2"] = dnsIP2.toString();
}
}
}
void WiFiService::manageSTA() {
if (WiFi.isConnected() || state().wifiSettings.empty()) return;
if ((WiFi.getMode() & WIFI_STA) == 0) connectToWiFi();
}
void WiFiService::connectToWiFi() {
// reset availability flag for all stored networks
for (auto &network : state().wifiSettings) {
network.available = false;
}
// scanning for available networks
int scanResult = WiFi.scanNetworks();
if (scanResult == WIFI_SCAN_FAILED) {
ESP_LOGE("WiFiSettingsService", "WiFi scan failed.");
} else if (scanResult == 0) {
ESP_LOGI("WiFiSettingsService", "No networks found.");
} else {
ESP_LOGI("WiFiSettingsService", "%d networks found.", scanResult);
// find the best network to connect
wifi_settings_t *bestNetwork = nullptr;
int32_t bestNetworkDb = FACTORY_WIFI_RSSI_THRESHOLD;
for (int i = 0; i < scanResult; ++i) {
String ssid_scan;
int32_t rssi_scan;
uint8_t sec_scan;
uint8_t *BSSID_scan;
int32_t chan_scan;
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan);
for (auto &network : state().wifiSettings) {
if (ssid_scan == network.ssid) {
if (rssi_scan >= FACTORY_WIFI_RSSI_THRESHOLD) {
network.available = true;
}
if (rssi_scan > bestNetworkDb) {
bestNetworkDb = rssi_scan;
bestNetwork = &network;
}
}
}
}
if (!state().priorityBySignalStrength) {
for (auto &network : state().wifiSettings) {
if (network.available == true) {
ESP_LOGI("WiFiSettingsService", "Connecting to first available network: %s", network.ssid.c_str());
configureNetwork(network);
break;
}
}
} else if (state().priorityBySignalStrength && bestNetwork) {
ESP_LOGI("WiFiSettingsService", "Connecting to strongest network: %s", bestNetwork->ssid.c_str());
configureNetwork(*bestNetwork);
WiFi.begin(bestNetwork->ssid.c_str(), bestNetwork->password.c_str());
} else {
ESP_LOGI("WiFiSettingsService", "No known networks found.");
}
WiFi.scanDelete();
}
}
void WiFiService::configureNetwork(wifi_settings_t &network) {
if (network.staticIPConfig) {
// configure for static IP
WiFi.config(network.localIP, network.gatewayIP, network.subnetMask, network.dnsIP1, network.dnsIP2);
} else {
// configure for DHCP
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
}
WiFi.setHostname(state().hostname.c_str());
// attempt to connect to the network
WiFi.begin(network.ssid.c_str(), network.password.c_str());
#if CONFIG_IDF_TARGET_ESP32C3
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
#endif
}
void WiFiService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
WiFi.disconnect(true);
ESP_LOGI("WiFiStatus", "WiFi Disconnected. Reason code=%d", info.wifi_sta_disconnected.reason);
}
void WiFiService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) {
if (_stopping) {
_lastConnectionAttempt = 0;
_stopping = false;
}
ESP_LOGI("WiFiStatus", "WiFi Connected.");
}
void WiFiService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
ESP_LOGI("WiFiStatus", "WiFi Got IP. localIP=%s, hostName=%s", WiFi.localIP().toString().c_str(),
WiFi.getHostname());
}