使用Wifi将Lua脚本上传到NodeMCU

时间:2015-12-14 11:50:26

标签: lua wifi nodemcu

是否可以使用Wifi界面而不是串行将Lua脚本上传到NodeMCU?

我发现的教程和示例都使用串行接口(即电缆)来编程NodeMCU,但我想更改程序而不连接任何东西(使用智能手机或浏览器)

5 个答案:

答案 0 :(得分:5)

我通过wifi上传所有模块。我首先以通常的方式(通过USB)上传bootstrap.lua程序。然后,该程序可用于上载实际(较大)有效载荷。这是引导程序:

ip, mask, host = wifi.sta.getip()
port, path, pgm = 80, "/upload", "u.lc"
file.remove(pgm) ; file.open(pgm, "w+") payloadFound = false
local conn = net.createConnection(net.TCP, 0)
conn:on("connection", function(conn)
        conn:send("GET "..path.."/"..pgm.." HTTP/1.0\r\n".."Host: "..host.."\r\nConnection: close\r\nAccept: */*\r\n\r\n") end)
conn:on("receive", function(conn, payload)
        if (payloadFound) then file.write(payload) file.flush()
        else payloadOffset = string.find(payload, "\r\n\r\n")
                if (payloadOffset) then
                        file.write(string.sub(payload, payloadOffset + 4)) file.flush() payloadFound = true
                end end end)
conn:on("disconnection", function(conn) file.close() dofile(pgm) end) conn:connect(port,host)

第一行使用网关服务器作为上传程序的Web服务器。 第二行设置要上载的程序的端口(80),路径(/upload)和名称(u.lc)。 然后它获取文件并最终运行它(最后一行)。

在运行此功能之前,您必须激活无线连接,当然,您的网络服务器应处于活动状态,并且您的有效负载位于/upload/u.lc

当然,您可以更改硬连线值,甚至可以使它们动态化。

标题##这应该是您想要的简单起点。

BTW,缩放格式可以快速进行初始上传,我使用luatool.py选项上传--dofile

稍后更新您的计划(u.lc)只是dofile("bootstrap.lua")的简单重复。

我的u.lc是第2阶段的引导程序,它上传了一长串文件(主要是.lc)。对于这个简短的回答,可能也太过牵扯。

最后,我要提一下,这是基于https://github.com/Manawyrm/ESP8266-HTTP/

HTH

答案 1 :(得分:2)

是的,这是可能的。它是一种自制的选择,但它在一定程度上起作用。当然,唯一的限制是尺寸,但除此之外它的效果非常好。看看:

http://www.instructables.com/id/ESP8266-WiFi-File-Management/

你需要有办法编写PHP程序(我用C#编写),如果你不能用另一种语言编写代码,你可以下载并重用这个用户编写的代码并使用你自己的PHP服务器和你应该好好去。

如果您有任何疑问,请询问。

答案 2 :(得分:2)

我有另一个解决方案,没有大小限制。此外,它不需要任何其他Web服务器,您可以直接从工作站发送文件。下面的文件提供了上传和下载到芯片的内容。

不幸的是,它没有使用网络浏览器使用的标准上传方案,最后提供了一个上传到它的javascript文件。可以在SendTo文件夹中创建js的快捷方式,从而将其添加到每个文件的上下文菜单中的“发送到”选项列表中,但它只能处理单个文件选择。 (处理多个选定文件时需要一个shell扩展名。)

它支持定期浏览器下载。

请注意,此方案主要依赖于某种XMLHTTPRequest约定,即POST的主体在请求之后的第二帧/后续帧中发送。如果不是这种情况,则代码需要在初始请求的有效负载中找到第一个\ r \ n \ r \ n,并将随后的数据附加到文件中。

毋庸置疑,芯片必须在呼叫前设置为AP。

headerBlock = "\r\nContent-type: text/html\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\nCache-Control: no-cache\r\n\r\n"
local currentFileName = ""
local isPostData = false
print("filexfer")
local srv=net.createServer(net.TCP, 60) 
srv:listen(80,
    function(conn) 
        local function writefile(name, mode, data)
            if (file.open("temp_" .. name, mode) == nil) then
                return -1
            end
            file.write(data)
            file.close()
        end
        conn:on("disconnection", 
            function(conn) 
                isPostData = false
            end
        )
        conn:on("sent", 
            function(conn) 
                currentFileName = ""
                isPostData = false
                conn:close()
            end
        )
        conn:on("receive",
            function(conn, payload)
                tmr.wdclr();
                local s, e, m, buf, k, v
                local tbl = {}
                local i = 1
                local retval = ""

                if isPostData then
                    writefile(currentFileName, "a+", payload)
                else
                    s, e = string.find(payload, "HTTP", 1, true)
                    if e ~= nil then
                        buf = string.sub(payload, 1, s - 2)
                        for m in string.gmatch(buf, "/?([%w+%p+][^/+]*)") do
                            tbl[i] = m
                            i = i + 1
                        end
                        m = nil
                        if #tbl > 2 then
                            local cmd = tbl[2]
                            if (tbl[3] ~= nil) and (tbl[3] ~= "/") then
                                currentFileName = tbl[3]
                            --else return an error
                            end

                            if (cmd == "put") then
                                writefile(currentFileName, "w+", "")
                            end

                            if (cmd == "append") then
                                isPostData = true
                            end

                            if (cmd == "persist") then
                                file.rename("temp_" .. currentFileName, currentFileName)
                            end

                            buf = ""
                            if retval == nil then
                                retval = "[nil]"
                            end
                            buf = "HTTP/1.1 200 OK" .. headerBlock .. retval
                        else
                            local filename = "index.html"
                            if tbl[2] ~= nil and tbl[2] ~= "/" then
                                filename = tbl[2]
                            end
                            require("fileupload")(conn, filename)
                            buf = ""
                        end
                        conn:send(buf)
                    end
                end
            end
        ) 
    end
)

这是fileupload.lua,由第75行附近的调用引用(因为芯片正在将文件发送到请求主机而上传。)它使用常规浏览器便于下载任何大小的文件。如果没有传递文件名,则默认为" index.html"。

local module =...
    return function(conn, fname)
        local buf
        tmr.wdclr()
        if file.list()[fname] ~= nil then
            file.open(fname, "r")
            buf = "HTTP/1.1 200 OK" .. headerBlock
        else
            file.open("error404.html", "r")
            buf = "HTTP/1.1 404 FILE NOT FOUND" .. headerBlock
        end

        conn:on ("sent",
            function(sck)
                function sendfile(sck)
                    buf = file.read(255)
                    if buf ~= nil then 
                        sck:send(buf)
                    else
                        sck:close()
                        if module ~= nil then
                            package.loaded[module] = nil
                        end
                        module = nil
                        return
                    end
                end
                sck:on("sent", sendfile)
                sck:on("disconnection",
                    function(sck)
                        print("[disconnection fileupload.sendfile]", node.heap())
                    end
                )
                sendfile(sck)
            end
        )
        conn:on ("receive",
            function(sck, pl)
                sck:close()
            end
        )
        if buf == nil then
            buf = ""    
        end
        conn:send(buf)
    end

这是用于上传到芯片的客户端javascript文件。将要上载的文件的完整路径或相对路径作为其第一个/唯一参数传递。 (如果没有传递args,则会抛出错误。)

var filepath = WScript.Arguments(0);
var fso = new ActiveXObject("Scripting.FileSystemObject");
var str = fso.OpenTextFile(filepath, 1);
var file = fso.GetFile(filepath);
var filename = file.Name;
var buf = "";

var xhr = new ActiveXObject("MSXML2.XMLHTTP.6.0");
xhr.open("GET", "http://192.168.4.1/put/" + filename, false);
xhr.send();

while (str.AtEndOfStream == false)
{
    buf = str.read(255);
    xhr.open("POST", "http://192.168.4.1/append/" + filename, false);
    xhr.send(buf);
} 

str.close();
xhr.open("GET", "http://192.168.4.1/persist/" + filename, false);
xhr.send();

答案 3 :(得分:2)

上面描述的解决方案的变体(http://www.instructables.com/id/ESP8266-WiFi-File-Management/)但使用桌面.NET应用程序而不是PHP Web服务器https://github.com/Orudnev/.Net-WiFi-File-Manager-for-ESP8266。如果您不想安装Web服务器可能会更方便,启动FileManager.exe应用程序就足够了。

答案 4 :(得分:0)

如果您使用Esplorer作为IDE,则另一种方法是here

它使用ESP8266上的telnet服务器,并将Esplorer串口重定向到telnet服务器的地址;这是一个Windows示例,但我已设法使用" socat"在linux下。

我发现的唯一问题是你想要多个tcp服务器,而Nodemcu不允许这种情况,在这种情况下,可能有另一个ESP8266充当tcp /串口控制台中继的答案。