From 555b3efd8dfb75716ef5da69d3e6d47e3de7c7a9 Mon Sep 17 00:00:00 2001 From: rjwats Date: Sat, 30 May 2020 09:47:24 +0100 Subject: [PATCH] Access point fixes (#137) * add lingering mode to access point fix bug which prevents active access point from being re-configured --- interface/src/ap/APModes.ts | 4 ++-- interface/src/ap/APSettingsForm.tsx | 8 ++++---- interface/src/ap/APStatus.ts | 28 +++++++++++++++++++++++----- interface/src/ap/types.ts | 12 +++++++++--- lib/framework/APSettingsService.cpp | 23 +++++++++++++++++------ lib/framework/APSettingsService.h | 24 +++++++++++++++++++----- lib/framework/APStatus.cpp | 6 +++--- lib/framework/APStatus.h | 4 +++- lib/framework/ESP8266React.cpp | 2 +- 9 files changed, 81 insertions(+), 30 deletions(-) diff --git a/interface/src/ap/APModes.ts b/interface/src/ap/APModes.ts index 95c9ebe..6a705db 100644 --- a/interface/src/ap/APModes.ts +++ b/interface/src/ap/APModes.ts @@ -1,5 +1,5 @@ -import { APSettings, ApProvisionMode } from "./types"; +import { APSettings, APProvisionMode } from "./types"; export const isAPEnabled = ({ provision_mode }: APSettings) => { - return provision_mode === ApProvisionMode.AP_MODE_ALWAYS || provision_mode === ApProvisionMode.AP_MODE_DISCONNECTED; + return provision_mode === APProvisionMode.AP_MODE_ALWAYS || provision_mode === APProvisionMode.AP_MODE_DISCONNECTED; } diff --git a/interface/src/ap/APSettingsForm.tsx b/interface/src/ap/APSettingsForm.tsx index f007de2..40f4093 100644 --- a/interface/src/ap/APSettingsForm.tsx +++ b/interface/src/ap/APSettingsForm.tsx @@ -7,7 +7,7 @@ import SaveIcon from '@material-ui/icons/Save'; import {PasswordValidator, RestFormProps, FormActions, FormButton} from '../components'; import { isAPEnabled } from './APModes'; -import { APSettings, ApProvisionMode } from './types'; +import { APSettings, APProvisionMode } from './types'; type APSettingsFormProps = RestFormProps; @@ -24,9 +24,9 @@ class APSettingsForm extends React.Component { variant="outlined" onChange={handleValueChange('provision_mode')} margin="normal"> - Always - When WiFi Disconnected - Never + Always + When WiFi Disconnected + Never { isAPEnabled(data) && diff --git a/interface/src/ap/APStatus.ts b/interface/src/ap/APStatus.ts index 8fc369d..c35cadc 100644 --- a/interface/src/ap/APStatus.ts +++ b/interface/src/ap/APStatus.ts @@ -1,10 +1,28 @@ import { Theme } from "@material-ui/core"; -import { APStatus } from "./types"; +import { APStatus, APNetworkStatus } from "./types"; -export const apStatusHighlight = ({ active }: APStatus, theme: Theme) => { - return active ? theme.palette.success.main : theme.palette.info.main; +export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => { + switch (status) { + case APNetworkStatus.ACTIVE: + return theme.palette.success.main; + case APNetworkStatus.INACTIVE: + return theme.palette.info.main; + case APNetworkStatus.LINGERING: + return theme.palette.warning.main; + default: + return theme.palette.warning.main; + } } -export const apStatus = ({ active }: APStatus) => { - return active ? "Active" : "Inactive"; +export const apStatus = ({ status }: APStatus) => { + switch (status) { + case APNetworkStatus.ACTIVE: + return "Active"; + case APNetworkStatus.INACTIVE: + return "Inactive"; + case APNetworkStatus.LINGERING: + return "Lingering until idle"; + default: + return "Unknown"; + } }; diff --git a/interface/src/ap/types.ts b/interface/src/ap/types.ts index bcf4620..a3b80ae 100644 --- a/interface/src/ap/types.ts +++ b/interface/src/ap/types.ts @@ -1,18 +1,24 @@ -export enum ApProvisionMode { +export enum APProvisionMode { AP_MODE_ALWAYS = 0, AP_MODE_DISCONNECTED = 1, AP_NEVER = 2 } +export enum APNetworkStatus { + ACTIVE = 0, + INACTIVE = 1, + LINGERING = 2 +} + export interface APStatus { - active: boolean; + status: APNetworkStatus; ip_address: string; mac_address: string; station_num: number; } export interface APSettings { - provision_mode: ApProvisionMode; + provision_mode: APProvisionMode; ssid: string; password: string; } diff --git a/lib/framework/APSettingsService.cpp b/lib/framework/APSettingsService.cpp index 677e972..8376b3d 100644 --- a/lib/framework/APSettingsService.cpp +++ b/lib/framework/APSettingsService.cpp @@ -4,7 +4,8 @@ APSettingsService::APSettingsService(AsyncWebServer* server, FS* fs, SecurityMan _httpEndpoint(APSettings::read, APSettings::update, this, server, AP_SETTINGS_SERVICE_PATH, securityManager), _fsPersistence(APSettings::read, APSettings::update, this, fs, AP_SETTINGS_FILE), _dnsServer(nullptr), - _lastManaged(0) { + _lastManaged(0), + _reconfigureAp(false) { addUpdateHandler([&](const String& originId) { reconfigureAP(); }, false); } @@ -15,6 +16,7 @@ void APSettingsService::begin() { void APSettingsService::reconfigureAP() { _lastManaged = millis() - MANAGE_NETWORK_DELAY; + _reconfigureAp = true; } void APSettingsService::loop() { @@ -31,14 +33,14 @@ void APSettingsService::manageAP() { WiFiMode_t currentWiFiMode = WiFi.getMode(); if (_state.provisionMode == AP_MODE_ALWAYS || (_state.provisionMode == AP_MODE_DISCONNECTED && WiFi.status() != WL_CONNECTED)) { - if (currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) { + if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) { startAP(); } - } else { - if (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA) { - stopAP(); - } + } else if ((currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA) && + (_reconfigureAp || !WiFi.softAPgetStationNum())) { + stopAP(); } + _reconfigureAp = false; } void APSettingsService::startAP() { @@ -69,3 +71,12 @@ void APSettingsService::handleDNS() { _dnsServer->processNextRequest(); } } + +APNetworkStatus APSettingsService::getAPNetworkStatus() { + WiFiMode_t currentWiFiMode = WiFi.getMode(); + bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA; + if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) { + return APNetworkStatus::LINGERING; + } + return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE; +} diff --git a/lib/framework/APSettingsService.h b/lib/framework/APSettingsService.h index 45fb547..c2bbe73 100644 --- a/lib/framework/APSettingsService.h +++ b/lib/framework/APSettingsService.h @@ -30,6 +30,12 @@ #define AP_SETTINGS_FILE "/config/apSettings.json" #define AP_SETTINGS_SERVICE_PATH "/rest/apSettings" +enum APNetworkStatus { + ACTIVE = 0, + INACTIVE, + LINGERING +}; + class APSettings { public: uint8_t provisionMode; @@ -43,17 +49,23 @@ class APSettings { } static StateUpdateResult update(JsonObject& root, APSettings& settings) { - settings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE; + APSettings newSettings = {}; + newSettings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE; switch (settings.provisionMode) { case AP_MODE_ALWAYS: case AP_MODE_DISCONNECTED: case AP_MODE_NEVER: break; default: - settings.provisionMode = AP_MODE_ALWAYS; + newSettings.provisionMode = AP_MODE_ALWAYS; + } + newSettings.ssid = root["ssid"] | FACTORY_AP_SSID; + newSettings.password = root["password"] | FACTORY_AP_PASSWORD; + if (newSettings.provisionMode == settings.provisionMode && newSettings.ssid.equals(settings.ssid) && + newSettings.password.equals(settings.password)) { + return StateUpdateResult::UNCHANGED; } - settings.ssid = root["ssid"] | FACTORY_AP_SSID; - settings.password = root["password"] | FACTORY_AP_PASSWORD; + settings = newSettings; return StateUpdateResult::CHANGED; } }; @@ -64,6 +76,7 @@ class APSettingsService : public StatefulService { void begin(); void loop(); + APNetworkStatus getAPNetworkStatus(); private: HttpEndpoint _httpEndpoint; @@ -73,7 +86,8 @@ class APSettingsService : public StatefulService { DNSServer* _dnsServer; // for the mangement delay loop - unsigned long _lastManaged; + volatile unsigned long _lastManaged; + volatile boolean _reconfigureAp; void reconfigureAP(); void manageAP(); diff --git a/lib/framework/APStatus.cpp b/lib/framework/APStatus.cpp index 17b66b5..5bfe300 100644 --- a/lib/framework/APStatus.cpp +++ b/lib/framework/APStatus.cpp @@ -1,6 +1,7 @@ #include -APStatus::APStatus(AsyncWebServer* server, SecurityManager* securityManager) { +APStatus::APStatus(AsyncWebServer* server, SecurityManager* securityManager, APSettingsService* apSettingsService) : + _apSettingsService(apSettingsService) { server->on(AP_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), @@ -11,8 +12,7 @@ void APStatus::apStatus(AsyncWebServerRequest* request) { AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AP_STATUS_SIZE); JsonObject root = response->getRoot(); - WiFiMode_t currentWiFiMode = WiFi.getMode(); - root["active"] = (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA); + root["status"] = _apSettingsService->getAPNetworkStatus(); root["ip_address"] = WiFi.softAPIP().toString(); root["mac_address"] = WiFi.softAPmacAddress(); root["station_num"] = WiFi.softAPgetStationNum(); diff --git a/lib/framework/APStatus.h b/lib/framework/APStatus.h index 54f90e9..12620b0 100644 --- a/lib/framework/APStatus.h +++ b/lib/framework/APStatus.h @@ -14,15 +14,17 @@ #include #include #include +#include #define MAX_AP_STATUS_SIZE 1024 #define AP_STATUS_SERVICE_PATH "/rest/apStatus" class APStatus { public: - APStatus(AsyncWebServer* server, SecurityManager* securityManager); + APStatus(AsyncWebServer* server, SecurityManager* securityManager, APSettingsService* apSettingsService); private: + APSettingsService* _apSettingsService; void apStatus(AsyncWebServerRequest* request); }; diff --git a/lib/framework/ESP8266React.cpp b/lib/framework/ESP8266React.cpp index 6ddcf9f..ba9b09c 100644 --- a/lib/framework/ESP8266React.cpp +++ b/lib/framework/ESP8266React.cpp @@ -13,7 +13,7 @@ ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs) : _wifiScanner(server, &_securitySettingsService), _wifiStatus(server, &_securitySettingsService), _ntpStatus(server, &_securitySettingsService), - _apStatus(server, &_securitySettingsService), + _apStatus(server, &_securitySettingsService, &_apSettingsService), _mqttStatus(server, &_mqttSettingsService, &_securitySettingsService), _systemStatus(server, &_securitySettingsService) { #ifdef PROGMEM_WWW