For source code see WiFi_123_code.
Summary: This page reviews 3 different designs for a basic WiFi server project that communicates directly with a browser (ie No router involved)
Audience: Programmers who wish to implement their first WiFi server or access point. There are some advanced concepts/library functions programmers will need to accept.
Keywords: WiFi, Server, Access Point, Client, Browser, asynchronous communication, HTML C++ lambda function
Hardware: The design uses an ESP8266 Mini Board.
Libraries Required: All libraries are part of the Arduino IDE or the Arduino ESP8266 Add-on
I have a model train layout. In the medium term I wish to set up a WiFi network that will allow me to display on a smartphone the position of trains in the layout and to use the smartphone to control points/turnouts. In the long term I might wish to provide autonomous control of the trains.
I could cobble together WiFi networks using examples from the Internet. However I decided it was better to undertake a study of various options so that I really understand what is happening. This page summarises some of the tests I performed and some of my conclusions.
This page will program the ESP8266 as an Access Point or Server. The client/browser (PC/Tablet/Smartphone) will communicate directly. There is no router involved.
The hardware used is an ESP8266 Mini board illustrated below:
The board shown is for an earlier project that receives serial data from Light Detecting Resistors and controls 4 sets of 3-aspect signals (RED-AMBER-GREEN) . Shown is the ESP8266 Mini board and two glue chips that transform serial information from the ESP8266 to drive the signals. This project is concerned with the ESP8266 Mini board only.
This project will use the ESP8266 in the Arduino IDE. To set up the ESP8266 see the Appendix.
To start create a new file called WiFi_123.
There will be 3 different WiFi implementations that are grouped in the source code using #define PROGRAM 0 ...#if PROGRAM == 0 ....#elif PROGRAM==1 ......#elif PROGRAM==2 ...#endif. Use #define to select code of interest.
A basic no-bells, no whistles WiFi program is given below:
This will give the following display on a PC/Tablet/Smartphone.
For this example with a smartphone select:
(i) WiFi: WiFi_123
(ii) Password: 12345678
(iii) Identifier: 192.168.4.1 See later section "Adding Debugging"
The program details are discussed in the following sections.
Using libraries avoids having to undertake the complicated work of understanding in detail how the ESP8266 works and allows a product to be rapidly prototyped. In general it can be assumed that libraries have been exhaustively tested and are free of bugs**. As seen in this example all the library detail is hidden in the background and is not visible to the end user.
The only include file required for this example is ESP8266WebServer.h. However this file will include many other files that in turn will include further files.
For example some WiFi examples seen on the Internet include the following
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
that are both already included by ESP8266WebServer.h so including them again is redundant.
ESP8266WiFi.h and WiFiClient,h both appear to include each other but not ESP8266WebServer.
Also many examples include <Arduino.h>. Developing code using the Arduino IDE includes Arduino.h automatically. Where it is necessary to include <Arduino.h> is with library development
The conclusion here is not to be concerned with examples that include different header files. Just assume that they all drill down the same essential file(s).
In summary
ESP8266WiFi.h is required for doing all WiFi related functionalities such as connection, AP, etc.
WiFiClient.h is required to send request to web browser
ESP8266WebServer.h handles all HTTP protocols
**I once used a GPS library that when used with an Arduino UNO gave incorrect results. The library would have been tested at low longitudes but at 138 degrees the position could no longer be represented to the required precision using only the 16 bits od the UNO.
This line creates an instance or object with label server of the type ESP8266WebServer. The object has the argument or port 80.
From https://www.techopedia.com/definition/15709/port-80 Port 80** is the port number assigned to commonly used internet communication protocol, Hypertext Transfer Protocol (HTTP). It is the port from which a computer sends and receives Web client-based communication and messages from a Web server and is used to send and receive HTML pages or data.
See also http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
**Other ports may be used. To open a web page with a different port number you have to enter port number after IP address. Ex. For port number 81 you have to type 192.168.4.1:81 in browser.
ESP8266WebServer.h includes the header ESP8266WiFi.h that declares a class ESP8266WiFiClass. WiFi is declared as an object/instance of the ESP8266WiFiClass.
Options include set mode to WIFI_AP, WIFI_STA, WIFI_AP_STA or WIFI_OFF. Refer to http://arduino.esp8266.com/Arduino/versions/2.1.0-rc1/doc/libraries.html
In this example the ESP8266 is set to an access point. That is the communication will be between the ESP8266 and the smartphone/tablet/PC. There is no router involved**.
**Many introductory examples on the Internet include a router. At a cursory glance the code can look very similar.
Sets the ESP8266 up as a soft access point using the ssid and password as defined earlier.
(i) WiFi.softAP(ssid) sets up an open network where as
(ii)WiFi.softAP(ssid, password) sets up a WPA2-PSK network (password should be at least 8 characters)
Additional arguments can be used. See https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/soft-access-point-class.html
Tells the server to begin listening for incoming connections.
The handleClient( ) will listen for incoming connections and build up the request character by character** from the client (Smartphone etc).
A possible sequence I obtained from another project where ^^ indicates carriage return- line feed was:
Once the complete request is received it is handled by the server.on( ). The critical line is +IPD,0,407:GET / HTTP/1.1.
**With an embedded system an absolute requirement is that no one operation holds up the system. That is it is non-blocking. In this case handleClient( ) will only read characters if they are available. On the next loop further characters will be read until the whole request is captured.
The server.on( ) method has set up how the client request will be handled.
In this example the critical portion is what follows the GET. In this case the program will look for the "/". When found the handleRoot method will be executed**.
**handleRoot is a label used by convention.
The handleRoot( ) will call the send( ) method that will respond to the client. There are three arguments:
(i). Status code: 200 for OK. (404 for '/' not found)
(ii) The type of response. In this example it is plain text.
(iii) The message - in this example "WiFi_123 using ESP8266!"
This is the message displayed by the browser.
To describe what is happening information may be sent to the serial monitor.
Further, in the previous it was assumed that the address was 192.168.4.1. If the address needs to be known it can be displayed using the method WiFi.softAPIP. Note the response is of type IPAddress that is defined in the one of the libraries.
The code becomes:
The top line in the response appears as junk. At reset the ESP8266 generates a message at 74880 baud^^. This can be seen by setting the serial monitor to 74880 and changing the Serial.begin( ).**
^^I do not believe that 74880 is the default baud rate for all ESP8266 devices.
**Most examples on the Internet use a baud rate of 115200
The client will normally expect a HTML response rather than plain text. The send message will become:
To change from plain text to HTML two changes are made to the code:
(i) In server.send method use "text/html"
(ii) also in server.send there needs to be HTML text. Since this will take several lines it is broken into a string "str" where "str" is assign to the const WiFi_123_page which describes a minimal HTML page.
Note the "R" directive that allows the text to be spread neatly over a number of lines.
The results are as shown with the title top left in the browser title bar and the main program centre lower. (Forensic detectives will note only one message has the full stop.)
Currently the HTML page is minute. In real applications it will be much larger so it is sensible to separate it and place it in an include file. Base HTML files often have the label "index" so this example will use "index.h".
In the Arduino IDE use the inverted triangle and New Tab to create the new file index.h. Move the HTML code from WiFi_123.ino to index.h.
In the main code include the index.h file.
The program should work as before.
Other methods are available that will provide additional information about what is happening.
The library ESP8266WebServer.h will also include classes WiFiServer and WiFiClient. To use:
i. make server an instance/object of class WiFiServer and add client as an object of WiFiClient.
ii. modify the code as shown - the major change is to the program loop( ).:
The modified program will display the program activity on the serial monitor.
Notes:
1. A new object/instance client of the class WiFiClient is created.
2. If the client is available the method reads the incoming string into the variable request up until the '\r' character
3. request is printed to the serial monitor. See first line below.
4. The client is flushed and the HTML page (response) printed to the client. That is the WiFi message
5. The same message is sent to the serial monitor.
As shown there is one handshake (request+ response) followed by a second request from the smartphone for the favicon.ico.**
At this point the ESP8266 does not have a response to the favicon request so it re-sends the root page.
**GET / HTTP/1.1 with the space after the "/" is the first request from the client/browser. If there is a space then the browser is expecting the root HTML page in response. With no space the browser is expecting a different response.
The favicon is a small icon that is displayed in the title line of the browser.
There are 3 choices:
i. Effectively ignore it and respond with the root page. My experience that browsers will request the favicon several times before giving up.
ii. Tell the browser to not make the request.
iii. Respond with a favicon.
At this point the browser will be told not to make a request. The following line is added to the header section of the code
The result can be seen (or not seen) by rerunning the code.
Metadata is not directly visible to the end user but adds functionality to the web page. It is inserted between the <HEAD> and </HEAD> tags. The <TITLE></TITLE> tags give the message that shows up in the web browser’s title bar.
For browsing on a range of devices a useful meta tag is
<meta name="viewport" content="width=device-width, initial-scale=1">
that will automatically adjust for different screen sizes and viewports. The parameter content=” width=device-width sets the width of the page to respond to the width of the screen. The second parameter initial-scale=1 helps in setting the initial zoom point of the page.
See https://www.w3schools.com/tags/tag_meta.asp
----------------------------------------------------------------
An alternate approach is to use asynchronous techniques. This has the advantage that the processor does not have to continually check if there is a browser request, it can be full time on other activies** and then handle the browser request in the background. This will require a different library: ESPAsyncWebServer.h.
Notes:
1. The program displays WiFi_123_page on the browser as before.
2. The program loop( ) does nothing at this point. In future projects monitoring LDR sensors and controlling the signals of a model train layout could be placed in the loop( ).
**In the examples given to date the sole processor activity is handling browser requests so there is no advantage in using an asynchronous response.
The server.on method specifies or configures the route where server will be listening for incoming HTTP requests and the function that will be executed when that request is received.
i.The first argument specifies the route on which server will be listening. In this example it is "/" hello route. Other examples will be more complex. For example "/led" might be looking for a route that handles a led (On/Off/toggle)
ii.The second argument is an enum of type WebRequestMethod defined as part of ESPAsyncWebServer.h. In this example HTTP_GET is used. Another option is HTTP_POST.
iii.The third argument is the handling function that will be executed when the request is received. As given this handling function receives as parameter a pointer to an object of type AsyncWebServerRequest. It will return void.
To keep the syntax compact the handling function uses a C++ lambda function. ie [captures](params){body}
In this example empty square brackets [] are used as there are no captures. The param(s) will be that of the handling function, which is specified by the ArRequestHandlerFunction type. That is a a pointer to an object of type AsyncWebServerRequest.
When the HTML GET is received the server.on method will respond with the body of the lamba described above**..
i.This method receives as first input the HTTP response code: 200 is the HTTP response code for “OK”.
ii.As second argument is the answer content-type of the response: “text/html for a HTML message.
iii.The third argument is a pointer to the actual content. In this example the constant WiFi_123_page
**.Since the request points to the object to be sent rather than the object itself the arrow operator calls the send method of the AsyncWebServerRequest object.
There are many basic examples of developing a WiFi on the internet. Some are for direct communication between the ESP8266 and the browser. Other examples use a router.
This page has presented three different WiFi programs with explanations for direct communication between the ESP8266 and a browser.
Future pages will enhance the HTML capability to send messages and perform some control functions.
This project will use the Arduino IDE with the ESP8266 Add-ons.
This will allow the Arduino IDE editor to be used but the results are then compiled for the ESP8266. The advantage is that applications can be developed for the ESP8266 without the developer having to learn more complex and/or different tools. The disadvantage is that some of the features/attributes of theESP8266 may be hidden in the simplification. It may also lead to the impression that the ESP8266 is similar to the ATMega828 in the Arduino when it is not.
If required Install the drivers: (I was using a WiFi Mini product code XC3802 from Jaycar) and found my PC recognized the XC3802 I was using so this step was not necessary)
If the library is not found the WiFi Mini uses a CH340G USB-Serial IC. The drivers for this can be downloaded from the IC manufacturer’s website: http://www.wch.cn/download/CH341SER_ZIP.html
To add board support for tjhe ESP8266 it is recommended to use Arduino IDE version 1.6.4 or later so that the Boards Manager can handle the installation.
1. To install board support for ESP8266, in File>Preferences>Additional Board Manager URLS add: http://arduino.esp8266.com/stable/package_esp8266com_index.json separating from existing entries with a comma.
2: Go to Tools>Boards>Boards Manager and type 'esp' in the search box
3. Install ESP8266 by ESP8266 Community. (Button on lower right) This is about 150MB download and can take a while.
4. Select the desired ESP6266 board. My board was identical to the 'WeMos D1 Mini Lite’
The Arduino IDE will now start creating, compiling and running programs with the ESP8266.