NodeMcu简单应用及拓展学习
前言
之所以想要学习使用NodeMcu,就是想要将其用在现实生活中,想要实现智能物联,将一些家用电气(比如简单的灯)可用通过手机或电脑进行简单的控制。当然有人会认为现在已经有很对智能产品,支持这些功能了,那还要花时间折腾做什么呢?我的想法是,这些智能电器,或多或少存在各自的局限性,要么只能自己顾自己无法联动,要么功能简单无法实现复杂场景应用,而且用这些产品,往往需要在自己的手机上安装各自的app,控制的东西越多,需要安装的东西也越多,反而违背了使用的初衷,我学习NodeMcu的目的,就是希望能实现各种产品的联动,同时简化自己的操作,让机器替我们思考甚至做决定,以及满足自己的个性化定制需要。
我的目标可能会比较难实现,我愿意一步一步学习实践吧。
这里我将从最基础开始学习,慢慢深入应用场景,希望通过这一过程,从易到难,逐渐掌握需要的技能。下面要写的东西可能比较啰嗦,慢慢来吧。
1、从应用着手
学习一项技能,最好是从自己实际需要的着手,先提出自己的需要:远程控制灯的开关(最简单的智能灯),当然只要买个智能灯或是智能插座配合亦或是用433Hz配合智能遥控,都能实现,这里我们用NodeMcu试试。
首先从NodeMcu的点灯程序开始吧:
1.1 NodeMcu的点灯程序
最简单的点亮板上的LED程序,之前文章提到过
gpio.mode(0,gpio.OUTPUT)
--开启gpio16端口--
gpio.write(0,gpio.LOW)
--置端口输出低电位,灯亮--
gpio.write(0,gpio.HIGH)
--置端口输出高电位,灯灭--
相关电路原理见2.NodeMcu上手准备中点灯原理图.png。
就可以看到靠近USB口的LED点亮。
1.2 远程点亮LED
1.2.1 连接WIFI
远程点亮,肯定需要NodeMcu连上WIFI了,根据官方教程连接路由
print(wifi.sta.getip())
--打印wifi连接端口,此时未连接,输出nil--
wifi.setmode(wifi.STATION)
--置NodeMcu为wifi为STATION工作模式--
wifi.sta.config("SSID","password")
--设置所连接wifi的参数,SSID为路由名称,password为路由密码(自己设置需替换自己的路由)--
print(wifi.sta.getip())
--输出连接上wifi后nodeMcu的地址--
当然也可以这么写
SSID="你的路由名"
password="你的路由密码"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
注意不要把注释也放到ESplorer中运行,我就这样出错了
这里很奇怪,为什么结果里是先出IP地址再出nil,欢迎网友解答。
1.2.2 建立服务器
接着需要设置nodeMcu为服务器,还是参照官方教程,这里复制官网的代码:
srv=net.createServer(net.TCP)
--创建一个server
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
print(payload)
conn:send("<h1> Hello, NodeMcu.</h1>")
end)
end)
这部分语法这里稍微解释:
srv=net.createServer(net.TCP)
这是创建一个server
后面是2部分组成,第一部分是net.server 子模块,相关语法是
listen()
描述
侦听指定ip地址的端口。
语法
net.server.listen(port,[ip],function(net.socket))
参数
port: 端口号
ip:ip地址字符串,可以省略
function(net.socket): 连接创建成功的回调函数,可以作为参数传给调用函数。
返回值
nil
第二部分是net.socket 子模块
on()
描述
向事件注册回调函数。
语法
on(event, function cb())
参数
event: 字符串,取值为: "connection", "reconnection", "disconnection", "receive", "sent"
function cb(net.socket, [string]): 回调函数。第一个参数是socket.
如果事件是"receive", 第二个参数则为接收到的字符串。
返回值
nil
send()
描述
通过连接向远端发送数据。
语法
send(string, function(sent))
参数
string: 待发送的字符串
function(sent): 发送字符串后的回调函数。
返回值
nil
这里解释一下"srv:listen()","conn:on()","conn:send()",这里用冒号等价"srv.listen(self)","conn.on(self)","conn.send(self)",这样对里面提到的语法就能比较好理解,其中self代表conn自己。"end"是对"function()"的结束。
conn:send("<h1> Hello, NodeMcu.</h1>")
这部分是服务器发送"<h1> Hello, NodeMcu.</h1>"
给接收者,这部分是可以用html代码写的,如果写得复杂些,可以用更漂亮的网页展示,但nodeMcu内存较小,每次只能发送1460byte,需要对网页代码进行分段传送。(如何分段,可以看下面几个作者的文章)
这部分代码如果还是不太好理解,可以参看@qq_32543253写得NODEMCU调试心得6 - 关于网络协议HTTP,也可以看看@谢mingmin写的9、nodeMCU学习笔记--net模块,对于相关的教程可以参看官方的教程中关于net部分教程。
还需要再解释一下,代码中conn或是srv可以用其它字符串替代,它是继承了net相关模块的功能。
1.2.3 使用服务器
合并连接WIFI和建立服务器两部分代码
SSID="你的路由名"
password="你的路由密码"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
srv=net.createServer(net.TCP)
--创建一个server
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
print(payload)
conn:send("<h1> Hello, NodeMcu.</h1>")
end)
end)
运行
这时NodeMcu已经作为一个http服务器开始运行了。用在同一局域网的电脑的浏览器打开对应http服务器的地址:192.168.8.145,就可以看到如下图结果
1.2.4 利用服务器点灯
直接上代码
SSID="你的路由名"
password="你的路由密码"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
srv=net.createServer(net.TCP)
--创建一个server
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
print(payload)
gpio.mode(0,gpio.OUTPUT)
gpio.write(0,gpio.LOW)
conn:send("<h1> Hello, NodeMcu.</h1>")
end)
end)
就增加了点灯的2行代码,记得按一下nodeMcu板上的RST,再在ESPlorer中的run点一下,再写入代码,重新Save to Esp,这时代码才更新好。这时重新打开浏览器输入http服务器的地址:192.168.8.145,就可以看到NodeMcu上的LED灯点亮了。print(payload)
是可以在ESPlorer打印从浏览器客户端收到的payload信息,可以删去。
1.2.5 能点灯还需要关灯
上面只是简单实现了点灯,但要实现控制随时点亮熄灭,还不行,所以还要改进。
SSID="路由器名称"
password="路由器密码"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
--连接路由器
pin=0
gpio.mode(pin,gpio.OUTPUT)
gpio.write(pin,gpio.HIGH)
--开启gpio16端口
srv=net.createServer(net.TCP)
--创建一个server
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
print(payload)
--打印从浏览器客户端收到的payload信息
local _, _, method, vars = string.find(payload, "([A-Z]+) /(.+) HTTP")
if(vars == "off")then
gpio.write(pin, gpio.HIGH)
--灭灯
conn:send("<h1> Light OFF.</h1>")
--传送给客户端 Light OFF.的页面
elseif(vars == "on")then
gpio.write(pin, gpio.LOW)
--开灯
conn:send("<h1> Light ON.</h1>")
--传送给客户端 Light ON.的页面
end
end)
end)
上述代码,如果复制,请删掉注释再运行!!!
这个代码实现使,在同一局域网客户端(手机浏览器或电脑浏览器)输入http://192.168.8.145/off
熄灭板上的LED灯,输入http://192.168.8.145/on
开启板上的LED灯。
这里解释一下local _, _, method, vars = string.find(payload, "([A-Z]+) /(.+) HTTP")
,这个我也开始学也弄不太懂,参看@qq_32543253的教程,明白了。其实就是Lua中的string.find()
语法的应用。具体这里不展开了,大家可以百度。这里的应用使采用string.find()
匹配payload
中的字符,提取出对应([A-Z]+)
和(.+)
的字符,赋值给method
, vars
,前面2个_,
是虚变量,我们简化一下这个代码
payload="GET /on HTTP/1.1"
local a, b, method, vars = string.find(payload, "([A-Z]+) /(.+) HTTP")
print(a,b,method,vars)
可以看到此时a=1,b=12,method="GET",vars="on",a和b对应匹配字符的起始1和结束12(注意不要忽略空格)。
再看一下http://192.168.8.145/on
中on
作用,回到之前的程序,当我们输入http://192.168.8.145/on
print(payload)
可以看到第1行是GET /on HTTP/1.1
,说明网址中的on
被传送过去了,程序就是这个被网址传送过去的字符进行了判断控制。当然我们可以用其它字符,其它判断来实现更复杂的控制。
如果html写得好,可以通过编制html按钮,来进行信息传送,原理是一样的。但个人觉得由于nodeMcu的机能限制,不太适合太复杂太精美的html再进行复杂控制,不如就用这样简单的网址字符输入控制(其实是我自己html还不会)。
我们可以选择更精美的UI和更优秀的硬件做服务器,而NodeMcu就做控制。这时后话了,下一节我们试试domoticz远程控制NodeMcu。
1.2.6 程序随NodeMcu启动而运行
前面的控制,都是在线调试而成,如何使自己的程序成为初始化程序,即NodeMcu启动后就能直接运行,不用点ESPlorer中的run。这里就需要用到init.lua
,它就是NodeMcu开机启动项。
方案1
这里我们可以把之前写的服务器代码用另存为 init.lua
写入板子。然后重启,把NodeMcu插在移动电源上或5V的充电器,再试试用同局域网的手机或电脑输入控制网址http://192.168.8.145/on
,看看板上LED是不是已经点亮了。
方案2
或者还可以这么调用
dofile("之前服务器程序文件名(包括后缀)")
比如
dofile("server20170316.lua")
存储为init.lua
,然后将服务器程序写入,再写入init.lua
。再重启把NodeMcu插在移动电源上或5V的充电器试试。是不是也成功。
结尾
这一章写了很多,比较啰嗦琐碎,但我想尽可能仔细,把一些东西解释清楚,这即加深了自己的学习理解,同时方便大家实践。如果这里点灯实践不成功,欢迎讨论。
总结一些吧,本节从点亮LED开始,再讨论NodeMcu的WIFi连接,服务器的建立,再到简单的命令控制,最终实现了远程LED的点亮控制。
这种网上教程比较多,大家也可以多多借鉴。
参考
官方教程:http://www.nodemcu.com/index_cn.html
@qq_32543253的博客:http://blog.csdn.net/qq_32543253/article/details/53240851
@谢mingmin的简书:http://www.jianshu.com/p/2535d6374a2b
官方的net教程:https://nodemcu.readthedocs.io/en/master/en/modules/net/