一、简介
在之前曾发布过一篇文章“华为云物联网平台的微信小程序开发”,在最近接到部分用户私信在使用开发过程中出现的问题,例如API访问的"401"现象等问题,在重新查看上面的文章教程时发现教程内容的步骤不详细,现对教程重新整理,将具体的开发过程以及工程源码分享给大家,文章可面向微信小程序开发的零基础小白。
二、开发前准备
由于我们小程序对接的时华为云物联网平台,所以我们需要提前在华为云物联网平台创建产品及设备,并准备以下相关信息:
1. 产品ID、设备ID、设备属性
在大家完成华为云物联网平台的MQTT数据通信测试后都回准备好了相关信息,如果还没有创建产品有设备,可以参考这篇文文章:华为云物联网平台创建产品与设备(含MQTT.fx测试).
2. 服务ID、控制名称、控制参数
在上传设备属性和命令下发时需要使用到服务ID、控制名称和控制参数,具体设置如下图:
3. IAM账户
1) 简介
IAM账户对初次接触华为云物联网平台的应用侧开发的伙伴来说可能比较陌生,首先介绍一下在我们使用API时的流程,API的使用需要通过IAM服务鉴权来获取token,然后将这个Token作为API的参数之一,官方开发文档:华为云物联网平台——API使用指导,如下图:
2) 创建IAM账户
首先进入华为云控制台,在右上角进入统一身份认证平台:
然后点击右上角的创建用户:
然后按下图创建用户:
3) IAM账户登录测试
首先复制登录链接:
然后打开新的浏览器(推荐)或者退出当前账户登录,然后进入刚才复制的链接:
输入新建的IAM用户和密码:
能够登录即可,登陆后如下图所示:
4. 相关API
1) 获取Token
查看开发文档:Token认证,如下图,可知需要构建一个HTTP请求,并且按下述格式完成调用。
其中地区可以在控制台接入信息中的地址中查看,大家选择自己对应的地区,不要随意修改:
我的HTTP请求JSON数据格式:
{"auth": {"identity": {"methods": ["password"],"password": {"user": {"name": "funiot_xyz","password": "www.funiot.xyz","domain": {"name": "hw_0086xxxxxxxxxxx"}}}},"scope": {"project": {"name": "cn-north-4"}}}}
2) 获取设备属性(通过设备影子)
在完成token获取后我们即可进行其他API的调用,例如获取设备影子来解析设备属性,只需要利用HTTP完成对应URL的GET请求,然后解析响应数据即可。
GET https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/shadow
3) 下发设备命令
同获取设备影子的API类似,也是利用HTTP完成对应URL的相应请求,然后解析响应数据即可,在下发设备命令时,我们暂时对返回结果不关心。
POST https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/commands{"service_id" : "Dev_data","command_name" : "Control","paras" : {"led" : "ON"}}
4) 终端节点Endpoint
大家可能看到了上面请求的URL链接中包含一个Endpoint信息,Endpoint为指定承载REST服务端点的服务器域名或IP,不同服务不同区域的Endpoint不同,我们可以在地区和终端节点中查看,例如我的HTTP访问的终端节点为:
-north-
5) 准备信息汇总
截止到目前,我们准备的信息有:产品ID、设备ID、设备属性、用户名、IAM用户名、IAM用户密码、服务ID、控制名称、控制参数、相应API的数据格式等,接下来我们就可以开始微信小程序的开发了。
三、微信小程序开发
1. 新建工程
1) 环境准备
官网下载并安装“微信开发工具”:微信开发者工具下载地址与更新日志
2) 获取AppID
进入微信小程序开发管理网页:微信小程序开发管理,然后点击开发设置,复制AppID。
3) 新建工程
填写在开发管理中复制的AppID并选择“JavaScript基础模板”,然后点击“确定”等待项目生成
4) 精简工程
我们把模板中无关的信息进行一下删减,首先删除page中的“index”以及“logs”界面,并新建page “Huawei_IOT”
系统会自动生成相关文件:
修改app.json文件,删除界面引用:
然后打开“Huawei_IOT.wxml”文件,这是小程序的页面布局文件,大家根据需要完成自己的界面设计:
2. 初始设计
1)初始界面设计
这里以非常简单的布局设计为例,在”Huawei_IOT.wxml“文件中添加三个按钮和两个文本提示信息,其中一个文本采用变量的形式,并为按钮添加触发函数名。
<text >提示信息:</text><text>{{result}}</text><button type="primary" bindtap="touchBtn_gettoken">获取token</button><button type="default" bindtap="touchBtn_getshadow">获取设备影子</button><button type="warn" bindtap="touchBtn_getshadow">设备命令下发</button>
2)初始功能设计
然后在“Huawei_IOT.js”文件中的date内补充变量以及按钮触发函数:
/*** 页面的初始数据*/data: {result:'等待获取token',},/*** 获取token按钮按下:*/touchBtn_gettoken:function(){console.log("获取token按钮按下");},/*** 获取设备影子按钮按下:*/touchBtn_getshadow:function(){console.log("获取设备影子按钮按下");},/*** 设备命令下发按钮按下:*/touchBtn_setCommand:function(){console.log("设备命令下发按钮按下");},
3)初始测试
编译之后在左侧模拟器中点击按钮,查看右侧的输出界面可以打印的信息,同时左侧模拟器的文本会对应更新:
接下来我们便开始完成华为云物联网平台的相关开发。
3. 华为云物联网平台通信
1)wx.request方法
wx.request方法用来建立http连接,完成GET或POST请求,实现各种HTTP API的调用, wx.request方法结构如下:
wx.request({url: '',data:'',method: '', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {}, // 设置请求的 header success: function(res){// success// successconsole.log(res);//打印完整消息},fail:function(){// fail},complete: function() {// complete} });
2)获取token
在前面我们已经学习了获取token的方法,即构建一个HTTP的POST请求,并且按对应格式完成调用。
a)url
在wx.request方法中的url为:
-north-/v3/auth/tokens
(注意更换自己的产品地区,我的是cn-north-4)
b)添加合法域名
由于微信小程序对域名访问有限制,需要手动添加为合法域名,首先打开微信小程序开发管理网页:微信小程序开发管理,然后点击开发设置,在服务器域名处点击修改,补充上述的根域名(注意:截止到.com),例如:
-north-
在项目中点击右上角的“详情”“项目配置”,可以看到合法域名已经被添加,如果没有,可以尝试点击刷新:
如果刷新后仍没有,请检查文章刚开始复制的AppID是否一致,如果不一致,可在右上角“详情”“基本信息”中修改:
此处有小伙伴因为AppID有误导致合法域名未有效添加引起,从而导致API调用失败的问题。
c)data
在wx.request方法中的data为上图URL下方的数据:
将自己的信息填写完整,例如我的data为:
{"auth": {"identity": {"methods": ["password"],"password": {"user": {"name": "funiot_xyz","password": "yourpassword","domain": {"name": "hw_0086xxxxxx"}}}},"scope": {"project": {"name": "cn-north-4"}}}}
建议大家在填写后进行json格式化验证,避免在填写过程中出现json数据格式错误,在线JSON校验格式化工具。(有部分小伙伴因为这个问题失败)。
d)method
method为POST:
e)header
请求头为:
{'content-type': 'application/json' }
f)补充request方法
将上述整理的所需数据填写完补充,如下所示:
/*** 获取token*/gettoken:function(){console.log("开始获取。。。");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取wx.request({url: '-north-/v3/auth/tokens',data:'{"auth": {"identity": {"methods": ["password"],"password": {"user": {"name": "funiot_xyz","password": "xxxxxxxx","domain": {"name": "hw_0086xxxxxxxx"}}}},"scope": {"project": {"name": "cn-north-4"}}}}',method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json' }, // 请求的 header success: function(res){// success// successconsole.log("获取token成功");//打印完整消息console.log(res);//打印完整消息},fail:function(){// failconsole.log("获取token失败");//打印完整消息},complete: function() {// completeconsole.log("获取token完成");//打印完整消息} });},
g)按键事件添加调用
this.gettoken();
h)编译运行
在输出端口可以看到打印了HTTP返回的消息,展开可以看到token:
i)添加解析
在wx.request方法中的 success回调函数,补充解析token的代码:
var token='';token=JSON.stringify(res.header['X-Subject-Token']);//解析消息头tokentoken=token.replaceAll("\"", "");console.log("获取token=\n"+token);//打印tokenwx.setStorageSync('token',token);//把token写到缓存中,以便可以随时随地调用
再次编译运行,可以看到提取了token:
j)获取token完整函数
/*** 获取token*/gettoken:function(){console.log("开始获取。。。");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取wx.request({url: '-north-/v3/auth/tokens',data:'{"auth": {"identity": {"methods": ["password"],"password": {"user": {"name": "funiot_xyz","password": "xxxxxxxx","domain": {"name": "hw_0086xxxxxxxx"}}}},"scope": {"project": {"name": "cn-north-4"}}}}',method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json' }, // 请求的 header success: function(res){// success// successconsole.log("获取token成功");//打印完整消息console.log(res);//打印完整消息var token='';token=JSON.stringify(res.header['X-Subject-Token']);//解析消息头的tokentoken=token.replaceAll("\"", "");console.log("获取token=\n"+token);//打印tokenwx.setStorageSync('token',token);//把token写到缓存中,以便可以随时随地调用},fail:function(){// failconsole.log("获取token失败");//打印完整消息},complete: function() {// completeconsole.log("获取token完成");//打印完整消息} });},
获取了token之后我们就可以开始使用其他API啦,接下来以获取设备影子为例。
3)获取设备属性(通过设备影子)
在前面我们已经学习了调用设备影子API的方法,即只需要利用HTTP完成对应URL的GET请求,然后解析响应数据即可。首先还是使用wx.request方法:
wx.request({url: '',data:'',method: '', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {}, // 设置请求的 header success: function(res){// success// success},fail:function(){// fail},complete: function() {// complete} });
a)URL
根据文档可知,其中URL为:
我们将自己的参数补充进去,例如我的URL为:
-north-/v5/iot/08e942062b80f46xxxxxxxxxxxxxx/devices/61fb2d7fde993xxxxxxx_esp8266_test01/shadow
b)添加合法域名
同上一次添加合法域名一样,打开微信小程序开发管理网页:微信小程序开发管理,然后点击开发设置,在服务器域名处点击修改,补充上述的根域名(注意:截止到.com),例如:
c)data
此处消息体没有数据,我们可以直接忽略
data:''
d)method
method采用GET请求
e)header
消息头为:
{'content-type': 'application/json','X-Auth-Token':token }
将获取的token作为参数X-Auth-Token的值,instance-Id可以忽略
f)补充request方法
将上述信息补充到wx.request中,例如:
getshadow:function(){console.log("开始获取影子");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取var token=wx.getStorageSync('token');//读缓存中保存的tokenconsole.log("我的toekn:"+token);//打印完整消息wx.request({url: '-north-/v5/iot/08e94206xxxxxxxxxxxxxxxxxx/devices/61fb2d7fde99xxxxxxxxx_esp8266_test01/shadow',data:'',method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json','X-Auth-Token':token }, //请求的header success: function(res){// success// successconsole.log(res);//打印完整消息},fail:function(){// failconsole.log("获取影子失败");//打印完整消息},complete: function() {// completeconsole.log("获取影子完成");//打印完整消息} });},
g)按键事件调用
this.getshadow();
h)编译运行
在输出端口可以看到打印了HTTP返回的消息,展开可以看到设备属性数据:
i)添加解析
在wx.request方法中的 success回调函数,补充解析设备属性的代码,再次编译运行:
var shadow=JSON.stringify(res.data.shadow[0].reported.properties);console.log('设备影子数据:'+shadow);//以下根据自己的设备属性进行解析//我的设备影子:{"Temp":30,"temp":89,"Dev_data":77.20592,"humi":80,"light":3000,"GPS_N":3904.2279,"GPS_E":11706.2279,"warning":1,"MPU6050":1,"foot":12,"led":1,"temps":"89"}var Temp=JSON.stringify(res.data.shadow[0].reported.properties.Temp);var Humi=JSON.stringify(res.data.shadow[0].reported.properties.humi);console.log('温度='+Temp+'℃');console.log('湿度='+Humi+'%');that.setData({result:'温度'+Temp+'℃,湿度'+Humi+'%'});
j)获取设备属性(通过设备影子)完整函数
/*** 获取设备影子*/getshadow:function(){console.log("开始获取影子");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取var token=wx.getStorageSync('token');//读缓存中保存的tokenwx.request({url: '-north-/v5/iot/08e942062xxxxxxxxxxxxxxxxxx/devices/61fb2d7fde9xxxxxxxxx_esp8266_test01/shadow',data:'',method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json','X-Auth-Token':token }, //请求的header success: function(res){// success// successconsole.log(res);//打印完整消息var shadow=JSON.stringify(res.data.shadow[0].reported.properties);console.log('设备影子数据:'+shadow);//以下根据自己的设备属性进行解析//我的设备影子:{"Temp":30,"temp":89,"Dev_data":77.20592,"humi":80,"light":3000,"GPS_N":3904.2279,"GPS_E":11706.2279,"warning":1,"MPU6050":1,"foot":12,"led":1,"temps":"89"}var Temp=JSON.stringify(res.data.shadow[0].reported.properties.Temp);var Humi=JSON.stringify(res.data.shadow[0].reported.properties.humi);console.log('温度='+Temp+'℃');console.log('湿度='+Humi+'%');that.setData({result:'温度'+Temp+'℃,湿度'+Humi+'%'});},fail:function(){// failconsole.log("获取影子失败");//打印完整消息console.log("请先获取token");//打印完整消息},complete: function() {// completeconsole.log("获取影子完成");//打印完整消息} });},
4)设备命令下发
通过前面的练习,我们可以了解到主要的就是访问的URL不同、mode不同,消息体和消息头不同,完成后解析对应的数据即可,在设备命令下发中前面已经介绍了这个API使用方法:
a)URL
根据文档可知,其中URL为:
补充参数后,我的URL为:
-north-/v5/iot/08e94206xxxxxxxxxxxxx/devices/61fb2d7fde99xxxxxxxx_esp8266_test01/commands
由于此域名与获取设备影子的域名一致,此处不用再次添加合法域名。
b)data
此处消息体为:
我的data:
{"service_id": "Dev_data","command_name": "Control","paras": {"led": 1}}
此处同样建议进行JSON格式化,避免在填写过程中出现json数据格式错误,在线JSON校验格式化工具。
c)method
method采用POST请求
d)header
消息头为:
{'content-type': 'application/json','X-Auth-Token':token}
e)按键事件调用
this.setCommand();
f)补充request方法
将上述信息补充到wx.request中,例如:
/*** 设备命令下发*/setCommand:function(){console.log("开始下发命令。。。");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取var token=wx.getStorageSync('token');//读缓存中保存的tokenwx.request({url: '-north-/v5/iot/08e942062b80xxxxxxxxxxxxxx/devices/61fb2d7fde9xxxxxxxxxxxxxx_esp8266_test01/commands',data:'{"service_id": "Dev_data","command_name": "Control","paras": {"led": 1}}',method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json','X-Auth-Token':token }, //请求的header success: function(res){// success// successconsole.log("下发命令成功");//打印完整消息console.log(res);//打印完整消息},fail:function(){// failconsole.log("命令下发失败");//打印完整消息console.log("请先获取token");//打印完整消息},complete: function() {// completeconsole.log("命令下发完成");//打印完整消息that.setData({result:'设备命令下发完成'});} });},
g)编译运行
在输出端口可以看到打印了HTTP返回的消息,展开可以看到命令下发情况:
在华为云物联网平台的监控运维中可以看到具体命令:
h)命令下发完整函数
/*** 设备命令下发*/setCommand:function(){console.log("开始下发命令。。。");//打印完整消息var that=this; //这个很重要,在下面的回调函数中由于异步问题不能有效修改变量,需要用that获取var token=wx.getStorageSync('token');//读缓存中保存的tokenwx.request({url: '-north-/v5/iot/08e942062b80xxxxxxxxxxxxxx/devices/61fb2d7fde9xxxxxxxxxxxxxx_esp8266_test01/commands',data:'{"service_id": "Dev_data","command_name": "Control","paras": {"led": 1}}',method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECTheader: {'content-type': 'application/json','X-Auth-Token':token }, //请求的header success: function(res){// success// successconsole.log("下发命令成功");//打印完整消息console.log(res);//打印完整消息},fail:function(){// failconsole.log("命令下发失败");//打印完整消息console.log("请先获取token");//打印完整消息},complete: function() {// completeconsole.log("命令下发完成");//打印完整消息that.setData({result:'设备命令下发完成'});} });},
至此,本期教程到此结束,大家可以通过这个项目完成基本的华为云物联网平台的设备属性查询与设备控制,所有相关代码均在文中给出,如有相关问题可以在文章下留言,收到留言后会第一时间处理,如果需要这个工程的项目文件,可以在公众号“IOT趣制作”内回复关键字“华为云WXIOT”或“0619”即可获得项目文件的下载链接。