阿里云物联网平台网关子设备接入JAVA Sample

简介: 子设备不直接连接物联网平台,而是通过网关接入物联网平台。首先,需在物联网平台上创建网关和子设备;然后,开发网关设备端SDK,实现网关直连物联网平台;再由网关向物联网平台上报网关与子设备的拓扑关系;通过网关上报子设备证书(一机一密方式)或者子设备动态注册的认证方式,物联网平台校验子设备的身份和该子设备与网关的拓扑关系。

概述

子设备不直接连接物联网平台,而是通过网关接入物联网平台。首先,需在物联网平台上创建网关和子设备;然后,开发网关设备端SDK,实现网关直连物联网平台;再由网关向物联网平台上报网关与子设备的拓扑关系;通过网关上报子设备证书(一机一密方式)或者子设备动态注册的认证方式,物联网平台校验子设备的身份和该子设备与网关的拓扑关系。所有校验通过,才会建立子设备逻辑通道,并绑定至网关物理通道上,实现子设备通过网关,与物联网平台建立连接,并进行通信。本文主要如何演示使用JAVA SDK实现相关过程。

关系图

_

操作步骤

1、创建网关和子设备,参考链接

2、子设备产品的物模型定义:
_

2、pom.xml

 <repositories>
        <repository>
            <id>alimaven</id>
            <name>aliyun maven</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.aliyun.alink.linksdk</groupId>
            <artifactId>iot-linkkit-java</artifactId>
            <version>1.2.0.1</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.1</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.40</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    
    <build>
        <finalName>iot-java-sdk</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

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 {

    // 初始化参数
    private static String regionId = "cn-shanghai";
    private static final String TAG = "TOPO";

    //网关设备三元组信息
    private static String GWproductKey = "********";
    private static String GWdeviceName = "********";
    private static String GWdeviceSecret = "********";

    public static void main(String[] args) {

        LinkKitInitParams params = new LinkKitInitParams();
        /**
         * 设置 Mqtt 初始化参数
         */
        IoTMqttClientConfig config = new IoTMqttClientConfig();
        config.productKey = GWproductKey;
        config.deviceName = GWdeviceName;
        config.deviceSecret = GWdeviceSecret;
        config.channelHost = GWproductKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883";
        /**
         * 是否接受离线消息
         * 对应 mqtt 的 cleanSession 字段
         */
        config.receiveOfflineMsg = false;
        params.mqttClientConfig = config;
        ALog.setLevel(LEVEL_DEBUG); // 设置日志打印级别
        ALog.i(TAG, "mqtt connetcion info=" + params);

        /**
         * 设置初始化,传入设备证书信息
         */
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.productKey = GWproductKey;
        deviceInfo.deviceName = GWdeviceName;
        deviceInfo.deviceSecret = GWdeviceSecret;
        params.deviceInfo = deviceInfo;

        /**建立链接**/
        LinkKit.getInstance().init(params, new ILinkKitConnectListener() {
            public void onError(AError aError) {
                ALog.e(TAG, "Init Error error=" + aError);
            }

            public void onInitDone(InitResult initResult) {
                ALog.i(TAG, "onInitDone result=" + initResult);

                //获取网关下topo关系,查询网关与子设备是否已经存在topo关系
                //如果已经存在,则直接上线子设备,不存在则需要添加网关子设备
                LinkKit.getInstance().getGateway().gatewayGetSubDevices(new IConnectSendListener() {
                    @Override
                    public void onResponse(ARequest request, AResponse aResponse) {
                        ALog.i(TAG, "获取网关的topo关系成功 : " + JSONObject.toJSONString(aResponse));

                        // 1、获取子设备列表结果
                        try {
                            ResponseModel<List<DeviceInfo>> response = JSONObject.parseObject(aResponse.data.toString(), new TypeReference<ResponseModel<List<DeviceInfo>>>() {
                            }.getType());
                            // TODO 根据实际应用场景处理
                            Integer subDeviceCounts = response.data.size();
                            System.out.println("topo下子设备的数目:" + subDeviceCounts);// topo网管下子设备的数目

//                            // 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));
//                                    }
//                                });
//                            }

                            // 3、使用子设备动态注册获取完子设备三元组信息后,添加到网关设备
                            List<BaseInfo> subDevices = new ArrayList<>();
                            BaseInfo baseInfo2 = new BaseInfo();
                            // 未激活的子设备三元组信息,可以通过上面的注释代码获取
                            baseInfo2.productKey = "********";
                            baseInfo2.deviceName = "********";
                            String deviceSecret = "********";
                            subDevices.add(baseInfo2);
                            LinkKit.getInstance().getGateway().gatewayAddSubDevice(baseInfo2, new ISubDeviceConnectListener() {
                                @Override
                                public String getSignMethod() {
                                    // 使用的签名方法
                                    return "hmacsha1";
                                }

                                @Override
                                public String getSignValue() {
                                    // 获取签名,用户使用 deviceSecret 获得签名结果
                                    Map<String, String> signMap = new HashMap<>();
                                    signMap.put("productKey", baseInfo2.productKey);
                                    signMap.put("deviceName", baseInfo2.deviceName);
                                    // signMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
                                    signMap.put("clientId", getClientId());
                                    return SignUtils.hmacSign(signMap, deviceSecret);
                                }

                                @Override
                                public String getClientId() {
                                    // clientId 可为任意值
                                    return "id";
                                }

                                @Override
                                public Map<String, Object> getSignExtraData() {
                                    return null;
                                }

                                @Override
                                public void onConnectResult(boolean isSuccess, ISubDeviceChannel iSubDeviceChannel, AError aError) {

                                    // 添加结果
                                    if (isSuccess) {
                                        // 子设备添加成功,接下来可以做子设备上线的逻辑
                                        ALog.i(TAG, "topo关系添加成功 : " + JSONObject.toJSONString(iSubDeviceChannel));

                                        // 子设备添加成功后,代理子设备上线
                                        LinkKit.getInstance().getGateway().gatewaySubDeviceLogin(baseInfo2, new ISubDeviceActionListener() {
                                            @Override
                                            public void onSuccess() {
                                                System.out.println("代理子设备上线成功!");

                                                // 基本信息设置
                                                System.out.println("使用网关的通道执行子设备的数据上下行");
                                                String topic = "/******/******/user/datapubandsub"; // 子设备自定义Topic
                                                String sysSubTopic = "/sys/******/******/thing/event/property/post";// 子设备系统属性设置Topic
                                                String payLoad = "{\"id\":\"123\",\"method\":\"thing.event.property.post\",\"params\":{\"RoomHumidity\":19},\"version\":\"1.0\"}"; //注意此处和第二步子设备物模型定义相关

                                                // 发布系统消息测试
                                                MqttPublishRequest request1 = new MqttPublishRequest();
//                                              // topic 用户根据实际场景填写
                                                request1.topic = sysSubTopic;
                                                request1.payloadObj = payLoad;

                                                LinkKit.getInstance().publish(request1, new IConnectSendListener(){
                                                    @Override
                                                    public void onResponse(ARequest aRequest, AResponse aResponse) {

                                                        System.out.println("发送成功");
                                                    }

                                                    @Override
                                                    public void onFailure(ARequest aRequest, AError aError) {
                                                        System.out.println("发送失败");

                                                    }
                                                });

                                                // 订阅
                                                MqttSubscribeRequest request = new MqttSubscribeRequest();
                                                // topic 用户根据实际场景填写
                                                request.topic = topic;
                                                request.isSubscribe = true;

                                                // 直接做Topic的订阅,注意自定义Topic需要使用这种方式,否则会出现订阅失败的情况,SDK有Bug,系统Topic没有问题
                                                LinkKit.getInstance().subscribe(request, new IConnectSubscribeListener(){
                                                    @Override
                                                    public void onSuccess() {
                                                        System.out.println("直接订阅成功");
                                                    }

                                                    @Override
                                                    public void onFailure(AError aError) {
                                                        System.out.println("直接订阅失败" + aError.getMsg());

                                                    }
                                                });

                                                // 注册下行监听
                                                LinkKit.getInstance().registerOnNotifyListener(new IConnectNotifyListener() {
                                                    @Override
                                                    public void onNotify(String s, String s1, AMessage aMessage) {
                                                        System.out.println("下行消息Topic:" + s);
                                                        System.out.println("下行消息:" + new String((byte[])aMessage.getData()));
                                                    }
                                                    @Override
                                                    public boolean shouldHandle(String s, String s1) {
                                                        return false;
                                                    }

                                                    @Override
                                                    public void onConnectStateChange(String s, ConnectState connectState) {
                                                        System.out.println("连接状态发生变化 :" + s + connectState);
                                                    }
                                                });
                                                System.out.println("---取消订阅---");
                                                // 取消订阅  参考订阅方法  request.isSubscribe = false; 即可
                                            }

                                            @Override
                                            public void onFailed(AError aError) {
                                                ALog.d(TAG, "onFailed() called with: aError = [" + aError + "]");
                                                System.out.println(aError.getMsg());
                                            }
                                        });
                                    } else {
                                        ALog.i(TAG, "topo关系添加失败 : " + JSONObject.toJSONString(aError));
                                    }
                                }

                                @Override
                                public void onDataPush(String s, AMessage aMessage) {
                                }
                            });
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onFailure(ARequest request, AError error) {
                        ALog.i(TAG, "获取网关的topo关系失败 : " + JSONObject.toJSONString(error));
                    }
                });
            }
        });
    }
}

说明

1、首先初始化网关设备,建立连接;
2、检查当前网关设备拓扑关系,获取现有子设备信息,示例演示网关设备尚未添加子设备;
3、动态注册获取网关子设备DeviceSecret,本部分注释,第一次运行需要取消注释;
4、添加子设备三元组信息到网关设备;
5、网关代理子设备进行Topic的订阅、消息的发布及下行监听注册。

注意

替换网关设备三元组信息、子设备三元组信息、子设备Topic信息。

4、运行结果

_

更多参考

设备安全认证
网关接入物联网平台
子设备接入物联网平台

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
相关文章
|
7月前
|
存储 运维 监控
物联网平台常见类别及对应平台(一)
物联网平台常见类别及对应平台(一)
504 0
|
2月前
|
消息中间件 DataWorks 物联网
MQTT问题之接入阿里云物联网平台如何解决
MQTT接入是指将设备或应用通过MQTT协议接入到消息服务器,以实现数据的发布和订阅;本合集着眼于MQTT接入的流程、配置指导以及常见接入问题的解决方法,帮助用户实现稳定可靠的消息交换。
176 1
|
7月前
|
存储 机器学习/深度学习 监控
物联网平台常见类别及对应平台(二)
物联网平台常见类别及对应平台(二)
253 0
|
监控 小程序 物联网
阿里云物联网平台专用工具详细说明
阿里云物联网平台专用工具基本涵盖了阿里云物联网平台提供你主要管理功能,可以方便创建产品、设备、物模型,查看设备实时属性,事件,发送服务和查看服务日志等等。
657 0
阿里云物联网平台专用工具详细说明
|
7月前
|
消息中间件 运维 监控
课时3:10分钟玩转阿里云物联网平台设备接入、管理、运维(二)
10分钟玩转阿里云物联网平台设备接入、管理、运维
330 0
|
7月前
|
物联网 开发工具 网络架构
基于AT模组连接阿里云物联网平台
本实验主要介绍基于AT模组,通过AT指令将端侧设备快速连接到阿里云物联网平台,助力设备智能化改造。
513 0
|
11月前
《阿里云产品手册2022-2023 版》——物联网平台
《阿里云产品手册2022-2023 版》——物联网平台
449 1
|
11月前
|
存储 人工智能 运维
|
11月前
|
存储 运维 监控
阿里云创新生态合作手册-阿里云物联网平台专场-物联网平台生态加速计划,助力企业数智转型(下)
阿里云创新生态合作手册-阿里云物联网平台专场-物联网平台生态加速计划,助力企业数智转型
174 0
|
11月前
|
运维 安全 小程序

相关产品

  • 物联网平台