2016-05-19 8 views
0

Ich versuche, eine LED mit ESP8266-01 durch Senden POST von meinem Laptop (mit node.js)Esp8266 NodeMCU Running Out of Heap-Speicher

habe ich jetzt ein Speicherproblem zu wechseln, weil, wenn ich POST-Anfrage senden, Der Speicher, der im ESP verwendet wird, nimmt zu, und der Heap-Speicher nimmt ab und es stürzt ab (Neustart), wenn kein Speicher mehr vorhanden ist.

irgendwelche Gedanken?

Hier ist mein Code auf der ESP-Seite (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) 

Auf dem 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); 
    } 
}) 

mein init.lua nur an Wifi verbinden.

Danke für Ihre Hilfe!

Rey

Antwort

1

Es gab ein Problem in der NodeMCU docs with the socket:send example Sie scheinen Ihre Implementierung zu haben basiert. Wir haben darüber gesprochen und ich habe es behoben. diese

Eine verbesserte Version des Codes ist:

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) 

ich einige duplizierten Code WRT entfernt bevöl message und entferne ich auch die „Zurücksetzen“ und GC-Code am Ende (nicht mehr relevant). Das eigentliche Problem war jedoch mit geschlossenen upvalues in den Callback-Funktionen.

Jede Ihrer Callback-Funktionen sollte eine eigene Kopie der übergebenen Socket-Instanz verwenden, die sich auf die einer Wrapping-Callback-Funktion bezieht.

  • Zeile 5 srv:listen(80, function(conn) die Buchse Variable im Callback ist conn.
  • In Zeile 6 gibt es eine andere Callback-Funktion, die einen Socket empfängt, diesmal sck genannt. Es sollte innerhalb dieser Funktion als sck (sck:on() und send(sck)) referenziert werden.
  • Der Callback socket:on("sent") selbst empfängt eine/die Socket-Instanz. Ihre ursprüngliche send()-Funktion hat das jedoch nicht verwendet und stattdessen conn verwendet. Also habe ich sk hinzugefügt und verwende dieses ausschließlich innerhalb send().
+0

Hey Marcel, danke für die Lösung! Ich habe es ausprobiert und es hat funktioniert :) Interessanterweise konnte ich das Problem auch mit einer anderen Methode lösen (ich werde es weiter unten veröffentlichen). – w13

0

Ihr auf gesendet Rückruf sollte einen Parameter, um eine Verbindung akzeptieren. Und Sie sollten den on send-Handler auf der gleichen Ebene wie beim Empfang einrichten - conn, das beim Empfang übergeben wird, ist nicht unbedingt das gleiche conn an srv: listen.

Schließlich redundante Kopien von Zeichenketten ist eine Verschwendung von Speicher, (obwohl das wahrscheinlich nicht dazu führen, lecken.)

0

So die Lösung von Marcel gearbeitet.

Hier ist nur eine weitere Möglichkeit, das Problem zu lösen:

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

Ich bin nicht überrascht, das funktioniert, aber Sie sollten das nicht tun! 'conn = nil' ist etwas, was die Firmware tun sollte, nicht mit der Socket-Instanz zu tun haben. Alle 'local xxx' Deklarationen nach' send() 'sind wirklich irreführend, da diese Variablen bereits deklariert wurden, sie sind obsolet. –