Skip to content

云端开发指南

一、概述

本文档用于指导北向应用开发者,通过物联云平台API接口,获取设备实时数据、设备告警数据、设备事件和服务调用实现业务应用接入开发。

应用接入主要分为设备实时数据查询、设备实时控制、设备告警数据接收。物联云平台通过提供Https Rest API和DDQ SDK用于设备数据查询、设备实时控制和设备实时数据推送、设备告警数据接收。开发者可根据本文档说明基于物联云平台进行北向应用对接。

二、数据流转过程示意图

数据流转过程示意图

数据流转过程说明:

1、设备上报数据到IoT平台;

2、数据通过规则引擎,存储在数据库;

3、数据通过DDQ 流转到企业的应用服务器;详见订阅设备数据(DDQ)章节

4、企业的应用系统调用IoT平台API,下发设备控制或配置指令;详见设备物模型接口章节;

三、API接口调用规范

3.1 API说明

物联云平台接口访问域名为api2.xlink.cn(如果是私有云,则需单独提供私有云访问地址)。

API网关是物联网平台面向开发者接口定义转发的服务,提供接口为Restful风格的HTTP接口。协议版本为HTTPS 1.1,HTTP 1.1(HTTPS暂不需要使用证书双向认证)。

物联云平台API接口为REST风格的HTTP接口,其资源访问路径结构为 协议://域名/API路径。

HTTP Request以及Response都采用JSON格式字符串作为消息实体。

注意:文件上传或其他流式数据传输另作讨论。

采用HTTP协议的GET、POST、PUT、DELETE Method作为资源操作动作。操作原则为:

  1. GET:进行数据获取;
  2. POST:数据添加。或者是复杂的数据查询,需要以Request Body作为查询参数的;
  3. PUT:数据修改;
  4. DELETE:数据删除。

3.2 请求鉴权

3.2.1 鉴权说明

  • HTTP请求API必须带上鉴权信息,平台通过鉴权信息来决定该请求能访问API范围以及数据范围。

  • 鉴权信息放入HTTP请求的Header中,Header字段为:“Access-Token"。

3.2.2 权限类型

  • HTTP请求API必须带上鉴权信息,平台通过鉴权信息来决定该请求能访问API范围以及数据范围。

  • 鉴权机制有两种,以具体的API以及业务为准

鉴权方式适用范围说明
AccessToken机制Web/App端管理平台API鉴权信息存入HTTP Header字段为:“Access-Token"
Signature机制SaaS服务云云对接鉴权信息存入HTTP Header字段为:“Signature"

3.2.3 鉴权信息类型

  • 注意:Access-Token为API网关北向应用调用时所需要传递的参数,但是SaaS应用本身设计API接口时,无需加入Access-Token字段。
  • 鉴权信息优先以AccessToken为准,即是在请求头发现Access-Token标识会进入Access-Token的鉴权逻辑,仅在请求头未发现Access-Token标识且发现Signature标识才会进入Signature鉴权逻辑。
  • 针对AccessToken鉴权机制和Signature机制鉴权机制,请求所需传的鉴权信息主要分为一下三种类型,不同的类型所能访问的权限结构不同,具体类型说明如下:
序号类型鉴权机制获取方式权限概述
1Corp企业登录验证AccessToken机制企业B端用户权限,主要用于管理台访问平台数据,包括不限于创建获取设备数据等
2User用户登录验证AccessToken机制企业C端用户权限,主要用于C端APP访问平台数据,包括不限于订阅设备、获取个人信息等
3App应用网关登录验证Signature机制应用网关权限,主要用于平台对接时,访问平台数据,可限制具体接口,包括不限于用户管理类数据、产品设备管理类数据等

3.3 请求头

  • 根据不同的鉴权机制所需传输的请求头有所不同

3.3.1 AccessToken机制

字段说明是否必须
Group前端API标识
Stage前端API所属环境, RELEASE:正式环境 TEST:测试环境 PRE_RELEASE:预发布环境
Content-Typeapplication/json
Access-Token调用凭证,一般为用户登录后平台下发的用户Token否,以具体接口为准
Request-BaseAPI网关解析Token后加入到Header中的基础字段否,请求通过API网关后自动加入

3.3.2 Signature机制

字段说明必填
Group前端API标识true
Stage前端API所属环境
RELEASE:正式环境
TEST:测试环境
PRE_RELEASE:预发布环境
true
Content-Typeapplication/jsontrue
Signature签名true
App-ID应用标识true
Timestamp时间戳true
Request-ID请求标识true
Content-MD5请求内容MD5散列值false
当请求为POST和PUT请求时必传

3.5 通用返回结果

json
{
  "code": 4081001,
  "status": 408,
  "msg": "Request Timeout",
  "data": {
    "name":"xlink"
  }
}
字段类型描述
codeInteger业务错误码,业务错误码由各个接口来具体定义。
statusInteger通用HTTP状态码,200表示执行成功。 其他表示错误或其他返回,看附录的HTTP状态码定义。
msgString错误的详细信息描述。
dataObject具体的接口响应数据。 无实际响应数据时,该字段为空。 其他数据以具体接口为准。

3.6 错误码定义

3.6.1 HTTP状态码

描述
200请求成功
302重定向跳转
400请求字段不合法
401缺少调用凭证
403授权不通过
404资源不存在
408请求超时
405方法不支持
502响应超时
503参数解析错误
504服务器异常

3.6.2 业务错误码(示例)

  • 业务错误码由各个接口来具体定义,以下为通用示例:
描述
4001002参数不能为空
4011001请求头缺少Access-Token
4031003无效Access-Token
4041001接口找不到
4051001Http方法不允许
5021001网关异常
5031002服务降级
5041001访问超时

四、 订阅设备数据(DDQ)

DDQ(Data Dispath Queue)数据调度队列是物联网平台面向外部数据调度分发的服务,是物联云平台通过队列的方式对外数据输出的方式,外部系统通过DDQ能以数据流的方式接收到物联网数据。

目前DDQ在传输协议上,采用http2协议。物联云平台提供了DDQ SDK便于应用开发者进行开发和接入,能够实时接收物联网平台设备数据,数据包含设备在线状态变化数据、设备属性变化数据、设备事件上报数据、设备告警数据。

4.1 DDQ物模型数据格式说明

通过DDQ SDK, 可以接收设备在线状态变化数据、物模型属性变化数据、设备事件上报数据,设备告警数据。 下列说明具体的事件主题和数据格式。

4.1.1 设备在线状态变化

当设备在线状态发生变化时,如设备从在线变化为离线,DDQ SDK会接收到如下格式的消息。

json
{
    "topic": "/device-biz/state/product",
    "message_id": "消息ID",
    "payload": {
        "device_id": "设备ID",
        "is_online": "是否在线",
        "product_id": "产品ID",
        "corp_id": "企业ID",
        "create_time": "时间,yyyy-MM-dd'T'HH:mm:ss.SS'Z'",
        "project_id": "设备所属的项目ID"
    }
}

字段说明

字段必填类型备注
product_idTrueString产品ID
device_idTrueInt设备ID
corp_idFalseStirng企业ID
create_timeFalseString创建时间
project_idFalseString所属项目ID

4.1.2 设备属性上报

当设备通过物模型属性上报数据时,DDQ SDK会接收到如下的消息内容。

json
{
    "topic": "thing/event/{product_id}/device_attribute_sync_event",
    "message_id": "消息ID",
    "payload": {
        "version": 1,
        "time": "触发时间",
        "type": "tml",
        "event": "device_attribute_sync_event",
        "thing_id": "设备ID",
        "corp_id": "企业ID",
        "product_id": "产品ID",
        "attributes": [
            {
                "field": "mode",
                "value": 1
            }
        ]
    }
}

字段说明:

字段必填类型备注
versionTrueInt消息版本号
timeTrueLong触发时间,毫秒时间戳
typeTrueString消息类型,固定为:tml
eventTrueString固定为:device_attribute_sync_event
thing_idTrueInt设备ID
corp_idFalseString企业ID
product_idFalseString产品ID
thing_model_groupFalseString品类分组
thing_model_categoryFalseString品类分类
thing_model_typeFalseString品类类型
attributesTrueList<Object>物模型属性集合
attributes.fieldTrueString属性字段名
attributes.valueTrueString物模型属性值

4.1.3 设备事件上报

当设备通过物模型上报事件时,DDQ SDK会接收到如下的消息内容。

json
{
    "topic": "thing/event/{product_id}/event_report",
    "message_id": "消息ID",
    "payload": {
        "version": 1,
        "time": "触发时间",
        "type": "tml",
        "event": "....",
        "thing_id": "设备ID",
        "corp_id": "企业ID",
        "product_id": "产品ID",
        "events": [
            {
                "field": "mode",
                "value": 1
            }
        ]
    }
}
字段必填类型备注
versionTrueInt消息版本号
timeTrueLong触发时间,毫秒时间戳
typeTrueString消息类型,固定为:tml
eventTrueString事件名
thing_idTrueInt设备ID
corp_idFalseString企业ID
product_idFalseString产品ID
thing_model_groupFalseString品类分组
thing_model_categoryFalseString品类分类
thing_model_typeFalseString品类类型
eventsTrueList<Object>事件信息集合
events.fieldTrueString事件字段名
events.valueTrueString事件字段值

4.1.4 设备告警事件

json
   当设备状态或者设备上报的物模型属性、事件满足管理台或者用户配置的告警条件时, DDQ SDK会接收到如下的消息内容。 {
       "topic": "/device/alert/product/{product_id}",
       "message_id": "消息ID",
       "payload": {
           "product_id": "产品ID",
           "corp_id": "企业ID",
           "device": {
               "id": "设备ID",
               "mac": "设备MAC"
           },
           "alert": {
               "exception": "当前是否异常,否则为恢复",
               "time": "异常/恢复时间, yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
               "rules": [
                   {
                       "id": "异常规则ID",
                       "status": " 异常状态,1报警2恢复3已手动处理",
                       "notify": "异常规则通知类型,1通知2告警",
                       "current": "当前值",
                       "count": "本次累计异常次数",
                       "new_time": "本次异常触发时间,yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                       "start_time": "本地异常开始时间,yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                       "recover_time": "本此异常恢复时间,yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                       "processed_time": "本此异常处理时间,yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                       "exception_describe": "异常描述",
                       "notification_content": "本次异常报警内容"
                   }
               ]
           }
       }
   }
字段必填类型备注
product_idTrueString产品ID
device.idTrueInt设备ID
device.macFalseStirng设备MAC
corp_idTrueString企业ID
alert.exceptionTrueBoolean是否异常
alert.timeTrueString异常/恢复时间
alert.rulesFalseList<Object>相关规则列表
alert.rules.idFalseString规则ID
alert.rules.statusFalseInt异常状态
alert.rules.notifyFalseInt通知类型
alert.rules.currentFalseString当前置
alert.rules.countFalseInt累计异常次数
alert.rules.new_timeFalseString异常触发最新时间
alert.rules.start_timeFalseString异常触发开始时间
alert.rules.recover_timeFalseString异常恢复时间
alert.rules.processed_timeFalseString异常处理时间
alert.rules.exception_describeFalseString异常描述
alert.rules.notification_contentFalseString异常内存

4.2 DDQ SDK关键参数说明

DDQ SDK初始化完成,发起连接时,需要提供用于连接和认证的必要参数,具体说明如下:

参数参数说明备注
hostDDQ服务器访问地址(IP或域名)公有云为h2-ddq.xlink.cn
portDDQ服务访问端口公有云为:80
authUrl客户端认证URL,客户端通过该url向DDQ服务器进行AppId、Token,成为有效客户端公有云为: https://api2.xlink.cn
appId应用ID通过管理台,应用中心->应用详情中查看
accessToken通过应用管理的AppId和AppSecret换取的AccessToken接口见下面获取AccessToken凭证说明

4.3 获取AccessToken凭证

AccessToken是用于DDQ SDK连接服务端时的凭证。本接口可以根据应用中心创建的AppId和AppSecre换取AccessToken。接口说明如下:

请求

http
POST /v2/plugin/app_auth

Header

Content-Type:application/json

Content

{  
"app_id": "应用网关标识",  
"app_secret": "应用网关密钥"  
}

响应

http
HTTP/\`\`1.1\` \`200\` \`OK

Content

{  
"access_token": "平台授予应用网关token",  
"refresh_token": "平台授予应用网关刷新token",  
"expire_in": "平台授予应用网关token过期时间"  
}

4.4 DDQ SDK使用示例代码

4.4.1 DDQ SDK初始化

java
private static void connect() throws Exception {
// 创建http2客户端,构造参数1为心跳间隔,参数2为判断超时时间,单位皆为毫秒  
        Http2Client http2Client = new Http2Client(1000, 15000);
//建立远程连接  
        Connection connection = http2Client.connect(socketAddress).get();
//设置接收数据回调  
        connection.setDefaultStreamListener(new Http2DataReceiver());
        connection.setConnectionListener(new Http2ConnectionListener());

		....
      	....
    }

4.4.2 发起连接认证

java
private static void connect() throws Exception {

//建立连接  
....
....
//客户端认证  
        Http2Headers headers = new DefaultHttp2Headers();
        headers.path(authUrl).scheme("http").method("POST").authority("xlink.cn");
//构建request data  
        JSONObject body = new JSONObject();
        body.put("app_id", appId);
        body.put("access_token", accessToken);
        body.put("auth_type", "accesskey");
        byte[] data = body.toJSONString().getBytes();
//发起认证请求  
        connection.writeHeaders(headers, false, new Http2StreamListener() {
            @Override
            public void onDataRead(Connection connection, Http2Stream streamData, byte[]
                    data, boolean endOfStream) {
                String dataString = new String(data);
                JSONObject json = JSONObject.parseObject(dataString);
                log.info("info {} ", json.toJSONString());
            }

            @Override
            public void onHeadersRead(Connection connection, Http2Stream stream,
                                      Http2Headers headers, boolean endOfStream) {
                log.info("info {} ", connection.getStatus());
            }

            @Override
            public void onStreamError(Connection connection, Http2Stream stream, IOException
                    e) {
                log.info("info {} ", connection.getStatus());
            }
        }).get().writeData(data, true).get();

    ....
    ....
    }

4.4.3 订阅数据

java
private static void connect() throws Exception{

//建立连接  
....  
....

//客户端认证  
....  
....

//订阅消息  
        Http2Headers headersSub = new DefaultHttp2Headers();
        JSONObject subData = new JSONObject();
        subData.put("topic", topic);
        headersSub.path(subscribeUrl).scheme("http").method("POST").authority("xlink.cn");

//发起订阅  
        connection.writeHeaders(headersSub, false, new Http2StreamListener() {
            @Override
            public void onDataRead(Connection connection, Http2Stream stream, byte[] data,
                                   boolean endOfStream) {
                String dataString = new String(data);
                JSONObject json = JSONObject.parseObject(dataString);
                log.info("info {} ", json.toJSONString());
            }

            @Override
            public void onHeadersRead(Connection connection, Http2Stream stream,
                                      Http2Headers headers, boolean endOfStream) {
                log.info("info {} ", connection.getStatus());
            }

            @Override
            public void onStreamError(Connection connection, Http2Stream stream, IOException
                    e) {
                log.info("info {} ", connection.getStatus());
            }
        }).get().writeData(subData.toJSONString().getBytes(), true).get();

    }

4.4.4 接收数据回调

java
 /**
     * 接收数据处理
     */
    public static class Http2DataReceiver extends AbstractHttp2StreamDataReceiver {

        @Override
        public void onDataRead(Connection connection, Http2Stream stream, StreamData
                streamData) {
            Http2Response response = new Http2Response(streamData.getHeaders(),
                    streamData.readAllData());
//接收到的数据  
            String content = new String(response.getContent());
            log.info("receiver data {}", content);
            JSONObject json = JSONObject.parseObject(content);
//...  
            String topic = json.getString("topic");
            String msgId = json.getString("msgId");
            JSONObject payload = json.getJSONObject("payload");

        }

        @Override
        public void onStreamError(Connection connection, Http2Stream stream, IOException
                e) {

        }
    }

4.4.5 连接状态监听

java
 /**
     * 连接状态监听
     */
    public static class Http2ConnectionListener implements ConnectionListener {

        @Override
        public void onSettingReceive(Connection connection, Http2Settings settings) {

        }

        @Override
        public void onStatusChange(ConnectionStatus status, Connection connection) {
//连接断开  
            if (status == ConnectionStatus.CLOSED){
                log.error("http/2 connection disconnected. ");
//当前连接断开时,进行重连  
                connection.close();
//开启重连线程  
                new ReconnectThread().start();
            }
        }
    }

4.4.6 当连接断开时,定时重连

java
/**
     * 重连线程
     */
    private static class ReconnectThread extends Thread{


        @Override
        public void run() {
            for(;;){
                try {
//每5秒进行重连  
                    Thread.sleep(5000L);
                    connect();
//没有异常说明连接成功,跳出定时重连  
                    break;
                }catch (Exception e){
                    log.error("", e);
                }
            }
        }
    }