作者:俏巴
概述
子设备不直接连接物联网平台,而是通过网关接入物联网平台。首先,需在物联网平台上创建网关和子设备;然后,开发网关设备端SDK,实现网关直连物联网平台;再由网关向物联网平台上报网关与子设备的拓扑关系;通过网关上报子设备证书(一机一密方式)或者子设备动态注册的认证方式,物联网平台校验子设备的身份和该子设备与网关的拓扑关系。所有校验通过,才会建立子设备逻辑通道,并绑定至网关物理通道上,实现子设备通过网关,与物联网平台建立连接,并进行通信。本文主要如何演示使用JAVA SDK实现相关过程。
关系图
操作步骤
1、创建网关和子设备,参考链接。
2、子设备产品的物模型定义:
2、pom.xml
<repositories>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">repository</span>></span>
<span class="hljs-tag"><<span class="hljs-name">id</span>></span>alimaven<span class="hljs-tag"></<span class="hljs-name">id</span>></span>
<span class="hljs-tag"><<span class="hljs-name">name</span>></span>aliyun maven<span class="hljs-tag"></<span class="hljs-name">name</span>></span>
<span class="hljs-tag"><<span class="hljs-name">url</span>></span>http://maven.aliyun.com/nexus/content/groups/public/<span class="hljs-tag"></<span class="hljs-name">url</span>></span>
<span class="hljs-tag"></<span class="hljs-name">repository</span>></span></span>
<<span class="hljs-regexp">/repositories>
<dependencies>
<dependency>
<groupId>com.aliyun.alink.linksdk</g</span>roupId>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>iot-linkkit-java<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span></span>
<version><span class="hljs-number">1.2</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span><<span class="hljs-regexp">/version>
<scope>compile</</span>scope>
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span></span>
<dependency>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.google.code.gson<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span></span>
<artifactId>gson<<span class="hljs-regexp">/artifactId>
<version>2.8.1</</span>version>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">scope</span>></span>compile<span class="hljs-tag"></<span class="hljs-name">scope</span>></span></span>
<<span class="hljs-regexp">/dependency>
<dependency>
<groupId>com.alibaba</g</span>roupId>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>fastjson<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span></span>
<version><span class="hljs-number">1.2</span><span class="hljs-number">.40</span><<span class="hljs-regexp">/version>
<scope>compile</</span>scope>
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span></span>
<<span class="hljs-regexp">/dependencies>
<build>
<finalName>iot-java-sdk</</span>finalName>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">plugins</span>></span>
<span class="hljs-tag"><<span class="hljs-name">plugin</span>></span>
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.apache.maven.plugins<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>maven-compiler-plugin<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
<span class="hljs-tag"><<span class="hljs-name">configuration</span>></span>
<span class="hljs-tag"><<span class="hljs-name">source</span>></span>1.8<span class="hljs-tag"></<span class="hljs-name">source</span>></span>
<span class="hljs-tag"><<span class="hljs-name">target</span>></span>1.8<span class="hljs-tag"></<span class="hljs-name">target</span>></span>
<span class="hljs-tag"><<span class="hljs-name">encoding</span>></span>UTF-8<span class="hljs-tag"></<span class="hljs-name">encoding</span>></span>
<span class="hljs-tag"></<span class="hljs-name">configuration</span>></span>
<span class="hljs-tag"></<span class="hljs-name">plugin</span>></span>
<span class="hljs-tag"></<span class="hljs-name">plugins</span>></span></span>
<<span class="hljs-regexp">/build></span></code></pre>
3、Code Sample
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.aliyun.alink.dm.api.BaseInfo;
import com.aliyun.alink.dm.api.DeviceInfo;
import com.aliyun.alink.dm.api.InitResult;
import com.aliyun.alink.dm.api.SignUtils;
import com.aliyun.alink.dm.model.ResponseModel;
import com.aliyun.alink.linkkit.api.ILinkKitConnectListener;
import com.aliyun.alink.linkkit.api.IoTMqttClientConfig;
import com.aliyun.alink.linkkit.api.LinkKit;
import com.aliyun.alink.linkkit.api.LinkKitInitParams;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceActionListener;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceChannel;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceConnectListener;
import com.aliyun.alink.linksdk.cmp.connect.channel.MqttPublishRequest;
import com.aliyun.alink.linksdk.cmp.connect.channel.MqttSubscribeRequest;
import com.aliyun.alink.linksdk.cmp.core.base.AMessage;
import com.aliyun.alink.linksdk.cmp.core.base.ARequest;
import com.aliyun.alink.linksdk.cmp.core.base.AResponse;
import com.aliyun.alink.linksdk.cmp.core.base.ConnectState;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectNotifyListener;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectSendListener;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectSubscribeListener;
import com.aliyun.alink.linksdk.tools.AError;
import com.aliyun.alink.linksdk.tools.ALog;
import java.util.*;
import static com.aliyun.alink.linksdk.tools.ALog.LEVEL_DEBUG;
// 子设备测试
public class SubDeviceDemo {
<span class="hljs-comment">// 初始化参数</span>
private <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> regionId = <span class="hljs-string">"cn-shanghai"</span>;
private <span class="hljs-keyword">static</span> final <span class="hljs-built_in">String</span> TAG = <span class="hljs-string">"TOPO"</span>;
<span class="hljs-comment">//网关设备三元组信息</span>
private <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> GWproductKey = <span class="hljs-string">"********"</span>;
private <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> GWdeviceName = <span class="hljs-string">"********"</span>;
private <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> GWdeviceSecret = <span class="hljs-string">"********"</span>;
public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
LinkKitInitParams params = <span class="hljs-keyword">new</span> LinkKitInitParams();
<span class="hljs-comment">/**
* 设置 Mqtt 初始化参数
*/</span>
IoTMqttClientConfig config = <span class="hljs-keyword">new</span> IoTMqttClientConfig();
config.productKey = GWproductKey;
config.deviceName = GWdeviceName;
config.deviceSecret = GWdeviceSecret;
config.channelHost = GWproductKey + <span class="hljs-string">".iot-as-mqtt."</span> + regionId + <span class="hljs-string">".aliyuncs.com:1883"</span>;
<span class="hljs-comment">/**
* 是否接受离线消息
* 对应 mqtt 的 cleanSession 字段
*/</span>
config.receiveOfflineMsg = <span class="hljs-literal">false</span>;
params.mqttClientConfig = config;
ALog.setLevel(LEVEL_DEBUG); <span class="hljs-comment">// 设置日志打印级别</span>
ALog.i(TAG, <span class="hljs-string">"mqtt connetcion info="</span> + params);
<span class="hljs-comment">/**
* 设置初始化,传入设备证书信息
*/</span>
DeviceInfo deviceInfo = <span class="hljs-keyword">new</span> DeviceInfo();
deviceInfo.productKey = GWproductKey;
deviceInfo.deviceName = GWdeviceName;
deviceInfo.deviceSecret = GWdeviceSecret;
params.deviceInfo = deviceInfo;
<span class="hljs-comment">/**建立链接**/</span>
LinkKit.getInstance().init(params, <span class="hljs-keyword">new</span> ILinkKitConnectListener() {
public <span class="hljs-keyword">void</span> onError(AError aError) {
ALog.e(TAG, <span class="hljs-string">"Init Error error="</span> + aError);
}
public <span class="hljs-keyword">void</span> onInitDone(InitResult initResult) {
ALog.i(TAG, <span class="hljs-string">"onInitDone result="</span> + initResult);
<span class="hljs-comment">//获取网关下topo关系,查询网关与子设备是否已经存在topo关系</span>
<span class="hljs-comment">//如果已经存在,则直接上线子设备,不存在则需要添加网关子设备</span>
LinkKit.getInstance().getGateway().gatewayGetSubDevices(<span class="hljs-keyword">new</span> IConnectSendListener() {
@Override
public <span class="hljs-keyword">void</span> onResponse(ARequest request, AResponse aResponse) {
ALog.i(TAG, <span class="hljs-string">"获取网关的topo关系成功 : "</span> + JSONObject.toJSONString(aResponse));
<span class="hljs-comment">// 1、获取子设备列表结果</span>
<span class="hljs-keyword">try</span> {
ResponseModel<List<DeviceInfo>> response = JSONObject.parseObject(aResponse.data.toString(), <span class="hljs-keyword">new</span> TypeReference<ResponseModel<List<DeviceInfo>>>() {
}.getType());
<span class="hljs-comment">// TODO 根据实际应用场景处理</span>
Integer subDeviceCounts = response.data.size();
System.out.println(<span class="hljs-string">"topo下子设备的数目:"</span> + subDeviceCounts);<span class="hljs-comment">// topo网管下子设备的数目</span>
// // 2、如果topo下面的子设备数目为0,则通过动态注册获取子设备Secret信息
// if (subDeviceCounts == 0)
// {
// /**
// * 子设备动态注册获取设备deviceSecret,如果设备已知三元组则忽略此步
// * 预注册设备时,可以使用设备的MAC地址或SN序列号等作为DeviceName
// */
// List<BaseInfo> subDevices = new ArrayList<>();
// BaseInfo baseInfo1 = new BaseInfo();
// // 未激活的子设备的信息
// baseInfo1.productKey = "";
// baseInfo1.deviceName = "";
// subDevices.add(baseInfo1);
//
// LinkKit.getInstance().getGateway().gatewaySubDevicRegister(subDevices, new IConnectSendListener() {
//
// @Override
// public void onResponse(ARequest request, AResponse response) {
// ALog.i(TAG, "子设备动态注册成功 : " + JSONObject.toJSONString(response));
//
// // 通过动态注册获取的子设备信息,供后续添加子设备到网关设备使用
// //{"iotId":"","deviceSecret":"","productKey":"","deviceName":""}
// }
// @Override
// public void onFailure(ARequest request, AError error) {
// ALog.i(TAG, "子设备注册失败 : " + JSONObject.toJSONString(error));
// }
// });
// }
<span class="hljs-comment">// 3、使用子设备动态注册获取完子设备三元组信息后,添加到网关设备</span>
List<BaseInfo> subDevices = <span class="hljs-keyword">new</span> ArrayList<>();
BaseInfo baseInfo2 = <span class="hljs-keyword">new</span> BaseInfo();
<span class="hljs-comment">// 未激活的子设备三元组信息,可以通过上面的注释代码获取</span>
baseInfo2.productKey = <span class="hljs-string">"********"</span>;
baseInfo2.deviceName = <span class="hljs-string">"********"</span>;
<span class="hljs-built_in">String</span> deviceSecret = <span class="hljs-string">"********"</span>;
subDevices.add(baseInfo2);
LinkKit.getInstance().getGateway().gatewayAddSubDevice(baseInfo2, <span class="hljs-keyword">new</span> ISubDeviceConnectListener() {
@Override
public <span class="hljs-built_in">String</span> getSignMethod() {
<span class="hljs-comment">// 使用的签名方法</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"hmacsha1"</span>;
}
@Override
public <span class="hljs-built_in">String</span> getSignValue() {
<span class="hljs-comment">// 获取签名,用户使用 deviceSecret 获得签名结果</span>
<span class="hljs-built_in">Map</span><<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>> signMap = <span class="hljs-keyword">new</span> HashMap<>();
signMap.put(<span class="hljs-string">"productKey"</span>, baseInfo2.productKey);
signMap.put(<span class="hljs-string">"deviceName"</span>, baseInfo2.deviceName);
<span class="hljs-comment">// signMap.put("timestamp", String.valueOf(System.currentTimeMillis()));</span>
signMap.put(<span class="hljs-string">"clientId"</span>, getClientId());
<span class="hljs-keyword">return</span> SignUtils.hmacSign(signMap, deviceSecret);
}
@Override
public <span class="hljs-built_in">String</span> getClientId() {
<span class="hljs-comment">// clientId 可为任意值</span>
<span class="hljs-keyword">return</span> <span class="hljs-string">"id"</span>;
}
@Override
public <span class="hljs-built_in">Map</span><<span class="hljs-built_in">String</span>, <span class="hljs-built_in">Object</span>> getSignExtraData() {
<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
@Override
public <span class="hljs-keyword">void</span> onConnectResult(boolean isSuccess, ISubDeviceChannel iSubDeviceChannel, AError aError) {
<span class="hljs-comment">// 添加结果</span>
<span class="hljs-keyword">if</span> (isSuccess) {
<span class="hljs-comment">// 子设备添加成功,接下来可以做子设备上线的逻辑</span>
ALog.i(TAG, <span class="hljs-string">"topo关系添加成功 : "</span> + JSONObject.toJSONString(iSubDeviceChannel));
<span class="hljs-comment">// 子设备添加成功后,代理子设备上线</span>
LinkKit.getInstance().getGateway().gatewaySubDeviceLogin(baseInfo2, <span class="hljs-keyword">new</span> ISubDeviceActionListener() {
@Override
public <span class="hljs-keyword">void</span> onSuccess() {
System.out.println(<span class="hljs-string">"代理子设备上线成功!"</span>);
<span class="hljs-comment">// 基本信息设置</span>
System.out.println(<span class="hljs-string">"使用网关的通道执行子设备的数据上下行"</span>);
<span class="hljs-built_in">String</span> topic = <span class="hljs-string">"/******/******/user/datapubandsub"</span>; <span class="hljs-comment">// 子设备自定义Topic</span>
<span class="hljs-built_in">String</span> sysSubTopic = <span class="hljs-string">"/sys/******/******/thing/event/property/post"</span>;<span class="hljs-comment">// 子设备系统属性设置Topic</span>
<span class="hljs-built_in">String</span> payLoad = <span class="hljs-string">"{\"id\":\"123\",\"method\":\"thing.event.property.post\",\"params\":{\"RoomHumidity\":19},\"version\":\"1.0\"}"</span>; <span class="hljs-comment">//注意此处和第二步子设备物模型定义相关</span>
<span class="hljs-comment">// 发布系统消息测试</span>
MqttPublishRequest request1 = <span class="hljs-keyword">new</span> MqttPublishRequest();
// // topic 用户根据实际场景填写
request1.topic = sysSubTopic;
request1.payloadObj = payLoad;
LinkKit.getInstance().publish(request1, <span class="hljs-keyword">new</span> IConnectSendListener(){
@Override
public <span class="hljs-keyword">void</span> onResponse(ARequest aRequest, AResponse aResponse) {
System.out.println(<span class="hljs-string">"发送成功"</span>);
}
@Override
public <span class="hljs-keyword">void</span> onFailure(ARequest aRequest, AError aError) {
System.out.println(<span class="hljs-string">"发送失败"</span>);
}
});
<span class="hljs-comment">// 订阅</span>
MqttSubscribeRequest request = <span class="hljs-keyword">new</span> MqttSubscribeRequest();
<span class="hljs-comment">// topic 用户根据实际场景填写</span>
request.topic = topic;
request.isSubscribe = <span class="hljs-literal">true</span>;
<span class="hljs-comment">// 直接做Topic的订阅,注意自定义Topic需要使用这种方式,否则会出现订阅失败的情况,SDK有Bug,系统Topic没有问题</span>
LinkKit.getInstance().subscribe(request, <span class="hljs-keyword">new</span> IConnectSubscribeListener(){
@Override
public <span class="hljs-keyword">void</span> onSuccess() {
System.out.println(<span class="hljs-string">"直接订阅成功"</span>);
}
@Override
public <span class="hljs-keyword">void</span> onFailure(AError aError) {
System.out.println(<span class="hljs-string">"直接订阅失败"</span> + aError.getMsg());
}
});
<span class="hljs-comment">// 注册下行监听</span>
LinkKit.getInstance().registerOnNotifyListener(<span class="hljs-keyword">new</span> IConnectNotifyListener() {
@Override
public <span class="hljs-keyword">void</span> onNotify(<span class="hljs-built_in">String</span> s, <span class="hljs-built_in">String</span> s1, AMessage aMessage) {
System.out.println(<span class="hljs-string">"下行消息Topic:"</span> + s);
System.out.println(<span class="hljs-string">"下行消息:"</span> + <span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>((byte[])aMessage.getData()));
}
@Override
public boolean shouldHandle(<span class="hljs-built_in">String</span> s, <span class="hljs-built_in">String</span> s1) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
@Override
public <span class="hljs-keyword">void</span> onConnectStateChange(<span class="hljs-built_in">String</span> s, ConnectState connectState) {
System.out.println(<span class="hljs-string">"连接状态发生变化 :"</span> + s + connectState);
}
});
System.out.println(<span class="hljs-string">"---取消订阅---"</span>);
<span class="hljs-comment">// 取消订阅 参考订阅方法 request.isSubscribe = false; 即可</span>
}
@Override
public <span class="hljs-keyword">void</span> onFailed(AError aError) {
ALog.d(TAG, <span class="hljs-string">"onFailed() called with: aError = ["</span> + aError + <span class="hljs-string">"]"</span>);
System.out.println(aError.getMsg());
}
});
} <span class="hljs-keyword">else</span> {
ALog.i(TAG, <span class="hljs-string">"topo关系添加失败 : "</span> + JSONObject.toJSONString(aError));
}
}
@Override
public <span class="hljs-keyword">void</span> onDataPush(<span class="hljs-built_in">String</span> s, AMessage aMessage) {
}
});
} <span class="hljs-keyword">catch</span> (Exception e) {
e.printStackTrace();
}
}
@Override
public <span class="hljs-keyword">void</span> onFailure(ARequest request, AError error) {
ALog.i(TAG, <span class="hljs-string">"获取网关的topo关系失败 : "</span> + JSONObject.toJSONString(error));
}
});
}
});
}
}
说明
1、首先初始化网关设备,建立连接;
2、检查当前网关设备拓扑关系,获取现有子设备信息,示例演示网关设备尚未添加子设备;
3、动态注册获取网关子设备DeviceSecret,本部分注释,第一次运行需要取消注释;
4、添加子设备三元组信息到网关设备;
5、网关代理子设备进行Topic的订阅、消息的发布及下行监听注册。
注意
替换网关设备三元组信息、子设备三元组信息、子设备Topic信息。
4、运行结果
更多参考