To interact with our NodeMCU, we could use an HTTP server. The Hello world version of this is quite simple:
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive",function(cn,request)
print(request)
cn:send("Hello world")
cn:close();
collectgarbage();
end)
end)
Upload and to your NodeMCU and execute it. If you now go to the IP of your NodeMCU, you should see Hello world.
The code is relatively straight forward. You create a TCP server which listens on port 80
If you want to try different things with your code and you execute it again, you will get the error message only one tcp server allowed if you have not restarted the NodeMCU since the last time you executed the code. Instead of restarting, executing the following:
srv:close()
This will stop the current server and you can execute your file again to restart it. Since LUA on the NodeMCU keeps variables even after the program has stopped we can create a more resilient version this way:
----------------------
-- --
-- httpserver.lua --
-- --
----------------------
-- check whether server is already started
if srv~=nil then
srv:close()
end
-- create webserver
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive",function(cn,request)
print(request)
-- the webpage
cn:send("Hello world")
cn:close()
collectgarbage()
end)
end)
Next step, actually interact with the NodeMCU. For this we need to be able to send it requests of some sort. For testing I connected two leds to the NodeMCU, port 2 and port 3. I want to use the webserver to control the leds. Let’s first post the code which I will explain below it:
-----------------------
-- --
-- httpserver2.lua --
-- --
-----------------------
-- 1:set variables and initial GPIO states
led1 = 2
led2 = 3
gpio.mode(led1,gpio.OUTPUT)
gpio.mode(led2,gpio.OUTPUT)
gpio.write(led1,gpio.LOW)
gpio.write(led2,gpio.LOW)
-- 2:check whether server is already started
if srv~=nil then
srv:close()
end
-- 3:create webserver
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive",function(cn,request)
local buf = ""
-- 4:extra path and variables
local _,_,method,path,vars = string.find(request,"([A-Z]+) (.+)?(.+) HTTP")
if(method==nil) then
_, _, method, path = string.find(request,"([A-Z]+) (.+) HTTP")
end
-- 5:extract the variables passed in the url
local _GET = {}
if (vars~=nil) then
for k,v in string.gmatch(vars,"(%w+)=(%w+)&*") do
_GET[k] = v
end
end
-- 6:the webpage
buf = buf.."
Demo server
” buf = buf..”Led 1 Turn on ” buf = buf..”Turn off
” buf = buf..”Led 2 Turn on ” buf = buf..”Turn off
” — 7:the actions if (_GET.pin==”L1On”) then gpio.write(led1,gpio.HIGH) elseif (_GET.pin==”L1Off”) then gpio.write(led1,gpio.LOW) elseif (_GET.pin==”L2On”) then gpio.write(led2,gpio.HIGH) elseif (_GET.pin==”L2Off”) then gpio.write(led2,gpio.LOW) end — 8:send the data and close the connection cn:send(buf) cn:close() collectgarbage() end) end)
Section 1 is straight forward, set variables for the ports of led 1 and 2 and turn off both leds.
In section 2 we close the current server if it is started to be followed by section 3 where the new http server is created, both described above.
Section 4 is where we take the request information send by the user and using pattern matching, extract the path and the variables (if any). In section 5 we put the variables in a LUA table, again using pattern matching.
Section 6 is the webpage. In this case we did not check the path variable. Regardless of what page you request, you will always get the same page.
Finally, section 7 is where we perform the GPIO actions based on the request and section 8 is where the data is send to the user and the connection is closed.