之前写到自己组装了一个黑群,由于黑群的硬件限制,无法实现自动开机,必须借助外部干预,因此购置了一个nodeMCU继电器实现定时开关机。
硬件电路搭完了,准备着手写nodeMCU的软件了
本方案采用的继电器电路如图,GPIO0控制继电器通断。
而GPIO在ESP8266里index为3
在写软件之前,有一个血泪经验需要分享,通过ESPlorer或LuaLoader给nodeMCU上传代码,无法中断代码的执行,并且也没有在线调试的功能,上传的代码如果有BUG,就很容易进入死循环或者无限重启,这时候只需要在ESPlorer或LuaLoader的命令行里执行如下代码就可及时中断程序执行,拼手速的时候到了。要是实在拼不过,或者系统宕了,只能重新下载固件了。
file.remove("init.lua")
file.rename("init.lua","init_bad.lua")
正式代码开始:
为了实现定时开关机,首先要知道自己的时间,上一次编译nodeMCU固件,忘记选择sntp了,重新编译并下载后,支持获取ntp时间。
以下代码是每5秒钟同步一下时间服务器,并打印当前时间,当然也没必要这么快,每小时甚至一天同步一次足矣。另外, 通过rtc.get()获取的时间单位是秒,并且要加上8小时才是北京时间,也就是东8区的时间,所以sec+8*60*60。
tmr.create():alarm(5000, tmr.ALARM_AUTO, function()
sec,usec,rate = rtctime.get()
time2 = rtctime.epoch2cal((sec+8*60*60),usec,rate)
print(string.format("nowtime=,%04d/%02d/%02d %02d:%02d:%02d",
time2["year"],
time2["mon"],
time2["day"],
time2["hour"],
time2["min"],
time2["sec"]))
end)
获取ntp时间后,就按ntp时间来控制开关机。
本方案中,考虑最简单的情况,每天0点关机,7点开机,也就是说time[“hour”]大于等于0,小于等于6(也就是最晚6点59)保持断电状态,其他时间保持开合状态。
另外,为了保护主机硬盘,不能直接关电,会等主机完全关闭后才关闭电源。拟通过ping来判断主机是否已经关机,连续ping不通60次(周期是5秒,也就是300秒)则认为主机已经关机了,则关掉电源。
这里需要用到net.ping,代码如下:
ping_lose = 0
tmr.create():alarm(5000, tmr.ALARM_AUTO, function()
sec,usec,rate = rtctime.get()
time2 = rtctime.epoch2cal((sec+8*60*60),usec,rate)
print(string.format("nowtime=,%04d/%02d/%02d %02d:%02d:%02d",
time2["year"],
time2["mon"],
time2["day"],
time2["hour"],
time2["min"],
time2["sec"]))
--在这里实现定时关机
--如果大于11点到第二天7点,如果连续ping不通nas,就关电,在其他时间,就开电
if ( time2["hour"] >= 0 and time2["hour"]<=6 )then
net.ping(host_ip, 1, function (b, ip, sq, tm)
if ip then print(("%d bytes from %s, icm p_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end
if b > 0 then ping_lose=0 else ping_lose=ping_lose + 1 end
if ping_lose > 60 then
gpio.mode(3,gpio.OUTPUT)
gpio.write(3,gpio.HIGH)
end
end)
else
ping_lose = 0
gpio.mode(3,gpio.OUTPUT)
gpio.write(3,gpio.Low)
end
end)
其中
gpio.mode(3,gpio.OUTPUT)
gpio.write(3,gpio.HIGH)
就是用来关闭继电器,gpio.write(3,gpio.LOW)就是用来打开电源。
主要程序就这么点,虽然有点简单粗暴,但是实用效果还是不错的。
如果要临时取消关电,只需要关闭黑群的自动开关机功能,保持主机开机,继电器就不会断电的。