資安

阿里雲物聯網平臺網關子設備接入JAVA Sample

作者:俏巴

概述

子設備不直接連接物聯網平臺,而是通過網關接入物聯網平臺。首先,需在物聯網平臺上創建網關和子設備;然後,開發網關設備端SDK,實現網關直連物聯網平臺;再由網關向物聯網平臺上報網關與子設備的拓撲關係;通過網關上報子設備證書(一機一密方式)或者子設備動態註冊的認證方式,物聯網平臺校驗子設備的身份和該子設備與網關的拓撲關係。所有校驗通過,才會建立子設備邏輯通道,並綁定至網關物理通道上,實現子設備通過網關,與物聯網平臺建立連接,並進行通信。本文主要如何演示使用JAVA SDK實現相關過程。

關係圖

_

操作步驟

1、創建網關和子設備,參考鏈接

2、子設備產品的物模型定義:
_

2、pom.xml

 <repositories>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">repository</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>alimaven<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>aliyun maven<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>http://maven.aliyun.com/nexus/content/groups/public/<span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">repository</span>&gt;</span></span>
&lt;<span class="hljs-regexp">/repositories&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.aliyun.alink.linksdk&lt;/g</span>roupId&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>iot-linkkit-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span></span>
        &lt;version&gt;<span class="hljs-number">1.2</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>&lt;<span class="hljs-regexp">/version&gt;
        &lt;scope&gt;compile&lt;/</span>scope&gt;
    <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span></span>
    &lt;dependency&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.google.code.gson<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span></span>
        &lt;artifactId&gt;gson&lt;<span class="hljs-regexp">/artifactId&gt;
        &lt;version&gt;2.8.1&lt;/</span>version&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>compile<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span></span>
    &lt;<span class="hljs-regexp">/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.alibaba&lt;/g</span>roupId&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>fastjson<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span></span>
        &lt;version&gt;<span class="hljs-number">1.2</span><span class="hljs-number">.40</span>&lt;<span class="hljs-regexp">/version&gt;
        &lt;scope&gt;compile&lt;/</span>scope&gt;
    <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span></span>
&lt;<span class="hljs-regexp">/dependencies&gt;

&lt;build&gt;
    &lt;finalName&gt;iot-java-sdk&lt;/</span>finalName&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">source</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">source</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">target</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">target</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">encoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">encoding</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span></span>
&lt;<span class="hljs-regexp">/build&gt;</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&lt;List&lt;DeviceInfo&gt;&gt; response = JSONObject.parseObject(aResponse.data.toString(), <span class="hljs-keyword">new</span> TypeReference&lt;ResponseModel&lt;List&lt;DeviceInfo&gt;&gt;&gt;() {
                        }.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&lt;BaseInfo&gt; subDevices = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
                        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>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>&gt; signMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
                                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>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">Object</span>&gt; 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、運行結果


_


更多參考


設備安全認證
網關接入物聯網平臺
子設備接入物聯網平臺


Leave a Reply

Your email address will not be published. Required fields are marked *