硬件|从无到有玩NodeMcu(web端控制)

从无到有玩NodeMcu:web端控制

我们的目标:
【硬件|从无到有玩NodeMcu(web端控制)】利用网页web端为搭载NodeMcu的esp8266连接wifi
硬件准备:
  • 基于NodeMcu的esp8266
  • 数据线:usb+micr-usb
  • 安装有Windows系统的电脑
软件准备:
  • java运行环境:自行安装,注意,需要下载jdk8,太高的版本会使软件闪退
  • nodemcu-flasher:esp8266固件烧录程序
  • ESPIorer:为NodeMcu设计的编辑、上传软件
  • CH340驱动:用来连接电脑和esp8266 验证码ja94
  • NodeMcu固件:NodeMcu团队为esp8266制作的固件 验证码u5zv
如何下载Github上的源码
我们以nodemcu-flasher的下载为例
进入GitHub相关界面 点击nodemcu-flasher进入nodemcu-flasher的项目主页,只下载的话是不用注册的:
硬件|从无到有玩NodeMcu(web端控制)
文章图片

点击项目有时间的clone or download按键后会弹出一个小框,选择小框里的download zip即可下载源代码,下载完毕后解压缩即可
硬件|从无到有玩NodeMcu(web端控制)
文章图片

如何安装CH340驱动
下载百度云内的文件,得到一个叫Setup 32.64位元.exe的程序,执行它安装驱动。安装成功后使用数据线连接esp8266,打开设备管理器,如果显示下面的情况,则说明驱动已经安装完成:
硬件|从无到有玩NodeMcu(web端控制)
文章图片

如果没有显示,则有可能是数据线的问题,换一根数据线。如果显示modify、repair、remove的话,说明你以前已经安装过这个驱动了,如果你的设备管理器没有正常的话,就需要remove把以前的程序删除再重新安装
固件烧录
下载NodeMcu固件,得到nodemcu-master-11-modules-2019-07-22-07-39-27-float.bin这个文件,然后我们打开NodeMcu-flash,连接esp8266到电脑:
我们选择config,再在下面绿色的框里填写NodeMcu固件的本地文件地址,也就是你放固件的地方
硬件|从无到有玩NodeMcu(web端控制)
文章图片

我们回到Operation(正常情况下COM Port后面的Select port是有值的,我这边为了操作方便没有连接电脑),点击Flash按钮,固件就会被烧录到esp8266中了。
硬件|从无到有玩NodeMcu(web端控制)
文章图片

源代码准备
源代码分为三类:
  • 控制esp8266的lua程序
  • 控制网页的html程序
  • 负责沟通esp8266和网页的http服务器程序
我们需要按以下步骤获得init.lua index.html HttpServe.lua三个文件,并把它们放在一个文件夹
  • 新建一个.txt文件
  • 复制代码
  • 重命名文件为相应的名字
它们的源程序如下:
  • init.lua
wifi.setmode(wifi.STATIONAP) cfg={} cfg.ssid="config" --我们的NodeMcu热点 cfg.pwd="00000000" --密码 wifi.ap.config(cfg) cfg2 = { ip="192.168.1.1", --设置IP netmask="255.255.255.0", --子网掩码 gateway="192.168.1.1" --默认网关 } wifi.ap.setip(cfg2) wifi.sta.autoconnect(1) --自动连接 dofile('httpServer.lua') --执行HttpServer.luahttpServer:use('/config', function(req, res) if req.query.ssid ~= nil and req.query.pwd ~= nil then print(req.query.ssid ..req.query.pwd) config={} config.ssid=req.query.ssid config.pwd=req.query.pwd wifi.sta.config(config) end res:send('配置终端 - 锐客网您设置的wifi是:'..req.query.ssid..',请等待红灯常亮即连接完成。') end)httpServer:listen(80) --启动Server

  • httpServer.lua
-------------------- -- helper -------------------- function urlDecode(url) return url:gsub('%%(%x%x)', function(x) return string.char(tonumber(x, 16)) end) endfunction guessType(filename) local types = { ['.css'] = 'text/css', ['.js'] = 'application/javascript', ['.html'] = 'text/html', ['.png'] = 'image/png', ['.jpg'] = 'image/jpeg' } for ext, type in pairs(types) do if string.sub(filename, -string.len(ext)) == ext or string.sub(filename, -string.len(ext .. '.gz')) == ext .. '.gz' then return type end end return 'text/plain' end-------------------- -- Response -------------------- Res = { _skt = nil, _type = nil, _status = nil, _redirectUrl = nil, }function Res:new(skt) local o = {} setmetatable(o, self) self.__index = self o._skt = skt return o endfunction Res:redirect(url, status) status = status or 302 self:status(status) self._redirectUrl = url self:send(status) endfunction Res:type(type) self._type = type endfunction Res:status(status) self._status = status endfunction Res:send(body) self._status = self._status or 200 self._type = self._type or 'text/html' local buf = 'HTTP/1.1 ' .. self._status .. '\r\n' .. 'Content-Type: ' .. self._type .. '\r\n' .. 'Content-Length:' .. string.len(body) .. '\r\n' if self._redirectUrl ~= nil then buf = buf .. 'Location: ' .. self._redirectUrl .. '\r\n' end buf = buf .. '\r\n' .. body local function doSend() if buf == '' then self:close() else self._skt:send(string.sub(buf, 1, 512)) buf = string.sub(buf, 513) end end self._skt:on('sent', doSend) doSend() endfunction Res:sendFile(filename) if file.exists(filename .. '.gz') then filename = filename .. '.gz' elseif not file.exists(filename) then self:status(404) if filename == '404.html' then self:send(404) else self:sendFile('404.html') end return end self._status = self._status or 200 local header = 'HTTP/1.1 ' .. self._status .. '\r\n' self._type = self._type or guessType(filename) header = header .. 'Content-Type: ' .. self._type .. '\r\n' if string.sub(filename, -3) == '.gz' then header = header .. 'Content-Encoding: gzip\r\n' end header = header .. '\r\n' print('* Sending ', filename) local pos = 0 local function doSend() file.open(filename, 'r') if file.seek('set', pos) == nil then self:close() print('* Finished ', filename) else local buf = file.read(512) pos = pos + 512 self._skt:send(buf) end file.close() end self._skt:on('sent', doSend) self._skt:send(header) endfunction Res:close() self._skt:on('sent', function() end) -- release closures context self._skt:on('receive', function() end) self._skt:close() self._skt = nil end-------------------- -- Middleware -------------------- function parseHeader(req, res) local _, _, method, path, vars = string.find(req.source, '([A-Z]+) (.+)?(.+) HTTP') if method == nil then _, _, method, path = string.find(req.source, '([A-Z]+) (.+) HTTP') end local _GET = {} if vars ~= nil then vars = urlDecode(vars) for k, v in string.gmatch(vars, '([^&]+)=([^&]*)&*') do _GET[k] = v end end req.method = method req.query = _GET req.path = path return true endfunction staticFile(req, res) local filename = '' if req.path == '/' then filename = 'index.html' else filename = string.gsub(string.sub(req.path, 2), '/', '_') end res:sendFile(filename) end-------------------- -- HttpServer -------------------- httpServer = { _srv = nil, _mids = {{ url = '.*', cb = parseHeader }, { url = '.*', cb = staticFile }} }function httpServer:use(url, cb) table.insert(self._mids, #self._mids, { url = url, cb = cb }) endfunction httpServer:close() self._srv:close() self._srv = nil endfunction httpServer:listen(port) self._srv = net.createServer(net.TCP) self._srv:listen(port, function(conn) conn:on('receive', function(skt, msg) local req = { source = msg, path = '', ip = skt:getpeer() } local res = Res:new(skt)for i = 1, #self._mids do if string.find(req.path, '^' .. self._mids[i].url .. '$') and not self._mids[i].cb(req, res) then break end endcollectgarbage() end) end) end

  • index.html
配置终端 - 锐客网 配置页面


注意:由于NodeMCU内存很小,附近热点过多时,扫描热点会造成内存不足自动重启。请手动输入WIFI信息进行配置。
> input{ margin-bottom:30px; }

硬件操作 上传服务器文件
我们把esp8266当作一个小型的服务器,我们需要把index.htmlinit.luaHttpServe.lua这两个文件传到esp8266上
打开ESPLore 我们运行ESPIorer.jar这个程序来运行这个软件,我们可以看到它的主界面:
硬件|从无到有玩NodeMcu(web端控制)
文章图片

连接硬件 我们通过数据线把esp8266和电脑连接起来
上传程序
  • 再确定命令执行框上方open右侧的波特率是否为115200,如果不是的话请调整
  • 在点击右边命令执行框上方的open来打开串口,会出现Communication with MCU..,此时马上按硬件上靠近数据线的rst
  • 看见屏幕出现一些NodeMcu的信息即可
  • 点击源代码编辑框的upload键,选择上传所有之前创立的三个文件
  • 点击右边的Reload按键,右键点击init.lua按键,点击Run init.lua
手机操作 手机连接esp8266产生的WiFi,名字是config 密码是00000000,连接它
使用浏览器进入http://192.168.1.1出现以下画面:
硬件|从无到有玩NodeMcu(web端控制)
文章图片

参考
  • NodeMCU-Tutorial
  • Nodemcu通过网页Web设置sta.config配置
  • win10如何安装CH340驱动? - 知乎
  • NodeMCU使用说明整理

    推荐阅读