🪄 Formats WiFiSettingsService

This commit is contained in:
Rune Harlyk
2024-07-09 19:59:35 +02:00
committed by Rune Harlyk
parent a4b41e845b
commit bec053ad18
2 changed files with 61 additions and 119 deletions
@@ -16,20 +16,18 @@
WiFiSettingsService::WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager, WiFiSettingsService::WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager,
EventSocket *socket) EventSocket *socket)
: _server(server), _securityManager(securityManager), : _server(server),
_securityManager(securityManager),
_httpEndpoint(WiFiSettings::read, WiFiSettings::update, this, server, WIFI_SETTINGS_SERVICE_PATH, securityManager, _httpEndpoint(WiFiSettings::read, WiFiSettings::update, this, server, WIFI_SETTINGS_SERVICE_PATH, securityManager,
AuthenticationPredicates::IS_ADMIN), AuthenticationPredicates::IS_ADMIN),
_eventEndpoint(WiFiSettings::read, WiFiSettings::update, this, socket, EVENT_WIFI_SETTINGS), _eventEndpoint(WiFiSettings::read, WiFiSettings::update, this, socket, EVENT_WIFI_SETTINGS),
_fsPersistence(WiFiSettings::read, WiFiSettings::update, this, fs, WIFI_SETTINGS_FILE), _lastConnectionAttempt(0), _fsPersistence(WiFiSettings::read, WiFiSettings::update, this, fs, WIFI_SETTINGS_FILE),
_socket(socket) _lastConnectionAttempt(0),
{ _socket(socket) {
addUpdateHandler([&](const String &originId) addUpdateHandler([&](const String &originId) { reconfigureWiFiConnection(); }, false);
{ reconfigureWiFiConnection(); },
false);
} }
void WiFiSettingsService::initWiFi() void WiFiSettingsService::initWiFi() {
{
WiFi.mode(WIFI_MODE_STA); // this is the default. WiFi.mode(WIFI_MODE_STA); // this is the default.
// Disable WiFi config persistance and auto reconnect // Disable WiFi config persistance and auto reconnect
@@ -46,88 +44,68 @@ void WiFiSettingsService::initWiFi()
reconfigureWiFiConnection(); reconfigureWiFiConnection();
} }
void WiFiSettingsService::begin() void WiFiSettingsService::begin() {
{
_httpEndpoint.begin(); _httpEndpoint.begin();
_eventEndpoint.begin(); _eventEndpoint.begin();
} }
void WiFiSettingsService::reconfigureWiFiConnection() void WiFiSettingsService::reconfigureWiFiConnection() {
{
// reset last connection attempt to force loop to reconnect immediately // reset last connection attempt to force loop to reconnect immediately
_lastConnectionAttempt = 0; _lastConnectionAttempt = 0;
// disconnect and de-configure wifi // disconnect and de-configure wifi
if (WiFi.disconnect(true)) if (WiFi.disconnect(true)) {
{
_stopping = true; _stopping = true;
} }
} }
void WiFiSettingsService::loop() void WiFiSettingsService::loop() {
{
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
{
_lastConnectionAttempt = currentMillis; _lastConnectionAttempt = currentMillis;
manageSTA(); manageSTA();
} }
if (!_lastRssiUpdate || (unsigned long)(currentMillis - _lastRssiUpdate) >= RSSI_EVENT_DELAY) if (!_lastRssiUpdate || (unsigned long)(currentMillis - _lastRssiUpdate) >= RSSI_EVENT_DELAY) {
{
_lastRssiUpdate = currentMillis; _lastRssiUpdate = currentMillis;
updateRSSI(); updateRSSI();
} }
} }
String WiFiSettingsService::getHostname() String WiFiSettingsService::getHostname() { return _state.hostname; }
{
return _state.hostname;
}
void WiFiSettingsService::manageSTA() void WiFiSettingsService::manageSTA() {
{
// Abort if already connected, or if we have no SSID // Abort if already connected, or if we have no SSID
if (WiFi.isConnected() || _state.wifiSettings.empty()) if (WiFi.isConnected() || _state.wifiSettings.empty()) {
{
return; return;
} }
// Connect or reconnect as required // Connect or reconnect as required
if ((WiFi.getMode() & WIFI_STA) == 0) if ((WiFi.getMode() & WIFI_STA) == 0) {
{
connectToWiFi(); connectToWiFi();
} }
} }
void WiFiSettingsService::connectToWiFi() void WiFiSettingsService::connectToWiFi() {
{
// reset availability flag for all stored networks // reset availability flag for all stored networks
for (auto &network : _state.wifiSettings) for (auto &network : _state.wifiSettings) {
{
network.available = false; network.available = false;
} }
// scanning for available networks // scanning for available networks
int scanResult = WiFi.scanNetworks(); int scanResult = WiFi.scanNetworks();
if (scanResult == WIFI_SCAN_FAILED) if (scanResult == WIFI_SCAN_FAILED) {
{
ESP_LOGE("WiFiSettingsService", "WiFi scan failed."); ESP_LOGE("WiFiSettingsService", "WiFi scan failed.");
} } else if (scanResult == 0) {
else if (scanResult == 0)
{
ESP_LOGI("WiFiSettingsService", "No networks found."); ESP_LOGI("WiFiSettingsService", "No networks found.");
} } else {
else
{
ESP_LOGI("WiFiSettingsService", "%d networks found.", scanResult); ESP_LOGI("WiFiSettingsService", "%d networks found.", scanResult);
// find the best network to connect // find the best network to connect
wifi_settings_t *bestNetwork = NULL; wifi_settings_t *bestNetwork = NULL;
int bestNetworkDb = FACTORY_WIFI_RSSI_THRESHOLD; int bestNetworkDb = FACTORY_WIFI_RSSI_THRESHOLD;
for (int i = 0; i < scanResult; ++i) for (int i = 0; i < scanResult; ++i) {
{
String ssid_scan; String ssid_scan;
int32_t rssi_scan; int32_t rssi_scan;
uint8_t sec_scan; uint8_t sec_scan;
@@ -137,18 +115,13 @@ void WiFiSettingsService::connectToWiFi()
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, 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); ESP_LOGV("WiFiSettingsService", "SSID: %s, RSSI: %d dbm", ssid_scan.c_str(), rssi_scan);
for (auto &network : _state.wifiSettings) for (auto &network : _state.wifiSettings) {
{ if (ssid_scan == network.ssid) { // SSID match
if (ssid_scan == network.ssid) if (rssi_scan > bestNetworkDb) { // best network
{ // SSID match
if (rssi_scan > bestNetworkDb)
{ // best network
bestNetworkDb = rssi_scan; bestNetworkDb = rssi_scan;
bestNetwork = &network; bestNetwork = &network;
network.available = true; network.available = true;
} } else if (rssi_scan >= FACTORY_WIFI_RSSI_THRESHOLD) { // available network
else if (rssi_scan >= FACTORY_WIFI_RSSI_THRESHOLD)
{ // available network
network.available = true; network.available = true;
} }
} }
@@ -157,25 +130,19 @@ void WiFiSettingsService::connectToWiFi()
} }
// if configured to prioritize signal strength, use the best network else use the first available network // if configured to prioritize signal strength, use the best network else use the first available network
if (_state.priorityBySignalStrength == false) if (_state.priorityBySignalStrength == false) {
{ for (auto &network : _state.wifiSettings) {
for (auto &network : _state.wifiSettings) if (network.available == true) {
{
if (network.available == true)
{
ESP_LOGI("WiFiSettingsService", "Connecting to first available network: %s", network.ssid.c_str()); ESP_LOGI("WiFiSettingsService", "Connecting to first available network: %s", network.ssid.c_str());
configureNetwork(network); configureNetwork(network);
break; break;
} }
} }
} } else if (_state.priorityBySignalStrength == true && bestNetwork) {
else if (_state.priorityBySignalStrength == true && bestNetwork)
{
ESP_LOGI("WiFiSettingsService", "Connecting to strongest network: %s", bestNetwork->ssid.c_str()); ESP_LOGI("WiFiSettingsService", "Connecting to strongest network: %s", bestNetwork->ssid.c_str());
configureNetwork(*bestNetwork); configureNetwork(*bestNetwork);
WiFi.begin(bestNetwork->ssid.c_str(), bestNetwork->password.c_str()); WiFi.begin(bestNetwork->ssid.c_str(), bestNetwork->password.c_str());
} } else // no suitable network to connect
else // no suitable network to connect
{ {
ESP_LOGI("WiFiSettingsService", "No known networks found."); ESP_LOGI("WiFiSettingsService", "No known networks found.");
} }
@@ -185,15 +152,11 @@ void WiFiSettingsService::connectToWiFi()
} }
} }
void WiFiSettingsService::configureNetwork(wifi_settings_t &network) void WiFiSettingsService::configureNetwork(wifi_settings_t &network) {
{ if (network.staticIPConfig) {
if (network.staticIPConfig)
{
// configure for static IP // configure for static IP
WiFi.config(network.localIP, network.gatewayIP, network.subnetMask, network.dnsIP1, network.dnsIP2); WiFi.config(network.localIP, network.gatewayIP, network.subnetMask, network.dnsIP1, network.dnsIP2);
} } else {
else
{
// configure for DHCP // configure for DHCP
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
} }
@@ -207,21 +170,15 @@ void WiFiSettingsService::configureNetwork(wifi_settings_t &network)
#endif #endif
} }
void WiFiSettingsService::updateRSSI() void WiFiSettingsService::updateRSSI() {
{
char buffer[4]; char buffer[4];
snprintf(buffer, sizeof(buffer), "%d", WiFi.RSSI()); snprintf(buffer, sizeof(buffer), "%d", WiFi.RSSI());
_socket->emit(EVENT_RSSI, buffer); _socket->emit(EVENT_RSSI, buffer);
} }
void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) { WiFi.disconnect(true); }
{ void WiFiSettingsService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) {
WiFi.disconnect(true); if (_stopping) {
}
void WiFiSettingsService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info)
{
if (_stopping)
{
_lastConnectionAttempt = 0; _lastConnectionAttempt = 0;
_stopping = false; _stopping = false;
} }
+18 -33
View File
@@ -54,8 +54,7 @@
#define EVENT_WIFI_SETTINGS "WiFiSettings" #define EVENT_WIFI_SETTINGS "WiFiSettings"
// Struct defining the wifi settings // Struct defining the wifi settings
typedef struct typedef struct {
{
String ssid; String ssid;
String password; String password;
bool staticIPConfig; bool staticIPConfig;
@@ -67,16 +66,14 @@ typedef struct
bool available; bool available;
} wifi_settings_t; } wifi_settings_t;
class WiFiSettings class WiFiSettings {
{
public: public:
// core wifi configuration // core wifi configuration
String hostname; String hostname;
bool priorityBySignalStrength; bool priorityBySignalStrength;
std::vector<wifi_settings_t> wifiSettings; std::vector<wifi_settings_t> wifiSettings;
static void read(WiFiSettings &settings, JsonObject &root) static void read(WiFiSettings &settings, JsonObject &root) {
{
root["hostname"] = settings.hostname; root["hostname"] = settings.hostname;
root["priority_RSSI"] = settings.priorityBySignalStrength; root["priority_RSSI"] = settings.priorityBySignalStrength;
@@ -84,8 +81,7 @@ public:
JsonArray wifiNetworks = root["wifi_networks"].to<JsonArray>(); JsonArray wifiNetworks = root["wifi_networks"].to<JsonArray>();
// iterate over the wifiSettings // iterate over the wifiSettings
for (auto &wifi : settings.wifiSettings) for (auto &wifi : settings.wifiSettings) {
{
// create JSON object for each wifi network // create JSON object for each wifi network
JsonObject wifiNetwork = wifiNetworks.add<JsonObject>(); JsonObject wifiNetwork = wifiNetworks.add<JsonObject>();
@@ -105,8 +101,7 @@ public:
ESP_LOGV("WiFiSettings", "WiFi Settings read"); ESP_LOGV("WiFiSettings", "WiFi Settings read");
} }
static StateUpdateResult update(JsonObject &root, WiFiSettings &settings) static StateUpdateResult update(JsonObject &root, WiFiSettings &settings) {
{
settings.hostname = root["hostname"] | SettingValue::format(FACTORY_WIFI_HOSTNAME); settings.hostname = root["hostname"] | SettingValue::format(FACTORY_WIFI_HOSTNAME);
settings.priorityBySignalStrength = root["priority_RSSI"] | true; settings.priorityBySignalStrength = root["priority_RSSI"] | true;
@@ -114,15 +109,12 @@ public:
// create JSON array from root // create JSON array from root
JsonArray wifiNetworks = root["wifi_networks"]; JsonArray wifiNetworks = root["wifi_networks"];
if (root["wifi_networks"].is<JsonArray>()) if (root["wifi_networks"].is<JsonArray>()) {
{
// iterate over the wifiSettings // iterate over the wifiSettings
int i = 0; int i = 0;
for (auto wifiNetwork : wifiNetworks) for (auto wifiNetwork : wifiNetworks) {
{
// max 5 wifi networks // max 5 wifi networks
if (i++ >= 5) if (i++ >= 5) {
{
ESP_LOGE("WiFiSettings", "Too many wifi networks"); ESP_LOGE("WiFiSettings", "Too many wifi networks");
break; break;
} }
@@ -131,12 +123,10 @@ public:
JsonObject wifi = wifiNetwork.as<JsonObject>(); JsonObject wifi = wifiNetwork.as<JsonObject>();
// Check if SSID length is between 1 and 31 characters and password between 0 and 64 characters // Check if SSID length is between 1 and 31 characters and password between 0 and 64 characters
if (wifi["ssid"].as<String>().length() < 1 || wifi["ssid"].as<String>().length() > 31 || wifi["password"].as<String>().length() > 64) if (wifi["ssid"].as<String>().length() < 1 || wifi["ssid"].as<String>().length() > 31 ||
{ wifi["password"].as<String>().length() > 64) {
ESP_LOGE("WiFiSettings", "SSID or password length is invalid"); ESP_LOGE("WiFiSettings", "SSID or password length is invalid");
} } else {
else
{
// add the ssid and password to the JSON object // add the ssid and password to the JSON object
wifi_settings_t wifiSettings; wifi_settings_t wifiSettings;
@@ -152,8 +142,7 @@ public:
JsonUtils::readIP(wifi, "dns_ip_2", wifiSettings.dnsIP2); JsonUtils::readIP(wifi, "dns_ip_2", wifiSettings.dnsIP2);
// Swap around the dns servers if 2 is populated but 1 is not // Swap around the dns servers if 2 is populated but 1 is not
if (IPUtils::isNotSet(wifiSettings.dnsIP1) && IPUtils::isSet(wifiSettings.dnsIP2)) if (IPUtils::isNotSet(wifiSettings.dnsIP1) && IPUtils::isSet(wifiSettings.dnsIP2)) {
{
wifiSettings.dnsIP1 = wifiSettings.dnsIP2; wifiSettings.dnsIP1 = wifiSettings.dnsIP2;
wifiSettings.dnsIP2 = INADDR_NONE; wifiSettings.dnsIP2 = INADDR_NONE;
} }
@@ -161,9 +150,9 @@ public:
// Turning off static ip config if we don't meet the minimum requirements // Turning off static ip config if we don't meet the minimum requirements
// of ipAddress, gateway and subnet. This may change to static ip only // of ipAddress, gateway and subnet. This may change to static ip only
// as sensible defaults can be assumed for gateway and subnet // as sensible defaults can be assumed for gateway and subnet
if (wifiSettings.staticIPConfig && (IPUtils::isNotSet(wifiSettings.localIP) || IPUtils::isNotSet(wifiSettings.gatewayIP) || if (wifiSettings.staticIPConfig &&
IPUtils::isNotSet(wifiSettings.subnetMask))) (IPUtils::isNotSet(wifiSettings.localIP) || IPUtils::isNotSet(wifiSettings.gatewayIP) ||
{ IPUtils::isNotSet(wifiSettings.subnetMask))) {
wifiSettings.staticIPConfig = false; wifiSettings.staticIPConfig = false;
} }
@@ -175,12 +164,9 @@ public:
i++; i++;
} }
} }
} } else {
else
{
// populate with factory defaults if they are present // populate with factory defaults if they are present
if (String(FACTORY_WIFI_SSID).length() > 0) if (String(FACTORY_WIFI_SSID).length() > 0) {
{
settings.wifiSettings.push_back(wifi_settings_t { settings.wifiSettings.push_back(wifi_settings_t {
.ssid = FACTORY_WIFI_SSID, .ssid = FACTORY_WIFI_SSID,
.password = FACTORY_WIFI_PASSWORD, .password = FACTORY_WIFI_PASSWORD,
@@ -200,8 +186,7 @@ public:
}; };
}; };
class WiFiSettingsService : public StatefulService<WiFiSettings> class WiFiSettingsService : public StatefulService<WiFiSettings> {
{
public: public:
WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager, EventSocket *socket); WiFiSettingsService(PsychicHttpServer *server, FS *fs, SecurityManager *securityManager, EventSocket *socket);