Andres S
Andres S

Reputation: 471

ESP8266 reset (no panic) after socket connection

I have a completely working esp chip that connects to wifi and creates a server. When I send it an OTA command, it runs a function that downloads a file using a socket connection.

This is the upgrader.lua that I am using:

--------------------------------------
-- Upgrader module for NODEMCU
-- LICENCE: http://opensource.org/licenses/MIT
-- cloudzhou<[email protected]> - Heavily modified by aschmois
--------------------------------------

--[[
update('file.lua', 'http://IP.ADRESS/path/file.lua')
]]--

local header = ''
local isTruncated = false
local function save(filename, response)
    if isTruncated then
        file.write(response)
        return
    end
    header = header..response
    local i, j = string.find(header, '\r\n\r\n')
    if i == nil or j == nil then
        return
    end
    prefixBody = string.sub(header, j+1, -1)
    file.write(prefixBody)
    header = ''
    isTruncated = true
    return
end

----
function update(filename, url, cn)
    local tmpError = nil
    local running = true
    local error = nil
    local success = false
    print("Downloading from: " .. url)
    local ip, port, path = string.gmatch(url, 'http://([0-9.]+):?([0-9]*)(/.*)')()
    if ip == nil then
        return false
    end
    if port == nil or port == '' then
        port = 80
    end
    port = port + 0
    if path == nil or path == '' then
        path = '/'
    end
    print("-- Detailed Connection Info --")
    print("IP: ".. ip)
    print("Port: ".. port)
    print("Path: ".. path)
    print("-- END --")
    local function timeout() 
        error = tmpError
        file.remove(filename)
        conn:close()
        running = false
    end
    conn = net.createConnection(net.TCP, false)
    conn:on('connection', function(sck, response)
        tmr.stop(1)
        file.open(filename, 'w')
        conn:send('GET '..path..' HTTP/1.0\r\nHost: '..ip..'\r\n'..'Connection: close\r\nAccept: */*\r\n\r\n')
        tmpError = "READ TIMEOUT"
        tmr.alarm(1, 10000, 0, timeout)
    end)
    conn:on('receive', function(sck, response)
        tmr.stop(1)
        tmpError = "READ(2) TIMEOUT"
        tmr.alarm(1, 10000, 0, timeout)
        print(response)
        save(filename, response)
    end)
    conn:on('disconnection', function(sck, response)
        tmr.stop(1)
        local function reset()
            local list = file.list()
            for k,v in pairs(list) do
                if(filename == k) then
                    if(v == 0) then
                        success = false
                        file.close()
                        file.remove(filename)
                    else
                        file.close()
                        success = true
                    end
                end
            end
            print(header)
            header = ''
            isTruncated = false
            if(success) then
                print(filename..' saved')
            else
                print("Could not download `".. filename.."`")
            end
            running = false
        end
        tmr.alarm(0, 2000, 0, reset)
    end)
    conn:connect(port, ip)
    tmpError = "CONN TIMEOUT"
    tmr.alarm(1, 10000, 0, timeout)
    tmr.alarm(2, 1000, 1, function()
        if(running == false) then
            tmr.stop(2)
            local buf = ''
            if(success) then
                buf = buf.."HTTP/1.1 200 OK\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n"
                buf = buf.."1"
            else
                buf = buf.."HTTP/1.1 500\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n"
                buf = buf.."0"
                buf = buf.."\n"
                if(error ~= nil) then
                    buf = buf..error
                else
                    buf = buf.."UNKNOWN ERROR"
                end
            end
            cn:send(buf)
            cn:close()
        end
    end)
    return true
end

As a test I am sending it: filename = rz.lua and url = http://192.168.1.132/rz.lua. The cn variable is the connection to send back information to the client.

The esp chip prints:

Downloading from: http://192.168.1.132/rz.lua
-- Detailed Connection Info --
IP: 192.168.1.132
Ò_ÇRöfJSúfÊÃjêÐÿ (junk reset data)

The problem seems to be connected with the conn:send() command. If it's inside the on connect function it resets. If it's outside, I will get a read timeout (since on read is never called). I really have no idea what else to do.

This is the ESP firmware info:

NodeMCU custom build by frightanic.com
    branch: master
    commit: 93421f2702fb02ce169f82f96be7f2a8865511e1
    SSL: false
    modules: node,file,gpio,wifi,net,tmr,uart

Upvotes: 0

Views: 1014

Answers (2)

TerryE
TerryE

Reputation: 10888

You are resetting. The "junk" is a BootROM message at the wrong baud rate.

Don't do a send followed by a close in the same callback. Use an on('sent', ... ) to trigger the close. So the 21 line body of your alarm 2 callback would be better written:

local response = "HTTP/1.1 200 OK\r\nServer: WiFi Relay\r\nContent-Type: text/plain\r\n\r\n%s"
cn:send(response:format(success and "1" or ("0\n\r" .. (error or "UNKNOWN ERROR")))
cn:on('sent', function(cn) cn:close() end)

On that note your 27 line disconnect callback would be better written:

tmr.stop(1)
tmr.alarm(0, 2000, 0, function()
  local len = file.list()(filename)
  success = len and len > 0
  file.close()
  if not success then file.remove(filename)
  file.flush()
  end)

Note that it's always wise to flush the SPIFFS after writing or removing files.

You use a standard pattern, so why not encapsulate it:

local conn = net.createConnection(net.TCP, false) 
local function setTimeout(reason)
 -- tmr.stop(1)   -- not needed is the next line resets the alarm
  tmr.alarm(1, 10000, 0, function ()
    -- you don't need tmpError as reason is a local and bound as an upval
    error, running = reason, false
    file.remove(filename) file.flush()
    return conn:close()
  end)
end

I could go on but I leave this to you. With a little thought, your code would be a third of the size and more readable.

Upvotes: 2

Andres S
Andres S

Reputation: 471

I can't be sure but the problem seems to have been a memory error (weird since there was no panic) so this is what I did to fix it:

local request = table.concat({"GET ", path,
                        " / HTTP/1.1\r\n", 
                        "Host: ", ip, "\r\n",
                        "Connection: close\r\n",
                        "Accept: */*\r\n",
                        "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)",
                        "\r\n\r\n"})
    conn = net.createConnection(net.TCP, false)
    conn:on('connection', function(sck, response)
        tmr.stop(1)
        tmpError = "READ TIMEOUT"
        tmr.alarm(1, 10000, 0, timeout)
        conn:send(request)
    end)

I created the request using the table.concat method and using a table instead of one big string. Hopefully this will help those in need.

Upvotes: 0

Related Questions