# 推送使用文档

# 概述

HanClouds对其用户提供推送的功能,可实时向App或者web页面推送数据、事件或者命令响应。如下图所示。

设备连接到HanClouds后,在应用层web页面或者手机App上实时显示最新的设备数据是一种常见的需求。在不使用推送功能时,需要web或者App侧定时调用HanClouds的restful api,以抽取最新的设备数据。但这种实现方式实时性较差,其实时性取决于定时调用的周期,会有大量无谓的api调用,实现较复杂,而且增加了平台的开销。

推送方式的原理为:web/app侧作为订阅者,HanClouds作为mqtt server,web/app以订阅者的身份订阅其感兴趣的数据,当HanClouds发现对应的数据时就实时推送给订阅者。对于web页面,Hanclouds支持通过websocket进行mqtt订阅。

推送平台监听的端口号说明:

  • tcp : 3883
  • websocket : 4883

# 订阅使用说明

# 订阅步骤概述

HanClouds在向外进行推送时,如何确保其数据不被非法订阅者订阅是推送平台要考虑的首要问题。为了解决这个问题,使用HanClouds推送服务的步骤如下图所示:

上图中蓝色箭头表示http请求,绿色箭头表示mqtt过程

订阅步骤概要说明:

  1. 订阅者调用HanClouds对外公开的http restful api,请求订阅某些topic filter的数据,请求中携带鉴权参数
  2. 平台校验请求参数,鉴权通过后,向订阅者返回订阅凭证
  3. 订阅者使用上一步中返回的订阅凭证构造mqtt connect消息,请求连接HanClouds推送平台,平台会校验订阅凭证,匹配则连接成功,否则订阅失败
  4. 订阅者用mqtt连接上HanClouds推送平台成功后,向HanClouds发送subscribe请求,请求订阅某些topic filter的数据

说明:第2步中反馈的订阅凭证只可以使用一次,第3步使用该订阅凭证后,该订阅凭证立即失效,再次使用时HanClouds会拒绝。

# 订阅步骤详细说明

在步骤1,订阅者调用HanClouds的restful api 申请推送token,请求订阅凭证时,对应的api形式如下:

  • method:POST

  • api 请求签名可以采用用户级签名或者产品级{queryKey:querySecret}签名

    • 如果不清楚产品级{queryKey:querySecret}请参阅鉴权模型
  • 请求的body为订阅者希望订阅的topic filter字符串数组,每个filter的形式必须为下面的形式,这里约定如下:

    • data/{productKey}/{deviceKey}/{stream}/{dataType}, 订阅某个设备某个指定数据类型的数据流数据,

    • data/{productKey}/{deviceKey}/{stream}/#, 订阅某个设备某个数据流的数据

    • data/{productKey}/{deviceKey}/#, 订阅某个设备所有数据流的数据

    • data/{productKey}/#, 订阅某个产品下所有设备的数据

    • deviceData/{productKey}/{deviceKey}/{stream}/{dataType}, 订阅某个设备某个指定数据类型的数据流数据,,

    • deviceData/{productKey}/{deviceKey}/{stream}/#, 订阅某个设备某个数据流的数据

    • deviceData/{productKey}/{deviceKey}/#, 订阅某个设备所有数据流的数据

    • deviceData/{productKey}/#, 订阅某个产品下所有设备的数据

    • event/{productKey}/{deviceKey}/{eventType}/{eventName}, 订阅设备某一类型的某一具体事件

    • event/{productKey}/{deviceKey}/{eventType}/#, 订阅设备某一类型的事件

    • event/{productKey}/{deviceKey}/#, 订阅设备的事件

    • event/{productKey}/#, 订阅某个产品下的设备事件

    • log/{productKey}/{deviceKey}/{logName}, 订阅设备指定系统日志

    • log/{productKey}/{deviceKey}/#, 订阅设备系统日志

    • log/{productKey}/#, 订阅某个产品下的设备系统日志

    • cmd/{productKey}/{deviceKey}/#,订阅设备命令响应

目前约定topic filter中第二部分为productKey,第一部分为数据类别,将来可扩充,其他部分可以包含通配符‘#’和‘+’

单次订阅请求时,只可订阅一个产品下的数据。如果订阅Filter字符串数组中包含多个filter,则每个filter中productKey必须一致,否则HanClouds会拒绝

dataType数据类型,包括json、int、string、double、bin、boolean、array、enum、float、gps、image、date共12种

eventType事件类型,包括1(信息)、2(告警)、3(错误)共3种

在步骤2,HanClouds校验请求中的topic filte数组中的productKey,并校验签名参数是否匹配,如果匹配,就反回鉴权凭证给订阅者。订阅凭证主要包括以下内容:

public class AppAuth {
    /**
     * mqtt Connect userName
     */
    private String userName;
    /**
     * mqtt Connect password
     */
    private String password;
    /**
     * Encryption secret key
     */
    private String secret;
}
  • userName为一个uuid
  • password为一个随机字符串
  • secret为16字节的加密秘钥

在步骤3,订阅者利用上一步收到订阅凭证,构造订阅用的mqtt Connect消息。订阅者可以请求HanClouds向其以加密模式传输数据,也可以请求HanClouds向其以明文模式传输数据。当以明文传输数据时,HanClouds会把符合订阅filter的数据以明文的形式发过来;当以加密模式传输数据时,HanClouds会把符合订阅filter的数据用订阅凭证(见平台返回的AppAuth)中的secret加后,在发送给订阅者。

mqtt Connect消息的构成如下:

  • clientId:
    • 明文模式:p:{productKey}:{userName}
    • 加密模式:ps:{productKey}:{userName}
  • userName:{userName}
  • password:{password}
  • keepalive: >= 120 second
  • clean-session: true

HanClouds收到上述订阅mqtt Connect消息后,会校验userName、password是否为有效的订阅凭证,如果有效就通过登陆鉴权。

特别说明:通过HTTP请求的订阅参数有时效性,同一个AppAuth在有效时间内只可以使用一次,第二次使用时会被拒绝。

在步骤4,订阅者向HanClouds发送mqtt Subscribe消息,请求订阅某些topic. 这些topic必须为步骤1中请求的topic filter数组子集。如果实际订阅的topic filter不与步骤1 http请求消息body中的任何一个filter一致,则HanClouds会拒绝。

后续HanClouds会把符合topic filter条件的数据用mqtt消息publish给订阅者。

如果网络断开,则订阅者必须重复上述4个步骤,重新发起http请求、重新订阅。

推送数据说明: 数据点/data 类别订阅,推送原始数据 数据点/deviceData 类别订阅,推送json串的二进制格式,json为{"time":时间戳,"data":数据部分} 事件/event 类别订阅,推送原始数据 系统日志/log 类别订阅,推送timestamp时间戳数据 命令/cmd 类别订阅,json串的二进制格式,json为{"state":"save","time":1234124xx} ,state包括save、send、ack、success、fail、cancel等

# 加密说明

HanClouds支持对订阅者进行加密推送。在加密模式一下,HanClouds会把符合订阅filter的数据进行加密后,把密文作为mqtt Publish的payload,再发给订阅者。订阅者需要对密文进行解密后才能提取到明文。

加密说明如下:

  • 加密算法: AES/cbc/Pkcs5padding
  • 加密秘钥:订阅凭证中的secret
  • payload说明:iv为mqtt Publish消息payload的头16个字节,剩余部分为密文