一、概述
1、文档目的
此文档主要用于指导厂商开发者使用PTP-SDK 或直接使用PTP协议,在基于物联网平台边缘技术架构开发边缘设备驱动。文档提供SDK相关的接口描述和使用示例,以及PTP协议的相关说明和接入流程。
2、阅读对象
本文档适用读者对象为:边缘端的驱动开发者、边缘端设备测试人员。
读者要求:需要具备对物联网行业有一定认识,如理解产品、设备、物模型等行业通用语所指含义。
3、名词解释
边缘盒子:指的是一个边缘服务器,内包含接入物联平台的必要组件,为边缘接入提供计算资源。
边缘网关(XEG):内嵌在边缘盒子里的应用程序,会将边缘盒子以一个网关设备的身份接入到IoT平台,并提供子设备对接能力,具备边缘驱动分发、管理能力;
物联平台:物联平台指云端管理台。
边缘驱动:一种面向不同厂商、应用系统的可运行应用程序,其用途是对接不同厂商、应用系统设备数据。
PTP协议:指物联云平台定义的一种面向多厂商、应用系统设备接入的通用协议,该协议运行基于MQTT 3.1.1 协议,支持不同边缘驱动相互隔离;
物模型:物模型从属性、服务和事件三个维度,分别描述了其在物理空间中指代的实体是什么,能够做什么,能够对外提供哪些信息。从这三个维度定义好产品相应的物模型之后,也代表定义好了该产品的功能定义。
4、前置条件
1、已部署云端管理台并开通设备中心整体功能模块;
2、边缘网关已初始化完成并正常联网;
3、创建边缘产品、匹配物模型、配置网关授权(或由项目方提供)
二、基本介绍
- 边缘驱动通过MQTT协议与边缘网关进行通讯,本文档主要介绍通过PTP-SDK进行开发,该sdk是基于paho mqtt client开发, 对边缘PTP协议进行封装的工具类程序。
- 您也可以不使用PTP-SDK,直接基于MQTT协议,自行选择MQTT客户端程序进行驱动开发。
三、基于PTP-SDK设备驱动开发
1、使用条件
1、用于边缘盒子的驱动开发
2、使用sdk前需要初始化环境变量 PTP-Process-Name 该环境变量指驱动的程序名称, 需要开发者自定义,该环境变量用于ptp_id和mqtt的client_id的生成
3、maven坐标
<dependency>
<groupId>cn.xlink</groupId>
<artifactId>ptp-sdk</artifactId>
<version>1.0.5</version>
</dependency>
2、SDK接口和功能说明
2.1、设备上线
用于边缘驱动启动后,边缘驱动与厂商系统、设备连接成功后,将设备在物联网平台上线 。
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
private static final String MAC = "ABCDEFG";
private static final String PRODUCT_ID = "160124c460d02009160004c460d0e401";
SDK.getInstance().deviceOnline(PRODUCT_ID, MAC);
2.2、设备下线
此接口用于边缘需求与厂商系统、设备连接断开后,将物联网平台对应的设备下线。
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
private static final String MAC = "ABCDEFG";
private static final String PRODUCT_ID = "160124c460d02009160004c460d0e401";
SDK.getInstance().deviceOffline(PRODUCT_ID, MAC);
2.3、设备属性发布(默认含有设备上线)
此接口用于将设备数据通过物模型属性上报到物联网平台。边缘驱动可以在厂商系统上报对应设备状态时或者定时查询厂商设备实时状态进行上报。
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
private static final String MAC = "ABCDEFG";
private static final String PRODUCT_ID = "160124c460d02009160004c460d0e401";
Map<String,Object> params = Maps.newConcurrentMap();
params.put("status",1);
params.put("controller_state",0);
SDK.getInstance().pulishAttr(PRODUCT_ID,MAC,params);
2.4、设备事件上报(默认含有设备上线)
此接口用于驱动将设备事件通过物模型上报到物联网平台,例如:设备告警事件、故障事件、通行记录。
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
private static final String MAC = "ABCDEFG";
private static final String PRODUCT_ID = "160124c460d02009160004c460d0e401";
Map<String,Object> event = Maps.newConcurrentMap();
event.put("message","非法卡开门报警");
event.put("code",1);
event.put("time",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(df.format(new Date())));
SDK.getInstance().pulishEvent(PRODUCT_ID,MAC, "alert",event);
// eventName 为物模型事件名称
// eventContent 为物模型事件对应的参数列表以及对应的值
2.5、设备属性设置回调
此接口通常用于云端或者APP、业务系统通过物联网平台远程控制设备状态。由云端将控制命令和数据通过物模型属性下发给边缘驱动,驱动接收到此回调后,需要通过厂商系统、设备接口实施控制设备状态。
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
SDK.getInstance().setSetAttrCallBack(new SetAttrCallBack() {
@Override
public void invokeService(String productId, String mac, Map<String, Object> params) {
// params 为云端下发的物模型属性列表以及对应的值
//logic...
return;
}
});
2.6、设备服务回调
此接口通常用于云端或者APP、业务系统通过物联网平台远程调用设备服务。例如:开门服务,设备入网服务等
//初始化PTP-Process-Name这个变量, 只需要在程序启动时初始化一次即可
System.setProperty(MqttConstants.PROCESS_NAME, "sdk-test");
//或者 System.setProperty(MqttConstants.PROCESS_NAME, UUID.randomUUID().toString().replace("-", ""));
public class OpenDoorCallBack implements ServiceInvokeCallBack {
/**
*
* @param productId 产品id
* @param mac 设备唯一标识 mac地址
* @param serviceName 服务名称
* @param params 云端下发的物模型属性列表以及对应的值
* @return 根据物模型,返回对应数据
*/
@Override
public Map<String, Object> invokeService(String productId, String mac, String serviceName, Map<String, Object> params) {
//业务逻辑 根据具体业务,调用API
//返回结果
Map<String,Object> resultMap = Maps.newConcurrentMap();
resultMap.put("code",200);
resultMap.put("message","open door success...");
return resultMap;
}
}
//服务回调
SDK.getInstance().addServiceInvokeCallBack("open", new OpenDoorCallBack());
2.7、Demo下载链接
Demo可以让你快速体验以上相关的SDK能力,可点此下载
3、常见问题
Q: 驱动正常上报设备MAC,IoT平台未显示设备注册上线?
A: 检查上报MAC是否按照偶数位16进制要求、平台产品是否授权自动注册、对应盒子是否关联相关产品。
Q: 设备上线后,驱动正常上报属性值,IoT显示属性值没有数据?
A: 检查上报属性名是否与物模型完全一致。
四、基于PTP协议设备驱动开发
1、接入流程
1.1、整体流程
参考下图,101了解其厂商设备、应用系统协议,确保该系统具备物联数据的能力以及接入方式;102是将其系统的数据进行对接开发,实现物联数据的转换逻辑;103将102开发好的驱动程序运行起来,实现系统数据打通,104是进行PTP协议的通信;105是边缘网关与云平台进行云边通信。
1.2、通信流程
1.2.1、交互通信流程
参考下图,边缘驱动与边缘网关建立TCP连接,连接建立成功后,发起MQTT Connect报文(见5.1.1),发起MQTT Connect报文成功后,发起MQTT Subscribe报文,用于接收设备数据下发指令;当设备数据变化时,发起MQTT Publish报文上报设备数据;当云平台对设备下发指令时,边缘网关发起MQTT Publish报文触发设备下发指令,边缘驱动收到(前提是设备驱动订阅了设备下发指令)设备下发指令后进行相应的逻辑处理,处理完成得到设备响应指令信息,发起MQTT Publish报文将设备响应指令信息发送给边缘网关,边缘网关将响应指令上报到云平台完成设备控制。
1.2.2、心跳机制
边缘驱动与边缘网关采用统一的心跳机制,为10分钟,边缘网关会定期清理10分钟没有任何数据包的MQTT客户端;
1.3、重连机制及驱动初始化
边缘驱动需要具备重连机制,当边缘驱动与边缘网关连接断开后,边缘驱动重新尝试连接;
当边缘网关识别边缘驱动断开连接后,会把边缘驱动以前上报过的设备状态置为离线;当边缘驱动与边缘网关重新连接时,需要将当前存量的设备状态同步给边缘网关;
2、协议说明
2.1、MQTT 协议
1.1 MQTT版本
支持的MQTT标准协议接入,支持3.1.1版本,具体参见MQTT3.1.1协议文档;
1.2 与标准MQTT的区别
- 支持MQTT的CONNECT、PUBLISH、SUBSCRIBE、PING、DISCONNECT报文;
- 不支持clean session = false;
- 不支持will、retain msg;
- 支持上下行QoS 0;支持上行QoS 1、不支持下行 QoS 1; 不支持上下行QoS 2;
1.3 MQTT Connect 报文约定
- Connect报文中ClientID必须当前边缘盒子唯一的,在发起Connect时,边缘网关识别ClientID冲突时,连接无法建立成功,Connack错误返回0x02;
- Connect报文中username、password字段不规定,可传空字符;
2.2、PTP协议
2.2.1、PTP 协议介绍
PTP协议完全基于MQTT Publish报文,通过PTP ID定义了多个通道,每个通道代表一类设备数据的传输,在每次通信传输中都会携带PTP ID,不同PTP通道之间相互隔离,同个通道下可以传输多个设备数据,主要分为以下指令:
- 设备物模型属性上报
- 设备物模型事件上报
- 设备物模型服务下发
- 设备物模型服务下发响应
PTP ID字段定义规范:以字母+数字、下划线定义,1-64位字符长度范围,通常一类驱动固定一个PTP ID,可以以厂商的英文简称来定义,这样一般不会冲突;
2.2.2、 PTP协议列表
指令 | MQTT主体 | 方向 |
---|---|---|
设备物模型属性上报 | $xlink/ptp/{ptp_id}/device/thing/publish_attributes | 驱动->XEG |
设备物模型事件上报 | $xlink/ptp/{ptp_id}/device/thing/event/{event_name}/report | 驱动->XEG |
设备物模型服务下发 | $xlink/ptp/{ptp_id}/device/thing/service/{service_name}/invoke | XEG->驱动 |
设备物模型服务下发响应 | $xlink/ptp/{ptp_id}/device/thing/service/{service_name}/invoke/result | 驱动->XEG |
2.2.3、PTP详细定义
设备物模型属性上报
说明
- 当设备属性改变以后,上报到XEG。
方向
- 驱动 -> XEG
Topic
- $xlink/ptp/{ptp_id}/device/thing/publish_attribute
Payload
{ "devices": [{ "name": "设备名称", "mac": "设备mac", "product_id": "设备所属产品ID", "state": "设备状态", "attribute": { "v": "物模型版本号", "time": "时间,long型时间戳表示", "extra": { "xxx": "xxx" } } }] }
字段 类型 是否必须 说明 name 字符串 否 设备名称,在触发设备注册时会将设备名称初始化至平台,设备已注册时该字段无效 mac 字符串 是 设备MAC地址,必须是偶数位,16进制大写格式 product_id 字符串 是 设备所属产品ID state 整形 是 设备状态,1表示设备在线;0表示设备离线 attribute 对象 否 设备改变的物属性 attribute.time 字符串 否 时间戳。格式为毫秒级utc时间戳,示例:“1616404559000”。 attribute.v 字符串 否 物模型版本号,当前值为”2.0” attribute.extra Object 是 物模型属性对象,例如:”extra”:{ “PowerSwitch”:0,”Status”: true }
设备物模型事件上报
说明
- 当设备触发事件以后,上报到XEG。
方向
- 驱动 -> XEG
Topic
- $xlink/ptp/{ptp_id}/device/thing/event/{event_name}/report
Payload
{ "devices": [{ "name": "设备名称", "mac": "设备mac", "product_id": "设备所属产品ID", "state": "设备状态", "event: { "v": "物模型版本号", "time": "时间,long型时间戳表示", "extra": { "xxx": "xxx" } } }] }
字段 | 类型 | 是否必须 | 说明 |
---|---|---|---|
name | 字符串 | 否 | 设备名称,在触发设备注册时会将设备名称初始化至平台,设备已注册时该字段无效 |
mac | 字符串 | 是 | 设备MAC地址,必须是偶数位,16进制大写格式 |
product_id | 字符串 | 是 | 设备所属产品ID |
state | 整形 | 是 | 设备状态,1表示设备在线;0表示设备离线 |
event | 对象 | 否 | 设备改变的物模型事件 |
event.v | 字符串 | 否 | 物模型版本号,当前值为”2” |
event.extra | Object | 是 | 物模型事件对象,例如:”extra”{ “code”:0,”message”: “OK” } |
设备物模型服务下发
说明
- XEG发送消息给驱动,下发设备物模型服务
方向
- XEG->驱动
Topic
- $xlink/ptp/{ptp_id}/device/thing/service/{service_name}/invoke
Payload
{ "msg_id":"消息ID", "mac":"设备mac", "product_id":"设备所属产品ID", "service":{ "v": "物模型版本号", "input": { "xxx": "xxx" } } }
字段 类型 是否必须 说明 msg_id 整形 是 消息ID,16位无符号数字 mac 字符串 是 设备MAC地址,必须是偶数位,16进制大写格式 product_id 字符串 是 设备所属产品ID service 对象 是 设备物模型服务 service.input Object 是 物模型服务输入参数,例如:”input” { “code”:0,”message”: “OK” } service.v 字符串 否 物模型版本号,当前 “2”
设备物模型服务下发响应
说明
- 驱动将物模型服务响应结果发送给XEG。
方向
- 驱动 -> XEG
Topic
- $xlink/ptp/{ptp_id}/device/thing/service/{service_name}/invoke/result
Payload
{ "msg_id": "消息ID", "mac": "设备mac", "product_id": "设备所属产品ID", "service_result": { "v": "物模型版本号", "code": "xx", "output": { "xxx": "xxx" } } }
字段 类型 是否必须 说明 msg_id 整型 是 消息ID,16位无符号数字 mac 字符串 是 设备MAC地址,必须是偶数位,16进制大写格式 product_id 字符串 是 设备所属产品ID service_result 对象 是 设备物模型服务调用返回结果 service_result.v 字符串 否 物模型版本号,当前 “2” service_result.oupput Object 是 物模型服务返回参数对象,例如”output”:{ “code”:0,”message”: “OK” }
3、对接参数
列举在边缘驱动对接过程中所需参数及获取方法。
参数 | 用途 | 值 | 获取方法 |
---|---|---|---|
MQTT IP地址 | 驱动接入XEG | 127.0.0.1 | 如果开发者是本地调试,需要跟盒子同一个局域网下,同时获取盒子局域网IP |
MQTT 端口 | 驱动接入XEG | 1889 | 默认固定值 |
产品ID | 驱动对接设备 | - | 物联云平台创建的产品ID |
mac | 驱动对接设备 | - | 获取厂商的设备标识 |
物模型定义 | 驱动对接设备 | - |
4、特殊说明及使用限制
- 边缘网关提供驱动接入的TCP层协议默认报文最大限制为128K,不可超过;
- 心跳机制为10分钟,驱动必须在闲时10分钟内向边缘网关发送报文;
- 一个常规的边缘盒子,默认最大支持20000个设备接入;
5、常见问题
Q:边缘盒子1889端口没有打开,或者没有telnet通。
A:可能是边缘盒子未激活,需按照实施文档将边缘盒子进行激活后才会打开1889端口。
Q:第一次上报了设备MAC,物联云平台没有显示设备。
A:可能上报MAC没有按照偶数位16进制要求,也可能是产品配置没有设置【设备自行授权】选项。
Q:在管理台新建了物模型服务,对设备下发时,驱动无法收到
A:设备已上线的情况下,动态新增物模型服务时,需要下线设备,再重新上线设备才可以识别新的物模型服务。