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

概述

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

关系图

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

操作步骤

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

2、子设备产品的物模型定义:
阿里云物联网平台网关子设备接入JAVA Sample

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、运行结果

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

更多参考

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

上一篇:ios-网络-ASIHTTPRequest


下一篇:CentOS 6.5 Varnish缓存服务详解及应用实现 推