[WiFi] Simplify state machine for WiFi STA

This commit is contained in:
TD-er
2026-06-10 14:51:39 +02:00
parent f527920019
commit 757d8a1668
11 changed files with 375 additions and 367 deletions
@@ -246,12 +246,16 @@ void NWPluginData_static_runtime::processEvents()
if (connected_changed || establishConnect_changed)
{
if (_connectedStats.isOn()) {
log_connected();
if (_establishConnectStats.isSet()) {
if (_connectedStats.isOn()) {
log_connected();
// _establishConnectStats.resetCount();
} else if (_connectedStats.isOff() && !_establishConnectStats.isOn()) {
log_disconnected();
// _establishConnectStats.resetCount();
} else if (_establishConnectStats.isSet() &&
_connectedStats.isOff() &&
!_establishConnectStats.isOn()) {
log_disconnected();
}
}
}
@@ -0,0 +1,54 @@
StateDiagram [frame=true framecolor=steelblue label="State Diagram ESPEasy WiFi_STA_State_e"] {
state Disabled
state TimeOut
state Idle
state IdleWaiting
state STA_Scanning
state STA_AP_Scanning
state STA_Connecting
state STA_Reconnecting
state STA_Connected
choice AlreadyConnected
choice AP_on_no_nw_found
choice KnownAPfound
choice KnownAPonDisconnect
choice ExitSTA
initialState->Disabled
Disabled -> IdleWaiting "Init STA"
Disabled <- ExitSTA "Exit STA"
IdleWaiting -> AlreadyConnected "Already\nConnected?"
AlreadyConnected -> STA_Connected "Connected"
AlreadyConnected -> Idle "Ready"
Idle -> KnownAPfound "Known\nNetwork\nfound?"
KnownAPfound -> AP_on_no_nw_found "Scan\nNeeded"
KnownAPfound -> STA_Connecting "No Scan\nNeeded"
AP_on_no_nw_found -> STA_AP_Scanning "AP"
AP_on_no_nw_found -> STA_Scanning "No AP"
STA_Connecting -> STA_Connected
STA_Reconnecting -> STA_Connected
KnownAPonDisconnect -> STA_Reconnecting "No Scan\nNeeded"
KnownAPonDisconnect <- STA_Connected "Disconnect"
IdleWaiting <- KnownAPonDisconnect "Scan\nNeeded"
IdleWaiting <- STA_Scanning "Scan\nDone"
IdleWaiting <- STA_AP_Scanning "Scan\nDone"
STA_AP_Scanning <- STA_AP_Scanning "Next\nChannel"
TimeOut <- STA_Scanning "Scan\nFail"
TimeOut <- STA_AP_Scanning "Scan\nFail"
TimeOut <- STA_Connecting "Connect\nFail"
TimeOut -> IdleWaiting
IdleWaiting <- IdleWaiting "Wait for\nStartup Delay/\nSetup"
TimeOut <- STA_Reconnecting "Reconnect\nFail"
}
@@ -0,0 +1,38 @@
StateDiagram [frame=true framecolor=steelblue label="State Diagram ESPEasyWiFi_mode_e"] {
state Off
state CredentialsUpdated
state STA_only
state STA_AP
state AP_only
state Setup
choice AllowSetup
choice HasCredentials
choice HasCredentialsSetupAllowed
choice APalwaysOn
choice APalwaysOnNoCred
initialState->Off
Off -> AllowSetup "Check\nAllowSetup"
AllowSetup -> HasCredentials "Setup not\nAllowed"
HasCredentials -> APalwaysOn "Has\nCredentials"
APalwaysOn -> STA_AP "AP"
APalwaysOn -> STA_only "No AP"
HasCredentials -> APalwaysOnNoCred "No\nCredentials"
APalwaysOnNoCred -> Off "No AP"
APalwaysOnNoCred -> AP_only "AP"
AllowSetup -> HasCredentialsSetupAllowed "Setup\nAllowed"
HasCredentialsSetupAllowed -> Setup "No\nCredentials"
HasCredentialsSetupAllowed -> APalwaysOn "Has\nCredentials"
CredentialsUpdated <- Setup "Setup\nDone"
CredentialsUpdated -> AllowSetup
STA_AP -> AP_only "No Known\nNetwork found"
STA_AP <- STA_AP "Retry/\nReconnect"
STA_only <- STA_only "Retry/\nReconnect"
}
+169 -307
View File
@@ -1,5 +1,5 @@
#include "../wifi/ESPEasyWiFi_state_machine.h"
#include "ESPEasy/net/wifi/WiFi_State.h"
#include "ESPEasy/net/wifi/WiFi_STA_State.h"
#if FEATURE_WIFI
@@ -27,6 +27,9 @@ namespace wifi {
void ESPEasyWiFi_t::setup() {
if (!Settings.getNetworkEnabled(NETWORK_INDEX_WIFI_STA)) { return; }
WiFi_AP_Candidates.clearCache();
WiFi_AP_Candidates.load_knownCredentials();
// TODO TD-er: Must maybe also call 'disable()' first?
// TODO TD-er: Load settings
@@ -43,28 +46,13 @@ void ESPEasyWiFi_t::setup() {
void ESPEasyWiFi_t::enable() {}
void ESPEasyWiFi_t::disable() { setState(WiFiState_e::Disabled, 100); }
void ESPEasyWiFi_t::disable() { setState(WiFi_STA_State_e::Disabled, 100); }
void ESPEasyWiFi_t::begin() {
if (connected()) setState(WiFiState_e::STA_Connected);
if (WiFi_AP_Candidates.hasCandidates()) {
setState(WiFiState_e::IdleWaiting, 100);
if (connected()) {
setState(WiFi_STA_State_e::STA_Connected, 0);
} else {
if (WiFi_AP_Candidates.hasScanned()) {
// Has no candidates, but scan was performed.
if (shouldStartAP_fallback()) {
setState(WiFiState_e::AP_only, WIFI_STATE_MACHINE_AP_ONLY_TIMEOUT);
}
} else {
if (WifiIsAP(WiFi.getMode())) {
// TODO TD-er: Must check if any client is connected.
// If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning
setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT);
} else {
// setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT);
setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT);
}
}
setState(WiFi_STA_State_e::IdleWaiting, 100);
}
}
@@ -75,245 +63,118 @@ void ESPEasyWiFi_t::loop()
if (!wifi_STA_data) { return; }
if (_state != WiFiState_e::IdleWaiting) {
if ((_state != WiFi_STA_State_e::IdleWaiting) &&
(_state != WiFi_STA_State_e::TimeOut)) {
if (_callbackError ||
(_state_timeout.isSet() && _state_timeout.timeReached()))
{
// TODO TD-er: Must check what error was given???
_callbackError = false;
if (getMode() == ESPEasyWiFi_mode_e::Setup /* && _state == WiFiState_e::AP_Fallback */) {
setState(_state == WiFiState_e::STA_Connected_Setup ? WiFiState_e::STA_Connected : WiFiState_e::IdleWaiting);
} else {
setState(WiFiState_e::WiFiOFF, 100);
}
// TODO TD-er: Must perhaps check what action was pending and act on it?
setState(WiFi_STA_State_e::TimeOut, 100);
return;
}
}
switch (_state)
{
case WiFiState_e::Disabled:
case WiFi_STA_State_e::Disabled:
// Do nothing here, as the device is disabled.
break;
case WiFiState_e::WiFiOFF:
begin();
// setState(WiFiState_e::IdleWaiting, 100);
case WiFi_STA_State_e::TimeOut:
// TODO TD-er: Not sure yet what else to do here.
setState(WiFi_STA_State_e::IdleWaiting, 100);
break;
case WiFiState_e::AP_only:
case WiFiState_e::AP_Fallback:
case WiFi_STA_State_e::IdleWaiting:
// TODO TD-er: Should also check for 'setup' mode, so we switch to connecting state instead of IdleWaiting
// For sure not just when there are candidates.
if (!ESPEasy::net::wifi::wifiAPmodeActivelyUsed()) {
if (WiFi_AP_Candidates.hasCandidates() ||
_state_timeout.timeReached()) {
setState(WiFiState_e::IdleWaiting, 100);
}
}
// TODO TD-er: Must check whether we are allowed to continue
setState(WiFi_STA_State_e::Idle, 100);
break;
case WiFiState_e::IdleWaiting:
if (connected()) {
if (getMode() == ESPEasyWiFi_mode_e::Setup) {
setState(WiFiState_e::STA_Connected_Setup, 60000);
}
else {
setState(WiFiState_e::STA_Connected, 100);
}
break;
}
if (_state_timeout.timeReached() || (getSTA_connected_state() == STA_connected_state::Idle)) {
// This is where we decide what to do next:
// - Reconnect
// - Scan
//
// Do we have candidate to connect to ?
if (WiFi_AP_Candidates.hasCandidates()) {
setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else if ((WiFi_AP_Candidates.scanComplete() == 0)
|| (WiFi_AP_Candidates.scanComplete() == -3)) {
if (WifiIsAP(WiFi.getMode())) {
// TODO TD-er: Must check if any client is connected.
// If not, then we can disable AP mode and switch to WiFiState_e::STA_Scanning
setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT);
} else {
// setState(WiFiState_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT);
setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT);
}
// Move up?
} else if (!WiFi_AP_Candidates.hasCandidateCredentials() ||
!Settings.DoNotStartAPfallback_ConnectFail()) {
if (!WiFi_AP_Candidates.hasCandidateCredentials()
// && !WiFiEventData.warnedNoValidWiFiSettings
)
{
// Check for whether No Valid WiFi settings was already logged
static uint32_t lastTimeLoggedNoWiFiCredentials = 0;
if (timePassedSince(lastTimeLoggedNoWiFiCredentials) > 5000) {
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings"));
lastTimeLoggedNoWiFiCredentials = millis();
}
// WiFiEventData.warnedNoValidWiFiSettings = true;
}
wifi_STA_data->mark_connect_failed();
wifi_STA_data->_establishConnectStats.clear();
// WiFiEventData.wifiConnectAttemptNeeded = false;
// end move up??
}
}
case WiFi_STA_State_e::Idle:
// All done when setState was called
// Just a placeholder in the loop()
break;
case WiFiState_e::STA_Scanning:
case WiFi_STA_State_e::STA_Scanning:
case WiFi_STA_State_e::STA_AP_Scanning:
{
// -1 if scan not finished
auto scanCompleteStatus = WiFi_AP_Candidates.scanComplete();
if (scanCompleteStatus >= 0) {
WiFi_AP_Candidates.load_knownCredentials();
WiFi_AP_Candidates.process_WiFiscan();
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(
F("WiFi : Scan done, found %d APs"),
WiFi_AP_Candidates.scanComplete()));
# endif // ifndef BUILD_NO_DEBUG
} else if (scanCompleteStatus == -2) { // WIFI_SCAN_FAILED
addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed"));
// WiFi.scanDelete();
setState(WiFiState_e::WiFiOFF, 1000);
}
if (_state_timeout.timeReached() || (scanCompleteStatus >= 0)) {
// WiFi.scanDelete();
if (_state_timeout.timeReached()) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout"));
# endif
}
if (WiFi_AP_Candidates.hasCandidates()) {
setState(WiFiState_e::WiFiOFF, 100);
} else {
// FIXME TD-er: This might not be a responsibility of this state machine....
if (shouldStartAP_fallback()) {
setState(WiFiState_e::AP_Fallback, Settings.APfallback_minimal_on_time_sec() * 1000);
// TODO TD-er: Must keep track of whether the user has forced AP to be autostarted.
} else {
setState(WiFiState_e::WiFiOFF, 1000);
}
}
}
break;
}
case WiFiState_e::STA_AP_Scanning:
{
// -1 if scan not finished
auto scanCompleteStatus = WiFi_AP_Candidates.scanComplete();
if (scanCompleteStatus >= 0) {
WiFi_AP_Candidates.load_knownCredentials();
WiFi_AP_Candidates.process_WiFiscan();
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(
F("WiFi : Scan channel %d done, found %d APs"),
_scan_channel,
WiFi_AP_Candidates.scanComplete()));
# endif // ifndef BUILD_NO_DEBUG
} else if (scanCompleteStatus == -2) { // WIFI_SCAN_FAILED
addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed"));
// WiFi.scanDelete();
setState(WiFiState_e::WiFiOFF, 1000);
}
if (_state_timeout.timeReached() || (scanCompleteStatus >= 0)) {
// WiFi.scanDelete();
if (_state_timeout.timeReached()) {
# ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_ERROR, F("WiFi : Scan Running Timeout"));
# endif
}
++_scan_channel;
if (_scan_channel > 14) {
_scan_channel = 0;
if (!WiFi_AP_Candidates.hasCandidateCredentials() &&
!Settings.DoNotStartAPfallback_ConnectFail()) {
if (shouldStartAP_fallback()) {
setState(WiFiState_e::AP_Fallback, Settings.APfallback_minimal_on_time_sec() * 1000);
} else {
setState(WiFiState_e::AP_only, WIFI_STATE_MACHINE_AP_ONLY_TIMEOUT);
}
} else {
setState(WiFiState_e::WiFiOFF, 100);
}
}
else {
setState(WiFiState_e::STA_AP_Scanning, 500);
}
}
break;
// Check if scanning is finished
// When scanning per channel, call for scanning next channel
if (scanCompleteStatus >= 0) {
WiFi_AP_Candidates.load_knownCredentials();
WiFi_AP_Candidates.process_WiFiscan();
# ifndef BUILD_NO_DEBUG
if (_state == WiFi_STA_State_e::STA_Scanning) {
addLog(LOG_LEVEL_INFO, strformat(
F("WiFi : Scan done, found %d APs"),
scanCompleteStatus));
} else {
addLog(LOG_LEVEL_INFO, strformat(
F("WiFi : Scan channel %d done, found %d APs"),
_scan_channel,
scanCompleteStatus));
}
# endif // ifndef BUILD_NO_DEBUG
if (_state == WiFi_STA_State_e::STA_AP_Scanning) {
++_scan_channel;
if (_scan_channel > 14) {
_scan_channel = 0;
setState(WiFi_STA_State_e::IdleWaiting, 100);
}
else {
setState(WiFi_STA_State_e::STA_AP_Scanning, 500);
}
} else {
setState(WiFi_STA_State_e::IdleWaiting, 100);
}
} else if (scanCompleteStatus == -2) { // WIFI_SCAN_FAILED
addLog(LOG_LEVEL_ERROR, F("WiFi : Scan failed"));
// WiFi.scanDelete();
setState(WiFi_STA_State_e::TimeOut, 1000);
}
break;
}
case WiFiState_e::STA_Connecting:
case WiFiState_e::STA_Reconnecting:
case WiFi_STA_State_e::STA_Connecting:
case WiFi_STA_State_e::STA_Reconnecting:
// Check if (re)connecting has finished
{
const STA_connected_state sta_connected_state = getSTA_connected_state();
if (sta_connected_state == STA_connected_state::Connected) {
if (getMode() == ESPEasyWiFi_mode_e::Setup) {
setState(WiFiState_e::STA_Connected_Setup, 60000);
}
else {
setState(WiFiState_e::STA_Connected, 100);
}
} else if (_state_timeout.timeReached()) {
if (_state == WiFiState_e::STA_Connecting) {
setState(WiFiState_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else {
wifi_STA_data->mark_connect_failed();
setState(WiFiState_e::WiFiOFF, 100);
}
setState(WiFi_STA_State_e::STA_Connected, 0);
}
break;
}
case WiFiState_e::STA_Connected:
case WiFi_STA_State_e::STA_Connected:
// Check if still connected
if (getSTA_connected_state() != STA_connected_state::Connected) {
// setState(WiFiState_e::WiFiOFF);
auto wifi_STA_data = getWiFi_STA_NWPluginData_static_runtime();
if (wifi_STA_data)
wifi_STA_data->mark_disconnected();
if (WiFi.status() == WL_CONNECTED) {
WiFi.disconnect(true);
}
if (WiFi_AP_Candidates.hasCandidates()) {
setState(WiFiState_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
setState(WiFi_STA_State_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else {
setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT);
setState(WiFi_STA_State_e::IdleWaiting, 100);
}
/*
if (Settings.UseRules)
{
eventQueue.addDeDup(F("WiFi#Disconnected"));
}
statusLED(false);
*/
} else {
// Else mark last timestamp seen as connected
_last_seen_connected.setNow();
@@ -338,23 +199,12 @@ bool ESPEasyWiFi_t::connected() const
void ESPEasyWiFi_t::disconnect() { doWiFiDisconnect(); }
void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) {
void ESPEasyWiFi_t::setState(WiFi_STA_State_e newState, uint32_t timeout) {
if (newState == _state) { return; }
//# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(
LOG_LEVEL_INFO,
concat(F("WiFi : Set state from: "), toString(_state)) +
concat(F(" to: "), toString(newState)) +
concat(F(" timeout: "), timeout));
}
//# endif // ifndef BUILD_NO_DEBUG
const WiFi_STA_State_e oldState = _state;
const WiFiState_e oldState = _state;
// Need to set the newState first as some of the functions below will call
// Need to set the newState first as some of the functions below will call
// setState, causing a loop, or calling to change state multiple times.
@@ -369,73 +219,100 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) {
_last_state_change.setNow();
_state = newState;
// # ifndef BUILD_NO_DEBUG
if (oldState == WiFiState_e::STA_Connected)
{
auto wifi_STA_data = getWiFi_STA_NWPluginData_static_runtime();
if (wifi_STA_data) {
wifi_STA_data->mark_disconnected();
if (WiFi.status() == WL_CONNECTED) {
WiFi.disconnect(true);
}
}
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(
LOG_LEVEL_INFO,
concat(F("WiFi : Set state from: "), toString(oldState)) +
concat(F(" to: "), toString(newState)) +
concat(F(" timeout: "), timeout));
}
if ((oldState == WiFiState_e::STA_AP_Scanning) ||
(oldState == WiFiState_e::STA_Scanning))
// # endif // ifndef BUILD_NO_DEBUG
if (oldState == WiFi_STA_State_e::STA_Connected)
{}
if ((oldState == WiFi_STA_State_e::STA_AP_Scanning) ||
(oldState == WiFi_STA_State_e::STA_Scanning))
{
WiFi_AP_Candidates.load_knownCredentials();
WiFi_AP_Candidates.process_WiFiscan();
}
if ((oldState == WiFiState_e::AP_only) ||
(oldState == WiFiState_e::AP_Fallback)) {
Scheduler.setNetworkExitTimer(0, NETWORK_INDEX_WIFI_AP);
// setAP(false);
}
switch (newState)
{
case WiFiState_e::Disabled:
case WiFi_STA_State_e::Disabled:
// Do nothing here, as the device is disabled.
// TODO TD-er: Maybe call scheduler?
// if (doWifiIsSTA(WiFi.getMode()))
// Scheduler.setNetworkExitTimer(0, NETWORK_INDEX_WIFI_STA);
WifiDisconnect();
setSTA(false);
break;
case WiFiState_e::WiFiOFF:
// TODO TD-er: Must cancel all and turn off WiFi.
if (doWifiIsAP(WiFi.getMode()))
Scheduler.setNetworkExitTimer(0, NETWORK_INDEX_WIFI_AP);
/*
if (doWifiIsSTA(WiFi.getMode()))
Scheduler.setNetworkExitTimer(0, NETWORK_INDEX_WIFI_STA);
*/
setSTA_AP(false, false);
break;
case WiFiState_e::AP_only:
case WiFiState_e::AP_Fallback:
Scheduler.setNetworkInitTimer(0, NETWORK_INDEX_WIFI_AP);
break;
case WiFiState_e::IdleWaiting:
// Do nothing here as we're waiting till the timeout is over
break;
case WiFiState_e::STA_AP_Scanning:
case WiFi_STA_State_e::TimeOut:
{
auto wifi_STA_data = getWiFi_STA_NWPluginData_static_runtime();
if (oldState == WiFi_STA_State_e::STA_Connecting) {
if (wifi_STA_data) {
wifi_STA_data->mark_connect_failed();
}
setState(WiFi_STA_State_e::STA_Reconnecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else if (oldState == WiFi_STA_State_e::STA_Reconnecting) {
if (wifi_STA_data) {
wifi_STA_data->mark_connect_failed();
}
}
setState(WiFi_STA_State_e::IdleWaiting, 100);
break;
}
case WiFi_STA_State_e::IdleWaiting:
if (connected()) {
setState(WiFi_STA_State_e::STA_Connected);
}
// Nothing else to do here as we're waiting till the timeout is over
break;
case WiFi_STA_State_e::Idle:
if (!doWifiIsSTA(WiFi.getMode()))
Scheduler.setNetworkInitTimer(0, NETWORK_INDEX_WIFI_STA);
// This is where we decide what to do next:
// - Reconnect
// - Scan
//
// Do we have candidate to connect to ?
if (WiFi_AP_Candidates.hasCandidates()) {
setState(WiFi_STA_State_e::STA_Connecting, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else {
// No known candidates, so need to scan first.
if (WifiIsAP(WiFi.getMode())) {
// TODO TD-er: Must check if any client is connected.
// If not, then we can disable AP mode and switch to WiFi_STA_State_e::STA_Scanning
setState(WiFi_STA_State_e::STA_AP_Scanning, WIFI_STATE_MACHINE_STA_AP_SCANNING_TIMEOUT);
} else {
setState(WiFi_STA_State_e::STA_Scanning, WIFI_STATE_MACHINE_STA_SCANNING_TIMEOUT);
}
}
break;
case WiFi_STA_State_e::STA_AP_Scanning:
// Start scanning per channel
if (_scan_channel == 0) { _scan_channel = 1; }
// break;
case WiFiState_e::STA_Scanning:
// fall through
case WiFi_STA_State_e::STA_Scanning:
// Start scanning
startScanning();
break;
case WiFiState_e::STA_Connecting:
case WiFiState_e::STA_Reconnecting:
case WiFi_STA_State_e::STA_Connecting:
case WiFi_STA_State_e::STA_Reconnecting:
// Start connecting
++_connect_attempt;
@@ -443,28 +320,12 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) {
if (!connectSTA()) {
// TODO TD-er: Must keep track of failed attempts and start AP when either no credentials present or nr. of attempts failed > some
// threshold.
if (!WiFi_AP_Candidates.hasCandidates()) {
setState(WiFiState_e::STA_Scanning, WIFI_STATE_MACHINE_STA_CONNECTING_TIMEOUT);
} else {
setState(WiFiState_e::IdleWaiting, 100);
}
addLog(LOG_LEVEL_ERROR, F("WiFi : Connect STA failed"));
setState(WiFi_STA_State_e::TimeOut, 100);
}
break;
case WiFiState_e::STA_Connected_Setup:
{
Scheduler.setNetworkInitTimer(0, NETWORK_INDEX_WIFI_AP);
_last_seen_connected.setNow();
auto wifi_STA_data = getWiFi_STA_NWPluginData_static_runtime();
if (wifi_STA_data) {
wifi_STA_data->mark_connected();
}
break;
}
case WiFiState_e::STA_Connected:
case WiFi_STA_State_e::STA_Connected:
{
# ifdef ESP32
@@ -472,10 +333,6 @@ void ESPEasyWiFi_t::setState(WiFiState_e newState, uint32_t timeout) {
// WiFi.STA.setDefault();
# endif // ifdef ESP32
if (oldState == WiFiState_e::STA_Connected_Setup) {
Scheduler.setNetworkExitTimer(0, NETWORK_INDEX_WIFI_AP);
setMode(ESPEasyWiFi_mode_e::STA_only);
}
_connect_attempt = 0;
_last_seen_connected.setNow();
_state_timeout.clear();
@@ -509,7 +366,7 @@ void ESPEasyWiFi_t::checkConnectProgress() {}
void ESPEasyWiFi_t::startScanning()
{
_state = _scan_channel == 0 ? WiFiState_e::STA_Scanning : WiFiState_e::STA_AP_Scanning;
_state = _scan_channel == 0 ? WiFi_STA_State_e::STA_Scanning : WiFi_STA_State_e::STA_AP_Scanning;
setSTA(true);
WifiScan(true, _scan_channel);
_last_state_change.setNow();
@@ -690,8 +547,13 @@ bool ESPEasyWiFi_t::shouldStartAP_fallback() const
bool ESPEasyWiFi_t::shouldRedirectTo_setup() const
{
if (!Settings.ApCaptivePortal()) return false;
if (Settings.StartAPfallback_NoCredentials() && !SecuritySettings.hasWiFiCredentials()) {
if (!Settings.ApCaptivePortal()) { return false; }
if (Settings.StartAPfallback_NoCredentials()
&& !WiFi_AP_Candidates.hasCandidateCredentials()
// && !SecuritySettings.hasWiFiCredentials()
) {
return true;
}
@@ -7,7 +7,7 @@
# include "../../../src/Helpers/LongTermTimer.h"
# include "../wifi/WiFi_STA_connected_state.h"
# include "../wifi/WiFi_State.h"
# include "../wifi/WiFi_STA_State.h"
# include <IPAddress.h>
@@ -63,7 +63,7 @@ public:
// Process the state machine for managing WiFi connection
void loop();
WiFiState_e getState() const
WiFi_STA_State_e getState() const
{
return _state;
}
@@ -80,7 +80,7 @@ public:
private:
void setState(WiFiState_e newState,
void setState(WiFi_STA_State_e newState,
uint32_t timeout = 0);
// Handle timeouts + start of AP mode
@@ -110,7 +110,7 @@ private:
// String _last_ssid;
// MAC_address _last_bssid;
// uint8_t _last_channel = 0;
WiFiState_e _state = WiFiState_e::Disabled;
WiFi_STA_State_e _state = WiFi_STA_State_e::Disabled;
ESPEasyWiFi_mode_e _mode = ESPEasyWiFi_mode_e::Off;
@@ -0,0 +1,56 @@
StateDiagram [frame=true framecolor=steelblue label="State Diagram ESPEasy WiFi_STA_State_e"] {
state Disabled
state TimeOut
state begin
state WiFiOFF
state AP_only
state AP_Fallback
state IdleWaiting
state STA_Scanning
state STA_AP_Scanning
state STA_Connecting
state STA_Reconnecting
state STA_Connected
state STA_Connected_Setup
choice bConn
choice bCand
choice bScan
choice bAPmode
choice timeoutSetupMode
initialState->WiFiOFF
TimeOut -> timeoutSetupMode "Setup"
timeoutSetupMode -> IdleWaiting "!connected"
timeoutSetupMode -> WiFiOFF "!Setup"
WiFiOFF -> begin
begin -> bConn
bConn -> STA_Connected "connected"
bConn -> bCand "!connected"
bCand -> IdleWaiting "hasCandidates"
bCand -> bScan "!hasCandidates"
bScan -> AP_only "scanned"
bScan -> bAPmode "!scanned"
bAPmode -> STA_AP_Scanning "APmode"
bAPmode -> STA_Scanning "!APmode"
AP_only -> IdleWaiting "!APactiveUsed & (hasCandidates || timeout)"
AP_Fallback -> IdleWaiting "!APactiveUsed & (hasCandidates || timeout)"
IdleWaiting -> STA_Connected_Setup "connected() && mode==setup"
IdleWaiting -> STA_Connected "connected() && mode!=setup"
IdleWaiting -> STA_Connecting "timeout & hasCandidates"
IdleWaiting -> STA_AP_Scanning "timeout & !hasCandidates & scanfail & APmode"
IdleWaiting -> STA_Scanning "timeout & !hasCandidates & scanfail & !APmode"
STA_Scanning -> WiFiOFF "scanfail || scansuccess || !startAP_fallback"
STA_Scanning -> AP_Fallback "scanfail & startAP_fallback"
STA_AP_Scanning -> WiFiOFF "scanfail || scansuccess || !startAP_fallback"
STA_AP_Scanning -> AP_Fallback "scanfail & startAP_fallback"
STA_AP_Scanning -> AP_only "scanfail & !startAP_fallback"
STA_AP_Scanning -> STA_AP_Scanning "scan next channel"
STA_Connecting -> STA_Connected_Setup "connected & SetupMode"
STA_Connecting -> STA_Connected "connected & !SetupMode"
STA_Connecting -> STA_Reconnecting "!connected & timeout"
STA_Reconnecting -> IdleWaiting "!connected & timeout"
STA_Reconnecting -> STA_Connected_Setup "connected & SetupMode"
STA_Reconnecting -> STA_Connected "connected & !SetupMode"
STA_Connected -> STA_Connecting "!connected & hasCandidates"
STA_Connected -> STA_Scanning "!connected & !hasCandidates"
STA_Connected -> STA_Connected "connected + setTXpwr"
}
+3 -1
View File
@@ -21,7 +21,9 @@
# define SOFTAP_STATION_COUNT WiFi.AP.stationCount()
# endif
# ifdef ESP8266
# define SOFTAP_STATION_COUNT WiFi.softAPgetStationNum()
//# define SOFTAP_STATION_COUNT WiFi.softAPgetStationNum()
# define SOFTAP_STATION_COUNT wifi_softap_get_station_num()
# endif
+31
View File
@@ -0,0 +1,31 @@
#include "../wifi/WiFi_STA_State.h"
#if FEATURE_WIFI
namespace ESPEasy {
namespace net {
namespace wifi {
const __FlashStringHelper* toString(WiFi_STA_State_e state)
{
switch (state)
{
case ESPEasy::net::wifi::WiFi_STA_State_e::Disabled: return F("Disabled");
case ESPEasy::net::wifi::WiFi_STA_State_e::TimeOut: return F("TimeOut");
case ESPEasy::net::wifi::WiFi_STA_State_e::Idle: return F("Idle");
case ESPEasy::net::wifi::WiFi_STA_State_e::IdleWaiting: return F("IdleWaiting");
case ESPEasy::net::wifi::WiFi_STA_State_e::STA_Scanning: return F("STA_Scanning");
case ESPEasy::net::wifi::WiFi_STA_State_e::STA_AP_Scanning: return F("STA_AP_Scanning");
case ESPEasy::net::wifi::WiFi_STA_State_e::STA_Connecting: return F("STA_Connecting");
case ESPEasy::net::wifi::WiFi_STA_State_e::STA_Reconnecting: return F("STA_Reconnecting");
case ESPEasy::net::wifi::WiFi_STA_State_e::STA_Connected: return F("STA_Connected");
}
return F("");
}
} // namespace wifi
} // namespace net
} // namespace ESPEasy
#endif // if FEATURE_WIFI
@@ -52,23 +52,20 @@ namespace wifi {
*/
enum class WiFiState_e
enum class WiFi_STA_State_e
{
// WiFi radio is off and no new attempt should be made (e.g. low power mode or Ethernet active)
Disabled,
// WiFi radio off, to continue, everything needs to be (re)initialized
WiFiOFF,
// Error state, some action failed
TimeOut,
// Only running in AP mode
// Typically this is only used when STA is off and AP Auto Start is checked
// TODO TD-er: Must implement this.
AP_only,
// State from where we decide to start scanning or connecting
Idle,
// Fallback mode which is started when connecting to AP was not possible
AP_Fallback,
// WiFi was in some kind of error state or needs waiting period
// Not allowed yet to continue (re)connecting.
// For example when the interface is a fallback interface and not yet allowed to start
// Or when in setup mode and no need to connect.
IdleWaiting,
// STA mode + scanning
@@ -86,13 +83,10 @@ enum class WiFiState_e
STA_Reconnecting,
// Connected to an AP
STA_Connected,
STA_Connected_Setup
STA_Connected
};
const __FlashStringHelper* toString(WiFiState_e state);
const __FlashStringHelper* toString(WiFi_STA_State_e state);
} // namespace wifi
-33
View File
@@ -1,33 +0,0 @@
#include "../wifi/WiFi_State.h"
#if FEATURE_WIFI
namespace ESPEasy {
namespace net {
namespace wifi {
const __FlashStringHelper* toString(WiFiState_e state)
{
switch (state)
{
case ESPEasy::net::wifi::WiFiState_e::Disabled: return F("Disabled");
case ESPEasy::net::wifi::WiFiState_e::WiFiOFF: return F("OFF");
case ESPEasy::net::wifi::WiFiState_e::AP_only: return F("AP_only");
case ESPEasy::net::wifi::WiFiState_e::AP_Fallback: return F("AP_Fallback");
case ESPEasy::net::wifi::WiFiState_e::IdleWaiting: return F("IdleWaiting");
case ESPEasy::net::wifi::WiFiState_e::STA_Scanning: return F("STA_Scanning");
case ESPEasy::net::wifi::WiFiState_e::STA_AP_Scanning: return F("STA_AP_Scanning");
case ESPEasy::net::wifi::WiFiState_e::STA_Connecting: return F("STA_Connecting");
case ESPEasy::net::wifi::WiFiState_e::STA_Reconnecting: return F("STA_Reconnecting");
case ESPEasy::net::wifi::WiFiState_e::STA_Connected: return F("STA_Connected");
case ESPEasy::net::wifi::WiFiState_e::STA_Connected_Setup: return F("STA_Connected_Setup");
}
return F("");
}
} // namespace wifi
} // namespace net
} // namespace ESPEasy
#endif // if FEATURE_WIFI
+1 -1
View File
@@ -38,7 +38,7 @@
#include "../../ESPEasy/net/Globals/ESPEasyWiFiEvent.h"
#include "../../ESPEasy/net/Globals/NetworkState.h"
#include "../../ESPEasy/net/Globals/NWPlugins.h"
#include "../../ESPEasy/net/wifi/WiFi_State.h"
#include "../../ESPEasy/net/wifi/WiFi_STA_State.h"
#ifdef USES_C015