This page shows you how to create an ESP8266 based webserver to control outputs. The
method is demonstrated by using the built in LED as a controlled
output.
This code uses a Lolin nodeMCU module (the built in LED is on
pin 4) but you could also use any ESP8266 based unit. It uses new
NodeMCU firmware lua 5.1.4 and SDK 2.2.1. flashed into the ESP8266.
ESP8266 based lolin nodeMCU breakout board
The previous examples show simpler bits of code while this one shows a
more useful framework.
Anyway the original code is split into 3 files:
credentials.lua
init.lua
application.lua
ESP8266 Webserver Operation
The credentials.lua file has only two lines - these contain your ssid and password.
The init.lua file starts the web interface (this is also started from re-boot).
The application file contains your html application code.
Webserver Application
The basic idea is that you write your html code in appication.lua and
that init.lua does the WiFi startup / monitoring / re-start (with output
to the serial terminal). Once the wifi is up and an IP address has been
assigned, it runs your html application code. So you can experiment
with code in application.lua and leave everything else alone (and know
that it will work!).
Note: To check the basic operation comment out
dofile("application.lua"). This will let you see the connection from
start, to IP assignment, to 3 sec delay and full start.
The file init.lua is the boot up start file that Lua always runs if it
is present. In that file is a three second delay (see below) which
allows you to stop the ESP module send the command stopWiFi() e.g. if you need to change some code.
Otherwise the ESP module will keep re-booting and you can't get access
to re-program it. It's even worse if you have no delay as you will then
need to re-flash the ESP module.
LED Blink Status
If you don't have a serial terminal attached to the ESP8266 Webserber
then there is no way to figure out what is going on so I have also
added a further file that
shows you what's going on by flashing the built in LED at different
rates - explained below.
Idle and waiting for connection to router : Relaxed flashing: Ok.
Connected to router waiting for IP : A bit more upbeat flashing: Ok.
Received the IP now waiting 3s to start : Triple flash urgent delay: Warning.
Error, restarting IP connection : Double flash longer delay: Error.
LED off after going through the above : Everything is running smoothly.
Note: Code for this is further down the page.
On my setup the WiFi router is a long way away so it sometimes gets a
re-connection request when it misses a beacon alert. The LED flash lets you see the
ESP module restart action.
The added file is:
LEDBlinkn.lua
I also modified init.lua to use this LED flash code placing the calls
to LEDBlinkn at strategic places in that code. This means you have some
feedback as to the status of the ESP8266 Webserver even with no serial
connection.
ESP8266 Webserver Lua Code Operation
ESP8266 Webserver Credentials
Once you have put in your credentials, you don't need to keep
re-entering them for different html applications because the
file is stored in the internal file system of the ESP8266.
It won't need
re-updating (if you don't format the file system) and any code you write
could use that file. Its a very good way to use the internal file
system so you don't need to repeat code for different WiFi applications. The code is adapted from code on github: here.
This file is trivial but useful containing 2 lines:
SSID="ssid"PASSWORD="password"
Save the above code as credentials.lua (change to your ssid and password).
TIP: You can usually find the ssid and password printed on your router.
ESP8266 Webserver Application
This is where "you" put your application code. in the example below
the first set of functions performs the blink operation and the bottom
one generates the html page.
-- ESP8266 webserver
-- This allows control of the builtin LED - On/Off/Blink/Blink Off.
--
localoutpin=4localstate=falsefunctioninit()gpio.mode(outpin,gpio.OUTPUT)gpio.write(outpin,gpio.HIGH)-- LED is pulled so HIGH = off
blinkOFF()endfunctiontogLED()ifstate==falsethengpio.write(outpin,gpio.HIGH)elsegpio.write(outpin,gpio.LOW)endstate=notstate; endfunctionblkinkON()ifmytimer~=nilthenreturnend-- Timer already on.
mytimer=tmr.create()mytimer:alarm(200,tmr.ALARM_AUTO,function()togLED()end)endfunctionblinkOFF()ifmytimer==nilthenreturnend-- Timer already off.
mytimer:unregister()mytimer=nilendsrv=net.createServer(net.TCP)init()srv:listen(80,function(conn)conn:on("receive",function(conn,payload)print(payload)-- View the received data,
functioncontrolLED()control=string.sub(payload,fnd[2]+1)-- Data is at end already.
ifcontrol=="ON"thengpio.write(outpin,gpio.LOW);blinkOFF()returnendifcontrol=="OFF"thengpio.write(outpin,gpio.HIGH);blinkOFF()returnendifcontrol=="Blink"thenblkinkON()returnendifcontrol=="Blinkoff"thenblinkOFF()returnendend--get control data from payload
fnd={string.find(payload,"ledbi=")}if#fnd~=0thencontrolLED()end-- Is there data in payload? - Take action if so.
conn:send('<!DOCTYPE HTML>\n')conn:send('<html>\n')conn:send('<head><meta http-equiv="content-type" content="text/html; charset=UTF-8">\n')-- Scale the viewport to fit the device.
conn:send('<meta name="viewport" content="width=device-width, initial-scale=1">')-- Title
conn:send('<title>ESP8266 Wifi LED Control</title>\n')-- CSS style definition for submit buttons
conn:send('<style>\n')conn:send('input[type="submit"] {\n')conn:send('color:#050; width:70px; padding:10px;\n')conn:send('font: bold 84% "trebuchet ms",helvetica,sans-serif;\n')conn:send('background-color:lightgreen;\n')conn:send('border:1px solid; border-radius: 12px;\n')conn:send('transition-duration: 0.4s;\n')conn:send('}\n')conn:send('input[type="submit"]:hover {\n')conn:send('background-color:lightblue;\n')conn:send('color: white;\n')conn:send('}')conn:send('</style></head>\n')-- HTML body Page content.
conn:send('<body>')conn:send('<h1>Control of nodeMCU<br>(ESP8266-E12) Built in LED.</h1>\n')conn:send('<p>The built in LED for NodeMCU V3 is on D4</p>\n')-- HTML Form (POST type) and buttons.
conn:send('<form action="" method="POST">\n')conn:send('<input type="submit" name="ledbi" value="ON" > Turn Built in LED on<br><br>\n')conn:send('<input type="submit" name="ledbi" value="OFF"> Turn Built in LED off<br><br>\n')conn:send('<input type="submit" name="ledbi" value="Blink"> Blink LED<br><br>\n')conn:send('<input type="submit" name="ledbi" value="Blinkoff"> Stop LED Blink</form>\n')conn:send('</body></html>\n')conn:on("sent",function(conn)conn:close()end) end)end)
Save the above code as application.lua
The application code is run after the webserver is started in init.lua. It has the following functions:
init()
- Initialises the port to drive the built in LED.
togLED()
- Toggle the state of the LED ( LED on is output low ).
blinkOFF()
- Turn off and unregister the blink timer.
controlLED()
- Decodes the data within the payload to control the led.
The line:
srv=net.createServer(net.TCP)
...creates a TCP Transfer Control Protocol server.
srv:listen(80,function(conn)
...sets the server to listen on port 80 for html data:
conn:on("receive",function(conn,payload).
Passes parameters 'conn' & 'payload' to the inline function when the ESP8266 receives a data on port 80
The inline function is activated which checks if the payload has the
string 'ledbi=' within - if it does, then the function controlLED is
used to control the LED. Data used, is the data following the string
'ledbi=' which is available following this string to the end of the
payload.
The rest of this function serves up the HTML page that the browser can display
.. allows a browser or mobile to show a reasonable sized page i.e. it scales to the viewport.
The CSS style after the comment
-- CSS style definition for submit buttons
...is used to style the submit button for size a and rounded corners and lightgreen background.
The section commeted as:
-- HTML Form (POST type) and buttons.
Is where the buttons are defined in a <form> section and where the values to be sent on each button press are specified.
ESP8266 Webserver LEDBlinkn
localLEDpin=4localLEDState=falselocaln=0local_nStart=0local_togDelaylocal_intervallocalblinkTimer=tmr.create()localblinkInterval=tmr.create()gpio.mode(4,gpio.OUTPUT)gpio.write(LEDpin,gpio.HIGH)-- high is off for builtin LED.
-- Blink n times with delay between on-off then wait interval - repeat
functionLEDBlinkN(numTog,togDelay,interval)-- Get round not having statics
ifblinkTimer:state()~=nilthenLEDBlinkStop()end-- Stop if was previously started.
_nStart=numTog_togDelay=togDelay_interval=intervaldoInterval()endfunctionLEDBlinkStop()ifblinkTimer:state()~=nilthenblinkTimer:unregister()blinkInterval:unregister()endgpio.write(LEDpin,gpio.HIGH)LEDState=falsen=0endfunctiontoggleLEDbuiltin()ifblinkTimer:state()~=nilandn<=0thenblinkTimer:unregister()returnendif(LEDstate)thengpio.write(LEDpin,gpio.LOW)elsegpio.write(LEDpin,gpio.HIGH)-- high is off for builtin LED.
n=n-1endLEDstate=notLEDstateend-- Fast toggle
functionLEDBlinkNStart()n=_nStart-- Initialise the toggle number
blinkTimer:alarm(_togDelay,tmr.ALARM_AUTO,function()toggleLEDbuiltin()end)end-- Interval timer
functiondoInterval()LEDBlinkNStart()-- Start with the led toggle before the interval
blinkInterval:alarm(_interval,tmr.ALARM_AUTO,function()LEDBlinkNStart()end)end--test
--LEDBlinkN_setNumBlinks(50,4)
--LEDBlinkN(3,50,1500)
Save the above code as LEDBlinkn.lua
The LEDBlinkn code has the following functions:
LEDBlinkN(numTog,
togDelay, interval)
- The user code to stat a blink. numTog is the
number of initial on/off flashes. togDelay defines the on and off
period. interval defines the time until re-starting the sequence i.e.
multiple flash followed by interval delay. the operation continues until
stopped by LEDBlinkStop() or is reset to a different sequence using LEDBlinkN().
LEDBlinkStop()
- Stop the blink aciton.
toggleLEDbuiltin()
- Toggle the built in LED.
LEDBlinkNStart()
- This is the fast flash timer - code flashes the LED n times.
doInterval()
- This timer times the interval calling
LEDBlinkNStart after the delay. It also calls LEDBlinkNStartat the
beginning so you get something displayed at the start of a sequence.
A typical example is
LEDBlinkN(3,50,550)
This creates 3 on/off flashes with period 50 * 2 * 3 = 300ms but also
starts the interval timer for a 550ms delay - this is the total time
ofthe sequence so numTog * togDelay must be smaller than interval -
you could update the code to print an erro if this is not the case.
This gives a blip of 3 fast flashes followed by the
delay and is used to warn of the 3 second timeout.
For an even M:S use:
LEDBlinkN(1,100,200)
On for 100ns and Off for 100 ms, total interval time 200ms.
ESP8266 Webserver Init
I modified init.lua slightly to give you a function to stop the
webserver after power up (there's a 3 second window to allow this -
and no obvious way to stop it).[ you can use wifi.sta.disconnect() as well ]
--nodemcu_test_startup
-- load credentials, 'SSID' and 'PASSWORD' declared and initialize in there
dofile("credentials.lua")dofile("LEDBlinkn.lua")functionstartup()iffile.open("init.lua")==nilthenprint("init.lua deleted or renamed")elseprint("Running")file.close("init.lua")LEDBlinkStop()file.close("LEDBlinkn.lua")-- the actual application is stored in 'application.lua'
dofile("application.lua")endend-- Define WiFi station event callbacks
wifi_connect_event=function(T)print("Connection to AP("..T.SSID..") established!")print("Waiting for IP address...")ifdisconnect_ct~=nilthendisconnect_ct=nilendLEDBlinkN(1,100,200)-- faster blinks
endwifi_got_ip_event=function(T)-- Note: Having an IP address does not mean there is internet access!
-- Internet connectivity can be determined with net.dns.resolve().
print("Wifi connection is ready! IP address is: "..T.IP)print("Startup will resume momentarily, you have 3 seconds to abort.")print("Waiting...")startUpTimer=tmr.create()-- JFM mod to allow abort
startUpTimer:alarm(3000,tmr.ALARM_SINGLE,startup)LEDBlinkN(3,50,550)-- fast warning 3, delay
endfunctionstopWiFi()-- JFM
LEDBlinkStop()startUpTimer:stop()startUpTimer:unregister()endwifi_disconnect_event=function(T)LEDBlinkN(2,100,700)-- double flash with delay = error
ifT.reason==wifi.eventmon.reason.ASSOC_LEAVEthen--the station has disassociated from a previously connected AP
returnend-- total_tries: how many times the station will attempt to connect to the AP. Should consider AP reboot duration.
localtotal_tries=75print("\nWiFi connection to AP("..T.SSID..") has failed!")--There are many possible disconnect reasons, the following iterates through
--the list and returns the string corresponding to the disconnect reason.
forkey,valinpairs(wifi.eventmon.reason)doifval==T.reasonthenprint("Disconnect reason: "..val.."("..key..")")breakendendifdisconnect_ct==nilthendisconnect_ct=1elsedisconnect_ct=disconnect_ct+1endifdisconnect_ct<total_triesthenprint("Retrying connection...(attempt "..(disconnect_ct+1).." of "..total_tries..")")elsewifi.sta.disconnect()print("Aborting connection to AP!")disconnect_ct=nilendend-- Register WiFi Station event callbacks
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED,wifi_connect_event)wifi.eventmon.register(wifi.eventmon.STA_GOT_IP,wifi_got_ip_event)wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED,wifi_disconnect_event)LEDBlinkN(1,200,400)-- Idle
print("Connecting to WiFi access point...")wifi.setmode(wifi.STATION)wifi.sta.config({ssid=SSID,pwd=PASSWORD})-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default
Save the above code as init.lua
The above code is a very good example of event driven programming (source here)
The LEDBlinkN() functions display WiFI connection status using the
builtin LED. In addition you can use the function stopWiFi() during the 3
second delay period to halt init.lua. You can also erase the init.lua
file from the ESP8266 to do the same (using
the ESPlorer interface) except blinking LEDs will keep blinking.
The other useful thing about the above code is that it will tell you
why a connection failed so you get a lot of information from it sent to the serial terminal.
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.