B4R Tutorial ESP8266 - WiFi Remote Configuration

Erel

Administrator
Staff member
Licensed User
Edit: A simpler and more powerful tool is available: https://www.b4x.com/android/forum/threads/esp-configurator-based-on-b4rserializator.81452/

The attached project allows the user to configure the ESP8266 WiFi settings (SSID and password).

When the program starts it does several things:
1. Creates an access point named 'esp'.
2. Creates a WiFiServerSocket that listens on port 80.
3. Tries to connect to a network based on the last settings stored in the EEPROM (if such are available).

The ip address of the device in the esp network is known. It is 192.168.4.1.
This means that we can connect to the esp network and then access the board with this ip address from any browser.

The server accepts two requests:
http://192.168.4.1 - Shows the current status
http://192.168.4.1/set/<ssid>/<password> - Sets the new ssid and password. Note that the password is optional.

Examples:

http://192.168.4.1/set/dlink
http://192.168.4.1/set/iPhone (2)/12345678

The SSID and password are stored in the EEPROM so the values are kept after a restart.

Note that the #StackBufferSize attribute is set to 600 as the string related methods require a larger stack buffer.
 

Attachments

Last edited:

barx

Well-Known Member
Licensed User
This is a good example and starting point for IoT projects. I didn't know whether the wemos had some built in EEPROM or not, I guess it does as it all seems to work. Thanks Erel for helping.
 

barx

Well-Known Member
Licensed User
It actually uses the flash for this.

BTW, the more I work with the ESP8266 the more I like it. This is indeed a great board.
I too feel the same, even though you are 1000 steps in fron tof me ;). At least it shows me there is still more good stuff to learn.

I downloaded a book called Kolban's book on ESP8266. Only just started it really, but it's quite interesting and hopefully it will help unlock some of the mysterious boards secrets.
 

Cableguy

Expert
Licensed User
A fail-safe should be introduced to the "set" procedure, as a blank set of credentials will make the board try to connect to a false network...
Also, a limit number of tries should be introduced so that the board should revert to server mode if all times expired...

I will try to add these myself, during the day...
 

Cableguy

Expert
Licensed User
Here is my small optimisation of the WiFi Remote Config code module

B4X:
'Jully 2016
'Original Code by EREL
'Small Optimisations by Cableguy

'Call WiFiServer.Start(False) from your code
'It will force the esp to first check the Board for saved SSID and Password
'After 5 attemps, it will revert the board to AP mode
'
'SSID Checked for empty value
Sub Process_Globals
    Private bc As ByteConverter
    Private Astream As AsyncStreams   
    Private server As WiFiServerSocket
    Private eeprom As EEPROM
    Private const MAGIC_EEPROM As Byte = 123
    Private APSSID As String = "esp"
    Private bc As ByteConverter
    Public WiFi As ESP8266WiFi
    Public esp As ESP8266
    Private NumberOfTries As Int
    Private MaxNumberOfTries As Int = 5
End Sub

Public Sub Start(AP As Boolean)
    If AP = False Then
        NumberOfTries = 0
        ConnectToNetwork
    Else
        Select WiFi.StartAccessPoint(APSSID)
            Case 1
                Log("Access Point Initialisation Successful")
                Log("SSID: ",APSSID)
                Log("ip: ", WiFi.AccessPointIp)
                server.Initialize(80, "server_NewConnection")
            server.Listen
            Case 0
                Log("Something Went wrong!")
                WiFi.Disconnect
        End Select
    End If
End Sub

Private Sub Server_NewConnection (NewSocket As WiFiSocket)
    Astream.Initialize(NewSocket.Stream, "astream_NewData", "astream_Error")
End Sub

Private Sub Astream_NewData (Buffer() As Byte)
    Log(Buffer)
    If bc.IndexOf(Buffer, "GET") <> -1 Then
        If bc.IndexOf(Buffer, "/set") <> -1 Then
           
            Dim ssid = "", password  = "" As String
            Dim i1 As Int = 0
            Dim i2 As Int = 0
            For Each b1() As Byte In bc.Split(Buffer, " ")
                If i1 = 1 Then
                    For Each b2() As Byte In bc.Split(b1, "/")
                        Select i2
                            Case 2
                                ssid = bc.StringFromBytes(b2)
                            Case 3
                                password = bc.StringFromBytes(b2)
                        End Select
                        i2 = i2 + 1
                    Next
                   
                End If
                i1 = i1 + 1
            Next
            Log("stact buffer :",StackBufferUsage)
            Astream.Write("HTTP/1.1 200").Write(CRLF)
            Astream.Write("Content-Type: text/html").Write(CRLF).Write(CRLF)
            Astream.Write("<script>setTimeout(function(){location.href=""http://192.168.4.1""} , 20000);</script>")
            If ssid.Length = 0 Then
                Astream.Write("SSID is invalid, please try again")
            Else
                Astream.Write("WiFi set to: ").Write(ssid).Write(", password: ").Write(password).Write("<br/>Please wait...")
                SaveNetworkDetails(ssid, password)
                CallSubPlus("ConnectWifi", 500, 0)
            End If
        Else If bc.IndexOf(Buffer, " / ") <> -1 Then
            Astream.Write("HTTP/1.1 200").Write(CRLF).Write(CRLF)
            If WiFi.IsConnected Then
                Astream.Write("Connected to network.").Write(CRLF)
                Astream.Write("ESP8266 IP address: ").Write(WiFi.LocalIp)
            Else
                Astream.Write("Not connected!")
            End If
        Else
            Astream.Write("HTTP/1.1 404").Write(CRLF)
        End If
        CallSubPlus("CloseConnection", 200, 0)
    End If
End Sub

Private Sub ConnectWifi(u As Byte)
    Start(False)
End Sub

Private Sub CloseConnection(u As Byte)
    Log("close connection")
    If server.Socket.Connected Then
        server.Socket.Stream.Flush
        server.Socket.Close
    End If
End Sub

Private Sub AStream_Error
    Log("Disconnected")
    server.Listen
End Sub

Public Sub ReplaceString(Original() As Byte, SearchFor() As Byte, ReplaceWith() As Byte) As Byte()
    'count number of occurrences
    Dim bc2 As ByteConverter
    Dim c As Int = 0
    Dim i As Int
    If SearchFor.Length <> ReplaceWith.Length Then
        i = bc2.IndexOf(Original, SearchFor)
        Do While i > -1
            c = c + 1
            i = bc2.IndexOf2(Original, SearchFor, i + SearchFor.Length)
        Loop
    End If
    Dim result(Original.Length + c * (ReplaceWith.Length - SearchFor.Length)) As Byte
    Dim prevIndex As Int = 0
    Dim targetIndex As Int = 0
    i = bc2.IndexOf(Original, SearchFor)
    Do While i > -1
        bc2.ArrayCopy2(Original, prevIndex, result, targetIndex, i - prevIndex)
        targetIndex = targetIndex + i - prevIndex
        bc2.ArrayCopy2(ReplaceWith, 0, result, targetIndex, ReplaceWith.Length)
        targetIndex = targetIndex + ReplaceWith.Length
        prevIndex = i + SearchFor.Length
        i = bc2.IndexOf2(Original, SearchFor, prevIndex)
    Loop
    If prevIndex < Original.Length Then
        bc2.ArrayCopy2(Original, prevIndex, result, targetIndex, Original.Length - prevIndex)
    End If
    Return result
End Sub

Public Sub SaveNetworkDetails(SSID As String, Password As String)
    Log("Saving network data: ", SSID, ", ", Password)
    SSID = bc.StringFromBytes(ReplaceString(SSID, "%20", " "))
    eeprom.WriteBytes(Array As Byte(MAGIC_EEPROM, SSID.Length + 1 + Password.Length), 0)
    Dim pos As Int = 2
    eeprom.WriteBytes(SSID, pos)
    pos = pos + SSID.Length
    eeprom.WriteBytes(Array As Byte(0), pos)
    pos = pos + 1
    eeprom.WriteBytes(Password, pos)
End Sub

Public Sub ConnectToNetwork
    Log("disconecting WiFi...")   
    WiFi.Disconnect
    'read settings from EEPROM
    Dim header() As Byte = eeprom.ReadBytes(0, 2)
    Do Until NumberOfTries = MaxNumberOfTries
        Log("try number : ", NumberOfTries)
        If header(0) = MAGIC_EEPROM Then
            Dim data() As Byte = eeprom.ReadBytes(2, header(1))
            Log ("DATA LENGTH =",data.Length)
            Dim i As Int = bc.IndexOf(data, Array As Byte(0))
            If i = -1 Then
                Log("Error parsing network data.")
                Return
            End If
            Dim SSID As String = bc.StringFromBytes(bc.SubString2(data, 0, i))
            If SSID.Length = 0 Then Start(True)
            Dim Password As String = bc.StringFromBytes(bc.SubString(data, i + 1))
            If Password.Length = 0 Then Password = "none"
            Log("Trying to connect to: ", SSID, " password: ", Password)
           
            If WiFi.Connect2(SSID, Password) Then
                Log("Connected successfully to: ", SSID)
                Log(WiFi.LocalIp)
                Else
                Log("Failed to connect.")
            End If
        Else
            Log("Network data not found.")
        End If
        NumberOfTries = NumberOfTries + 1
    Loop
    If NumberOfTries = MaxNumberOfTries Then
        Start(True)
    End If
End Sub

What do my small changes do?

Well, if you are as weird as me, when testing things out, you could be inclined to enter a blank SSID... the code now checks for that, since a SSID should never be empty!
Wen you call WiFiServer.start(False), it will try to connect to the saved SSID for 5 times, and if unsuccessful, start in AP mode by calling WiFiServer.Start(true).
AP mode is also started if no save data is found.

Please test this last part as I had already something saved in the eeprom, and had no time to test the rest.
 

techknight

Well-Known Member
Licensed User
I would add a reset button to the ESP to get it to go back into AP mode if the associated router/AP isnt available. I can see this exploited in a multitude of ways.
 

Gaver Powers

Member
Licensed User
New to the ESP8266 board... quick question for the experts here...
In AP mode - can a browser connect directly to the board by entering the url http://192.168.4.1 ?

G
 

Gaver Powers

Member
Licensed User
I need to clarify my question...
Can a browser in an android phone connect directly to the esp8266 while in AP mode without going thru a network router?
Or must the esp8266 first connect to a network (router) ?

G
 

Bangdido

Member
Licensed User
Hello Erel, thank you soo much for the Tutorial, i have a inssue, i'm using a ESP-01 and works fine, except i have the "headers" from the browser splited,
i'm trying to get a header, for example :

cookies: somecookie=somevalue;(crlf)
otherhreader: other value(crlf)


However sometimes I get something like the following
cook(crlf)
ies: somecookies=somevalue;(crlf)
etc=etc
etc=etc.
othe(crlf)
erheader=value(crlf)


i'm trying to parse the headers using ByteConverter.split

Regards
 

positrom2

Active Member
Licensed User
Running the code from this tutorial results in the creation of an open network named "esp".
The B4r log shows this:
"Network data not found.
My AP ip: 192.168.4.1
Network data not found.
"
Then I can connect to the "esp" network.
Trying 192.168.4.1 from a browser the message is "no connection".
What is going wrong?
 
Top