消息下发
概述
消息下发不依赖产品模型,提供给设备的单向通知,具有消息缓存功能;云端消息下发中,平台会以异步方式(消息下发后无需等待设备侧回复响应)下发消息给设备;若设备不在线,则在设备上线后发送数据(支持配置,最长缓存时间24小时)。平台对每个设备默认只保存20条消息,超过20条后,后续的消息会替换下发最早的消息。同时,消息下发支持使用自定义topic的格式进行数据下发。
消息下发Topic类别 |
描述 |
---|---|
系统Topic |
平台预先定义了各种设备和平台通信的Topic,具体Topic列表和功能说明可参考Topic定义。 |
自定义Topic |
用户可以自定义Topic,设备和平台间可以基于用户自定义的Topic进行通信。 自定义topic分类:
|
使用场景
- 数据格式需要自定义,不依赖物模型。
使用限制
- 单个消息内容不大于256KB。
- 单个设备下发消息缓存数量为20个。
- MQTT自定义Topic支持的最大长度为128字节。
- 缓存时间支持配置,最长不超过24小时。
使用服务质量
- 支持MQTT的服务质量等级为QoS 0、QoS 1,不支持QoS 2。
- Topic的QoS为 0 时,消息下发不需要等设备回ACK,仅只下发一次; Topic的QoS为 1时,消息下发需要等设备回ACK。
- 平台默认该设备订阅了QoS为0的系统Topic, 如果需要QoS为1的下行系统Topic,需要设备设置订阅QoS。
- 设备订阅非$oc开头的自定义Topic, 如果需要平台支持该Topic的QoS为1, 需向平台提交工单联系申请。
- 如果设备订阅Topic的QoS为1, 平台下发消息没有收到设备确认ACK时, 平台会重发消息, 默认每隔2s重发1次, 共重发3次;
重发后设备依旧没有回确认响应且消息还在缓存时间内, 设备再次上线或订阅Topic时, 平台会再重发消息, 默认每隔10s重发1次, 共重发5次;
同时每次重发也会触发每隔2s重发机制, 故订阅Topic的QoS为1时平台会重发消息。平台重发消息后,设备会收到重复消息,建议设备要有去重机制。
消息缓存下发使用说明
消息下发是平台向设备直接下发消息的一种方式。消息下发具有缓存特性,当设备不在线时,平台会对下发的消息进行缓存,直到设备上线。
- 应用侧或平台用下发设备消息接口,下发请求到物联网平台,下发消息样例如下:
POST https://{Endpoint}/v5/iot/{project_id}/devices/{device_id}/messages Content-Type: application/json X-Auth-Token: ******** { "message_id": "99b32da9-cd17-4cdf-a286-f6e849cbc364", "name": "messageName", "message": "HelloWorld" }
- 物联网平台向应用返回201 Created,消息状态为PENDING。
- 物联网平台通过设备消息状态变更通知接口推送消息结果给应用,设备未上线时,设备消息状态为缓存(PENDING),对应的消息样例如下:
Topic: $oc/devices/{device_id}/sys/messages/down 数据格式: { "resource": "device.message.status", "event": "update", "notify_data": { "message_id": "string", "name": "string", "device_id": "string", "status": "PENDING", "timestamp": "string" } }
- 设备上线。
- 设备订阅消息下发的topic(平台采用了隐式订阅的功能,对于下行的系统topic,设备无需订阅,非系统topic需要设备订阅),用于接收消息。
- 物联网平台根据协议规范下发消息给设备。下发的消息样例如下:
Topic: $oc/devices/{device_id}/sys/messages/down 数据格式: { "object_device_id": "{object_device_id}", "name": "name", "id": "id", "content": "hello" }
- 平台将消息的最终结果推送给应用服务器,设备消息状态为已发送(DELIVERED)。使用接口:设备消息状态变更通知接口。
Topic: $oc/devices/{device_id}/sys/messages/down 数据格式: { "resource": "device.message.status", "event": "update", "notify_data": { "message_id": "string", "name": "string", "device_id": "string", "status": "DELIVERED", "timestamp": "string" } }
消息下发使用QoS 1说明
MQTT设备接入,使用QoS 1的系统Topic进行设备消息下发说明:
- 设备上线。
- 订阅Topic,设置订阅Topic的QoS为1。
图3 订阅Topic的QoS为1
- 应用侧或平台用下发设备消息接口,下发请求到物联网平台,下发消息样例如下:
POST https://{Endpoint}/v5/iot/{project_id}/devices/{device_id}/messages Content-Type: application/json X-Auth-Token: ******** { "message_id": "99b32da9-cd17-4cdf-a286-f6e849cbc364", "name": "messageName", "message": "HelloWorld" }
- 物联网平台根据协议规范下发消息给设备。MQTT设备必须先订阅对应的Topic才能收到平台下发的消息(平台采用了隐式订阅的功能,对于下行的系统topic,设备无需订阅,非系统topic需要设备订阅),消息样例如下:
Topic: $oc/devices/{device_id}/sys/messages/down 数据格式: { "object_device_id": "{object_device_id}", "name": "name", "id": "id", "content": "hello" }
- 物联网平台向设备下发消息后,向应用服务器返回201 Created,消息状态为DELIVERED。消息下发是异步操作,不需要等设备ACK就可以回响应。
- 物联网平台没有收到设备接收消息的ACK响应,重发消息;默认每隔2s重发一次,总下发3次。
- 设备再次上线或订阅Topic。
- 物联网平台会重发之前设备未回ACK且未超时的消息,默认每隔10s重发一次,总下发5次;每次重发也会触发每隔2s重发机制。
- 平台将消息的最终结果推送给应用服务器,设备消息状态为已发送(DELIVERED)或超时(TIMEOUT)。使用接口:设备消息状态变更通知接口。
Topic: $oc/devices/{device_id}/sys/messages/down 数据格式: { "resource": "device.message.status", "event": "update", "notify_data": { "message_id": "string", "name": "string", "device_id": "string", "status": "DELIVERED", "timestamp": "string" } }
下发消息状态
MQTT设备消息执行状态以及状态变化机制如下所示。
消息执行状态 |
说明 |
---|---|
缓存(PENDING) |
MQTT协议设备不在线,物联网平台会将消息进行缓存,此时任务状态为“缓存”状态。 |
超时(TIMEOUT) |
物联网平台缓存的PENDING状态的消息,如果1天之内(支持配置,最长缓存时间24小时)还没有下发下去,物联网平台会将消息状态设置为“超时”。 |
已发送(DELIVERED) |
物联网平台将消息发送给设备后,状态变为“已发送”。 |
失败(FAILED) |
物联网平台发送消息给设备不成功,消息状态变为“失败”。 |
平台消息下发使用示例
云端消息下发,控制台上创建下发任务,MQTT协议设备接入为例,在设备接入控制台上进行消息缓存下发。
- 访问设备接入服务,单击“管理控制台”进入设备接入控制台。选择您的实例,单击实例卡片进入。
- 选择左侧导航栏的 ,在设备列表中,单击具体的设备进入到设备的详情页面。
- 在“下发消息”,在弹出的窗口中选择需要下发的命令并设置命令参数。
标签页,单击图5 下发消息-MQTT
- 可以在平台看到下发状态为已发送。
图6 下发消息-查询结果
配置应用侧Java SDK步骤如下:
- 配置Maven依赖,本示例使用的开发环境为JDK 1.8及以上版本。SDK代码获取:SDK下载。
<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 MessageDistributionSolution { // 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(); // 实例化请求对象 CreateMessageRequest request = new CreateMessageRequest(); request.withDeviceId("<YOUR DEVICE_ID>"); DeviceMessageRequest body = new DeviceMessageRequest(); body.withMessage("<YOUR DEVICE MESSAGE>"); request.withBody(body); try { CreateMessageResponse response = client.createMessage(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()); } } }
表3 参数说明 参数
说明
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,只允许字母、数字、下划线(_)、连接符(-)的组合。
配置设备侧Java SDK步骤如下,示例中使用的开发环境为JDK 1.8及以上版本。SDK代码获取:SDK下载。
- 配置设备侧SDK的Maven依赖。
<dependency> <groupId>com.huaweicloud</groupId> <artifactId>iot-device-sdk-java</artifactId> <version>1.1.4</version> </dependency>
- 配置设备侧SDK,设备连接参数。
//加载iot平台的ca证书,获取连接参考:https://support.huaweicloud.com/intl/zh-cn/devg-iothub/iot_02_1004.html URL resource = BroadcastMessageSample.class.getClassLoader().getResource("ca.jks"); File file = new File(resource.getPath()); //注意格式为:ssl://域名信息:端口号。 //域名获取方式:登录华为云IoTDA控制台左侧导航栏“总览”页签,在选择的实例基本信息中,单击“接入信息”。选择8883端口对应的接入域名。 String serverUrl = "ssl://localhost:8883"; //在IoT平台创建的设备ID。 String deviceId = "deviceId"; //设备ID对应的密钥。 String deviceSecret = "secret"; //创建设备 IoTDevice device = new IoTDevice(serverUrl, deviceId, deviceSecret, file); if (device.init() != 0) { return; }
- 消息下发回调函数定义。
client.setDeviceMessageListener(deviceMessage -> { log.info("the onDeviceMessage is {}", deviceMessage.toString()); });
测试验证步骤如下:
- 在设备接入控制台,选择您的实例,单击实例卡片进入。选择左侧导航栏的
,单击具体设备 进入设备详情,在 页签内,启动 。图7 消息跟踪-启动消息跟踪
- 运行应用侧SDK代码,下发消息,应用侧可以看到平台响应样例如下:
图8 应用侧消息下发成功响应
- 在平台的消息跟踪中可以看到:
图9 消息跟踪-缓存下发消息
- 设备端运行设备侧 SDK代码,设备侧收到消息时日志格式样例如下:
图10 设备消息下发成功