参考文章
NodeMCU 通过MQTT 连接阿里云物联网 https://blog.csdn.net/weixin_43368807/article/details/82984796
谢谢。
概要
本文与参考文章有一点的重复,但有几点会不同,一,更加具体的添加了一个实际功能,本文监控了温度与湿度信息;二,对代码进行了重新的组织,更加清晰简单。
阿里云平台方面的准备工作
创建产品、创建设备
可以参考最前边列出的参考文章。另外,阿里云平台也有很好的引导,按着引导下一步下一步就可以了。
添加功能
这个是与参考文章不同的地方。对了让读者更容易理解为什么要添加功能,我把产品、设备、功能的关系简单描述下。产品就像一个抽象的概念,例如电视机,只有把电视机变成具体的东西,我们才能具体触摸感知,这个就是设备,很类似于类与对象的概念。而一个产品对普通人来说,主要就是关注与它能做什么,也就是它的功能。功能是在产品中定义的,每个设备都会具备这个功能,这个就类似与类方法。
首先,选择产品,进入产品查看页面
然后,选择功能定义,在功能定义中选择自定义功能的添加
最后,进行自定义功能的设置
信息复制
后期设备端连接阿里云服务器时有几个信息需要设置,所以现在就要把对应的信息准备好:
- 在产品查看页面获取ProductKey与ProductSecret两个信息;
-
在功能定义页面获取温度、湿度的标识名,例如:
上图中,温度标识符:CurrentTemperature,湿度标识符:humidity,这两个是读者在前边自己设置。
- 在设备查看页面获取DeviceName信息;
- 在设备查看页面获取Topic链接信息,是一个类似/sys/*********/DeviceA/thing/event/property/post的字符串。
到此为止,阿里云端的设置就已经完成了。
设备端操作
固件烧写
请参考本文最前的参考文章的说明,以及本人其他关于NodeMCU操作的文章。但需要注意的是,固件注意选择温度传感器模块,例如我使用了DHT温度传感器模块。
我的固件包含了如下模块:This was built against the master branch and includes the following modules: crypto, dht, encoder, enduser_setup, file, gpio, http, i2c, mqtt, net, node, pwm, sntp, spi, tmr, uart, wifi, wifi_monitor.
代码编写逻辑
在代码设计上,分为了五个文件,一个是初始化wifi逻辑文件,init.lua,另一个是mqtt的连接处理文件,再一个就是配置文件,用来记录不同使用者信息的文件,config.lua,再一个是mqtt的逻辑处理文件,这个是针对一个物联网项目需要编写的逻辑,mqtt_app.lua。最后一个文件是应用模块管理文件application.lua。未来,可能会有其他功能添加,例如添加一个HTTP服务器支持,那么很可能会需要添加新的模块实现,那么就在application.lua中加载新的模块实现。
配置文件config.lua
-- WIFI 设置
SSID = "HiWiFi_**********"
PASSWORD = "**********"
-- MQTT设置
ProductKey ="************"
DeviceName ="*******"
DeviceSecret="*********************************************"
RegionId="cn-shanghai" --华东2
-- MQTT发送消息的topic
publish_topic = "/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post"
Wifi初始化逻辑文件init.lua
dofile("config.lua")
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
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 = 75
print("\nWiFi connection to AP("..T.SSID..") has failed!")
--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({ssid=SSID, pwd=PASSWORD})
-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default
应用模块管理文件application.lua
-- MQTT 模块 ----
dofile("mqtt.lua")
--print("Hello ...")
mqtt的连接处理模块mqtt.lua
-- 加载配置信息
dofile("config.lua")
-- 加载MQTT应用逻辑
mqtt_app = require("mqtt_app")
-- 连接阿里云
ClientId =wifi.sta.getmac()
myMQTTport=1883
myMQTT=nil
myMQTThost=ProductKey..".iot-as-mqtt."..RegionId..".aliyuncs.com"
myMQTTusername=DeviceName.."&"..ProductKey
myMQTTtimes='1234567890'
hmacdata="clientId"..ClientId.."deviceName"..DeviceName.."productKey"..ProductKey.."timestamp"..myMQTTtimes
myMQTTpassword=crypto.toHex(crypto.hmac("sha1",hmacdata,DeviceSecret))
myMQTTClientId=ClientId.."|securemode=3,signmethod=hmacsha1,timestamp="..myMQTTtimes.."|"
myMQTT=mqtt.Client(myMQTTClientId, 120,myMQTTusername,myMQTTpassword)
mqtt_app.MQTT_Init(myMQTT)
print("Attempting client connect...")
local re = myMQTT:connect(myMQTThost, myMQTTport,0, mqtt_app.MQTTSuccess,mqtt_app.MQTTFailed)
mqtt的应用逻辑实现模块mqtt_app.lua
dofile("config.lua")
local myqq_app = {};
MQTTconnectFlag = 0;
mClient = nil;
function myqq_app.MQTT_Init(client)
--[设备offline 事件]-----
myMQTT:on("offline", function(client)
print ("offline")
--tmr.start(0)
end)
--[注册 设备接收到订阅的topic 事件]-----
myMQTT:on("message", function(client, topic, data)
print(topic ..":")
if data ~= nil then
print(data)
end
end)
end
---[连接成功]---
function myqq_app.MQTTSuccess(client)
print("MQTT connected")
-- 注册通道
--client:subscribe(topic0,0, function(conn) --注册topic0
-- print("subscribe success")
--end)
mClient = client;
MQTTconnectFlag=1
--tmr.stop(0) --关闭定时连接
--[topic 定时上传数据]
tmr.create():alarm(5000, 1, function() --等待连接上
if MQTTconnectFlag==1 and mClient~=nil then
re,t,s,x = dht.read11(1);
msg = "{\"id\":\"bc:dd:c2:30:cb:dc\", \"params\":{\"CurrentTemperature\":"..tostring(t)..",\"humidity\":"..tostring(s).."},\"method\":\"thing.event.property.post\"}"
mClient:publish(publish_topic,msg,0,0,function(client)
print("send ok" )
end)
end
end)
end
---[连接失败]---
function myqq_app.MQTTFailed(client,reson)
print("Fail reson:"..reson)
MQTTconnectFlag=0
--tmr.start(0) --重新启动连接
end
return myqq_app;