0

我有一个完全可以工作的 esp 芯片,可以连接到 wifi 并创建一个服务器。当我向它发送 OTA 命令时,它会运行一个使用套接字连接下载文件的函数。

这是我正在使用的 upgrader.lua:

--------------------------------------
-- Upgrader module for NODEMCU
-- LICENCE: http://opensource.org/licenses/MIT
-- cloudzhou<wuyunzhou@espressif.com> - 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

作为测试,我发送它: filename = rz.lua 和 url = http://192.168.1.132/rz.lua。cn 变量是将信息发送回客户端的连接。

esp芯片打印:

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

该问题似乎与 conn:send() 命令有关。如果它在 on connect 函数中,它会重置。如果它在外面,我会得到一个读取超时(因为读取时永远不会被调用)。我真的不知道还能做什么。

这是 ESP 固件信息:

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

2 回答 2

2

你正在重置。“垃圾”是波特率错误的 BootROM 消息。

不要在同一个回调中先发送后关闭。使用 on('sent', ... ) 触发关闭。因此,您的警报 2 回调的 21 行正文会更好地编写:

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)

在那一点上,您的 27 行断开回调会更好地编写:

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)

请注意,在写入或删除文件后刷新 SPIFFS 总是明智的。

您使用标准模式,为什么不封装它:

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

我可以继续,但我把这个留给你。稍加考虑,您的代码将只有三分之一的大小并且更具可读性。

于 2016-01-08T13:36:58.927 回答
0

我不能确定,但​​问题似乎是内存错误(很奇怪,因为没有恐慌)所以这就是我修复它的方法:

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)

我使用 table.concat 方法并使用表格而不是一个大字符串创建了请求。希望这对有需要的人有所帮助。

于 2015-12-28T03:30:21.523 回答