云端开发指南

一、概述

本文档用于指导北向应用开发者,通过物联云平台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机制鉴权机制,请求所需传的鉴权信息主要分为一下三种类型,不同的类型所能访问的权限结构不同,具体类型说明如下:
序号 类型 鉴权机制 获取方式 权限概述
1 Corp 企业登录验证 AccessToken机制 企业B端用户权限,主要用于管理台访问平台数据,包括不限于创建获取设备数据等
2 User 用户登录验证 AccessToken机制 企业C端用户权限,主要用于C端APP访问平台数据,包括不限于订阅设备、获取个人信息等
3 App 应用网关登录验证 Signature机制 应用网关权限,主要用于平台对接时,访问平台数据,可限制具体接口,包括不限于用户管理类数据、产品设备管理类数据等

3.3 请求头

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

3.3.1 AccessToken机制

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

3.3.2 Signature机制

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

3.5 通用返回结果

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

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 接口找不到
4051001 Http方法不允许
5021001 网关异常
5031002 服务降级
5041001 访问超时

四、 订阅设备数据(DDQ)

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

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

4.1 DDQ物模型数据格式说明

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

4.1.1 设备在线状态变化

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

{
    "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_id True String 产品ID
device_id True Int 设备ID
corp_id False Stirng 企业ID
create_time False String 创建时间
project_id False String 所属项目ID

4.1.2 设备属性上报

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

{
    "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
            }
        ]
    }
}

字段说明:

字段 必填 类型 备注
version True Int 消息版本号
time True Long 触发时间,毫秒时间戳
type True String 消息类型,固定为:tml
event True String 固定为:device_attribute_sync_event
thing_id True Int 设备ID
corp_id False String 企业ID
product_id False String 产品ID
thing_model_group False String 品类分组
thing_model_category False String 品类分类
thing_model_type False String 品类类型
attributes True List<Object> 物模型属性集合
attributes.field True String 属性字段名
attributes.value True String 物模型属性值

4.1.3 设备事件上报

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

{
    "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
            }
        ]
    }
}
字段 必填 类型 备注
version True Int 消息版本号
time True Long 触发时间,毫秒时间戳
type True String 消息类型,固定为:tml
event True String 事件名
thing_id True Int 设备ID
corp_id False String 企业ID
product_id False String 产品ID
thing_model_group False String 品类分组
thing_model_category False String 品类分类
thing_model_type False String 品类类型
events True List<Object> 事件信息集合
events.field True String 事件字段名
events.value True String 事件字段值

4.1.4 设备告警事件

当设备状态或者设备上报的物模型属性、事件满足管理台或者用户配置的告警条件时, 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_id True String 产品ID
device.id True Int 设备ID
device.mac False Stirng 设备MAC
corp_id True String 企业ID
alert.exception True Boolean 是否异常
alert.time True String 异常/恢复时间
alert.rules False List<Object> 相关规则列表
alert.rules.id False String 规则ID
alert.rules.status False Int 异常状态
alert.rules.notify False Int 通知类型
alert.rules.current False String 当前置
alert.rules.count False Int 累计异常次数
alert.rules.new_time False String 异常触发最新时间
alert.rules.start_time False String 异常触发开始时间
alert.rules.recover_time False String 异常恢复时间
alert.rules.processed_time False String 异常处理时间
alert.rules.exception_describe False String 异常描述
alert.rules.notification_content False String 异常内存

4.2 DDQ SDK关键参数说明

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

参数 参数说明 备注
host DDQ服务器访问地址(IP或域名) 公有云为h2-ddq.xlink.cn
port DDQ服务访问端口 公有云为: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。接口说明如下:

请求

POST /v2/plugin/app_auth

Header

Content-Type:application/json

Content

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

响应

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

Content

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

4.4 DDQ SDK使用示例代码

4.4.1 DDQ SDK初始化

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 发起连接认证

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 订阅数据

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 接收数据回调

 /**
     * 接收数据处理
     */
    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 连接状态监听

 /**
     * 连接状态监听
     */
    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 当连接断开时,定时重连

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


        @Override
        public void run() {
            for(;;){
                try {
//每5秒进行重连  
                    Thread.sleep(5000L);
                    connect();
//没有异常说明连接成功,跳出定时重连  
                    break;
                }catch (Exception e){
                    log.error("", e);
                }
            }
        }
    }
没找到需要的文档?
你可以提交工单反馈 或 阅读常见问题