0%

NodeMCU远程开关

github:https://github.com/maplesugarr/raspberrypi-nodemcu

使用教程

简介

NodeMCU,是一个开源的物联网平台。 它使用Lua脚本语言编程。该平台基于eLua开源项目,底层使用ESP8266 sdk 0.9.5版本。该平台使用了很多开源项目, 例如 lua-cjson, spiffs. NodeMCU包含了可以运行在 esp8266 Wi-Fi SoC芯片之上的固件,以及基于ESP-12模组的硬件。

购买

大概十多块一个。

构建固件

这个网站:https://nodemcu-build.com/ 提供构建固件的服务,只要选好模块,构建完成后,就会发邮件通知。不过我使用一次后,就再也没有收到构建成功的邮件了。

还是自己手动编译,搜索github,有人已经做好了docker。 https://github.com/marcelstoer/docker-nodemcu-build/blob/master/README-CN.md

1.克隆nodemcu固件仓库
git clone https://github.com/nodemcu/nodemcu-firmware.git

2.拉取docker镜像
docker pull marcelstoer/nodemcu-build

3.更改编译配置
查找 https://nodemcu.readthedocs.io/en/master/en/build/ 文档,更改固件目录下的app/include/user_modules.h,app/include/user_config.h。

1
2
3
4
5
6
7
8
9
user_modules.h中编译的模块:LUA_USE_MODULES_CRYPTO、LUA_USE_MODULES_ENCODER、
LUA_USE_MODULES_FILE、LUA_USE_MODULES_GPIO、LUA_USE_MODULES_HTTP、LUA_USE_MODULES_NET、
LUA_USE_MODULES_NODE、LUA_USE_MODULES_SJSON、LUA_USE_MODULES_TLS、LUA_USE_MODULES_TMR、
LUA_USE_MODULES_WIFI

user_config.h制定的特性:
#define BIT_RATE_DEFAULT BIT_RATE_115200(波特率,连接nodemcu也要使用这个波特率)、
#define LUA_NUMBER_INTEGRAL(指定支持整数运算,减小内存占用,默认是浮点运算。)、
#define CLIENT_SSL_ENABLE(支持tls,后来证明一直报错,只能使用http)

4.进入克隆好的固件目录,进行编译。

1
2
3
4
docker run --rm -ti -v `pwd`:/opt/nodemcu-firmware marcelstoer/nodemcu-build build
最后一个build是命令,还可以使用lfs-image命令,把lua直接写到固件中:
docker run --rm -ti -v `pwd`:/opt/nodemcu-firmware -v {PathToLuaSourceFolder}:/opt/lua marcelstoer/nodemcu-build lfs-image
这将编译并存储给定文件夹及其目录中中的所有 Lua 文件。

5.进入固件目录/bin中,得到编译完成后的固件。

刷入固件

为了避免不必要的麻烦,就不要尝试其他的烧录软件了。

flashmode需要根据芯片型号选择。

上传代码

推荐使用ESPlorer,需要Java环境。下载ESPlorer.zip。

注意连接的波特率根据刷入的固件不同而有所不同,就是上面编译固件时候规定的波特率。

lua代码教程

参考:https://github.com/wangzexi/NodeMCU-Tutorial ,由于api的变化,它的代码已经不适合自己编译好的固件了,对应改一下就可以,看我的github仓库也可以。思路是没问题的。

api文档(nodemcu documentation):https://nodemcu.readthedocs.io/en/master/

配置wifi的原理

nodemcu可以作为一个station连接到wifi,同时又能作为一个ap,为其他设备提供wifi连接。由于没有网线连接,被称为soft-ap。同时它还可以ap和station共存,可以实现中继的功能。

按一下按键,设置nodemcu为station和ap共存状态,手机脸上nodemcu的ap就可以配网了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
wifi.setmode(wifi.STATION)
--使用无线配网,不要声明。
--wifi.sta.config({ssid='wifi1', pwd='12345678'})
wifi.sta.sethostname("NodeMCU-raspi2") --设置设备的名字
wifi.sta.autoconnect(1)

function switchCfg()
if wifi.getmode() == wifi.STATION then
--停止任务。
tmr.stop(TMR_CHECK_NETWORK)
wifi.setmode(wifi.STATIONAP)--station和ap共存
wifi.ap.config({ssid='NodeMCUConfig'})--设置ap的名字
httpServer:listen(80)
blinking({1000, 1000})
else
--配好网络后,开始任务。
tmr.start(TMR_CONNECT)
wifi.setmode(wifi.STATION)
httpServer:close()
blinking()
end
end

树莓派远程开关

买了一个路由器的ups,用来给树莓派供电,防止突然关机损坏树莓派sd卡。

nodemcu通过http协议去请求服务器的json数据,来控制继电器开关,进而控制树莓派电源。根据文档导入证书后,使用https协议连接不上,找毛病浪费时间,就不用https了。要用mqtt协议的自行研究。

实际上nodemcu连接两个继电器,控制树莓派电源和树莓派引脚的通断。
第一个继电器控制树莓派的一个GPIO信号。树莓派的这个GPIO拉高后,接地,平时是不通的,也就是GPIO一直是高电平。第一个继电器闭合后,树莓派的这个GPIO接地,变成低电平。树莓派通过检测这个GPIO变成低电平来执行shutdown命令关闭树莓派。等待二分钟后,保证树莓派已经关机,就控制第二个继电器关闭树莓派电源。

同时,由于树莓派不能读取ups剩余电量,就由nodemcu控制ups断电使用时间了。nodemcu检查网络断掉后,就认为已经断电,维持适当时间后,关闭树莓派。当来电后,nodemcu检查到网络联通后,就认为来电了,打开树莓派。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
function forceShutdownRaspi()
--树莓派接到信号后,开始执行shutdown now命令
gpio.write(IO_RELAY_RASPI_OFF_SIGNAL, gpio.HIGH)
--等待二分钟,关闭树莓派电源
tmr.alarm(TMR_RELAY, 120000, tmr.ALARM_SINGLE, function()
gpio.write(IO_RELAY_RASPI_POWER_SUPPLY, gpio.LOW)
--一定等到关机完成后,才设置标志位。否则可能再执行过程中,nodemcu重新启动,判断为关机状态,直接重启了,损坏树莓派。
is_raspi_on = false
--开始检查网络
tmr.start(TMR_CHECK_NETWORK)
end)
end

function closeRaspi()
is_raspi_on = false
--关闭继电器电源
gpio.write(IO_RELAY_RASPI_POWER_SUPPLY, gpio.LOW)
--关闭树莓派信号
gpio.write(IO_RELAY_RASPI_OFF_SIGNAL, gpio.HIGH)
end

function openRaspi()
is_raspi_on = true
--打开继电器电源
gpio.write(IO_RELAY_RASPI_POWER_SUPPLY, gpio.HIGH)
--关闭树莓派信号
gpio.write(IO_RELAY_RASPI_OFF_SIGNAL, gpio.LOW)
end

function bootRaspi()
--重启继电器电源
gpio.write(IO_RELAY_RASPI_POWER_SUPPLY, gpio.LOW)
--先关闭树莓派GPIO关机信号
gpio.write(IO_RELAY_RASPI_OFF_SIGNAL, gpio.LOW)
tmr.alarm(TMR_RELAY, 5000, tmr.ALARM_SINGLE, function()
gpio.write(IO_RELAY_RASPI_POWER_SUPPLY, gpio.HIGH)
--一定等到开机完成后,才设置标志位。否则可能再执行过程中,nodemcu重新启动,判断为开机状态,执行forceshutdown函数,浪费时间。
is_raspi_on = true
end)
end


--初始化标识
fail_count = 0
--树莓派是否开机
is_raspi_on = false

tmr.alarm(TMR_CHECK_NETWORK, 60000, tmr.ALARM_AUTO, function()
--if isConnect() == true then
http.get("http://xxx.com/xxx", nil, function(code, data)
if is_raspi_on==false then --树莓派处于关机状态
if (code ~= 200) then --断电
print("HTTP request failed")
else --来电
--网络通畅,判断远程控制是否要打开树莓派。
fail_count = 0
local result = sjson.decode(data)
print(result["switch"])
if (result["switch"]) then
bootRaspi()
else
closeRaspi()
end

end
else --树莓派处于开机状态
if (code ~= 200) then --断电
fail_count = fail_count + 1
print(fail_count)
-- 连续五分钟都失败,认为网络不通,或者断电。这时关闭继电器。
if(fail_count >= 5) then
--重置计数
fail_count = 0
--停止检查网络
tmr.stop(TMR_CHECK_NETWORK)
--关闭树莓派
forceShutdownRaspi()
end
print("HTTP request failed")
else --来电
fail_count = 0
local result = sjson.decode(data)
print(result["switch"])
if (result["switch"]) then
openRaspi()
else
--没有执行断电关机,树莓派还在运行,需要先关树莓派,再关继电器。
--停止检查网络
tmr.stop(TMR_CHECK_NETWORK)
--关闭树莓派
forceShutdownRaspi()
end

end
end

end)

--end
end)