使用 Wifi 将 Lua 脚本上传到 NodeMCU
Uploading a Lua script to NodeMCU using Wifi
是否可以使用 Wifi 接口而不是串口将 Lua 脚本上传到 NodeMCU?
我找到的教程和示例都使用串行接口,即电缆,对 NodeMCU 进行编程,但我想在不连接任何东西(使用智能手机或浏览器)的情况下更改程序
是的,这是可能的。这是一种自制的选择,但它在一定程度上起作用。当然,唯一的限制是尺寸,但除此之外效果还不错。看看:
http://www.instructables.com/id/ESP8266-WiFi-File-Management/
您需要有一种方法来编写 PHP 程序(我是用 C# 编写的)如果您不能用另一种语言编写代码,您可以下载并重复使用该用户编写的代码并使用您的拥有 PHP 服务器,你应该可以开始了。
如有疑问,请提问。
我通过 wifi 上传所有模块。我首先以通常的方式(通过 USB)上传一个 bootstrap.lua
程序。然后可以使用该程序上传真实(更大)的有效负载。这是 bootstrap 程序:
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
)。
然后它获取文件并最终运行它(最后一行)。
您必须在 运行 之前激活您的无线连接,并且您的 Web 服务器当然应该处于活动状态,并且您的负载在 /upload/u.lc
。
当然,您可以更改硬连线值,甚至可以使它们动态化。
标题 ##This 应该是您想要的内容的简单起点。
顺便说一句,压缩格式可以使初始上传速度更快,我使用 --dofile
选项以 luatool.py
上传。
稍后更新您的程序 (u.lc
) 是对 dofile("bootstrap.lua")
的简单重复。
我的 u.lc
是第 2 阶段 bootstrap,它上传了一长串文件(主要是 .lc
)。对于这个简短的回答,可能太复杂了。
最后,我要提一下,这是基于 https://github.com/Manawyrm/ESP8266-HTTP/
HTH
如果您使用 Esplorer 作为 IDE 的另一种方法已记录在案 here
在ESP8266上使用telnet服务器,将Esplorer串口重定向到telnet服务器地址;这是一个 windows 示例,但我已经设法使用 linux 下的 "socat" 使其工作。
我发现的唯一问题是,如果您想要多个 tcp 服务器,而 Nodemcu 不允许,在这种情况下,也许另一个 ESP8266 充当 tcp/serial 控制台中继可能是答案。
我有另一个解决方案,没有大小限制。此外,它不需要任何其他网络服务器,您可以直接从您的工作站发送文件。下面的文件提供上传和下载 to/from 芯片。
编辑:我将下面的源示例开发成一个文件管理器,能够上传、重命名、备份、删除,当然还提供文件服务,运行 在 ESP8266 和 ESP32 上(WiFi 连接差异被抽象化了) .) The project can be found here。 (取决于 NodeMCU。)
不幸的是,它没有使用网络浏览器使用的标准上传方案,最后提供了一个上传到它的 javascript 文件。可以在 SendTo 文件夹中创建 js 的快捷方式,从而将其添加到每个文件的上下文菜单中的“发送到”选项列表中,但它只能处理单个文件选择。 (需要 shell 扩展来处理多个选定的文件。)
支持常规浏览器下载。
请注意,此方案主要依赖于特定的 XMLHTTPRequest 约定,即 POST 的主体在请求后的 second/subsequent 帧中发送。如果不是这种情况,代码将需要在初始请求的有效负载中找到第一个 \r\n\r\n 并将后面的数据附加到文件中。
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 行附近的 require 调用中引用(上传,因为芯片正在将文件发送到请求主机。)它有助于使用常规浏览器下载任何大小的文件。如果没有传递文件名,则默认为“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文件。将要上传的文件的完整路径或相对路径作为其 first/only 参数传递。 (如果没有传递任何参数,它将抛出一个错误。)
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();
上述解决方案有一个变体(http://www.instructables.com/id/ESP8266-WiFi-File-Management/) but desktop .NET application is used instead of PHP Web Server https://github.com/Orudnev/.Net-WiFi-File-Manager-for-ESP8266。如果您不喜欢安装网络服务器,可能会更方便,启动 FileManager.exe 应用程序就足够了。
是否可以使用 Wifi 接口而不是串口将 Lua 脚本上传到 NodeMCU?
我找到的教程和示例都使用串行接口,即电缆,对 NodeMCU 进行编程,但我想在不连接任何东西(使用智能手机或浏览器)的情况下更改程序
是的,这是可能的。这是一种自制的选择,但它在一定程度上起作用。当然,唯一的限制是尺寸,但除此之外效果还不错。看看:
http://www.instructables.com/id/ESP8266-WiFi-File-Management/
您需要有一种方法来编写 PHP 程序(我是用 C# 编写的)如果您不能用另一种语言编写代码,您可以下载并重复使用该用户编写的代码并使用您的拥有 PHP 服务器,你应该可以开始了。
如有疑问,请提问。
我通过 wifi 上传所有模块。我首先以通常的方式(通过 USB)上传一个 bootstrap.lua
程序。然后可以使用该程序上传真实(更大)的有效负载。这是 bootstrap 程序:
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
)。
然后它获取文件并最终运行它(最后一行)。
您必须在 运行 之前激活您的无线连接,并且您的 Web 服务器当然应该处于活动状态,并且您的负载在 /upload/u.lc
。
当然,您可以更改硬连线值,甚至可以使它们动态化。
标题 ##This 应该是您想要的内容的简单起点。
顺便说一句,压缩格式可以使初始上传速度更快,我使用 --dofile
选项以 luatool.py
上传。
稍后更新您的程序 (u.lc
) 是对 dofile("bootstrap.lua")
的简单重复。
我的 u.lc
是第 2 阶段 bootstrap,它上传了一长串文件(主要是 .lc
)。对于这个简短的回答,可能太复杂了。
最后,我要提一下,这是基于 https://github.com/Manawyrm/ESP8266-HTTP/
HTH
如果您使用 Esplorer 作为 IDE 的另一种方法已记录在案 here
在ESP8266上使用telnet服务器,将Esplorer串口重定向到telnet服务器地址;这是一个 windows 示例,但我已经设法使用 linux 下的 "socat" 使其工作。
我发现的唯一问题是,如果您想要多个 tcp 服务器,而 Nodemcu 不允许,在这种情况下,也许另一个 ESP8266 充当 tcp/serial 控制台中继可能是答案。
我有另一个解决方案,没有大小限制。此外,它不需要任何其他网络服务器,您可以直接从您的工作站发送文件。下面的文件提供上传和下载 to/from 芯片。
编辑:我将下面的源示例开发成一个文件管理器,能够上传、重命名、备份、删除,当然还提供文件服务,运行 在 ESP8266 和 ESP32 上(WiFi 连接差异被抽象化了) .) The project can be found here。 (取决于 NodeMCU。)
不幸的是,它没有使用网络浏览器使用的标准上传方案,最后提供了一个上传到它的 javascript 文件。可以在 SendTo 文件夹中创建 js 的快捷方式,从而将其添加到每个文件的上下文菜单中的“发送到”选项列表中,但它只能处理单个文件选择。 (需要 shell 扩展来处理多个选定的文件。)
支持常规浏览器下载。
请注意,此方案主要依赖于特定的 XMLHTTPRequest 约定,即 POST 的主体在请求后的 second/subsequent 帧中发送。如果不是这种情况,代码将需要在初始请求的有效负载中找到第一个 \r\n\r\n 并将后面的数据附加到文件中。
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 行附近的 require 调用中引用(上传,因为芯片正在将文件发送到请求主机。)它有助于使用常规浏览器下载任何大小的文件。如果没有传递文件名,则默认为“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文件。将要上传的文件的完整路径或相对路径作为其 first/only 参数传递。 (如果没有传递任何参数,它将抛出一个错误。)
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();
上述解决方案有一个变体(http://www.instructables.com/id/ESP8266-WiFi-File-Management/) but desktop .NET application is used instead of PHP Web Server https://github.com/Orudnev/.Net-WiFi-File-Manager-for-ESP8266。如果您不喜欢安装网络服务器,可能会更方便,启动 FileManager.exe 应用程序就足够了。