Left here for archival purposes.

User avatar
By cebrax
#32309 I am trying to create a webserver and an easy config user interface based on Marcos Kirsch's nodemcu-httpserver. I am using nodemcu-master build v0.9 with flashid of 1261768. I have downloaded the master build from http://frightanic.com/nodemcu-custom-build/.

I want to send list of APs back to the user with a script file "get_nw.lua", however whenever the callback that is defined in the argument of function wifi.sta.getap(), the system reboots with below output:

Code: Select allRequested URL: /nw.html
Method: GET
File: nw.html
Begin sending:   nw.html
Sent   nw.html   1024
Sent   nw.html   2048
Sent   nw.html   3072
Sent   nw.html   4096
Sent   nw.html   5120
Sent   nw.html   5426
Finished sending:   nw.html
 
Requested URL: /get_nw.lua
Method: GET
File: get_nw.lua
Begin sending:   get_nw.lua
Finished sending:   get_nw.lua
 

 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x40100000, len 28608, room 16
tail 0
chksum 0x5b
load 0x3ffe8000, len 3020, room 8
tail 4
chksum 0x61
load 0x3ffe8bcc, len 8, room 4
tail 4
chksum 0xb1
csum 0xb1
rL


I have tried various things with the callback function including the function in the examples of nodemcu wiki. All the things I've tried works when run in a standalone script file or somewhere else in the program. However, it creates problem when called within the function in "get_nw.lua"

Here are the various files:

init.lua:
Code: Select alltmr.delay(4000000)
print("Started nodeMCU...")

-- Set UART Configuration
uart.setup(0,115200,8,0,1)

-- Work at 160 MHz
node.setcpufreq(node.CPU160MHZ)

-- Begin WiFi configuration

local wifiConfig = {}

-- wifi.STATION         -- station: join a WiFi network
-- wifi.SOFTAP          -- access point: create a WiFi network
-- wifi.wifi.STATIONAP  -- both station and access point
wifiConfig.mode = wifi.STATIONAP  -- both station and access point

wifiConfig.accessPointConfig = {}
wifiConfig.accessPointConfig.ssid = "ahsa-IOT-node-"..node.chipid()   -- Name of the SSID you want to create
wifiConfig.accessPointConfig.pwd = "abdullah12345"    -- WiFi password - at least 8 characters

wifiConfig.accessPointIpConfig = {}
wifiConfig.accessPointIpConfig.ip = "192.168.25.1"
wifiConfig.accessPointIpConfig.netmask = "255.255.255.0"
wifiConfig.accessPointIpConfig.gateway = "192.168.25.1"

wifiConfig.stationPointConfig = {}
wifiConfig.stationPointConfig.ssid = "ahsa-wireles"        -- Name of the WiFi network you want to join
wifiConfig.stationPointConfig.pwd =  "ikizdere12345"                -- Password for the WiFi network

-- Tell the chip to connect to the access point

wifi.setmode(wifiConfig.mode)
print('set (mode='..wifi.getmode()..')')

if (wifiConfig.mode == wifi.SOFTAP) or (wifiConfig.mode == wifi.STATIONAP) then
    print('AP MAC: ',wifi.ap.getmac())
    wifi.ap.config(wifiConfig.accessPointConfig)
    wifi.ap.setip(wifiConfig.accessPointIpConfig)
end
if (wifiConfig.mode == wifi.STATION) or (wifiConfig.mode == wifi.STATIONAP) then
    print('Client MAC: ',wifi.sta.getmac())
    wifi.sta.config(wifiConfig.stationPointConfig.ssid, wifiConfig.stationPointConfig.pwd, 1)
end

print('chip: ',node.chipid())
print('heap: ',node.heap())

wifiConfig = nil

-- End WiFi configuration

-- Compile server code and remove original .lua files.
-- This only happens the first time afer the .lua files are uploaded.

local compileAndRemoveIfNeeded = function(f)
   if file.open(f) then
      file.close()
      print('Compiling:', f)
      node.compile(f)
      file.remove(f)
   end
end

local serverFiles = {'httpserver.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-header.lua', 'httpserver-error.lua'}
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end

compileAndRemoveIfNeeded = nil
serverFiles = nil

-- Connect to the WiFi access point.
-- Once the device is connected, you may start the HTTP server.

if (wifi.getmode() == wifi.STATION) or (wifi.getmode() == wifi.STATIONAP) then
    local joinCounter = 0
    local joinMaxAttempts = 5
    tmr.alarm(0, 3000, 1, function()
       local ip = wifi.sta.getip()
       if ip == nil and joinCounter < joinMaxAttempts then
          print('Connecting to WiFi Access Point ...')
          joinCounter = joinCounter +1
       else
          if joinCounter == joinMaxAttempts then
             print('Failed to connect to WiFi Access Point.')
          else
             print('IP: ',ip)
          end
          tmr.stop(0)
          joinCounter = nil
          joinMaxAttempts = nil
       end
    end)
end

-- Uncomment to automatically start the server in port 80
if (not not wifi.sta.getip()) or (not not wifi.ap.getip()) then
    dofile("httpserver.lc")(80)   
end


httpserver.lua:
Code: Select all-- httpserver
-- Author: Marcos Kirsch

-- Starts web server in the specified port.
return function (port)
   local s = net.createServer(net.TCP, 10) -- 10 seconds client timeout
   s:listen(
      port,
      function (connection)

         -- This variable holds the thread used for sending data back to the user.
         -- We do it in a separate thread because we need to yield when sending lots
         -- of data in order to avoid overflowing the mcu's buffer.
         local connectionThread
         
         local function onRequest(connection, req)
            collectgarbage()
            local method = req.method
            local uri = req.uri
            local fileServeFunction = nil
           
            print("Method: " .. method)
            print("File: " .. uri.file)
           
            if #(uri.file) > 32 then
               -- nodemcu-firmware cannot handle long filenames.
               uri.args = {code = 400, errorString = "Bad Request"}
               fileServeFunction = dofile("httpserver-error.lc")
            else
               local fileExists = file.open(uri.file, "r")
               file.close()
           
               if not fileExists then
                  uri.args = {code = 404, errorString = "Not Found"}
                  fileServeFunction = dofile("httpserver-error.lc")
               else
                  uri.args = {file = uri.file, ext = uri.ext, args = uri.args}
                  fileServeFunction = dofile("httpserver-static.lc")
               end
            end
            connectionThread = coroutine.create(fileServeFunction)
            coroutine.resume(connectionThread, connection, req, uri.args)
            -- print(uri.args.file, uri.args.ext, uri.args.args)
            -- fileServeFunction(connection, req, uri.args)
            -- connection:close()
         end

         local function onReceive(connection, payload)
            collectgarbage()

            -- parse payload and decide what to serve.
            local req = dofile("httpserver-request.lc")(payload)
            print("Requested URL: " .. req.request)
           
            onRequest(connection, req)
         end

         local function onSent(connection, payload)
            collectgarbage()
            if connectionThread then
               local connectionThreadStatus = coroutine.status(connectionThread)
               if connectionThreadStatus == "suspended" then
                  -- Not finished sending file, resume.
                  coroutine.resume(connectionThread)
               elseif connectionThreadStatus == "dead" then
                  -- We're done sending file.
                  connection:close()
                  connectionThread = nil
               end
            end
         end

         connection:on("receive", onReceive)
         connection:on("sent", onSent)

      end
   )
   -- false and nil evaluate as false
   local ip = wifi.sta.getip()
   if not ip then ip = wifi.ap.getip() end
   print("nodemcu-httpserver running at http://" .. ip .. ":" ..  port)
   return s
end



httpserver-static.lua:
Code: Select all-- Part of nodemcu-httpserver, handles sending static files to client.
-- Author: Marcos Kirsch

return function (connection, req, args)
   print("Begin sending:", args.file)
   -- Send file in little chunks
   local continue = true
   local bytesSent = 0
   if args.ext == "lua" then
      dofile(args.file)(connection, req, args.args)
      continue = false
   end
   if continue then
      dofile("httpserver-header.lc")(connection, 200, args.ext)   
   end
   while continue do
      collectgarbage()
      -- NodeMCU file API lets you open 1 file at a time.
      -- So we need to open, seek, close each time in order
      -- to support multiple simultaneous clients.
      file.open(args.file)
      file.seek("set", bytesSent)
      local chunk = file.read(1024)
      file.close()
      if chunk == nil then
            continue = false
      else
         coroutine.yield()
         connection:send(chunk)
         bytesSent = bytesSent + #chunk
         chunk = nil
         print("Sent", args.file, bytesSent)
      end
   end
   print("Finished sending:", args.file)
   print(" ")
   bytesSent = nil
   continue = nil
end



get_nw.lua:
Code: Select allreturn function (connection, req, args)
   collectgarbage()
   local fin = 0
   local info_table = {}
   local json_string = '{';
   info_table.ssid, info_table.pwd = wifi.sta.getconfig()
   info_table.ip,
    info_table.netmask,
    info_table.gateway = wifi.sta.getip()
   if (wifi.sta.status() == 5) then
      info_table.connected = "true"
   else
      info_table.connected = "false"
   end
   for key, val in pairs(info_table) do
      json_string = json_string .. '"' .. tostring(key) .. '" : "' .. tostring(val) .. '", '
   end
   wifi.sta.getap(print)
   json_string = string.sub(json_string, 1, -3)
   json_string = json_string .. '}'
   connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n")
    connection:send(json_string)
    fin = nil
    info_table = nil
    json_string = nil
end