ESP8266 NodeMCU 运行 堆内存不足

ESP8266 NodeMCU Running Out of Heap Memory

我正在尝试通过从我的笔记本电脑发送 POST(使用 node.js)来使用 ESP8266-01 切换 LED

我现在有一个内存问题,因为每当我发送 POST 请求时,ESP 中使用的内存增加,堆内存减少,当没有剩余内存时它会崩溃(重新启动)。

有什么想法吗?

这是我在 ESP 端的代码 (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)

在 node.js:

var request = require('request');
// Configure request
var options = {
    url: 'http://192.168.1.91',//ESP's 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);
    }
})

我的 init.lua 正在连接 Wifi。

感谢您的帮助!

雷伊

您发送的回调应该接受一个参数,一个连接。并且您应该将 on sent 处理程序设置为与 on receive 相同的级别 - 传递给 on receive 的 conn 不一定与传递给 srv:listen.

的 conn 相同

最后,字符串文字的冗余副本是一种内存浪费,(尽管这可能不会导致内存泄漏。)

NodeMCU docs with the socket:send example 您的实施似乎基于该文件。我们讨论了它,我修复了它。

您的代码的改进版本是:

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)

我删除了一些填充 message 的重复代码,我还删除了最后的 "resetting" 和 GC 代码(不再相关)。真正的问题是回调函数中的 closed upvalues

你的每个回调函数都应该使用它自己的传递套接字实例的副本,而不是引用包装回调函数之一。

  • 第 5 行 srv:listen(80, function(conn) 回调中的套接字变量是 conn.
  • 在第 6 行有另一个接收套接字的回调函数,这次称为 sck。它应该在该函数中被引用为 scksck:on()send(sck))。
  • socket:on("sent") 回调本身接收 a/the 套接字实例。您原来的 send() 函数并没有使用它,而是使用了 conn 。所以,我添加了 sk 并在 send().
  • 中专门使用了这个

所以 Marcel 的解决方案奏效了。

这里只是解决问题的另一种选择:

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)