NodeMcu簡單應(yīng)用及拓展學(xué)習(xí)
前言
之所以想要學(xué)習(xí)使用NodeMcu,就是想要將其用在現(xiàn)實(shí)生活中,想要實(shí)現(xiàn)智能物聯(lián),將一些家用電氣(比如簡單的燈)可用通過手機(jī)或電腦進(jìn)行簡單的控制。當(dāng)然有人會(huì)認(rèn)為現(xiàn)在已經(jīng)有很對智能產(chǎn)品,支持這些功能了,那還要花時(shí)間折騰做什么呢?我的想法是,這些智能電器,或多或少存在各自的局限性,要么只能自己顧自己無法聯(lián)動(dòng),要么功能簡單無法實(shí)現(xiàn)復(fù)雜場景應(yīng)用,而且用這些產(chǎn)品,往往需要在自己的手機(jī)上安裝各自的app,控制的東西越多,需要安裝的東西也越多,反而違背了使用的初衷,我學(xué)習(xí)NodeMcu的目的,就是希望能實(shí)現(xiàn)各種產(chǎn)品的聯(lián)動(dòng),同時(shí)簡化自己的操作,讓機(jī)器替我們思考甚至做決定,以及滿足自己的個(gè)性化定制需要。
我的目標(biāo)可能會(huì)比較難實(shí)現(xiàn),我愿意一步一步學(xué)習(xí)實(shí)踐吧。
這里我將從最基礎(chǔ)開始學(xué)習(xí),慢慢深入應(yīng)用場景,希望通過這一過程,從易到難,逐漸掌握需要的技能。下面要寫的東西可能比較啰嗦,慢慢來吧。
1、從應(yīng)用著手
學(xué)習(xí)一項(xiàng)技能,最好是從自己實(shí)際需要的著手,先提出自己的需要:遠(yuǎn)程控制燈的開關(guān)(最簡單的智能燈),當(dāng)然只要買個(gè)智能燈或是智能插座配合亦或是用433Hz配合智能遙控,都能實(shí)現(xiàn),這里我們用NodeMcu試試。
首先從NodeMcu的點(diǎn)燈程序開始吧:
1.1 NodeMcu的點(diǎn)燈程序
最簡單的點(diǎn)亮板上的LED程序,之前文章提到過
gpio.mode(0,gpio.OUTPUT)
--開啟gpio16端口--
gpio.write(0,gpio.LOW)
--置端口輸出低電位,燈亮--
gpio.write(0,gpio.HIGH)
--置端口輸出高電位,燈滅--
相關(guān)電路原理見2.NodeMcu上手準(zhǔn)備中點(diǎn)燈原理圖.png。
就可以看到靠近USB口的LED點(diǎn)亮。
1.2 遠(yuǎn)程點(diǎn)亮LED
1.2.1 連接WIFI
遠(yuǎn)程點(diǎn)亮,肯定需要NodeMcu連上WIFI了,根據(jù)官方教程連接路由
print(wifi.sta.getip())
--打印wifi連接端口,此時(shí)未連接,輸出nil--
wifi.setmode(wifi.STATION)
--置NodeMcu為wifi為STATION工作模式--
wifi.sta.config("SSID","password")
--設(shè)置所連接wifi的參數(shù),SSID為路由名稱,password為路由密碼(自己設(shè)置需替換自己的路由)--
print(wifi.sta.getip())
--輸出連接上wifi后nodeMcu的地址--
當(dāng)然也可以這么寫
SSID="你的路由名"
password="你的路由密碼"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
注意不要把注釋也放到ESplorer中運(yùn)行,我就這樣出錯(cuò)了
這里很奇怪,為什么結(jié)果里是先出IP地址再出nil,歡迎網(wǎng)友解答。
1.2.2 建立服務(wù)器
接著需要設(shè)置nodeMcu為服務(wù)器,還是參照官方教程,這里復(fù)制官網(wǎng)的代碼:
srv=net.createServer(net.TCP)
--創(chuàng)建一個(gè)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)
這是創(chuàng)建一個(gè)server
后面是2部分組成,第一部分是net.server 子模塊,相關(guān)語法是
listen()
描述
偵聽指定ip地址的端口。
語法
net.server.listen(port,[ip],function(net.socket))
參數(shù)
port: 端口號
ip:ip地址字符串,可以省略
function(net.socket): 連接創(chuàng)建成功的回調(diào)函數(shù),可以作為參數(shù)傳給調(diào)用函數(shù)。
返回值
nil
第二部分是net.socket 子模塊
on()
描述
向事件注冊回調(diào)函數(shù)。
語法
on(event, function cb())
參數(shù)
event: 字符串,取值為: "connection", "reconnection", "disconnection", "receive", "sent"
function cb(net.socket, [string]): 回調(diào)函數(shù)。第一個(gè)參數(shù)是socket.
如果事件是"receive", 第二個(gè)參數(shù)則為接收到的字符串。
返回值
nil
send()
描述
通過連接向遠(yuǎn)端發(fā)送數(shù)據(jù)。
語法
send(string, function(sent))
參數(shù)
string: 待發(fā)送的字符串
function(sent): 發(fā)送字符串后的回調(diào)函數(shù)。
返回值
nil
這里解釋一下"srv:listen()","conn:on()","conn:send()",這里用冒號等價(jià)"srv.listen(self)","conn.on(self)","conn.send(self)",這樣對里面提到的語法就能比較好理解,其中self代表conn自己。"end"是對"function()"的結(jié)束。
conn:send("<h1> Hello, NodeMcu.</h1>")
這部分是服務(wù)器發(fā)送"<h1> Hello, NodeMcu.</h1>"
給接收者,這部分是可以用html代碼寫的,如果寫得復(fù)雜些,可以用更漂亮的網(wǎng)頁展示,但nodeMcu內(nèi)存較小,每次只能發(fā)送1460byte,需要對網(wǎng)頁代碼進(jìn)行分段傳送。(如何分段,可以看下面幾個(gè)作者的文章)
這部分代碼如果還是不太好理解,可以參看@qq_32543253寫得NODEMCU調(diào)試心得6 - 關(guān)于網(wǎng)絡(luò)協(xié)議HTTP,也可以看看@謝mingmin寫的9、nodeMCU學(xué)習(xí)筆記--net模塊,對于相關(guān)的教程可以參看官方的教程中關(guān)于net部分教程。
還需要再解釋一下,代碼中conn或是srv可以用其它字符串替代,它是繼承了net相關(guān)模塊的功能。
1.2.3 使用服務(wù)器
合并連接WIFI和建立服務(wù)器兩部分代碼
SSID="你的路由名"
password="你的路由密碼"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
srv=net.createServer(net.TCP)
--創(chuàng)建一個(gè)server
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
print(payload)
conn:send("<h1> Hello, NodeMcu.</h1>")
end)
end)
運(yùn)行
這時(shí)NodeMcu已經(jīng)作為一個(gè)http服務(wù)器開始運(yùn)行了。用在同一局域網(wǎng)的電腦的瀏覽器打開對應(yīng)http服務(wù)器的地址:192.168.8.145,就可以看到如下圖結(jié)果
1.2.4 利用服務(wù)器點(diǎn)燈
直接上代碼
SSID="你的路由名"
password="你的路由密碼"
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID,password)
print(wifi.sta.getip())
srv=net.createServer(net.TCP)
--創(chuàng)建一個(gè)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)
就增加了點(diǎn)燈的2行代碼,記得按一下nodeMcu板上的RST,再在ESPlorer中的run點(diǎn)一下,再寫入代碼,重新Save to Esp,這時(shí)代碼才更新好。這時(shí)重新打開瀏覽器輸入http服務(wù)器的地址:192.168.8.145,就可以看到NodeMcu上的LED燈點(diǎn)亮了。print(payload)
是可以在ESPlorer打印從瀏覽器客戶端收到的payload信息,可以刪去。
1.2.5 能點(diǎn)燈還需要關(guān)燈
上面只是簡單實(shí)現(xiàn)了點(diǎn)燈,但要實(shí)現(xiàn)控制隨時(shí)點(diǎn)亮熄滅,還不行,所以還要改進(jìn)。
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)
--創(chuàng)建一個(gè)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)
上述代碼,如果復(fù)制,請刪掉注釋再運(yùn)行!!!
這個(gè)代碼實(shí)現(xiàn)使,在同一局域網(wǎng)客戶端(手機(jī)瀏覽器或電腦瀏覽器)輸入http://192.168.8.145/off
熄滅板上的LED燈,輸入http://192.168.8.145/on
開啟板上的LED燈。
這里解釋一下local _, _, method, vars = string.find(payload, "([A-Z]+) /(.+) HTTP")
,這個(gè)我也開始學(xué)也弄不太懂,參看@qq_32543253的教程,明白了。其實(shí)就是Lua中的string.find()
語法的應(yīng)用。具體這里不展開了,大家可以百度。這里的應(yīng)用使采用string.find()
匹配payload
中的字符,提取出對應(yīng)([A-Z]+)
和(.+)
的字符,賦值給method
, vars
,前面2個(gè)_,
是虛變量,我們簡化一下這個(gè)代碼
payload="GET /on HTTP/1.1"
local a, b, method, vars = string.find(payload, "([A-Z]+) /(.+) HTTP")
print(a,b,method,vars)
可以看到此時(shí)a=1,b=12,method="GET",vars="on",a和b對應(yīng)匹配字符的起始1和結(jié)束12(注意不要忽略空格)。
再看一下http://192.168.8.145/on
中on
作用,回到之前的程序,當(dāng)我們輸入http://192.168.8.145/on
print(payload)
可以看到第1行是GET /on HTTP/1.1
,說明網(wǎng)址中的on
被傳送過去了,程序就是這個(gè)被網(wǎng)址傳送過去的字符進(jìn)行了判斷控制。當(dāng)然我們可以用其它字符,其它判斷來實(shí)現(xiàn)更復(fù)雜的控制。
如果html寫得好,可以通過編制html按鈕,來進(jìn)行信息傳送,原理是一樣的。但個(gè)人覺得由于nodeMcu的機(jī)能限制,不太適合太復(fù)雜太精美的html再進(jìn)行復(fù)雜控制,不如就用這樣簡單的網(wǎng)址字符輸入控制(其實(shí)是我自己html還不會(huì))。
我們可以選擇更精美的UI和更優(yōu)秀的硬件做服務(wù)器,而NodeMcu就做控制。這時(shí)后話了,下一節(jié)我們試試domoticz遠(yuǎn)程控制NodeMcu。
1.2.6 程序隨NodeMcu啟動(dòng)而運(yùn)行
前面的控制,都是在線調(diào)試而成,如何使自己的程序成為初始化程序,即NodeMcu啟動(dòng)后就能直接運(yùn)行,不用點(diǎn)ESPlorer中的run。這里就需要用到init.lua
,它就是NodeMcu開機(jī)啟動(dòng)項(xiàng)。
方案1
這里我們可以把之前寫的服務(wù)器代碼用另存為 init.lua
寫入板子。然后重啟,把NodeMcu插在移動(dòng)電源上或5V的充電器,再試試用同局域網(wǎng)的手機(jī)或電腦輸入控制網(wǎng)址http://192.168.8.145/on
,看看板上LED是不是已經(jīng)點(diǎn)亮了。
方案2
或者還可以這么調(diào)用
dofile("之前服務(wù)器程序文件名(包括后綴)")
比如
dofile("server20170316.lua")
存儲(chǔ)為init.lua
,然后將服務(wù)器程序?qū)懭耄賹懭?code>init.lua。再重啟把NodeMcu插在移動(dòng)電源上或5V的充電器試試。是不是也成功。
結(jié)尾
這一章寫了很多,比較啰嗦瑣碎,但我想盡可能仔細(xì),把一些東西解釋清楚,這即加深了自己的學(xué)習(xí)理解,同時(shí)方便大家實(shí)踐。如果這里點(diǎn)燈實(shí)踐不成功,歡迎討論。
總結(jié)一些吧,本節(jié)從點(diǎn)亮LED開始,再討論NodeMcu的WIFi連接,服務(wù)器的建立,再到簡單的命令控制,最終實(shí)現(xiàn)了遠(yuǎn)程LED的點(diǎn)亮控制。
這種網(wǎng)上教程比較多,大家也可以多多借鑒。
參考
官方教程:http://www.nodemcu.com/index_cn.html
@qq_32543253的博客:http://blog.csdn.net/qq_32543253/article/details/53240851
@謝mingmin的簡書:http://www.lxweimin.com/p/2535d6374a2b
官方的net教程:https://nodemcu.readthedocs.io/en/master/en/modules/net/