Post your best Lua script examples here

User avatar
By ac21
#15644 In this code why is it when i get to "node.restart()" it doesn't restart and start my wifi.lua? It just skips it :|

Code: Select all--file.open("init.lua","w")
--file.write(print("Wifi connect timed out."))

 --file.close()
print("WIFI control")
-- put module in AP mode
wifi.setmode(wifi.SOFTAP)
print("ESP8266 mode is: " .. wifi.getmode())
cfg={}
-- Set the SSID of the module in AP mode and access password
cfg.ssid="ESP_STATION"
cfg.pwd="password"
if ssid and password then
print("ESP8266 SSID is: " .. cfg.ssid .. " and PASSWORD is: " .. cfg.password)
end
-- Now you should see an SSID wireless router named ESP_STATION when you scan for available WIFI networks
-- Lets connect to the module from a computer or mobile device. So, find the SSID and connect using the password selected
wifi.ap.config(cfg)
ap_mac = wifi.ap.getmac()
-- create a server on port 80 and wait for a connection, when a connection is coming in function c will be executed
sv=net.createServer(net.TCP,30)
sv:listen(80,function(c)
c:on("receive", function(c, pl)

-- print the payload pl received from the connection
print(pl)
print(string.len(pl))

-- wait until SSID comes back and parse the SSID and the password
print(string.match(pl,"GET"))
ssid_start,ssid_end=string.find(pl,"SSID=")
if ssid_start and ssid_end then
amper1_start, amper1_end =string.find(pl,"&", ssid_end+1)
if amper1_start and amper1_end then
http_start, http_end =string.find(pl,"HTTP/1.1", ssid_end+1)
if http_start and http_end then
ssid=string.sub(pl,ssid_end+1, amper1_start-1)
password=string.sub(pl,amper1_end+10, http_start-2)
print("ESP8266 connecting to SSID: " .. ssid .. " with PASSWORD: " .. password)
if ssid and password then
sv:close()
-- close the server and set the module to STATION mode
--wifi.setmode(wifi.STATIONAP)
wifi.setmode(wifi.STATION);
print("ESP8266 mode now is: " .. wifi.getmode())
-- configure the module wso it can connect to the network using the received SSID and password
wifi.sta.config(ssid,password)
wifi.sta.connect()
file.open("init.lua","w")
file.write('dofile("wifi.lua")')

 file.close()
node.restart()
for i = 1, 10 do            -- count up
   print(i..' banana')
print(wifi.sta.getip())
   tmr.delay(1000000)
end



print("before timer")
--print("before timer" .. wifi_ip )
print("Setting up ESP8266 for station mode…Please wait.")
print(wifi.sta.getip())
--print("before timer" ..wifi.ap.getip() )

 
print("ESP8266 STATION IP now is: " .. wifi.sta.getip())
print("ESP8266 AP IP now is: " .. wifi.ap.getip())
-- now the module is configured and connected to the network so lets start setting things up for the control logic
print("Made it here" ..wifi.sta.getip() )
gpio.mode(8,gpio.OUTPUT)
gpio.mode(9,gpio.OUTPUT)

tmr.delay(10)
--gpio.write(8,gpio.HIGH)
tmr.delay(10)
--gpio.write(8,gpio.LOW)
sv=net.createServer(net.TCP, 30)
sv:listen(9999,function(c)
c:on("receive", function(c, pl)
if tonumber(pl) ~= nil then
if tonumber(pl) >= 1 and tonumber(pl) <= 16 then
print(tonumber(pl))
tmr.delay(10)
--gpio.write(8,gpio.HIGH)
tmr.delay(10)
--gpio.write(8,gpio.LOW)
for count =1,tonumber(pl) do
 print(count)
tmr.delay(10)
-- gpio.write(9,gpio.LOW)
tmr.delay(10)
--gpio.write(9,gpio.HIGH)
c:send("Sequence finished")
end
end
end


print("ESP8266 STATION IP now is: " .. new_ip)

c:send("ESP8266 STATION IP now is: " .. new_ip)

c:send("Action completed")
end)
end)

end
end
end
end
-- this is the web page that requests the SSID and password from the user
c:send("<!DOCTYPE html> ")
c:send('<html lang="en">')
c:send("<body> ")
c:send("<h1>ESP8266 Wireless control setup</h1> ")
mac_mess1 = "The module MAC address is: " .. ap_mac
c:send("<h2>" .. mac_mess1 .. "</h2> ")
--c:send("<h2>" .. mac_mess2 .. "</h2> ")
c:send("<h2>Enter SSID and Password for your WIFI router</h2> ")
c:send("</form> </body> </html>")
c:send('<form action=" method="get">')
c:send("SSID:")
c:send('<input type="text" name="SSID"  />')
c:send("<br />")
c:send("Password:")
c:send('<input type="text" name="Password" />')
c:send('<input type="submit" value="Submit" />')
end)
end)

 --   file.close()
User avatar
By TerryE
#15698 I am not sure how to put thist, but I am not sure how your code works at all let alone that you are not correctly executing the code path with the node.restart in it. Have you built this up incrementally and unit tested each component, or have you just written in as a one-shot and are now trying to get it working?

As I have tried to explain on other topics, (open-source) nodeMCU Lua is layered over the (closed source) ESP8266 firmware, but the ESP8266 SDK / API is intrinsically event driven, which means that you organise your applications code as a set of event-driven action routines very much the same way as you'd write jQuery code for a browser.

Lua on the ESP8266 works in exactly the same way. My suggestion is to keep your action routines short as practical and sequence the overall execution through some global variables to hold the context. There aren't any mutex issues because each Lua action function runs to completion before another action can fire.

So using a node.delay() to pulse an I/O pin high for 10μS is fine, but trying to use it delay for a second is just crazy as this will just block whatever you are waiting for from happening.

So I could start rewriting your code, but its better if you do this restructuring:
  • To keep things readable, I suggest that you split out any action routes to the module top level (because that's where they run on the call stack anyway.
  • Avoid using inheritance (upvalues) in your action routines because how these work in practice is counter intuitive and you could get burnt. Move this stuff into global context.
  • Use local variables for everything else, as this generates tighter and more efficient code anyway.
  • If you need to sequence stuff at a higher level then hang this all off a timer alarm loop. This lets other asynchronous system functions (e.g. wifi negotiation) in to do its stuff.
  • The ESP8266 SDK doesn't seem to use Nagle's algorithm for TCP packet marshalling so it makes send to do this in your code; this generates less code and works more reliably anyway. For example:
    Code: Select allc:send([[<!DOCTYPE html>
      <html lang="en"><body>
      <h1>ESP8266 Wireless control setup</h1>
      <h2>The module MAC address is: ]] .. ap_mac .. [[</h2>
      <h2>Enter SSID and Password for your WIFI router</h2>
      <form action=" method="get">
      SSID: <input type="text" name="SSID"  /> <br />
      Password: <input type="text" name="Password" />
      <input type="submit" value="Submit" />
      </form> </body> </html>
    ]])
    And BTW, writing this way made it clear enough to spot an error in your HTML as well.
  • just because you've called send doesn't mean that the record has been sent; it means that the send has been scheduled. It hasn't been send until the corresponding on("send" fires.
Anyway, I am only trying to give sound advice, and so forgive me if I seem a little abrupt. //Terry
User avatar
By ac21
#15705 I understand, thank you, I'm still learning the proper way to write code.

This was something i copied and made some changes...

Code: Select allfile.open("init.lua","w")
file.write('dofile("wifi.lua")')

 file.close()
node.restart()
for i = 1, 10 do            -- count up
   print(i..' banana')
print(wifi.sta.getip())
   tmr.delay(1000000)
end


I can see watching the serial monitor it starts counting "banana" and it created a init file with dofile, but just not understanding why it skipped the restart code.
I'm running NodeMCU 0.9.6 build 20150406, Lua 5.1.4
User avatar
By TerryE
#15706 I was going to PM you this, but as far as I can see the admin has disabled PMs, so I will post it here. It have just hacked your code around to give you a general idea of how to structure this. I don't think that you need the reboot between changing the station mode but if you do then remember that you will need to write the status to a file to allow you to detect which mode you are in by writing/reading a file (e.g. a one-liner Lua file with do_next=some_routine in it. Anyway here is my attempt at this. Just remember that I've not even tried to compile it. :P
Code: Select all--file.open("init.lua","w")
--file.write(print("Wifi connect timed out."))

 --file.close()

function setup_AP()
  print("WIFI control")
  -- put module in AP mode
  wifi.setmode(wifi.SOFTAP)
  print("ESP8266 mode is: " .. wifi.getmode())

  -- Set the SSID of the module in AP mode and access password
  cfg = {sid="ESP_STATION", pwd="password"}
  if ssid and password then
    print("ESP8266 SSID is: " .. cfg.ssid .. " and PASSWORD is: " .. cfg.password)
  end
  -- Now you should see an SSID wireless router named ESP_STATION when you scan for available WIFI networks
  -- Lets connect to the module from a computer or mobile device. So, find the SSID and connect using the password selected
  wifi.ap.config(cfg)
  do_next = connect_to_80
end

function connect_to_80()
  ap_mac = wifi.ap.getmac()
  if not ap_mac then return
  -- create a server on port 80 and wait for a connection, when a connection is coming in function c will be executed
  sv=net.createServer(net.TCP,30)
  sv:listen(80,function(c)
    c:on("receive", Receive_80)
    do_next = sent_form
    end)
end

function sent_form()
    -- this is the web page that requests the SSID and password from the user
 c:send([[<!DOCTYPE html>
  <html lang="en"><body>
  <h1>ESP8266 Wireless control setup</h1>
  <h2>The module MAC address is: ]] .. ap_mac .. [[</h2>
  <h2>Enter SSID and Password for your WIFI router</h2>
  <form action=" method="get">
  SSID: <input type="text" name="SSID"  /> <br />
  Password: <input type="text" name="Password" />
  <input type="submit" value="Submit" />
  </form> </body> </html>
]])
end

function Receive_80(c, pl)
  -- print the payload pl received from the connection
  print(#pl, pl)

  if not pl:match( "GET ") return end
 
  local _, ssid_end = pl:find("SSID=", 1, true)
  local _, amper1_end = pl:find("&Password=", 1, true)
  local _, http_end = pl:find("HTTP/1.1", 1, true
 
  if ssid_end and amper1_end and http_end and
     ssid_end < amper1_end < http_end then
    _G.ssid = pl:sub(ssid_end+1, amper1_start-1)
    _G.password = pl:sub(amper1_end+1, http_start-2)
    print("ESP8266 connecting to SSID: " .. ssid .. " with PASSWORD: " .. password)
    if ssid and password then
      sv:close()
      do_next = setup_station
    end
  end
end

function setup_station()       
  -- close the server and set the module to STATION mode
  --wifi.setmode(wifi.STATIONAP)
  wifi.setmode(wifi.STATION);
  print("ESP8266 mode now is: " .. wifi.getmode())
  -- configure the module wso it can connect to the network using the received SSID and password
  wifi.sta.config(ssid,password)
  wifi.sta.connect()
  file.open("init.lua","w")
  file.write('dofile("wifi.lua")')
  file.close()
  do_next = check_setup
end
   
function check_setup()
  local ip = wifi.sta.getip()
  if not ip then return end
       
  print("before timer")
  --print("before timer" .. wifi_ip )
  print("Setting up ESP8266 for station mode…Please wait.")
  print(wifi.sta.getip())
  --print("before timer" ..wifi.ap.getip() )
  print("ESP8266 STATION IP now is: " .. wifi.sta.getip())
  print("ESP8266 AP IP now is: " .. wifi.ap.getip())
  -- now the module is configured and connected to the network so lets start setting things up for the control logic
  print("Made it here" ..wifi.sta.getip() )
  gpio.mode(8,gpio.OUTPUT)
  gpio.mode(9,gpio.OUTPUT)

  tmr.delay(10)
  --gpio.write(8,gpio.HIGH)
  tmr.delay(10)
  --gpio.write(8,gpio.LOW)
  sv=net.createServer(net.TCP, 30)
  sv:listen(9999,function(c)
    c:on("receive", Receiver9999)
  end)
  tmr.stop(0); tmr.alarm( 0, 1000, 0, print);  tmr.stop(0)
end

function Receive9999(c, pl)
  if tonumber(pl) ~= nil then
    if tonumber(pl) >= 1 and tonumber(pl) <= 16 then
      print(tonumber(pl))
      tmr.delay(10)
      --gpio.write(8,gpio.HIGH)
      tmr.delay(10)
      --gpio.write(8,gpio.LOW)
      for count =1,tonumber(pl) do
        print(count)
        tmr.delay(10)
        -- gpio.write(9,gpio.LOW)
        tmr.delay(10)
        --gpio.write(9,gpio.HIGH)
-- ????? The output is HTML. What is debug doing here ??????
        c:send("Sequence finished")
-- ?????????????????????????????????????????????????????????
      end
    end
  end

  print("ESP8266 STATION IP now is: " .. new_ip)

-- ????? The output is HTML. What is debug doing here ??????
  c:send("ESP8266 STATION IP now is: " .. new_ip .. "Action completed")
-- ?????????????????????????????????????????????????????????
end


do_next = setup_AP
tmr.alarm( 0, 1000, 1, function() do_next() end)

Hope this gets you in the right directiom. Terry