ESP8266 NodeMCU Run from heap memory

I am trying to switch an LED using an ESP8266-01 by sending a POST from my laptop (using node.js)

I now have a memory problem because whenever I send a POST request, the memory used in ESP increases and the heap memory decreases and it crashes (restarts) when there is no memory.

any thoughts?

Here is my code on the ESP side (main.lua):

gpio.mode(3, gpio.OUTPUT)
srv=net.createServer(net.TCP,28800)
print("Server created... \n")
local pinState=0
srv:listen(80,function(conn)
    conn:on("receive", function(conn,request)
        local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
        if(method == nil)then
            _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
        end
        local message={}
        print("Method:"..method);
        if(method == "POST")then
          if(pinState==0)then
              gpio.write(3,gpio.HIGH)
              pinState=1
              print("LED ON")
              message[#message + 1] = "HTTP/1.1 200 OK\r\n"
              message[#message + 1] = "Content-Type: text/html\r\n\r\n"
              message[#message + 1] = "POST request successfully received\r\n"
           elseif(pinState==1)then
              gpio.write(3,gpio.LOW)
              pinState=0
              print("LED OFF")
              message[#message + 1] = "HTTP/1.1 200 OK\r\n"
              message[#message + 1] = "Content-Type: text/html\r\n\r\n"
              message[#message + 1] = "POST request successfully received\r\n"
           end 
        elseif(method == "GET")then
           message[#message + 1] = "HTTP/1.1 200 OK\r\n"
           message[#message + 1] = "Content-Type: text/html\r\n\r\n"
           message[#message + 1] = "LED STATE="..tostring(pinState).."\r\n"
        end
        local function send()
          if #message > 0 then 
             conn:send(table.remove(message, 1))
          else
             conn:close()
          end
        end
        conn:on("sent", send)
        send()
        local message={}
        local _, _, method, path, vars= {}
        local heapSize=node.heap()
        if heapSize<1000 then
           node.restart()
        end
        collectgarbage()
        print("Memory Used:"..collectgarbage("count"))
        print("Heap Available:"..heapSize)
    end)
end)

      

On node.js:

var request = require('request');
// Configure request
var options = {
    url: 'http://192.168.1.91',//ESP IP address
    method: 'POST'
}
// Start the request
request(options, function (error, response, body) 
{
    if(!error) 
    {
        return console.log('Server responded with:',body);
    }
    if(error)
    {
        return console.error('ERROR:', error);
    }
})

      

my init.lua just connects to wifi.

Thank you for your help!

Rey

0


source to share


3 answers


There was a problem in the NodeMCU docs with an example socket:send

that you think your implementation was included in. We discussed this and I fixed it.

An improved version of your code is this:

gpio.mode(3, gpio.OUTPUT)
srv = net.createServer(net.TCP, 28800)
print("Server created... \n")
local pinState = 0
srv:listen(80, function(conn)
    conn:on("receive", function(sck, request)
        local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
        if (method == nil) then
            _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
        end
        local message = {}
        message[#message + 1] = "HTTP/1.1 200 OK\r\n"
        message[#message + 1] = "Content-Type: text/html\r\n\r\n"
        print("Method:" .. method);
        if (method == "POST") then
            message[#message + 1] = "POST request successfully received\r\n"
            if (pinState == 0) then
                gpio.write(3, gpio.HIGH)
                pinState = 1
                print("LED ON")
            elseif (pinState == 1) then
                gpio.write(3, gpio.LOW)
                pinState = 0
                print("LED OFF")
            end
        elseif (method == "GET") then
            message[#message + 1] = "LED STATE=" .. tostring(pinState) .. "\r\n"
        end
        local function send(sk)
            if #message > 0 then
                sk:send(table.remove(message, 1))
            else
                sk:close()
                message = nil
                print("Heap Available:" .. node.heap())
            end
        end
        sck:on("sent", send)
        send(sck)
    end)
end)

      



I removed some duplicate padding code message

and I also remove the "reset" and GC code at the end (no longer relevant). The real problem was the closed upvalues to the callback function.

Each of your callback functions should use its own copy of the passed socket instance, rather by referencing one of the callback functions.

  • Line 5 srv:listen(80, function(conn)

    shows the socket variable in the callback conn

    .
  • On line 6 there is another callback function that receives the socket, this time called sck

    . This function should be referred to as sck

    ( sck:on()

    and send(sck)

    ).
  • socket:on("sent")

    the callback itself gets an instance / socket. Your original function send()

    did not use this, it did conn

    . So I added sk

    and only use this in send()

    .
+1


source


Your callback must have one parameter, connection. And you have to configure your sent sender handler at the same level as when you receive it - the conn that is sent to receive is not necessarily the same connection passed to srv: listen.



Finally, redundant copies of string literals are a waste of memory (although this probably won't leak it.)

0


source


So the solution from Marcel worked.

Here's another solution to the problem:

print("Starting main.lua... \n")
gpio.mode(3, gpio.OUTPUT)
srv=net.createServer(net.TCP,28800)
print("Server created... \n")
srv:listen(80,function(conn)
    conn:on("receive", function(conn,request)
        local _,_,method,path= string.find(request, "([A-Z]+) (.+)?(.+) HTTP")
        local _,_,key,light_level = string.find(request, "(%a+)%s*:%s*(%d+)")
        if(method == nil)then
            _,_,method,path = string.find(request, "([A-Z]+) (.+) HTTP")
        end
        local duty=light_level*1023/100
        pwm.setup(3, 500, duty)
        local message={}
        print("Level:"..light_level)
        if(method == "POST")then --light_level was sent from node.js as the header of the request
           if(duty>0)then
              pwm.start(3)
              message = {"HTTP/1.0 200 OK\r\n Content-Type: text/html\r\n\r\n"}
              message[#message + 1] = (light_level/100)
           elseif(duty==0)then
              pwm.stop(3)
              message = {"HTTP/1.0 200 OK\r\n Content-Type: text/html\r\n\r\n"}
              message[#message + 1] = 0
           end 
        elseif(method == "GET")then
           message[#message + 1] = "HTTP/1.1 200 OK\r\n Content-Type: text/html\r\n\r\n"
           message[#message + 1] = "LED STATE="..tostring(pinState).."\r\n"
        end
        local function send()
          if #message > 0 then 
             conn:send(table.remove(message, 1))
          else
             conn:close()
             conn = nil
             collectgarbage()
          end
        end
        conn:on("sent", send)
        send()
        local message = nil
        local _,_,method,path = nil
        local _,_,key,light_level = nil
        local duty=nil
        --for debugging
        local heapSize=node.heap()
        if heapSize<2000 then
           node.restart()
        end
        print("Memory Used:"..collectgarbage("count"))
        print("Heap Available:"..heapSize)
        local heapSize=nil
        --debugging end
    end)
end)

      

0


source







All Articles