美文网首页NODEMCU
4.NodeMcu简单应用及拓展学习

4.NodeMcu简单应用及拓展学习

作者: yangmouren | 来源:发表于2017-03-17 23:21 被阅读1124次

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。

ESPlorer输入前面2段点亮LED
就可以看到靠近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中运行,我就这样出错了

运行截图.png

这里很奇怪,为什么结果里是先出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)

运行

运行服务器代码.png
这时NodeMcu已经作为一个http服务器开始运行了。用在同一局域网的电脑的浏览器打开对应http服务器的地址:192.168.8.145,就可以看到如下图结果 浏览器返回结果.png

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)
运行结果.png

可以看到此时a=1,b=12,method="GET",vars="on",a和b对应匹配字符的起始1和结束12(注意不要忽略空格)。

再看一下http://192.168.8.145/onon作用,回到之前的程序,当我们输入http://192.168.8.145/on

on的作用.png

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/

相关文章

网友评论

  • f248cec1a22a:写的很好很详细,就喜欢你这种把细节写的很全的文章,对我们这些小白简直是福利!
  • abin8888:关于 “结果里是先出IP地址再出nil” 的问题,我来说说我的看法

    第一个为什么有Iip地址,是因为程序之前已经连到wifi上,所以会有IIP地址。如果你断开wifi, wifi.sta.disconnect() ,然后再 print(wifi.sta.getip()) ,结果就是nil 。

    第二个为什么是nil,因为在执行
    wifi.setmode(wifi.STATION)
    wifi.sta.config(SSID,password)
    时,会把IP地址清空,然后再连接到指定的WIFI,由于 第二个 print(wifi.sta.getip()) 是在wifi.sta.config(SSID,password)之后马上执行,这时wifi还没连接上,所以Ip的结果是nil,wifi连接要延迟1-3秒, 所以马上得出Ip是不可能的。加个延迟就可以了。

    tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
    if wifi.sta.getip()== nil then
    print("IP unavaiable, Waiting...")
    else tmr.stop(1)
    print("Config done, IP is "..wifi.sta.getip())
    end
    end)

    以上是我的理解,请参考

本文标题:4.NodeMcu简单应用及拓展学习

本文链接:https://www.haomeiwen.com/subject/lrwxnttx.html