ESP8266 fallback to SoftAP when WiFi network not found?

I have created an ESP-07 based project where one can configure the unit to run in either STA mode (using SSID and password from its configuration in EEPROM) or as a SoftAP unit.
Now I have run into a problem when the device is moved from one location to another where the configured WiFi network does not exist. In this case I want it to fall back to its SoftAP mode, which it uses during initial configuration, so can change the SSID/password it shall connect to.

Is it possible to add such a mode of operation and if so is there some sample code on how to do it?
It seems like in setup() one should provide for the case that it is configured for STA but cannot connect...

One approach could be this:

    InitConfig(); //Initialize handling of configuration via EEPROM

    int sta_connected = 0;
    if (ESPConf.mode == WIFI_STA)
    {
        WiFi.mode((WiFiMode)ESPConf.mode);  //WIFI_AP, WIFI_STA, WIFI_AP_STA, WIFI_OFF
        local_ip = IPAddress(0,0,0,0);
        WiFi.config(local_ip, local_ip, local_ip);    //Reset to use DHCP
        WiFi.hostname(ESPConf.host); //This is the hostrname that should be supplied to the DHCP server
        WiFi.begin(ESPConf.ssid, ESPConf.passwd);
        if(WiFi.waitForConnectResult() == WL_CONNECTED)
        {
            IP2str(ipbuf, WiFi.localIP());
            MsgDbg = "STA ADDR = " + String(ipbuf);
            sta_connected = 1;
        }
        else
            MsgDbg = "WiFi connection to " + String(ESPConf.ssid) + " failed! Starting SoftAP instead";
        SerialDebug.println(MsgDbg);
    }
    if ((ESPConf.mode == WIFI_AP) || (!sta_connected)) //Mode WIFI_AP or failed to connect WIFI_STA
    {
        WiFi.mode(WIFI_AP);  //WIFI_OFF, WIFI_STA, WIFI_AP, WIFI_AP_STA
        WiFi.softAPConfig((IPAddress)ESPConf.addr, (IPAddress)ESPConf.addr, netmask); 
        WiFi.softAP(ESPConf.ssid, ESPConf.passwd, ESPConf.wichannel, true);
    }

But is it possible to restart WiFi in AP mode after it has been initialized in STA mode but failed to connect?
Is there some master reset that has to be done first (when it fails to connect)?

no, only change the mode

Yes that is possible. I have a clock that syncs to network time over wifi.
If it can't connect to the local WiFi network, it falls back to an access point that allows configuring the WiFi parameters.

I use WiFiManager. It is very easy to use.
Here is a link to the project: GitHub - tzapu/WiFiManager: ESP8266 WiFi Connection manager with web captive portal

It is available in the IDE library manager.

It includes examples.

--- bill

@bperrybap thanks for your reply.
I have now tersted what my device does when started up and it just keeps on trying to reconnect to the non-existing WiFi network eternally.
I have already looked at WiFiManager, but since it uses its own configuration method I cannot use it, unfortunately.
Instead I am trying to implement a startup function to fall back to the SoftAP as indicated in my post (I edited it to remove unclarity in the code example following @Juraj response).

Will this be enough for starting in AP mode if the WiFi network is missing?
Right now I have to figure out how I can reprogram the chip when it does not come up on the network (I am using the WebUpdate function, which needs the board to be accessible via the network).

it should stop connecting if you turn off STA mode. you can use WiFi.disconnect () to stop connecting if you don"t want to turn off STA mode.

Now I have tested my fallback code and it sort-of works but not really well.
This is the debug log when it tries to connect in STA mode but the target network does not exist, most entries are output by the ESP itself and do not come from my code:

bcn 0
del if1
usl
mode : sta(b4:e6:2d:03:d6:6f)
add if0
scandone
no xxxx_Net found, reconnect after 1s
reconnect
scandone
no xxxx_Net found, reconnect after 1s
reconnect
scandone
no xxxx_Net found, reconnect after 1s
WiFi Connection to xxxx_Net failed! Starting SoftAP instead <== My debug output after STA failed
del if0
usl
mode : softAP(b6:e6:2d:03:d6:6f)
add if1
dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1) <== Why? I have set IP 192.168.211.1!
bcn 100

Now I wonder how I can safely switch from STA mode to AP mode and properly reconfigure network settings?

You indicate that I could use WiFi.disconnect(), does this reset the device to the starting condition ready for entry of new parameters? It seems like disconnect() has a parameter with default 0, what does it do and how should that be set?
My current code is like this:

    if (ESPConf.mode == WIFI_STA)
    {
        WiFi.mode(WIFI_STA);  //WIFI_AP, WIFI_STA, WIFI_AP_STA, WIFI_OFF
        local_ip = IPAddress(0,0,0,0);
        WiFi.config(local_ip, local_ip, local_ip);    //Reset to use DHCP
        WiFi.hostname(ESPConf.host); //This is the hostname that should be supplied to the DHCP server
        WiFi.begin(ESPConf.sta_ssid, ESPConf.sta_passwd);
        if(WiFi.waitForConnectResult() == WL_CONNECTED)
        {
            local_ip = WiFi.localIP();
            MsgDbg = "STA ADDR = " + local_ip.toString();
            sta_connected = 1;
        }
        else
        {
            MsgDbg = "WiFi Connection to " + String(ESPConf.sta_ssid) + " failed! Starting SoftAP instead";
            //Here we need to reconfigure the device to use SoftAP instead, so set parameters accordingly...
            //What do I enter here?
        }

        SerialDebug.println(MsgDbg);
    }

    if ((ESPConf.mode == WIFI_AP) || (!sta_connected)) //Mode WIFI_AP or failed to connect WIFI_STA so start mode WIFI_AP
    {
        WiFi.mode(WIFI_AP);  //WIFI_OFF, WIFI_STA, WIFI_AP, WIFI_AP_STA
        WiFi.softAPConfig((IPAddress)ESPConf.addr, (IPAddress)ESPConf.addr, netmask); //ESPConf.addr is 192.168.211.1 in this case
        if (ESPConf.wichannel == 0)
            WiFi.softAP(ESPConf.ap_ssid, ESPConf.ap_passwd);
        else if (ESPConf.hidden == 0)
            WiFi.softAP(ESPConf.ap_ssid, ESPConf.ap_passwd, ESPConf.wichannel);
        else
            WiFi.softAP(ESPConf.ap_ssid, ESPConf.ap_passwd, ESPConf.wichannel, true);
    }

Since the device reports the wrong IP address I guess I have not properly reset from STA mode before setting AP....

disconnect parametet is not used.

localIP() applies only for STA mode. calling it if STA mode is not active has undefined result

From library source file ESP8266WiFiSTA.ccp:

/**
 * Disconnect from the network
 * @param wifioff
 * @return  one value of wl_status_t enum
 */
bool ESP8266WiFiSTAClass::disconnect(bool wifioff) {
    bool ret;
    struct station_config conf;
    *conf.ssid = 0;
    *conf.password = 0;

    ETS_UART_INTR_DISABLE();
    if(WiFi._persistent) {
        wifi_station_set_config(&conf);
    } else {
        wifi_station_set_config_current(&conf);
    }
    ret = wifi_station_disconnect();
    ETS_UART_INTR_ENABLE();

    if(wifioff) {
        WiFi.enableSTA(false);
    }

    return ret;
}

Seems like WiFi.enableSTA is set to false if the the disconnect() parameter is true.
So I guess I better set it true...

I ended up doing this after the STA connect failed:

        if(WiFi.waitForConnectResult() == WL_CONNECTED)
        {
            local_ip = WiFi.localIP();
            MsgDbg = "STA ADDR = " + local_ip.toString();
            sta_connected = 1;
        }
        else
        {
            MsgDbg = "WiFi Connection to " + String(ESPConf.sta_ssid) + " failed! Restarting in SoftAP mode instead";
            //Modify the ESPConfig.mode setting to AP and restart ESP?
            SerialDebug.println(MsgDbg);
            ESPConf.mode = WIFI_AP;
            WriteConfig(&ESPConf);  //Store new config in EEPROM
            delay(1000);
            ESP.restart();
        }

So when the problem is discovered it resets to AP via a normal reboot after config has been altered.

Its been a while, but I remember having issues with Wifi.disconnect()
The chip remembers previous wifi settings.
I had to do this in my code to get it to forget those and start clean:

 // disconnect() should clear saved WiFi parameters
 // but it only works when in WIFI_STA mode.
 WiFi.mode(WIFI_STA);
 WiFi.disconnect(true);

--- bill

In my case the connection details are stored inside EEPROM and read every time the device starts up.
In setup() these data (SSID, Password, mode etc) are set on the WiFi before it is started.
Thus if I change the WiFi mode in the config struct to AP and reset the device it will read the new mode and configure WiFi appropriately.
Now tested and it works fine.

BosseB:
In my case the connection details are stored inside EEPROM and read every time the device starts up.
In setup() these data (SSID, Password, mode etc) are set on the WiFi before it is started.
Thus if I change the WiFi mode in the config struct to AP and reset the device it will read the new mode and configure WiFi appropriately.
Now tested and it works fine.

The esp8266 SDK remembers SSID and password on it's own a uses it to connect before your sketch starts.

You should call disconnect() while still in STA mode. It clears the remembered SSID and pasword and turns of STA mode.

WiFi.persistent(false) disables storing the SSID and pasword by SDK.
WiFi.setAutoConnect(false); disables the auto connect of the SDK

Juraj:
The esp8266 SDK remembers SSID and password on it's own and uses it to connect before your sketch starts.
You should call disconnect() while still in STA mode. It clears the remembered SSID and pasword and turns of STA mode.

I have read multiple posts in various forums that state that disconnect() cannot be used to clear the remembered items unless STA is currently connected. Your comment also indicates this.
But what I want to do is to switch operation to AP mode when the configured and previously available SSID is no longer present, like when moved to another location. So the STA mode cannot then be connected.
In my code it happens when the STA connect fails.

WiFi.persistent(false) disables storing the SSID and pasword by SDK.
WiFi.setAutoConnect(false); disables the auto connect of the SDK

When can I use these commends? Does the ESP have to be in a specific state for them to work?
Maybe like this:

    else  //Here when STA connect fails
    {
        MsgDbg = "WiFi Connection to " + String(ESPConf.sta_ssid) + " failed! Restarting in SoftAP mode instead";
        SerialDebug.println(MsgDbg);
        WiFi.persistent(false);
        WiFi.setAutoConnect(false);
        WiFi.disconnect(true);
        ESPConf.mode = WIFI_AP; //Reconfigue device in struct
        WriteConfig(&ESPConf);  //Save to EEPROM
        delay(1000);
        ESP.restart();  //Reset ESP
    }

I am sure disconnect() is like AT+CWQAP in AT firmware (and then changing the mode). It should work if the connection was not successful.

persistent and autoConnect (AT+CWAUTOCONN) are remembered settings of STA. AT+CWQAP—Disconnects from the AP

I changed the code as shown above and tested it by setting config to STA mode with an invalid SSID and power cycle the board.
The end result is the same, my configured AP comes up. But the serial debug messages show this generated by the ESP itself:

usl
mode : softAP(b6:e6:2d:03:d6:6f)
add if1
dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1)
bcn 100
Swapping pins for Serial, use 7/10 for Rx/Tx!
Serialserver ready!
Config server ready!
Use 192.168.211.1:2101 to connect serial

So during restart in AP mode it erroneously starts a dhcp server on 192.168.4.1, which is an IP I have never used on this device.
Is there some built-in AP mode using that address?
After setup() has finished fully the last message shows the correct AP address.
And after modifying the config SSID and setting it to STA mode it connects properly on a reboot.
So in principle this is OK.
I will call it good enough and move on.

yes. 192.168.4.1 is default SoftAP IP