【经验分享】使用Spring Boot实现华为云IoTDA设备接入

举报
亦瑾zzz 发表于 2023/10/06 01:37:09 2023/10/06
【摘要】 初次使用华为云设备接入IoTDA服务, 发现网络上的参考资料较少, 分享一下我的配置经历

【经验分享】使用Spring Boot实现华为云IoTDA设备接入并进行测试

初次使用华为云设备接入IoTDA服务, 发现网络上的参考资料较少, 分享一下我的配置经历XD

1. 创建产品模型

产品模型是用来描述设备能力的文件,通过JSON的格式定义了设备的基本属性、上报数据和下发命令的消息格式(这个JSON可以自动解析)。定义产品模型,即在物联网平台构建一款设备的抽象模型,使平台理解该款设备的功能。

【华为云技术分享】浅谈产品模型(Profile)在程序设计中的作用-CSDN博客

  1. 创建产品

  2. 添加服务

  3. 测试

2. 配置测试设备(以MQTTX为例)

官方文档

使用MQTT.fx调测_设备接入 IoTDA_开发指南

这里以MQTT作为测试工具进行简单测试

2.1 设备注册

  1. 在平台上注册设备
  2. 保存设备ID和设备密钥

2.2 设备连接

  1. 安装MQTTX工具 MQTTX:全功能 MQTT 客户端工具

  2. 使用华为云提供的工具生成连接信息

  3. MQTTX建立连接

    • 注:服务器地址在总览–接入信息中查看
  4. 连接后, 设备在华为云中的状态将由离线转为在线

2.3 属性上报测试

  1. topic配置

    • topic: $oc/devices/{device_id}/sys/properties/report 其中device_id为[设备注册](# 2.1 设备注册)结果中的设备ID
  2. 填写上报数据

    • 请求参数

      字段名 必选/可选 类型 参数描述
      services 必选 List<ServiceProperty> 设备服务数据列表(具体结构参考下表ServiceProperty定义表)

      ServiceProperty定义表:

      字段名 必选/可选 类型 参数描述
      service_id 必选 String 设备服务的ID。
      properties 必选 Object 设备服务的属性列表,具体字段在设备关联的产品模型中定义。
      event_time 可选 String 设备采集数据UTC时间(格式:yyyyMMddTHHmmssZ),如:20161219T114920Z。设备上报数据不带该参数或参数格式错误时,则数据上报时间以平台时间为准。
    • {
          "services": [{
                  "service_id": "DeviceInfo",
                  "properties": {
                      "deviceName": "testDevice",
                      "deviceType": "wirelessLock"
                  },
                  "event_time": "20151212T121212Z"
              },
              {
                  // another service
              }
          ]
      }
      
    • 上传结果

  3. 查看上传情况

3. 配置数据转发

官方文档

消息上报概述_设备接入 IoTDA

使用HTTP/HTTPS订阅推送_设备接入 IoTDA

数据转发简介_设备接入 IoTDA_用户指南

我们可以基于华为云平台的数据转发功能, 将设备上报的信息通过http推送的方式转发到服务器上

具体实现方式为

  1. 创建规则触发条件: 当设备发生指定动作(消息上报)时, 触发某个规则动作

  2. 设置转发目标(后端服务器)

    • 可以配置内网穿透来在本地开发环境下接收
  3. 测试

    • MQTTX客户端上报消息(发送json数据)

    • 消息上报格式

      Topic $oc/devices/{device_id}/sys/messages/up 
      数据样例: 
      {
      	"message" : "this is test message"
      }
      
    • springboot接收并打印消息

另附-消息上报格式

json

{
  "resource": "device.message",
  "event": "report",
  "event_time": "20231003T124226Z",
  "event_time_ms": "2023-10-03T12:42:26.858Z",
  "request_id": "92afcc30-491c-4770-836d-7968391a6f66",
  "notify_data": {
    "header": {
      "app_id": "53e14eee94854*********4f3e434ea1",
      "device_id": "6519606da55*********be49_testDevice",
      "node_id": "testDevice",
      "product_id": "6519606da55*********be49",
      "gateway_id": "6519606da55*********be49_testDevice"
    },
    "body": {
      "topic": "$oc/devices/{6519606da55*********be49_testDevice}/sys/messages/up",
      "content": {
        "message" : "this is test message"
      }
    }
  }
}

DeviceData

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeviceData<T> {
    private String resource;
    private String event;
    private Date eventTime;
    private Date eventTimeMs;
    private String request_id;
    private NotifyData<T> notifyData;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class NotifyData<T> {
        private Header header;
        private Body<T> body;
    }

}

Header

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Header {
    private String app_id;
    private String device_id;
    private String node_id;
    private String product_id;
    private String gateway_id;
}

4. 命令下发

官方文档

为能有效地对设备进行管理,设备的产品模型中定义了物联网平台可向设备下发的命令,应用服务器可以调用物联网平台应用侧API接口向设备下发命令,以实现对设备的远程控制。

命令下发概述_设备接入 IoTDA

  • 属性下发和消息下发也可以实现, 但是使用情景相对较少(确信)

4.1 API Explorer平台测试

平台链接: API ExplorerCreateCommand下发设备命令 (huaweicloud.com)

平台接口测试

进行测试

  • 这里因为设备端没有设置response, 没有回复是正常的

==★★★请注意★★★==

如果使用的是不是基础版, 使用API Explorer的代码示例是不能跑通的, 我这边报错如下

(甚至使用华为云的ADK代码测试平台都不能正常运行)

设备上行响应

当然, 在这里, 我们在MQTTX客户端, 眼疾手快地手动回复也是可行的

  1. 参考官方文档 平台命令下发_设备接入 IoTDA 得知下行和上行的topic, 手动进行发送

    下行: $oc/devices/{device_id}/sys/commands/request_id={request_id}
    上行:$oc/devices/{device_id}/sys/commands/response/request_id={request_id}
    
    • 下行的request_id为平台生成的 用于标识这次请求的唯一id, 上行时需要带上
  2. 设备上行响应体示例

    {
        "result_code": 0,
        "response_name": "test response",
        "paras": {
            "result": "success"
        }
    }
    
  3. 测试结果

4.2 在Java项目中进行命令下发

测试成功, 现在我们需要将接口在我们的项目中实现

  1. 添加maven依赖

    <dependency>
        <groupId>com.huaweicloud.sdk</groupId>
        <artifactId>huaweicloud-sdk-core</artifactId>
        <version>[3.0.40-rc, 3.2.0)</version>
    </dependency>
    <dependency>
        <groupId>com.huaweicloud.sdk</groupId>
        <artifactId>huaweicloud-sdk-iotda</artifactId>
        <version>[3.0.40-rc, 3.2.0)</version>
    </dependency>
    
    
  2. 官方同步下发样例

    public class CommandSolution {
        // REGION_ID:如果是上海一,请填写"cn-east-3";如果是北京四,请填写"cn-north-4";如果是华南广州,请填写"cn-south-4"
        private static final String REGION_ID = "<YOUR REGION ID>";
        // ENDPOINT:请在控制台的"总览"界面的"平台接入地址"中查看“应用侧”的https接入地址。
        private static final String ENDPOINT = "<YOUR ENDPOINT>";
        // 标准版/企业版:需自行创建Region对象
        public static final Region REGION_CN_NORTH_4 = new Region(REGION_ID, ENDPOINT);
        public static void main(String[] args) {
            String ak = "<YOUR AK>";
            String sk = "<YOUR SK>";
            String projectId = "<YOUR PROJECTID>";
            // 创建认证
            ICredential auth = new BasicCredentials().withDerivedPredicate(AbstractCredentials.DEFAULT_DERIVED_PREDICATE)
                .withAk(ak)
                .withSk(sk)
                .withProjectId(projectId);
            // 创建IoTDAClient实例并初始化
            IoTDAClient client = IoTDAClient.newBuilder().withCredential(auth)
                // 基础版:请选择IoTDARegion中的Region对象
                //.withRegion(IoTDARegion.CN_NORTH_4)
                // 标准版/企业版:需自行创建Region对象
                .withRegion(REGION_CN_NORTH_4).build();
            // 实例化请求对象
            CreateCommandRequest request = new CreateCommandRequest();
            request.withDeviceId("<YOUR DEVICE_ID>");
            DeviceCommandRequest body = new DeviceCommandRequest();
            body.withParas("{\"value\":\"1\"}");
            request.withBody(body);
            try {
                CreateCommandResponse response = client.createCommand(request);
                System.out.println(response.toString());
            } catch (ConnectionException e) {
                e.printStackTrace();
            } catch (RequestTimeoutException e) {
                e.printStackTrace();
            } catch (ServiceResponseException e) {
                e.printStackTrace();
                System.out.println(e.getHttpStatusCode());
                System.out.println(e.getRequestId());
                System.out.println(e.getErrorCode());
                System.out.println(e.getErrorMsg());
            }
        }
    }
    
    
    • 参数说明
    参数 说明
    ak 您的华为云账号访问密钥ID(Access Key ID)。请在华为云控制台“我的凭证 > 访问密钥”页面上创建和查看您的 AK/SK。更多信息请查看访问密钥
    sk 您的华为云账号秘密访问密钥(Secret Access Key)。
    projectId 项目ID。获取方法请参见 获取项目ID
    IoTDARegion.CN_NORTH_4 请替换为您要访问的物联网平台的区域,当前物联网平台可以访问的区域,在SDK代码IoTDARegion.java中已经定义。您可以在控制台上查看当前服务所在区域名称,区域名称、区域和终端节点的对应关系,具体步骤请参考平台对接信息
    REGION_ID 如果是上海一,请填写“cn-east-3”;如果是北京四,请填写“cn-north-4”;如果是华南广州,请填写“cn-south-4”。
    ENDPOINT 请在控制台的“总览”界面的“接入信息”中查看“应用接入”的https接入地址。
    DEVICE_ID 下发消息的设备ID,用于唯一标识一个设备,在注册设备时由物联网平台分配获得。 取值范围:长度不超过128,只允许字母、数字、下划线(_)、连接符(-)的组合。
    • 注意区分基础版和标准版/企业版 (免费使用的都是专业版-标准版)
  3. 以下是我的修改版 (基于SpringBoot)

    @Service("createCommandService")
    @PropertySource("classpath:key.properties")
    public class DeviceCommandServiceImpl implements DeviceCommandService {
    
        @Value("${hw.lyj.AK}")
        private String accessKey;
        @Value("${hw.lyj.SK}")
        private String secretKey;
        @Value("${hw.lyj.InstanceID}")
        private String instanceId;
        @Value("${hw.lyj.ProjectID}")
        private String projectId;
    
        // REGION_ID:如果是上海一,请填写"cn-east-3";如果是北京四,请填写"cn-north-4";如果是华南广州,请填写"cn-south-4"
        private String REGION_ID = "cn-north-4";
        // ENDPOINT:请在控制台的"总览"界面的"平台接入地址"中查看“应用侧”的https接入地址。
        @Value("${hw.lyj.Endpoint}")
        private String ENDPOINT;
        // 标准版/企业版:需自行创建Region对象
    
    
        @Override
        public ResponseResult createCommand(String deviceId, DeviceCommandEnum deviceCommand, Object paras) {
    
            // 创建认证
            ICredential auth = new BasicCredentials().withDerivedPredicate(AbstractCredentials.DEFAULT_DERIVED_PREDICATE)
                    .withAk(accessKey)
                    .withSk(secretKey)
                    .withProjectId(projectId);
            // 创建IoTDAClient实例并初始化
            Region REGION_CN_NORTH_4 = new Region(REGION_ID, ENDPOINT);
            IoTDAClient client = IoTDAClient.newBuilder().withCredential(auth)
                    // 基础版:请选择IoTDARegion中的Region对象
    //            .withRegion(IoTDARegion.CN_NORTH_4)
                    // 标准版/企业版:需自行创建Region对象
                    .withRegion(REGION_CN_NORTH_4).build();
            // 实例化请求对象
            CreateCommandRequest request = new CreateCommandRequest();
    //        request.withDeviceId("6519606da559fd7cd414be49_testDevice");
            request.withDeviceId(deviceId);
            DeviceCommandRequest body = new DeviceCommandRequest();
    //        body.withParas("{\"value\":\"1\"}");
            body.withParas(JSON.toJSONString(paras));
            request.withBody(body);
            try {
                CreateCommandResponse response = client.createCommand(request);
                System.out.println(response.toString());
            } catch (ConnectionException e) {
                e.printStackTrace();
            } catch (RequestTimeoutException e) {
                e.printStackTrace();
            } catch (ServiceResponseException e) {
                e.printStackTrace();
                System.out.println(e.getHttpStatusCode());
                System.out.println(e.getRequestId());
                System.out.println(e.getErrorCode());
                System.out.println(e.getErrorMsg());
            }
    
            return ResponseResult.okResult();
        }
    }
    
    

5. 常见问题

一些我在使用时遇到的问题, 大家可以参考一下

  1. 调用API时, 报错The device does not exist.

    • 详细报错信息

      {
          "request_id": "93e660a1f02c957998fdf3821569c4d5",
          "error_code": "IOTDA.014000",
          "error_message": "The device does not exist."
      }
      
    • 解决方法:

      1. 检查你的device_id是否真的填对了
      2. 查看instance_id, 自动填充的是basic instance的id
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。