【经验分享】使用Spring Boot实现华为云IoTDA设备接入
【经验分享】使用Spring Boot实现华为云IoTDA设备接入并进行测试
初次使用华为云设备接入IoTDA服务, 发现网络上的参考资料较少, 分享一下我的配置经历XD
1. 创建产品模型
产品模型是用来描述设备能力的文件,通过JSON的格式定义了设备的基本属性、上报数据和下发命令的消息格式(这个JSON可以自动解析)。定义产品模型,即在物联网平台构建一款设备的抽象模型,使平台理解该款设备的功能。
创建产品
添加服务
测试
2. 配置测试设备(以MQTTX为例)
官方文档
这里以MQTT作为测试工具进行简单测试
2.1 设备注册
- 在平台上注册设备
- 保存设备ID和设备密钥
2.2 设备连接
安装MQTTX工具 MQTTX:全功能 MQTT 客户端工具
使用华为云提供的工具生成连接信息
MQTTX建立连接
- 注:服务器地址在总览–接入信息中查看
连接后, 设备在华为云中的状态将由离线转为在线
2.3 属性上报测试
topic配置
- topic:
$oc/devices/{device_id}/sys/properties/report
其中device_id为[设备注册](# 2.1 设备注册)结果中的设备ID
值
- topic:
填写上报数据
请求参数
字段名 必选/可选 类型 参数描述 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. 配置数据转发
官方文档
我们可以基于华为云平台的数据转发
功能, 将设备上报的信息通过http推送的方式转发到服务器上
具体实现方式为
创建规则触发条件: 当设备发生指定动作(消息上报)时, 触发某个规则动作
设置转发目标(后端服务器)
- 可以配置内网穿透来在本地开发环境下接收
测试
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接口向设备下发命令,以实现对设备的远程控制。
- 属性下发和消息下发也可以实现, 但是使用情景相对较少(确信)
4.1 API Explorer平台测试
平台链接: API ExplorerCreateCommand下发设备命令 (huaweicloud.com)
平台接口测试
进行测试
- 这里因为设备端没有设置response, 没有回复是正常的
==★★★请注意★★★==
如果使用的是不是基础版, 使用API Explorer的代码示例是不能跑通的, 我这边报错如下
(甚至使用华为云的ADK代码测试平台都不能正常运行)
设备上行响应
当然, 在这里, 我们在MQTTX客户端, 眼疾手快地手动回复也是可行的
参考官方文档 平台命令下发_设备接入 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, 上行时需要带上
设备上行响应体示例
{ "result_code": 0, "response_name": "test response", "paras": { "result": "success" } }
测试结果
4.2 在Java项目中进行命令下发
测试成功, 现在我们需要将接口在我们的项目中实现
添加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>
官方同步下发样例
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,只允许字母、数字、下划线(_)、连接符(-)的组合。 - 注意区分基础版和标准版/企业版 (免费使用的都是专业版-标准版)
以下是我的修改版 (基于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. 常见问题
一些我在使用时遇到的问题, 大家可以参考一下
调用API时, 报错The device does not exist.
详细报错信息
{ "request_id": "93e660a1f02c957998fdf3821569c4d5", "error_code": "IOTDA.014000", "error_message": "The device does not exist." }
解决方法:
- 检查你的device_id是否真的填对了
- 查看instance_id, 自动填充的是basic instance的id
- 点赞
- 收藏
- 关注作者
评论(0)