阿里云影子文件操作指南

不废话,直接上代码吧

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
--- 模块功能:阿里云功能测试.
-- 支持数据传输和OTA功能
-- @author openLuat
-- @module aLiYun.testALiYun
-- @license MIT
-- @copyright openLuat
-- @release 2018.04.14

module(...,package.seeall)

require "aLiYun"
require "misc"
require "nvm"


--阿里云华东2站点上创建的产品的ProductKey,用户根据实际值自行修改
--local PRODUCT_KEY = "你自己的产品key"
--采用“一机一密”认证方案除了上面的PRODUCT_KEY外,还需要设备名称和设备密钥
--设备名称使用函数getDeviceName的返回值,默认为设备的IMEI
--设备密钥使用函数getDeviceSecret的返回值,默认为设备的SN
--单体测试时,可以直接修改getDeviceName和getDeviceSecret的返回值
--批量量产时,使用设备的IMEI和SN;合宙生产的模块,都有唯一的IMEI,用户可以在自己的产线批量写入跟IMEI(设备名称)对应的SN(设备密钥)
--或者用户自建一个服务器,设备上报IMEI给服务器,服务器返回对应的设备密钥,然后调用misc.setSn接口写到设备的SN中

local PRODUCT_KEY = "你自己的产品key"
local PRODUCE_SECRET="你自己的产品密钥"
local Shadow_Changed = false
--采用“一型一密”认证方案时打开上面的注释,比“一机一密”认证方式额外提供提供PRODUCE_SECRET,PRODUCE_SECRET的值根据实际值自行修改
--设备请求接入时,云端动态下发该设备的DeviceSecret,DeviceSecret的保存方法默认使用setDeviceSecret将设备的SN替换成DeviceSecret
--之后设备密钥的获取便使用函数getDeviceSecret的返回值,然后使用ProductKey、DeviceName和DeviceSecret进行认证并建立连接。
--请参考126行的aLiYun.setup(PRODUCT_KEY,PRODUCE_SECRET,getDeviceName,getDeviceSecret,setDeviceSecret)去配置参数

--[[
函数名:getDeviceName
功能 :获取设备名称
参数 :无
返回值:设备名称
]]
local function getDeviceName()
--默认使用设备的IMEI作为设备名称
--用户单体测试时,可以在此处直接返回阿里云的iot控制台上注册的设备名称,例如return "868575021150844"
--return "Air202Test13"
--return "862991419835241"
return misc.getImei()
end

--[[
函数名:setDeviceSecret
功能 :修改设备密钥
参数 :设备密钥
返回值:无
]]
local function setDeviceSecret(s)
--默认使用设备的SN作为设备密钥
misc.setSn(s)
end


--[[
函数名:getDeviceSecret
功能 :获取设备密钥
参数 :无
返回值:设备密钥
]]
local function getDeviceSecret()
--默认使用设备的SN作为设备密钥
--用户单体测试时,可以在此处直接返回阿里云的iot控制台上生成的设备密钥,例如return "y7MTCG6Gk33Ux26bbWSpANl4OaI0bg5Q"
--return "y7MTCG6Gk33Ux26bbWSpANl4OaI0bg5Q"
return misc.getSn()
end

--阿里云客户端是否处于连接状态
sConnected = false

--[[
函数名:pubqos1testackcb
功能 :发布1条qos为1的消息后收到PUBACK的回调函数
参数 :
usertag:调用mqttclient:publish时传入的usertag
result:true表示发布成功,false或者nil表示失败
返回值:无
]]
local function publishTestCb(result,para)
log.info("myALiYun.publishTestCb",result,para)
end

--发布一条shadow更新消息
function updateShadow(desired)
if sConnected then
desired["rssi"] = net.getRssi()
desired["PowerSwitch"] = nvm.get("PowerSwitch")
local jdata = json.encode(desired)
_G.shadow_version = _G.shadow_version + 1
local resp = "{\"method\":\"update\",\"state\": {\"reported\":" .. jdata .."},\"version\":".._G.shadow_version.."}"
aLiYun.publish("/shadow/update/"..PRODUCT_KEY.."/"..getDeviceName(), resp, 1,publishTestCb, resp)
else
log.info("sorry, sConnected=false")
end
end



---数据接收的处理函数
-- @string topic,UTF8编码的消息主题
-- @number qos,消息质量等级
-- @string payload,原始编码的消息负载
local function rcvCbFnc(topic,qos,payload)
log.info("myALiYun.rcvCbFnc",topic,qos,payload)
if topic == "/shadow/get/"..PRODUCT_KEY.."/"..getDeviceName() then
local shadow,result,errinfo = json.decode(payload)
if result then
log.info("Shadow Method=" .. shadow["method"])
if shadow["version"] ~= nil then
_G.shadow_version = shadow["version"]
log.info("Shadow Version = " .. _G.shadow_version)
end
local desired = nil
if shadow["method"] == "reply" and shadow["payload"]["state"] ~= nil and shadow["payload"]["state"]["desired"] ~= nil then
return
end
if shadow["method"] == "control" and shadow["payload"]["state"] ~= nil and shadow["payload"]["state"]["desired"] ~= nil then
desired = shadow["payload"]["state"]["desired"]
end
if desired ~= nil then
-- reply如果有数据,那么肯定是get请求, 要更新本地状态
log.info("Shadow control/reply begin ...")
--if shadow["payload"]["status"] == "success" then
local tmp = json.encode(desired)
log.info("desired=" .. tmp)
Shadow_Changed = false
-- 这里写业务逻辑
if Shadow_Changed then
updateShadow(desired)
end
--else
-- log.info("desired is emtry")
--end
--end
log.info("Shadow control ... end")
end
else
log.info("Bad Shadow JSON!")
end
return
end
local tjsondata,result,errinfo = json.decode(payload)
if result then
-- 处理mqtt payload
else
log.info("BAD JSON")
end
end

--- 连接结果的处理函数
-- @bool result,连接结果,true表示连接成功,false或者nil表示连接失败
local function connectCbFnc(result)
log.info("testALiYun.connectCbFnc",result)
sConnected = result
if result then
--订阅主题,不需要考虑订阅结果,如果订阅失败,aLiYun库中会自动重连
aLiYun.subscribe({["/"..PRODUCT_KEY.."/"..getDeviceName().."/get"]=0,
["/"..PRODUCT_KEY.."/"..getDeviceName().."/get"]=1,
["/shadow/get/"..PRODUCT_KEY.."/"..getDeviceName()]=0})
--注册数据接收的处理函数
aLiYun.on("receive",rcvCbFnc)
--PUBLISH消息测试
aLiYun.publish("/shadow/update/"..PRODUCT_KEY.."/"..getDeviceName(), "{\"method\":\"get\"}", 1,publishTestCb, "{\"method\":\"get\"}")
end
end

--配置产品key,设备名称和设备密钥;采用一机一密的认证方式是,第二个参数传入nil,采用一型一密认证方式时,需要PRODUCE_SECRET,并提供第五个参数
--注意:如果使用imei和sn作为设备名称和设备证书时,不要把getDeviceName和getDeviceSecret替换为misc.getImei()和misc.getSn()
--注意:采用一型一密认证方式时,仅在首次激活时动态下发DeviceSecret
--因为开机就调用misc.getImei()和misc.getSn(),获取不到值
--一机一密
--aLiYun.setup(PRODUCT_KEY,nil,getDeviceName,getDeviceSecret)
--一型一密
aLiYun.setup(PRODUCT_KEY,PRODUCE_SECRET,getDeviceName,getDeviceSecret,setDeviceSecret)

--setMqtt接口不是必须的,aLiYun.lua中有这个接口设置的参数默认值,如果默认值满足不了需求,参考下面注释掉的代码,去设置参数
--aLiYun.setMqtt(1, nil, 65)
aLiYun.on("connect",connectCbFnc)


--要使用阿里云OTA功能,必须参考本文件124或者126行aLiYun.setup去配置参数
--然后加载阿里云OTA功能模块(打开下面的代码注释)
require"aLiYunOta"

流程

  1. 开机
  2. 连接阿里云
  3. 定义shadow更新的topic
  4. 发送一个{“method”:”get”}到/shadow/update的topic,以获取最新的shadow version
  5. 阿里云下发最新的shadow,读取verison,更新本地状态
  6. 根据业务逻辑发送最新shadow或者处理下发的shadow状态

上次更新 2021-01-28