逍遥游

之前淋花, 控制灯的开关 都是nodemcu 做的,但是都是基于cron服务. 也就是定时服务. 定时服务简单,就是一个缺点,有时候这些东西要修改的时候比较麻烦, 要接上串口修改, 不接上串口 ,用telnet 去改也就可以但是总没那么直观,很容易出错而不知.

上去家中花严重缺水, 原来上次淋花器的一个程序有问题, 自己修改的时候不够细心,出错,倒是一个多月缺水, 于是下定决心修改一下.

现在把所有控制器都改到用mqtt协议连接到mqtt server上面, mqtt server 是自己搭建的. 运行在一个openwrt路由器上, 域名是阿里云域名,然后自己动态更新. 电信网络有公网IP ,于是就有了一些列的服务.

nodemcu 连接到mqtt server 上面,然后所有动作,都由服务器的cron 服务统一操作. 这样随时可以修改动作的时间,内容. 方便多了. 具体来说, 而且还可以根据当天天气清空改变淋花次数, 改变喂鱼机投喂次数, 比如天气寒冷,停止投喂.

代码
init.lua

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
101
102
103
104
105
106
107
--init for water 

gpio.mode(5, gpio.OUTPUT);
--gpio.mode(4, gpio.OUTPUT);
gpio.write(5, gpio.LOW);

station_cfg={}
station_cfg.ssid="sdfasd";
station_cfg.pwd="fasdfa"

-- 标识mqtt是否已经初始化
mqtt_inited = 0

-- 标识mqtt 是否已经连接
mqtt_connecting = 0



function startup()
-- if file.open("init.lua") == nil then
--print("init.lua deleted or renamed")
--else
--print("Running")
--file.close("init.lua")
-- the actual application is stored in 'application.lua'
-- dofile("application.lua")
--end
dofile("synctime.lua");


mdns.register("water", {hardware='NodeMCU'});
print("mdns:water.local/");

print("connecting mqtt server");
dofile("mqtt.lua")
end


-- Define WiFi station event callbacks
wifi_connect_event = function(T)
print("Connection to AP("..T.SSID..") established!")
print("Waiting for IP address...")
if disconnect_ct ~= nil then disconnect_ct = nil end
end

wifi_got_ip_event = function(T)
-- Note: Having an IP address does not mean there is internet access!
-- Internet connectivity can be determined with net.dns.resolve().
print("Wifi connection is ready! IP address is: "..T.IP)
print("Startup will resume momentarily, you have 3 seconds to abort.")
print("Waiting...")
tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end

wifi_disconnect_event = function(T)
if T.reason == wifi.eventmon.reason.ASSOC_LEAVE then
--the station has disassociated from a previously connected AP
return
end
-- total_tries: how many times the station will attempt to connect to the AP. Should consider AP reboot duration.
local total_tries = 5000
print("\nWiFi connection to AP("..T.SSID..") has failed!")

wifi_connetion1=0;

--There are many possible disconnect reasons, the following iterates through
--the list and returns the string corresponding to the disconnect reason.
for key,val in pairs(wifi.eventmon.reason) do
if val == T.reason then
print("Disconnect reason: "..val.."("..key..")")
break
end
end

--if disconnect_ct == nil then
-- disconnect_ct = 1
-- else
--disconnect_ct = disconnect_ct + 1
--end
--if disconnect_ct < total_tries then
-- print("Retrying connection...(attempt "..(disconnect_ct+1).." of "..total_tries..")")
--else
-- wifi.sta.disconnect()
--print("Aborting connection to AP!")
--disconnect_ct = nil
--end
end

-- Register WiFi Station event callbacks
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, wifi_connect_event)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, wifi_got_ip_event)
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, wifi_disconnect_event)

print("Connecting to WiFi access point...")
wifi.setmode(wifi.STATION)
wifi.sta.config(station_cfg)
wifi.sta.autoconnect(1)
-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default



dofile("http.lua");
print("runing http");
dofile("task.lua");
print("runing cron task");
dofile("telnet.lua");
print("runing telnet server");

mqtt.lua

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117



function stopReconnect()
-- clear connecting state and clear connect timer!
mqtt_connecting = 0
tmr.stop(3)
end

-- 重连方法
function reconnect()
if mqtt_connecting == 0 then
tmr.alarm(3, 20000, 1, function()
print("start mqtt server reconnect!")
mq:close()
mq:connect("x.x.x.x", 1883, 0)
end)
mqtt_connecting = 1
end
end



-- 初始化mqtt连接方法
function init()
print("init mqtt")
mqtt_inited = 1
-- 初始化无需登陆的客户端, 心跳时间 120秒
mq = mqtt.Client("recv_earth1", 120)

--mq:lwt("/lwt", "offline", 0, 0)
-- 设置连接ip 以及 端口

-- 对于 TLS: m:connect("192.168.11.118", secure-port, 1)
mq:connect("192.168.1.1", 1883, 0,
function(client)
print("connected")
end,
function(client, reason)
print("failed reason: " .. reason)
reconnect()
end
)

--连接到服务器触发事件
mq:on("connect", function(client)
print("connected")
stopReconnect()
mq:subscribe("tai3_water",0, function(conn) print("subscribe success") end)
--mq:subscribe("rpt_temp",0, function(conn) print("subscribe success") end)

end)



mq:on("offline", function(client)
print ("offline")
reconnect()
end) --掉线触发事件


-- 收到消息时触发事件
mq:on("message", function(client, topic, data)
print(topic .. ":" )
if data ~= nil then
if topic == "tai3_water" then
print(data)
if data == "water1min" then
dofile("water.lua")
--mq:publish("report_info","tai3_water1",0,0)
elseif data == "water2min" then
dofile("water2.lua")
--mq:publish("report_info","tai3_water2",0,0)
elseif data == "water4min" then
dofile("water4.lua")
--mq:publish("report_info","tai3_water4",0,0)
end
end

--if topic == "rpt_water" and tonumber(data) > 12 then
--print("aaa"..data)
--end

end
end)

end




--function do_get_adc() -- 定义定时器处理函数
--mq:publish("rpt_water", adc.read(0), 0, 0)
--end

--tmr.create():alarm(60000, tmr.ALARM_AUTO , do_get_adc)

-- 确保subscribe/publish方法在连接上服务器后再调用,在实际应用中是把他们放在connect回调函数里或者确定连接成功

-- 订阅/topic主题、服务质量为0
--m:subscribe("topicxx",0, function(conn) print("subscribe success") end)
--m:subscribe("blinkdr",0, function(conn) print("subscribe success") end)
-- 发送一条信息 data = hello, QoS = 0, retain = 0

--m:close();
-- 你可以再次调用 m:connect 连接函数





-- 如果没有初始化过,进行初始化
if mqtt_inited == 0 then
init()
else
reconnect()
end

synctime.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local tm
local sec

sec=rtctime.get();
rtctime.set(0);
sntp.sync("ntp1.aliyun.com",
function() -- success
rtctime.set(rtctime.get() + 8*3600 , 0)
tm = rtctime.epoch2cal(rtctime.get())
print(string.format("%04d/%02d/%02d %02d:%02d:%02d", tm["year"], tm["mon"], tm["day"], tm["hour"], tm["min"], tm["sec"]))
end,
function() -- fail
rtctime.set(sec);
print("fail!");
end

)

task.lua

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
cron.schedule("1 5 */2 * *", function(e)
dofile("synctime.lua");
end)

--cron.schedule("*/15 * * * *", function(e)
-- dofile("imap_read.lua");
--end)


cron.schedule("1 8 * * *", function(e)
if mqtt_connecting == 1 then
dofile("water2.lua");
end
end)

--cron.schedule("1 9 * * *", function(e)
-- dofile("water.lua");
--end)


cron.schedule("1 11 * * *", function(e)
if mqtt_connecting == 1 then
dofile("water2.lua");
end
end)


--cron.schedule("1 12 * * *", function(e)
-- dofile("water.lua");
--end)


cron.schedule("30 17 * * *", function(e)
if mqtt_connecting == 1 then
dofile("water2.lua");
end
end)


--cron.schedule("30 18 * * *", function(e)
--dofile("water.lua");
--end)