客户端接入

客户端接入

接入方式

客户端接入架构图

如上图所示,涂鸦云支持客户端以HTTPS、MQTT方式接入涂鸦云。HTTPS接入的场景主要有:设备指令下发、设备状态数据获取、用户注册和登录、设备管理等。MQTT接入等场景有:订阅设备实时数据、发布设备控制指令。

名词解释:

  • HTTP/HTTPS 涂鸦的HTTP(ATOP网关) API是基于HTTP或HTTPS协议来调用的,开发者可以根据涂鸦的ATOP协议来封装HTTP请求进行调用。

  • MQTT MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输。MQTT是专门针对物联网开发的轻量级传输协议。涂鸦云平台支持MQTT方式调用,并提供相应的AppKey与AppSecret供用户使用。

建议:

  • 如果需要获取分析统计类或用户、设备类等非实时数据,推荐使用HTTP。
  • 如果需要实时的控制指令或硬件上报数据类数据,推荐使用MQTT订阅。

调用入口

涂鸦云根据中国企业内外销区域结合海底光缆分布和全球各城市的实测结果,部署覆盖亚、欧、美三个可用区。

调用API的服务域名如下:

可用区 协议 域名 数据安全级别 服务区域
AY http/https/mqtt *.tuyacn.com HTTPS+AES 亚洲
AZ http/https/mqtt *.tuyaus.com HTTPS+AES 美洲
EU http/https/mqtt *.tuyaeu.com HTTPS+AES 欧洲

注: 涂鸦云提供Http、Https、Mqtt等多种通信协议,根据业务需求可以灵活选择使用

  • https: a1.tuya(cn/eu/us).com/api.json (APP调用,如:https://a1.tuyacn.com/api.json)
  • http: a.gw.tuya(cn/eu/us).com/gw.json (硬件调用,如:http://a.gw.tuyacn.com/gw.json)
  • mqtt: mq.mb.tuya(cn/eu/us).com(APP调用,如:tcp://mq.mb.tuyacn.com)
  • mqtt: mq.gw.tuya(cn/eu/us).com(硬件调用,如:tcp://mq.gw.tuyacn.com)

协议概述

HTTPS

  • 调用流程 根据ATOP的协议,通过HTTPS调用云服务的详细步骤为:填充参数 > 生成签名 > 拼装HTTP请求 > 发起HTTP请求> 得到HTTP响应 > 解释json结果。

    大致的调用过程如下图所示:

    HTTP调用

  • 公共参数 调用任何一个API都必须传入的公共参数有:

参数名称 参数类型 是否必须 是否签名 参数描述
a String API名称
v String API接口版本
sid String 用户登录授权成功后,ATOP颁发给应用的用户session
time String 时间戳,格式为数字,大小到秒非毫秒,时区为标准时区,例如:1458010495。API服务端允许客户端请求最大时间误差为540分钟。
sign String API输入参数签名结果,签名算法参照下面的介绍
clientId String 用户的APPID(注各平台不一样如:ios、android、云云对接的id都不一样)
lang String APP的语言,如"en",“zh_cn”,错误信息根据语言自动翻译
ttid String APP渠道或云端渠道,如公司名,用于数据分析跟踪
os String 手机操作系统,如"Android",“ios”,云端可以写linux或写公司名

MQTT

  • 调用流程 根据MQTT的协议,通过MQTT与云端交互的详细步骤为:使用MQTT客户端发起连接–>用户名密码连接认证–>Topic订阅–>心跳维持。

    大致的调用过程如下图所示: MQTT MQTT

接入教程

HTTPS接入方式

调用参数补充

除上述公共参数外,APP客户端调用需要补充的参数有:
参数名称 参数类型 是否必须 是否签名 参数描述
deviceid String 手机对应的deviceId,如"01324FB3-816D-48BE-AB65-A421B611E537"(仅APP需要)
appVersion String 客户App的版本号,如"1.0.2"
lat String 纬度,用户当前所在纬度
lon String 经度,用户当前所在经度
imei String 手机的IMEI,如"460029674019947"
imsi String 手机的IMSI,如"867830021505039"
isH5 String 是否H5(app中H5免登时才需要)
h5Token String H5Token(app中H5免登时才需要)
注意:对于非必填参数且参与签名的,在值为空的情况下不参与签名,只有在有值情况下才参与签名。

接入原理

客户端若通过HTTP方式接入涂鸦云,需要对请求进行拼接。除了必须包含公共参数外,如果API本身有业务级的参数也必须传入,每个API的业务级参数请考下节:客户端API定义。业务参数全部放入postData中传到服务端,例如API有两个业务参数devId和userId,则格式为postData={“devId”:“XXX”,“userId”:“XXX”}。

1.首先,对业务参数postData进行Md5HexUtil.md5Hex签名。
2.然后,客户端需要对所有请求参数进行组装,以key1=value1,key2=value2形式表示,并根据key的字典顺序排序。
3.然后,将排好序的每一对参数拼接到一起,参数对间用||连接。
4.然后,在上面已经拼接好的参数串** 前面**添加appSecret。
5.之后,对第三步中的参数串进行MD5签名。
6.最后,即可向涂鸦云发送请求。
具体实现请参考客户端API定义。

注:签名算法与云端接入稍有不同,具体签名工具类参实现如下:

public class AtopThirdMobileSignUtil {

private static Logger logger = LoggerFactory.getLogger(AtopMobileSignUtil.class);

private static TreeMap<String, String> paramsBuild(ApiRequestDO apiRequestDo) {
TreeMap<String, String> params = new TreeMap<String, String>();
params.put("a", apiRequestDo.getApi());
params.put("v", apiRequestDo.getApiContextDo().getApiVersion());
params.put("lat", apiRequestDo.getApiContextDo().getLat());
params.put("lon", apiRequestDo.getApiContextDo().getLon());
params.put("lang", apiRequestDo.getApiContextDo().getLang());
params.put("deviceId", apiRequestDo.getApiContextDo().getDeviceid());
params.put("imei", apiRequestDo.getApiContextDo().getImei());
params.put("imsi", apiRequestDo.getApiContextDo().getImsi());
params.put("appVersion", apiRequestDo.getApiContextDo().getAppVersion());
params.put("ttid", apiRequestDo.getApiContextDo().getTtid());
params.put("isH5", apiRequestDo.getApiContextDo().getIsH5());
params.put("h5Token", apiRequestDo.getH5Token());
params.put("os", apiRequestDo.getApiContextDo().getOs());
params.put("clientId", apiRequestDo.getAppInfoDo().getClientId());
params.put("time", apiRequestDo.getT());
if (StringUtils.isNotBlank(apiRequestDo.getSession())) {
params.put("sid", apiRequestDo.getSession());
}
if (StringUtils.isNotBlank(apiRequestDo.getData())) {
params.put("postData", Md5HexUtil.md5Hex(apiRequestDo.getData()));
}
return params;
}

private static String signAssembly(TreeMap<String, String> params, String secretKey){
//LinkedHashMap 使用LinkedHashMap保持顺序
StringBuilder str = new StringBuilder();
Set<String> keySet = params.keySet();
Iterator<String> iter = keySet.iterator();
while (iter.hasNext()) {
String key = iter.next();
if (StringUtils.isBlank(params.get(key))) {
continue;
}
str.append(key);
str.append("=");
str.append(params.get(key));
str.append("||");
}
str.append(secretKey);
return str.toString();
}

private static String getSign(ApiRequestDO apiRequestDo, String secretKey) {
TreeMap<String, String> params = paramsBuild(apiRequestDo);
String signString = signAssembly(params, secretKey);
return signString;
}
public static void main(String[] args) {
ApiRequestDO apiRequestDo = new ApiRequestDO();

apiRequestDo.setApi("tuya.p.weather.city.info.list");
ApiContextDO apiContextDO = new ApiContextDO();
apiContextDO.setApiVersion("1.0");
apiContextDO.setOs("Linux");
apiContextDO.setLang("zh-Hans");

AppInfoDO appInfoDO = new AppInfoDO();
appInfoDO.setClientId("{accessId}");
apiRequestDo.setAppInfoDo(appInfoDO);

apiRequestDo.setT("1490004310");
apiRequestDo.setData("{\"countryCode\":\"CN\");

apiRequestDo.setApiContextDo(apiContextDO);

String s = getSign(apiRequestDo, "{accessKey}");
String sign = MD5Util.getMD5(s.getBytes());
System.out.println(sign);
}
    public class Md5HexUtil {
protected static Logger logger = LoggerFactory.getLogger(Md5HexUtil.class);
public Md5HexUtil() {
}
public static String md5Hex(String data) {
return md5Hex(data, false);
}
public static String md5Hex(String data, boolean isMd5) {
String hex = "";
if(StringUtils.isNotBlank(data)) {
if(!isMd5) {
hex = MD5Util.getMD5(data);
}

StringBuffer sb = new StringBuffer();
sb.append(hex.substring(8, 16))
.append(hex.substring(0, 8))
.append(hex.substring(24, 32))
.append(hex.substring(16,24));
hex = sb.toString();
}
return hex;
}
}
400-881-8611