更新时间:2024-08-21 GMT+08:00

命令下发

概述

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

物联网平台有同步命令下发和异步命令下发两种命令下发机制,如下表所示。

表1 命令下发概述

命令下发机制

定义

适用场景

LwM2M/CoAP协议设备

MQTT协议设备

同步命令下发

应用服务器可调用同步命令下发接口向指定设备下发命令,以实现对设备的同步控制。平台负责将命令以同步方式发送给设备,并将设备执行命令结果在HTTP请求中同步返回, 如果设备没有响应,平台会返回给应用服务器超时。

同步命令下发适合对命令实时性有要求的场景,比如路灯开关灯,燃气表开关阀。使用同步命令下发时,命令下发的时机需要由应用服务器来保证。

不适用

适用

异步命令下发

应用服务器可调用异步命令下发接口向指定设备下发命令,以实现对设备的控制。平台负责将命令发送给设备,并将命令执行结果异步推送给应用。

异步命令下发又分为缓存下发和立即下发。

  • 立即下发:不管设备是否在线,平台收到命令后立即下发给设备。如果设备不在线或者设备没收到指令则下发失败。
  • 缓存下发:物联网平台在收到命令后先缓存,等设备上线或者设备上报属性时再下发给设备,如果单个设备存在多条缓存命令,则进行排队串行下发。
  • 立即命令下发适用于实时性要求高的场景;
  • 缓存下发适合对命令实时性要求不高的场景,比如配置水表的参数。

适用

不适用

具体使用流程请见:同步命令下发异步命令下发

使用场景

  • 同步下发适合对命令实时性有要求的场景。异步用于实现对设备的控制。
  • 需要通过数据转发规则转发到华为云其他云服务上进行存储和处理的场景。

使用限制

  • 单个消息内容不大于256KB。
  • 需要定义产品模型
  • 同步命令设备响应时间为20秒以内。
  • 设备异步命令缓存数量为20个。
  • 设备异步命令缓存时间支持配置,最长不超过48小时。

命令下发相关API接口

同步命令下发概述

同步命令下发主要用于MQTT设备,分为单个MQTT设备同步命令下发与批量MQTT设备同步命令下发。

表2 同步命令下发

类型

描述

适用场景

使用示例

单个MQTT设备命令下发

平台向单个设备下发设备控制命令。

对单个设备进行下发设备控制命令。

单个MQTT设备同步命令下发

批量MQTT设备命令下发

平台向多个设备下发设备控制命令。可创建批量处理任务,对多个设备进行批量操作

对多个设备进行批量下发设备控制命令。

批量MQTT设备同步命令下发

单个MQTT设备同步命令下发

属性设置和属性查询分别参考查询设备属性修改设备属性接口。

图1 命令下发流程图
  1. 应用调用下发设备命令接口,下发请求到物联网平台,命令下发消息样例如下:
    POST https://{Endpoint}/v5/iot/{project_id}/devices/{device_id}/commands
    Content-Type: application/json
    X-Auth-Token: ********
    
    {
      "service_id" : "WaterMeter",
      "command_name" : "ON_OFF",
      "paras" : {
        "value" : "ON"
      }
    }
  2. 物联网平台根据协议规范下发命令给设备。消息样例如下:
    Topic: $oc/devices/{device_id}/sys/commands/request_id={request_id} 
    数据格式:  
    {
      "object_device_id": "{object_device_id}",
      "command_name": "ON_OFF",
      "service_id": "WaterMeter",
      "paras": {
        "value": "ON"
      }
    }
  3. 设备执行命令后通过平台命令下发上行接口返回命令执行结果,消息样例如下:
    Topic:$oc/devices/{device_id}/sys/commands/response/request_id={request_id}
    数据格式:  
    {
        "result_code": 0,
        "response_name": "COMMAND_RESPONSE",
        "paras": {
            "result": "success"
        }
    }
  4. 应用侧收到发送HTTP下发命令的同步响应结果。消息样例如下:
    Status Code: 200 OK
    Content-Type: application/json
    
    {
      "command_id" : "b1224afb-e9f0-4916-8220-b6bab568e888",
      "response" : {
        "result_code" : 0,
        "response_name" : "COMMAND_RESPONSE",
        "paras" : {
          "result" : "success"
        }
      }
    }

批量MQTT设备同步命令下发

平台支持通过调用创建批量任务接口,对多个MQTT协议设备下发同步命令。下面介绍如何调用创建批量任务下发批量命令。

  1. 应用调用创建批量任务接口,下发请求到物联网平台,下发消息样例如下。
    POST https://{Endpoint}/v5/iot/{project_id}/batchtasks 
    Content-Type: application/json
    X-Auth-Token: ********
    {
      "app_id": "********",
      "task_name": "task123",
      "task_type": "createCommands",
      "targets": [
        "********", 
        "********"
      ],
      "document": {
        "service_id": "water",
        "command_name": "ON_OFF",
        "paras": {
          "value": "ON"
        }
      }
    }
    表3 命令下发创建批量任务参数表

    参数

    是否必选

    描述

    app_id

    资源空间ID。

    task_name

    任务名(自定义)。

    task_type

    批量任务类型。具体可见创建批量任务,命令下发中取值有:

    • createCommands-批量创建同步命令任务
    • createAsyncCommands-批量创建异步命令任务

    targets

    设备ID数组,执行批量任务的目标。

    document

    命令相关参数,执行任务数据文档,Json格式,Json里面是(K,V)键值对。参考设备同步命令

  2. 物联网平台向应用返回“201 Created”。
  3. 设备接收命令,并通过上行topic向平台响应命令结果,参考平台命令下发
  4. 通过调用查询批量任务列表接口查询批量命令下发任务执行情况。

异步命令下发概述

异步命令下发主要用于LwM2M/CoAP设备接入物联网平台,平台或应用侧可通过以下方式进行命令下发:

表4 异步命令下发

类型

描述

适用场景

使用流程

异步命令立即下发

不管设备是否在线,平台收到命令后立即下发给设备。如果设备不在线或者设备没收到指令则下发失败。

适用于实时性要求高的场景。

异步命令立即下发

异步命令缓存下发

物联网平台在收到命令后先缓存,等设备上线或者设备上报属性时再下发给设备,如果单个设备存在多条缓存命令,则进行排队串行下发。

适合对命令实时性要求不高的场景,比如配置水表的参数。

异步命令缓存下发

异步命令立即下发

图2 LwM2M/CoAP命令下发流程

按照上述使用流程,进行对应步骤的示例如下:

  1. 应用调用下发异步设备命令接口,下发请求到物联网平台,携带send_strategy为immediately。消息样例如下:
    POST https://{endpoint}/v5/iot/{project_id}/devices/{device_id}/async-commands
    Content-Type: application/json
    X-Auth-Token: ********
    
    {
      "service_id" : "WaterMeter",
      "command_name" : "ON_OFF",
      "paras" : {
        "value" : "ON"
      },
       "expire_time": 0,
       "send_strategy": "immediately"
    }
  2. 物联网平台调用编解码插件对命令请求进行编码后,会通过LwM2M协议定义的设备管理和服务实现接口的Execute操作下发命令,消息体为二进制格式。
  3. 物联网平台向应用返回200 OK,携带命令状态为SENT。(如果设备不在线或者设备没收到指令则下发失败,命令状态为FAILED
  4. 设备收到命令后返回ACK响应。
  5. 若应用订阅了命令的状态变更通知,物联网平台通过命令状态更新通知接口推送消息给应用,携带命令状态为DELIVERED。消息样例如下:
    Method: POST
    request:
    Body:
    {
        "resource": "device.commmad.status",
        "event": "update",
        "event_time": "20200811T080745Z",
        "notify_data": {
            "header": {
                "app_id": "********",
                "device_id": "********",
                "node_id": "test0001",
                "product_id": "********",
                "gateway_id": "********",
                "tags": []
            },
            "body": {
                "command_id": "********",
                "created_time": "20200811T080738Z",
                "sent_time": "20200811T080738Z",
                "delivered_time": "20200811T080745Z",
                "response_time": "",
                "status": "DELIVERED",
                "result": null
            }
        }
    }
  6. 设备执行命令后通过205 Content响应返回命令执行结果。
  7. 若应用订阅了命令的状态变更通知,物联网平台会调用编解码插件对设备响应进行解码,然后通过命令状态更新通知接口推送消息给应用,携带命令状态为SUCCESSFUL。消息样例如下:
    Method: POST
    request:
    Body:
    {
        "resource": "device.commmad.status",
        "event": "update",
        "event_time": "20200811T080745Z",
        "notify_data": {
            "header": {
                "app_id": "********",
                "device_id": "********",
                "node_id": "test0001",
                "product_id": "********",
                "gateway_id": "********",
                "tags": []
            },
            "body": {
                "command_id": "********",
                "created_time": "20200811T080738Z",
                "sent_time": "20200811T080738Z",
                "delivered_time": "20200811T080745Z",
                "response_time": "20200811T081745Z",
                "status": "SUCCESSFUL",
                "result": {
                    "resultCode":"SUCCESSFUL",
                    "resultDetail": {
                        "value": "ON"
                    }
                }
            }
        }
    }

异步命令缓存下发

图3 LwM2M/CoAP命令缓存下发流程
  1. 应用调用下发异步设备命令接口,下发请求到物联网平台,携带send_strategy为delay。
  2. 物联网平台将命令写入缓存队列,并上报200 OK,携带命令状态为PENDING
  3. 设备上线或设备上报数据到平台。
  4. 物联网平台调用编解码插件对命令请求进行编码后,根据协议规范下发命令给设备。
  5. 若应用订阅了命令的状态变更通知,物联网平台通过命令状态变化通知接口推送消息给应用,携带命令状态为SENT
  6. 后续流程请参考“命令立即下发”的步骤4到步骤7

LwM2M/CoAP设备命令执行状态说明

命令执行状态以及状态变化机制如下所示。

图4 LwM2M/CoAP命令下发状态
表5 LwM2M/CoAP命令执行状态

命令执行状态

说明

等待(PENDING)

  • LwM2M/CoAP设备采用缓存下发模式下发命令时,如果设备未上报数据,物联网平台会将命令进行缓存,此时任务状态为“等待”状态。
  • LwM2M/CoAP设备采用立即下发模式下发命令时,无此状态。

超期(EXPIRED)

  • LwM2M/CoAP设备采用缓存下发模式下发命令时,如果在设置的超期时间内,物联网平台未将命令下发给设备,则状态变更为“超期”。超期时间会根据应用侧接口中携带的expireTime为准,如果未携带,默认24h。
  • LwM2M/CoAP设备采用立即下发模式下发命令时,无此状态。

已发送(SENT)

  • LwM2M/CoAP设备采用缓存下发模式下发命令时,设备上报数据,物联网平台会将缓存的命令发送给设备,此时状态会由“等待”变为“已发送”。
  • LWM2M/CoAP设备采用立即下发模式下发命令时,如果设备在线,状态为“已发送”。

超时(TIMEOUT)

LwM2M/CoAP设备收到命令后,物联网平台在180秒内未收到设备反馈的收到命令响应,此时状态会变为“超时”。

已送达(DELIVERED)

物联网平台收到设备反馈的已收到下发命令响应后,状态变为“已送达”。

成功(SUCCESSFUL)

如果设备在执行完命令后,会给物联网平台反馈命令执行成功的结果,将任务状态变更为“成功”。

失败(FAILED)

  • 如果设备在执行完命令后,会给物联网平台反馈命令执行失败的结果,将任务状态变更为“失败”。
  • LwM2M/CoAP设备采用立即下发模式下发命令时,如果设备离线,状态为“失败”。

平台命令下发使用示例

  1. 访问设备接入服务,单击管理控制台进入设备接入控制台。选择您的实例,单击实例卡片进入。
  2. 选择左侧导航栏的设备 > 所有设备,在设备列表中,单击具体的设备进入到设备的详情页面。
  3. 云端下发>命令下发页签,根据设备协议的不同,界面也有所不同。

    • MQTT设备仅支持同步命令下发,单击右侧的“命令下发”,在弹出的窗口中选择需要下发的命令并设置命令参数。
      图5 命令下发-同步命令下发
    • LwM2M/CoAP设备仅支持异步命令下发,单击右侧的“命令下发”,在弹出的窗口中选择需要下发的命令并设置命令参数。您可以选择立即下发或者缓存下发。
      图6 命令下发-异步命令下发

  • 消息跟踪可以查看下发的历史命令列表,通过该功能详细查看命令下发任务的创建时间、平台发送命令的时间、送达的时间、发送的状态等信息,便于用户了解命令的执行状态
  • 命令下发支持通过调用查询设备命令接口,在物联网平台查询下发命令的状态及内容信息,以了解命令的执行情况。

配置应用侧使用JAVA SDK进行同步命令下发的开发步骤如下,本示例使用的开发环境为JDK 1.8及以上版本。SDK代码获取:SDK下载

  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());
            }
        }
    }
    表6 参数说明

    参数

    说明

    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及以上版本。

  1. 配置设备侧SDK的Maven依赖。

    <dependency>
    	<groupId>com.huaweicloud</groupId>
    	<artifactId>iot-device-sdk-java</artifactId>
    	<version>1.1.4</version>
    </dependency>

  2. 配置设备侧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;
    }

  3. 设置命令下发回调函数、发送响应。

     client.setCommandListener(new CommandListener() {
        @Override
        public void onCommand(String requestId, String serviceId, String commandName, Map<String, Object> paras) {
            log.info("onCommand, serviceId = " +serviceId);
            log.info("onCommand , name = " + commandName);
            log.info("onCommand, paras =  " + paras.toString());
    
            //处理命令用户自定义
    
            //发送命令响应
            device.getClient().respondCommand(requestId, new CommandRsp(0));
        }   
    });

测试验证步骤如下:

  1. 在设备接入控制台,选择您的实例,单击实例卡片进入。选择左侧导航栏的设备 > 所有设备,在设备列表中,单击具体设备详情进入设备详情,在消息跟踪页签内,启动消息跟踪

    图7 消息跟踪-启动消息跟踪

  2. 先运行设备侧 SDK代码,使设备上线。
  3. 运行应用侧代码,当设备接收到设备下发的命令后,进行数据处理及响应。设备侧收到的命令下发样例如下:

    图8 设备侧命令下发成功结果

  4. 消息跟踪显示结果如下:

    图9 消息跟踪-命令下发