🛜 Simplify wifi services
This commit is contained in:
@@ -21,9 +21,6 @@ ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server, unsigned int numberEnd
|
|||||||
_taskManager(),
|
_taskManager(),
|
||||||
_featureService(server),
|
_featureService(server),
|
||||||
_securitySettingsService(server, &ESPFS),
|
_securitySettingsService(server, &ESPFS),
|
||||||
_wifiSettingsService(server, &ESPFS, &_securitySettingsService, &_socket),
|
|
||||||
_wifiScanner(server, &_securitySettingsService),
|
|
||||||
_wifiStatus(server, &_securitySettingsService),
|
|
||||||
_apSettingsService(server, &ESPFS, &_securitySettingsService),
|
_apSettingsService(server, &ESPFS, &_securitySettingsService),
|
||||||
_apStatus(server, &_securitySettingsService, &_apSettingsService),
|
_apStatus(server, &_securitySettingsService, &_apSettingsService),
|
||||||
_socket(server, &_securitySettingsService, AuthenticationPredicates::IS_AUTHENTICATED),
|
_socket(server, &_securitySettingsService, AuthenticationPredicates::IS_AUTHENTICATED),
|
||||||
@@ -72,14 +69,12 @@ void ESP32SvelteKit::begin() {
|
|||||||
ESP_LOGI("Running Firmware Version: %s", APP_VERSION);
|
ESP_LOGI("Running Firmware Version: %s", APP_VERSION);
|
||||||
ESPFS.begin(true);
|
ESPFS.begin(true);
|
||||||
|
|
||||||
_wifiSettingsService.initWiFi();
|
startServices();
|
||||||
|
|
||||||
setupServer();
|
setupServer();
|
||||||
|
|
||||||
setupMDNS();
|
setupMDNS();
|
||||||
|
|
||||||
startServices();
|
|
||||||
|
|
||||||
ESP_LOGV("ESP32SvelteKit", "Starting loop task");
|
ESP_LOGV("ESP32SvelteKit", "Starting loop task");
|
||||||
_taskManager.createTask(this->_loopImpl, "Spot main", 4096, this, 2, NULL, ESP32SVELTEKIT_RUNNING_CORE);
|
_taskManager.createTask(this->_loopImpl, "Spot main", 4096, this, 2, NULL, ESP32SVELTEKIT_RUNNING_CORE);
|
||||||
}
|
}
|
||||||
@@ -88,6 +83,17 @@ void ESP32SvelteKit::setupServer() {
|
|||||||
_server->config.max_uri_handlers = _numberEndpoints;
|
_server->config.max_uri_handlers = _numberEndpoints;
|
||||||
_server->listen(80);
|
_server->listen(80);
|
||||||
|
|
||||||
|
_server->on("/api/wifi/scan", HTTP_GET, _wifiService.handleScan);
|
||||||
|
_server->on("/api/wifi/networks", HTTP_GET,
|
||||||
|
[this](PsychicRequest *request) { return _wifiService.getNetworks(request); });
|
||||||
|
_server->on("/api/wifi/sta/status", HTTP_GET,
|
||||||
|
[this](PsychicRequest *request) { return _wifiService.getNetworkStatus(request); });
|
||||||
|
_server->on("/api/wifi/sta/settings", HTTP_GET,
|
||||||
|
[this](PsychicRequest *request) { return _wifiService.endpoint.getState(request); });
|
||||||
|
_server->on("/api/wifi/sta/settings", HTTP_POST, [this](PsychicRequest *request, JsonVariant &json) {
|
||||||
|
return _wifiService.endpoint.handleStateUpdate(request, json);
|
||||||
|
});
|
||||||
|
|
||||||
#ifdef EMBED_WWW
|
#ifdef EMBED_WWW
|
||||||
ESP_LOGV("ESP32SvelteKit", "Registering routes from PROGMEM static resources");
|
ESP_LOGV("ESP32SvelteKit", "Registering routes from PROGMEM static resources");
|
||||||
WWWData::registerRoutes([&](const String &uri, const String &contentType, const uint8_t *content, size_t len) {
|
WWWData::registerRoutes([&](const String &uri, const String &contentType, const uint8_t *content, size_t len) {
|
||||||
@@ -140,7 +146,7 @@ void ESP32SvelteKit::setupServer() {
|
|||||||
|
|
||||||
void ESP32SvelteKit::setupMDNS() {
|
void ESP32SvelteKit::setupMDNS() {
|
||||||
ESP_LOGV("ESP32SvelteKit", "Starting MDNS");
|
ESP_LOGV("ESP32SvelteKit", "Starting MDNS");
|
||||||
MDNS.begin(_wifiSettingsService.getHostname().c_str());
|
MDNS.begin(_wifiService.getHostname());
|
||||||
MDNS.setInstanceName(_appName);
|
MDNS.setInstanceName(_appName);
|
||||||
MDNS.addService("http", "tcp", 80);
|
MDNS.addService("http", "tcp", 80);
|
||||||
MDNS.addService("ws", "tcp", 80);
|
MDNS.addService("ws", "tcp", 80);
|
||||||
@@ -148,6 +154,7 @@ void ESP32SvelteKit::setupMDNS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP32SvelteKit::startServices() {
|
void ESP32SvelteKit::startServices() {
|
||||||
|
_wifiService.begin();
|
||||||
_apStatus.begin();
|
_apStatus.begin();
|
||||||
_socket.begin();
|
_socket.begin();
|
||||||
_apSettingsService.begin();
|
_apSettingsService.begin();
|
||||||
@@ -155,9 +162,6 @@ void ESP32SvelteKit::startServices() {
|
|||||||
_featureService.begin();
|
_featureService.begin();
|
||||||
_restartService.begin();
|
_restartService.begin();
|
||||||
_systemStatus.begin();
|
_systemStatus.begin();
|
||||||
_wifiSettingsService.begin();
|
|
||||||
_wifiScanner.begin();
|
|
||||||
_wifiStatus.begin();
|
|
||||||
|
|
||||||
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
#if FT_ENABLED(USE_UPLOAD_FIRMWARE)
|
||||||
_uploadFirmwareService.begin();
|
_uploadFirmwareService.begin();
|
||||||
@@ -203,7 +207,7 @@ void IRAM_ATTR ESP32SvelteKit::loop() {
|
|||||||
#if FT_ENABLED(USE_WS2812)
|
#if FT_ENABLED(USE_WS2812)
|
||||||
_ledService.loop();
|
_ledService.loop();
|
||||||
#endif
|
#endif
|
||||||
_wifiSettingsService.loop();
|
_wifiService.loop();
|
||||||
_apSettingsService.loop();
|
_apSettingsService.loop();
|
||||||
#if FT_ENABLED(USE_ANALYTICS)
|
#if FT_ENABLED(USE_ANALYTICS)
|
||||||
_analyticsService.loop();
|
_analyticsService.loop();
|
||||||
|
|||||||
@@ -46,9 +46,7 @@
|
|||||||
#include <TaskManager.h>
|
#include <TaskManager.h>
|
||||||
#include <UploadFirmwareService.h>
|
#include <UploadFirmwareService.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiScanner.h>
|
#include <wifi_service.h>
|
||||||
#include <WiFiSettingsService.h>
|
|
||||||
#include <WiFiStatus.h>
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
#ifdef EMBED_WWW
|
#ifdef EMBED_WWW
|
||||||
@@ -85,8 +83,6 @@ class ESP32SvelteKit {
|
|||||||
|
|
||||||
EventSocket *getSocket() { return &_socket; }
|
EventSocket *getSocket() { return &_socket; }
|
||||||
|
|
||||||
StatefulService<WiFiSettings> *getWiFiSettingsService() { return &_wifiSettingsService; }
|
|
||||||
|
|
||||||
StatefulService<APSettings> *getAPSettingsService() { return &_apSettingsService; }
|
StatefulService<APSettings> *getAPSettingsService() { return &_apSettingsService; }
|
||||||
|
|
||||||
#if FT_ENABLED(USE_NTP)
|
#if FT_ENABLED(USE_NTP)
|
||||||
@@ -135,9 +131,10 @@ class ESP32SvelteKit {
|
|||||||
unsigned int _numberEndpoints;
|
unsigned int _numberEndpoints;
|
||||||
FeaturesService _featureService;
|
FeaturesService _featureService;
|
||||||
SecuritySettingsService _securitySettingsService;
|
SecuritySettingsService _securitySettingsService;
|
||||||
WiFiSettingsService _wifiSettingsService;
|
WiFiService _wifiService;
|
||||||
WiFiScanner _wifiScanner;
|
// WiFiSettingsService _wifiSettingsService;
|
||||||
WiFiStatus _wifiStatus;
|
// WiFiScanner _wifiScanner;
|
||||||
|
// WiFiStatus _wifiStatus;
|
||||||
APSettingsService _apSettingsService;
|
APSettingsService _apSettingsService;
|
||||||
APStatus _apStatus;
|
APStatus _apStatus;
|
||||||
EventSocket _socket;
|
EventSocket _socket;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
* Copyright (C) 2018 - 2023 rjwats
|
||||||
* Copyright (C) 2023 theelims
|
* Copyright (C) 2023 theelims
|
||||||
|
* Copyright (C) 2024 runeharlyk
|
||||||
*
|
*
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
* All Rights Reserved. This software may be modified and distributed under
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
|
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <StatefulService.h>
|
#include <StatefulService.h>
|
||||||
|
#include <ESPFS.h>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class FSPersistence {
|
class FSPersistence {
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <StatefulService.h>
|
|
||||||
|
|
||||||
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;
|
|
||||||
hook_handler_id_t StateHookHandlerInfo::currentHookHandlerId = 0;
|
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
* Copyright (C) 2018 - 2023 rjwats
|
||||||
* Copyright (C) 2023 theelims
|
* Copyright (C) 2023 theelims
|
||||||
|
* Copyright (C) 2024 runeharlyk
|
||||||
*
|
*
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
* All Rights Reserved. This software may be modified and distributed under
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||||
@@ -23,11 +24,7 @@
|
|||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
|
|
||||||
enum class StateUpdateResult {
|
#include <state_result.h>
|
||||||
CHANGED = 0, // The update changed the state and propagation should take place if required
|
|
||||||
UNCHANGED, // The state was unchanged, propagation should not take place
|
|
||||||
ERROR // There was a problem updating the state, propagation should not take place
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using JsonStateUpdater = std::function<StateUpdateResult(JsonObject &root, T &settings)>;
|
using JsonStateUpdater = std::function<StateUpdateResult(JsonObject &root, T &settings)>;
|
||||||
@@ -41,7 +38,7 @@ typedef std::function<void(const String &originId)> StateUpdateCallback;
|
|||||||
typedef std::function<void(const String &originId, StateUpdateResult &result)> StateHookCallback;
|
typedef std::function<void(const String &originId, StateUpdateResult &result)> StateHookCallback;
|
||||||
|
|
||||||
typedef struct StateUpdateHandlerInfo {
|
typedef struct StateUpdateHandlerInfo {
|
||||||
static update_handler_id_t currentUpdatedHandlerId;
|
static inline update_handler_id_t currentUpdatedHandlerId = 0;
|
||||||
update_handler_id_t _id;
|
update_handler_id_t _id;
|
||||||
StateUpdateCallback _cb;
|
StateUpdateCallback _cb;
|
||||||
bool _allowRemove;
|
bool _allowRemove;
|
||||||
@@ -50,7 +47,7 @@ typedef struct StateUpdateHandlerInfo {
|
|||||||
} StateUpdateHandlerInfo_t;
|
} StateUpdateHandlerInfo_t;
|
||||||
|
|
||||||
typedef struct StateHookHandlerInfo {
|
typedef struct StateHookHandlerInfo {
|
||||||
static hook_handler_id_t currentHookHandlerId;
|
static inline hook_handler_id_t currentHookHandlerId = 0;
|
||||||
hook_handler_id_t _id;
|
hook_handler_id_t _id;
|
||||||
StateHookCallback _cb;
|
StateHookCallback _cb;
|
||||||
bool _allowRemove;
|
bool _allowRemove;
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFiScanner.h>
|
|
||||||
|
|
||||||
WiFiScanner::WiFiScanner(PsychicHttpServer *server, SecurityManager *securityManager)
|
|
||||||
: _server(server), _securityManager(securityManager) {}
|
|
||||||
|
|
||||||
void WiFiScanner::begin() {
|
|
||||||
_server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET,
|
|
||||||
_securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1),
|
|
||||||
AuthenticationPredicates::IS_ADMIN));
|
|
||||||
|
|
||||||
ESP_LOGV("WiFiScanner", "Registered GET endpoint: %s", SCAN_NETWORKS_SERVICE_PATH);
|
|
||||||
|
|
||||||
_server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET,
|
|
||||||
_securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1),
|
|
||||||
AuthenticationPredicates::IS_ADMIN));
|
|
||||||
|
|
||||||
ESP_LOGV("WiFiScanner", "Registered GET endpoint: %s", LIST_NETWORKS_SERVICE_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t WiFiScanner::scanNetworks(PsychicRequest *request) {
|
|
||||||
if (WiFi.scanComplete() != -1) {
|
|
||||||
WiFi.scanDelete();
|
|
||||||
WiFi.scanNetworks(true);
|
|
||||||
}
|
|
||||||
return request->reply(202);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t WiFiScanner::listNetworks(PsychicRequest *request) {
|
|
||||||
int numNetworks = WiFi.scanComplete();
|
|
||||||
if (numNetworks > -1) {
|
|
||||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
|
||||||
JsonObject root = response.getRoot();
|
|
||||||
JsonArray networks = root["networks"].to<JsonArray>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.send();
|
|
||||||
} else if (numNetworks == -1) {
|
|
||||||
return request->reply(202);
|
|
||||||
} else {
|
|
||||||
return scanNetworks(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#ifndef WiFiScanner_h
|
|
||||||
#define WiFiScanner_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <PsychicHttp.h>
|
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
|
||||||
#define SCAN_NETWORKS_SERVICE_PATH "/api/scanNetworks"
|
|
||||||
#define LIST_NETWORKS_SERVICE_PATH "/api/listNetworks"
|
|
||||||
|
|
||||||
class WiFiScanner {
|
|
||||||
public:
|
|
||||||
WiFiScanner(PsychicHttpServer *server, SecurityManager *securityManager);
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
SecurityManager *_securityManager;
|
|
||||||
|
|
||||||
esp_err_t scanNetworks(PsychicRequest *request);
|
|
||||||
esp_err_t listNetworks(PsychicRequest *request);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end WiFiScanner_h
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFiSettingsService.h>
|
|
||||||
|
|
||||||
WiFiSettingsService::WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager,
|
|
||||||
EventSocket *socket)
|
|
||||||
: _server(server),
|
|
||||||
_securityManager(securityManager),
|
|
||||||
_httpEndpoint(WiFiSettings::read, WiFiSettings::update, this, server, WIFI_SETTINGS_SERVICE_PATH, securityManager,
|
|
||||||
AuthenticationPredicates::IS_ADMIN),
|
|
||||||
_eventEndpoint(WiFiSettings::read, WiFiSettings::update, this, socket, EVENT_WIFI_SETTINGS),
|
|
||||||
_fsPersistence(WiFiSettings::read, WiFiSettings::update, this, fs, WIFI_SETTINGS_FILE),
|
|
||||||
_lastConnectionAttempt(0),
|
|
||||||
_socket(socket) {
|
|
||||||
addUpdateHandler([&](const String &originId) { reconfigureWiFiConnection(); }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::initWiFi() {
|
|
||||||
WiFi.mode(WIFI_MODE_STA); // this is the default.
|
|
||||||
|
|
||||||
// Disable WiFi config persistance and auto reconnect
|
|
||||||
WiFi.persistent(false);
|
|
||||||
WiFi.setAutoReconnect(false);
|
|
||||||
|
|
||||||
WiFi.onEvent(
|
|
||||||
std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
|
||||||
WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeStop, this, std::placeholders::_1, std::placeholders::_2),
|
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_STOP);
|
|
||||||
|
|
||||||
_fsPersistence.readFromFS();
|
|
||||||
reconfigureWiFiConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::begin() {
|
|
||||||
_httpEndpoint.begin();
|
|
||||||
_eventEndpoint.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::reconfigureWiFiConnection() {
|
|
||||||
// reset last connection attempt to force loop to reconnect immediately
|
|
||||||
_lastConnectionAttempt = 0;
|
|
||||||
|
|
||||||
// disconnect and de-configure wifi
|
|
||||||
if (WiFi.disconnect(true)) {
|
|
||||||
_stopping = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::loop() {
|
|
||||||
EXECUTE_EVERY_N_MS(WIFI_RECONNECTION_DELAY, manageSTA());
|
|
||||||
EXECUTE_EVERY_N_MS(RSSI_EVENT_DELAY, updateRSSI());
|
|
||||||
}
|
|
||||||
|
|
||||||
String WiFiSettingsService::getHostname() { return _state.hostname; }
|
|
||||||
|
|
||||||
void WiFiSettingsService::manageSTA() {
|
|
||||||
// Abort if already connected, or if we have no SSID
|
|
||||||
if (WiFi.isConnected() || _state.wifiSettings.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect or reconnect as required
|
|
||||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
|
||||||
connectToWiFi();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::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 = NULL;
|
|
||||||
int 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);
|
|
||||||
ESP_LOGV("WiFiSettingsService", "SSID: %s, RSSI: %d dbm", ssid_scan.c_str(), rssi_scan);
|
|
||||||
|
|
||||||
for (auto &network : _state.wifiSettings) {
|
|
||||||
if (ssid_scan == network.ssid) { // SSID match
|
|
||||||
if (rssi_scan > bestNetworkDb) { // best network
|
|
||||||
bestNetworkDb = rssi_scan;
|
|
||||||
bestNetwork = &network;
|
|
||||||
network.available = true;
|
|
||||||
} else if (rssi_scan >= FACTORY_WIFI_RSSI_THRESHOLD) { // available network
|
|
||||||
network.available = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if configured to prioritize signal strength, use the best network else use the first available network
|
|
||||||
if (_state.priorityBySignalStrength == false) {
|
|
||||||
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 == true && 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 // no suitable network to connect
|
|
||||||
{
|
|
||||||
ESP_LOGI("WiFiSettingsService", "No known networks found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete scan results
|
|
||||||
WiFi.scanDelete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::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 WiFiSettingsService::updateRSSI() {
|
|
||||||
char buffer[8];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%d", WiFi.RSSI());
|
|
||||||
_socket->emit(EVENT_RSSI, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { WiFi.disconnect(true); }
|
|
||||||
void WiFiSettingsService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
||||||
if (_stopping) {
|
|
||||||
_lastConnectionAttempt = 0;
|
|
||||||
_stopping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFiStatus.h>
|
|
||||||
|
|
||||||
WiFiStatus::WiFiStatus(PsychicHttpServer *server, SecurityManager *securityManager)
|
|
||||||
: _server(server), _securityManager(securityManager) {}
|
|
||||||
|
|
||||||
void WiFiStatus::begin() {
|
|
||||||
_server->on(WIFI_STATUS_SERVICE_PATH, HTTP_GET,
|
|
||||||
_securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1),
|
|
||||||
AuthenticationPredicates::IS_AUTHENTICATED));
|
|
||||||
|
|
||||||
ESP_LOGV("WiFiStatus", "Registered GET endpoint: %s", WIFI_STATUS_SERVICE_PATH);
|
|
||||||
|
|
||||||
WiFi.onEvent(onStationModeConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED);
|
|
||||||
WiFi.onEvent(onStationModeDisconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
|
||||||
WiFi.onEvent(onStationModeGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiStatus::onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
||||||
ESP_LOGI("WiFiStatus", "WiFi Connected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiStatus::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
||||||
ESP_LOGI("WiFiStatus", "WiFi Disconnected. Reason code=%d", info.wifi_sta_disconnected.reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WiFiStatus::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|
||||||
ESP_LOGI("WiFiStatus", "WiFi Got IP. localIP=%s, hostName=%s", WiFi.localIP().toString().c_str(),
|
|
||||||
WiFi.getHostname());
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t WiFiStatus::wifiStatus(PsychicRequest *request) {
|
|
||||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
|
||||||
JsonObject root = response.getRoot();
|
|
||||||
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 (IPUtils::isSet(dnsIP1)) {
|
|
||||||
root["dns_ip_1"] = dnsIP1.toString();
|
|
||||||
}
|
|
||||||
if (IPUtils::isSet(dnsIP2)) {
|
|
||||||
root["dns_ip_2"] = dnsIP2.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.send();
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#ifndef WiFiStatus_h
|
|
||||||
#define WiFiStatus_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <PsychicHttp.h>
|
|
||||||
#include <IPUtils.h>
|
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
|
||||||
#define WIFI_STATUS_SERVICE_PATH "/api/wifiStatus"
|
|
||||||
|
|
||||||
class WiFiStatus {
|
|
||||||
public:
|
|
||||||
WiFiStatus(PsychicHttpServer *server, SecurityManager *securityManager);
|
|
||||||
|
|
||||||
void begin();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
SecurityManager *_securityManager;
|
|
||||||
|
|
||||||
// static functions for logging WiFi events to the UART
|
|
||||||
static void onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
static void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
esp_err_t wifiStatus(PsychicRequest *request);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end WiFiStatus_h
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class StateUpdateResult {
|
||||||
|
CHANGED = 0, // The update changed the state and propagation should take place if required
|
||||||
|
UNCHANGED, // The state was unchanged, propagation should not take place
|
||||||
|
ERROR // There was a problem updating the state, propagation should not take place
|
||||||
|
};
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <PsychicHttp.h>
|
||||||
|
#include <stateful_service_endpoint.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
||||||
|
#define HTTPS_ENDPOINT_ORIGIN_ID "https"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class StatefulHttpEndpoint {
|
||||||
|
protected:
|
||||||
|
JsonStateReader<T> _stateReader;
|
||||||
|
JsonStateUpdater<T> _stateUpdater;
|
||||||
|
StatefulService<T> *_statefulService;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StatefulHttpEndpoint(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater,
|
||||||
|
StatefulService<T> *statefulService)
|
||||||
|
: _stateReader(stateReader), _stateUpdater(stateUpdater), _statefulService(statefulService) {}
|
||||||
|
|
||||||
|
esp_err_t handleStateUpdate(PsychicRequest *request, JsonVariant &json) {
|
||||||
|
if (!json.is<JsonObject>()) {
|
||||||
|
return request->reply(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject jsonObject = json.as<JsonObject>();
|
||||||
|
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||||
|
|
||||||
|
if (outcome == StateUpdateResult::ERROR) {
|
||||||
|
return request->reply(400);
|
||||||
|
} else if ((outcome == StateUpdateResult::CHANGED)) {
|
||||||
|
// persist the changes to the FS
|
||||||
|
_statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||||
|
jsonObject = response.getRoot();
|
||||||
|
|
||||||
|
_statefulService->read(jsonObject, _stateReader);
|
||||||
|
|
||||||
|
return response.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t getState(PsychicRequest *request) {
|
||||||
|
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||||
|
JsonObject jsonObject = response.getRoot();
|
||||||
|
_statefulService->read(jsonObject, _stateReader);
|
||||||
|
return response.send();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
#include <wifi_service.h>
|
||||||
|
|
||||||
|
WiFiService::WiFiService()
|
||||||
|
: endpoint(WiFiSettings::read, WiFiSettings::update, this),
|
||||||
|
_fsPersistence(WiFiSettings::read, WiFiSettings::update, this, &ESPFS, 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);
|
||||||
|
|
||||||
|
_fsPersistence.readFromFS();
|
||||||
|
reconfigureWiFiConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <PsychicHttp.h>
|
||||||
|
#include <IPAddress.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
|
||||||
|
#include <ESPFS.h>
|
||||||
|
#include <Timing.h>
|
||||||
|
#include <StatefulService.h>
|
||||||
|
#include <FSPersistence.h>
|
||||||
|
#include <stateful_service_endpoint.h>
|
||||||
|
#include <wifi_settings.h>
|
||||||
|
|
||||||
|
class WiFiService : public StatefulService<WiFiSettings> {
|
||||||
|
private:
|
||||||
|
static void getNetworks(JsonObject &root);
|
||||||
|
static void getNetworkStatus(JsonObject &root);
|
||||||
|
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
|
||||||
|
FSPersistence<WiFiSettings> _fsPersistence;
|
||||||
|
|
||||||
|
void reconfigureWiFiConnection();
|
||||||
|
void manageSTA();
|
||||||
|
void connectToWiFi();
|
||||||
|
void configureNetwork(wifi_settings_t &network);
|
||||||
|
|
||||||
|
unsigned long _lastConnectionAttempt;
|
||||||
|
bool _stopping;
|
||||||
|
|
||||||
|
constexpr static uint16_t reconnectDelay {10000};
|
||||||
|
|
||||||
|
public:
|
||||||
|
WiFiService();
|
||||||
|
~WiFiService();
|
||||||
|
|
||||||
|
void begin();
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
void setupMDNS(const char *hostname);
|
||||||
|
|
||||||
|
const char *getHostname() { return _state.hostname.c_str(); }
|
||||||
|
|
||||||
|
static esp_err_t handleScan(PsychicRequest *request);
|
||||||
|
static esp_err_t getNetworks(PsychicRequest *request);
|
||||||
|
static esp_err_t getNetworkStatus(PsychicRequest *request);
|
||||||
|
|
||||||
|
StatefulHttpEndpoint<WiFiSettings> endpoint;
|
||||||
|
};
|
||||||
+8
-83
@@ -1,60 +1,17 @@
|
|||||||
#ifndef WiFiSettingsService_h
|
#pragma once
|
||||||
#define WiFiSettingsService_h
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ESP32 SvelteKit
|
|
||||||
*
|
|
||||||
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
|
|
||||||
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
|
|
||||||
* https://github.com/theelims/ESP32-sveltekit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 - 2023 rjwats
|
|
||||||
* Copyright (C) 2023 theelims
|
|
||||||
*
|
|
||||||
* All Rights Reserved. This software may be modified and distributed under
|
|
||||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include <EventEndpoint.h>
|
|
||||||
#include <EventSocket.h>
|
|
||||||
#include <FSPersistence.h>
|
|
||||||
#include <HttpEndpoint.h>
|
|
||||||
#include <JsonUtils.h>
|
|
||||||
#include <PsychicHttp.h>
|
|
||||||
#include <SecurityManager.h>
|
|
||||||
#include <SettingValue.h>
|
|
||||||
#include <StatefulService.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiMulti.h>
|
#include <IPAddress.h>
|
||||||
#include <vector>
|
#include <ArduinoJson.h>
|
||||||
#include <Timing.h>
|
#include <JsonUtils.h>
|
||||||
#include <ESPFS.h>
|
#include <IPUtils.h>
|
||||||
|
#include <SettingValue.h>
|
||||||
#ifndef FACTORY_WIFI_SSID
|
#include <state_result.h>
|
||||||
#define FACTORY_WIFI_SSID ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_WIFI_PASSWORD
|
|
||||||
#define FACTORY_WIFI_PASSWORD ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_WIFI_HOSTNAME
|
|
||||||
#define FACTORY_WIFI_HOSTNAME "#{platform}-#{unique_id}"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FACTORY_WIFI_RSSI_THRESHOLD
|
#ifndef FACTORY_WIFI_RSSI_THRESHOLD
|
||||||
#define FACTORY_WIFI_RSSI_THRESHOLD -80
|
#define FACTORY_WIFI_RSSI_THRESHOLD -80
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WIFI_SETTINGS_SERVICE_PATH "/api/wifiSettings"
|
|
||||||
|
|
||||||
#define WIFI_RECONNECTION_DELAY 1000 * 30
|
|
||||||
#define RSSI_EVENT_DELAY 500
|
|
||||||
|
|
||||||
#define EVENT_RSSI "rssi"
|
|
||||||
#define EVENT_WIFI_SETTINGS "WiFiSettings"
|
|
||||||
|
|
||||||
// Struct defining the wifi settings
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
String ssid;
|
String ssid;
|
||||||
String password;
|
String password;
|
||||||
@@ -69,7 +26,6 @@ typedef struct {
|
|||||||
|
|
||||||
class WiFiSettings {
|
class WiFiSettings {
|
||||||
public:
|
public:
|
||||||
// core wifi configuration
|
|
||||||
String hostname;
|
String hostname;
|
||||||
bool priorityBySignalStrength;
|
bool priorityBySignalStrength;
|
||||||
std::vector<wifi_settings_t> wifiSettings;
|
std::vector<wifi_settings_t> wifiSettings;
|
||||||
@@ -185,35 +141,4 @@ class WiFiSettings {
|
|||||||
|
|
||||||
return StateUpdateResult::CHANGED;
|
return StateUpdateResult::CHANGED;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class WiFiSettingsService : public StatefulService<WiFiSettings> {
|
|
||||||
public:
|
|
||||||
WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager, EventSocket *socket);
|
|
||||||
|
|
||||||
void initWiFi();
|
|
||||||
void begin();
|
|
||||||
void loop();
|
|
||||||
String getHostname();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PsychicHttpServer *_server;
|
|
||||||
SecurityManager *_securityManager;
|
|
||||||
HttpEndpoint<WiFiSettings> _httpEndpoint;
|
|
||||||
EventEndpoint<WiFiSettings> _eventEndpoint;
|
|
||||||
FSPersistence<WiFiSettings> _fsPersistence;
|
|
||||||
EventSocket *_socket;
|
|
||||||
unsigned long _lastConnectionAttempt;
|
|
||||||
|
|
||||||
bool _stopping;
|
|
||||||
void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
void onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
|
|
||||||
void reconfigureWiFiConnection();
|
|
||||||
void manageSTA();
|
|
||||||
void connectToWiFi();
|
|
||||||
void configureNetwork(wifi_settings_t &network);
|
|
||||||
void updateRSSI();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // end WiFiSettingsService_h
|
|
||||||
Reference in New Issue
Block a user