IoTSDK接入
IoTSDK主要维护和服务器之间的信令连接,采用纯C实现,主要支持设备绑定、解绑、信令解析、物模型处理相关的操作。
IoTSDK-API 列表
IoTSDK 相关的 API 功能说明如下:
API 接口 | 功能说明 |
---|---|
xs_iot_init | SDK 初始化 |
xs_iot_unInit | SDK 反初始化 |
xs_iot_setLogLevel | 设置日志级别 |
xs_iot_open | 创建设备(包含主设备和子设备) |
xs_iot_connect | 建立设备连接 |
xs_iot_disconnect | 断开设备连接 |
xs_iot_close | 销毁设备 |
xs_iot_report | 上报物模型定义的属性和状态信息 |
xs_iot_setBindInfo | 设备绑定过程中使用,设置绑定信息 |
xs_iot_handleExternalMsg | 处理外部消息(streamsdk 回调的消息) |
xs_iot_notifyHostStatus | SDK分离模式下:用于告知 主控芯片(streamsdk 运行的芯片) 的运行状态 |
xs_iot_get_version | 获取SDK版本号 |
xs_iot_set_timezone | 设置时区信息,海外设备需要使用此接口,SDK内部会根据设置的时区信息处理夏令时切换机制 |
SDK接口调用流程
以普通长电IPC为例,SDK接口调用流程以及示例代码如下:
步骤1:初始化SDK
int initSdk()
{
/*初始化iotsdk回调函数指针*/
xs_iot_callbackFun_st cbFun;
initIotCallbackFun(&cbFun);
/*设置初始化参数*/
xs_iotInitParam_st initParam;
memset(&initParam, 0, sizeof(initParam));
initParam.configPath = "/etc/config"; //设置配置文件路径,flash中可读写路径
initParam.workMode = XS_IOT_WORK_MODE_LONG_TIME_POWER;
initParam.maxSubDeviceNum = 0; //没有子设备
initParam.regionType = 0; //国内设备
initParam.heartbeatInterval = 15; //最小15
/*初始化iotsdk*/
ret = xs_iot_init(&cbFun, &initParam);
return ret;
}
步骤2:创建设备并启动连接
int connectDevice()
{
int devId = xs_iot_open(XS_IOT_DEV_TYPE_MASTER, &deviceInfo);
if (devId < 0) {
LOG_PRINT("open device failed, err=%d\n", g_devId);
return -1;
}
LOG_PRINT("open device success, id=%d\n", g_devId);
/*创建设备连接*/
ret = xs_iot_connect(g_devId);
if (ret != XSIOT_EC_SUCCESS) {
LOG_PRINT("xs_iot_connect failed, code=%d\n", ret);
return -1;
}
return ret;
}
设备上线后,会将在线状态和绑定状态回调出来,具体可以参考设备上线章节
步骤3: 绑定设备
此步骤在设备配网绑定过程中才需要触发,一般是APP生成二维码、或者通过蓝牙、局域网等方式将绑定信息传到设备端,设备端解析出绑定信息(目前有bindToken以及regionId,regionId是可选字段),然后将绑定信息传入到SDK,
int bindDevice()
{
xs_bindInfo_st bindInfo;
bindInfo.bindToken = "797B05";
bindInfo.regionId = -1; //如果没有regionId,填为 -1
xs_iot_setBindInfo(&bindInfo);
return 0;
}
绑定结果通过回调函数通知设备层,具体细节参数设备绑定章节。
步骤4: 上报物模型属性&消息&固件版本号等
注意以下上报消息的动作,必须是设备在线且已经绑定过的状态下才能上报,否则直接返回失败
/*测试上报属性值*/
void testReportProperty()
{
/*此处模拟上报声音侦测灵敏度*/
const char* property = "{\"VoiceDetectionSensitivity\":2,\"SoundDetectionSensitivity\":3,\"time\":\"1732691271662\"}"; //time字段不填默认为当前时间
xs_uint32 serviceId = 0;
xs_iot_report(g_devId, XS_IOT_MSG_POST_PROPERTY, property, strlen(property), &serviceId);
}
/*测试上报物模型自定义的事件消息*/
void testReportTslEvent()
{
/*此处模拟上报物模型自定义事件消息*/
char* eventId = "LockAllEvent"; /*物模型中定义的event Identifier*/
char* payload = (char*)malloc(512);
strcpy(payload, "{\"lockEvent\":[-59],\"type\":9}"); /*事件内容*/
xs_uint32 serviceId = 0;
xs_iot_report_event(g_devId, eventId, getCurrentUtcMs(), payload, strlen(payload), &serviceId);
free(payload);
}
/*设备上报版本号*/
void testOtaInform()
{
const char* inform = "{\"version\": \"1.1.0\",\"module\": \"MCU\"}";
xs_uint32 serviceId = 0;
xs_iot_report(g_devId, XS_IOT_MSG_OTA_INFORM, inform, strlen(inform), &serviceId);
}
功能接口详述
设备初始化
说明:
初始化函数必须在其他函数之前调用(xs_iot_setLogLevel/xs_iot_get_version 接口除外),主要用于初始化 SDK 内部一些资源,设备侧需要实现接口中定义的回调函数指针,并做相应处理
相关接口定义:
函数定义:
/**
* @brief 初始化函数
* @param [IN] cbFun: 回调函数指针列表
* @param [IN] initParam: 初始化参数
* @return 0:成功, 其他值:错误码
*/
xs_int32 xs_iot_init(xs_iot_callbackFun_st* cbFun, xs_iotInitParam_st* initParam);
初始化过程中,需要设置回调函数列表,设备需要处理的回调函数说明:
回调函数 | 说明 |
---|---|
xs_msgCallback | sdk内部消息的回调函数,设备侧收到此回调之后,直接将参数转给StreamSDK处理即可(xs_stream_inputIotMsg),不需要关心参数内容 |
xs_systimeCallback | 同步设备系统时间,SDK只负责同步主设备的系统时间,子设备的时间需要厂商自行处理 |
xs_logCallback | SDK日志回调 |
xs_bindStatusCallback | 设备绑定状态回调,注意绑定状态绑定过程中,或者每次登录服务器成功后都会回调,设备根据绑定状态可以控制设备自身的状态 |
xs_connectStatusCallback | 设备在线、离线状态回调 |
xs_setPropertyCallback | 设置物模型属性的回调,关于物模型属性的格式定义,详细说明请参考下面的章节 |
xs_upgradeCallback | 设备升级回调 |
xs_serviceCallback | 设置物模型服务的回调 |
xs_serverAddressCallback | 服务器地址回调,一般不需要处理,有些特殊设备需要对ip地址和端口打开白名单需要处理此消息 |
xs_wakeupHostCallback | 唤醒主控streamsdk的回调(iotsdk和streamsdk运行在不同进程的时候需要处理此回调,将streamsdk主控唤醒) |
xs_cloudTokenCallback | 设备绑定成功或解绑时会调用此接口,应用层收到此回调需要将token保存到flash中,并在启动的时候放在初始化参数中传入SDK(initParm.cloudToken) |
xs_reportMsgCallback | xs_iot_report 和 xs_iot_report_event 上报消息结果的异步回调 |
xs_timezoneCallback | 时区信息回调 |
xs_keepliveCallback | 保活信息回调(非分离模式下的低功耗保活设备使用) |
初始化参数结构体:
/*初始化信息*/
typedef struct {
xs_uint32 maxSubDeviceNum; /*最大子设备个数,普通IPC设备填0, 网关NVR设备 > 0*/
xs_iotWorkMode_en workMode; /*工作模式,主要区分低功耗设备和长电设备*/
xs_uint32 heartbeatInterval; /*心跳间隔,小于15默认为15秒,最大不超过180秒*/
xs_char* serverHostName; /*服务器域名,NULL表示使用SDK内部默认的(正式环境域名),最长不能超过127个字符*/
xs_char* configPath; /*flash中可读写的路径(例如 /etc/config/),sdk会在此路径下创建文件,保存一些配置信息数据,如果设备系统中不支持传入可读写路径,可以填写NULL(网 关NVR设备必须支持), SDK配置文件大小不超过30KB*/
xs_char* cloudToken; /*设备绑定成功后的token信息,注意:如果configPath不为空,不需要填写此参数,固定为NULL即可,SDK内部会保存token信息。
*否则需要应用层将xs_cloudTokenCallback回调函数返回的信息保存到flash中,启动的时候在初始化参数中传入,没有就传NULL。*/
xs_uint32 regionType; /*region:0 表示国内,1表示国外*/
}xs_iotInitParam_st;
设备上线
- 设备侧调用 xs_iot_open 接口创建设备资源之后,才能对该设备进行操作(目前暂时不支持子设备)
- 设备侧调用 xs_iot_connect 接口,建立和信令服务器之间的连接通道
备注:xs_iot_connect 函数在设备无网络的时候也可以调用,SDK 内部会维护重连逻辑
接口定义:
/**
* @brief 创建设备,设备启动的时候必须先创建主设备,然后再创建子设备(目前暂时不支持子设备)
* @param [IN] devType: 设备类型,标识主设备或者子设备
* @param [IN] deviceParams: 设备参数信息
* @return >=0 表示设备ID,用于后续设备操作。 <0 表示创建失败的错误码
*/
xs_int32 xs_iot_open(xs_iotDeviceType_en devType, xs_deviceInfo_st* deviceParams);
/**
* @brief 建立设备和服务器的信令连接
* @return 0:成功, 其他值:错误码
*/
xs_int32 xs_iot_connect(xs_int32 devId);
设备在线/离线状态的回调函数通知如下,设备可以根据不同的状态做不同处理:
/**
* @brief 设备在线状态回调
* @param [IN] devId: 设备ID,xs_iot_open接口返回的ID,目前仅支持主设备
* @param [IN] connectStatus: 在线状态,1表示设备在线, 0 表示设备离线
* @return 0:成功, 其他值:错误码
*/
typedef xs_int32(*xs_connectStatusCallback)(xs_int32 devId, xs_int32 connectStatus);
创建设备的时候要将设备认证信息(三元组)传入SDK,productSecret目前可以填NULL
/*设备信息*/
typedef struct {
xs_char* productKey; /*产品型号, 长度不超过64,主设备必填*/
xs_char* productSecret; /*产品秘钥,长度不超过64,目前还没有实际用途,可以填NULL*/
xs_char* deviceName; /*设备序 列号,长度不超过64,主设备和子设备都必填*/
xs_char* deviceSecret; /*设备秘钥,长度不超过64,主设备必填*/
}xs_deviceInfo_st;
时间同步
SDK连接云端之后,会触发同步系统时间的回调,设备需要将utc时间戳设置到系统中。
同步成功之后,SDK内部每8个小时定时检查是否需要重新同步时间,如果需要(时间差5秒以上),还会触发此回调。
/**
* @brief 同步设备系统时间[SDK只负责同步主设备的系统时间,子设备的时间需要厂商自行处理]
* @param [IN] utcTime: utc时间戳,毫秒
* @return 0:成功, 其他值:错误码
*/
typedef xs_int32(*xs_systimeCallback)(xs_uint64 utcTime);
设备绑定
注意:SDK不处理设备配网和连接Wifi相关的工作,此部分内容由设备侧和APP自行交互处理。
设备绑定过程中,APP需要将bindToken(参考 设备绑定开发指南)通过二维码(或者蓝牙、局域网等其他方式)传递给设备,设备解析成功之后,将bindToken信息(海外设备还会有个regionId信息),通过xs_iot_setBindInfo接口传递给IoTSDK。 IoTSDK调用云平台,确认bindToken的有效性,如果有效,则云平台会通知AppSDK发起绑定请求。绑定接口异步回调(xs_bindStatusCallback)给设备,设备需要监听绑定成功返回的token并保存。
相关接口:
/**
* @brief 设备绑定过程中使用,设备从app生成的二维码或者蓝牙声波等信息中提取出相应信息,通过此接口通知SDK,绑定结果通过 xs_bindStatusCallback 回调出来
* @param [IN] bindInfo: 绑定信息,目前包括app生成的临时绑定token以及regionId信息
* @return 0:成功, 其他值:错误码
*/
xs_int32 xs_iot_setBindInfo(const xs_bindInfo_st* bindInfo);
设备绑定结果回调通知如下:
/**
* @brief 设备绑定状态回调
* @param [IN] devId: 设备ID,xs_iot_open接口返回的ID,目前仅支持主设备
* @param [IN] bindStatus: 设备状态
* @param [IN] extra: 扩展信息,deviceStatus=DEVICE_STATUS_BIND_FAILED 时有效,返回错误原因和错误码
* @return 0:成功, 其他值:错误码
*/
typedef xs_int32(*xs_bindStatusCallback)(xs_int32 devId, xs_bindStatus_en bindStatus , const xs_char* extra);
注意点:
- 设备需要记录绑定状态,DEVICE_STATUS_BIND、DEVICE_STATUS_UNBIND 状态在设备每次启动或者重连的时候都会回调出来,设备需要自行判断当前状态,并做相应的控制。另外设备绑定成功的时候也会回调 DEVICE_STATUS_BIND
- 绑定失败或者绑定超时后,需要重新进入绑定流程
另外绑定成功后,IoTSDK会将设备认证token信息回调给设备,设备应用层需要将token信息保存到flash中。并且在每次启动的时候通过初始化接口传入SDK。
回调函数接口如下:
/**
* @brief 设备绑定成功或解绑时会调用此接口,应用层收到此回调需要将token保存到flash中,并在启动的时候放在初始化参数中传入SDK
* @param [IN] token: 绑定成功后的token信息,NULL表示需要清空flash中保存的token信息
*/
typedef xs_int32 (*xs_cloudTokenCallback)(const xs_char* token);
设备解绑
设备解绑的通知也是通过上述回调函数(xs_bindStatusCallback)进行通知,设备层收到解绑通知后,建议将设备 reset(清空本地配置信息),并重启设备进入绑定模式。同时也会触发xs_cloudTokenCallback 的回调,应用层清空保存的token信息
物模型
物模型是对设备是什么,能做什么的描述,包括设备的属性(properties)、服务(services)、事件(events)等。RTCX-IOT 通过定义一种物的描述语言来描述物模型,称之为 TSL(即 Thing Specification Language)。
功能类型 | 说明 |
---|---|
属性(Property) | 用于描述设备运行时具体信息和状态。例如,环境监测设备所读取的当前环境温度、智能灯开关状态、电风扇风力等级等。属性可分为读写和只读两种类型。读写类型支持读取和设置属性值,只读类型仅支持读取属性值。 |
服务(Service) | 指设备可供外部调用的指令或方法。服务调用中可设置输入和输出参数。输入参数是服务执行时的参数,输出参数是服务执行后的结果。相比于属性,服务可通过一条指令实现更复杂的业务逻辑,例如执行某项特定的任务。服务分为异步和同步两种调用方式。 |
事件(Event) | 设备运行时,主动上报给云端的信息,一般包含需要被外部感知和处理的信息、告警和故障。事件中可包含多个输出参数。例如,某项任务完成后的通知信息;设备发生故障时的温度、时间信息;设备告警时的运行状态等。事件可以被订阅和推送。 |
接入客户可以在控制台管理页面配置和导出物模型定义,具体细节参考其他文档。
设备端、服务器、客户端交互的时候,必须严格按照物模型定义的参数和类型进行通信,否则会出现类型不匹配的问题,导致异常或者崩溃等问题
属性
SDK 提供了物模型属性的设置和上报接口,具体如下:
修改物模型参数
服务器或客户端修改物模型属性参数,会触发以下回调函数:
/**
* @brief 设置物模型属性的回调
* @param [IN] devId: 设备ID,xs_iot_open接口返回的ID,目前仅支持主设备
* @param [IN] property: 物模型属性,json字符串,支持同时修改多个属性,格式和物模型定义中的格式匹配
* @param [IN] propertyLength: 字符串长度
* @return 0:成功, 其他值:错误码
*/
typedef xs_int32(*xs_setPropertyCallback)(xs_int32 devId, const xs_char* property, xs_uint32 propertyLength);
参数格式说明
设备收到的property字段格式为json字符串,包含要修改的参数的key和value,举例如下:
{
"VoiceDetectionSensitivity": {
"value": 2
},
"SoundDetectionSensitivity": {
"value": 3
}
}
物模型属性上报
以下情况设备需要上报物模型参数到平台:
- 设备收到上述设置请求之后,修改对应参数值并且修改成功
- 设备启动后,或者设备绑定成功后
上报接口定义( msgType = XS_IOT_MSG_POST_PROPERTY):
/**
* @brief 上报消息到云端(主要包括物模型属性消息、事件消息、OTA相关消息)
* @param [IN] devId: xs_iot_open 接口返回的 deviceId
* @param [IN] msgType: 上报的消息类型
* @param [IN] payload: 消息内容,物模型中定义的带结束符(\0)的json格式字符串,格式参考文档定义
* @param [IN] payloadLen: 消息长度,不能超过4096字节
* @param [OUT] serviceId: 本地上报消息生成的serviceId,和回调(xs_reportMsgCallback)中的serviceId对应
* @return 0:成功, 其他值:错误码
* @note
* 1. 此接口需要设备已绑定且在线的情况下才能调用成功,否则会返回失败,返回失败后
* 2. 此接口为异步接口,调用成功仅代表塞入到本地消息队列中,不表示上报成功
* 3. 上报结果通过 xs_reportMsgCallback 回调函数通知
* 3. 如果内部上报失败,会有重传机制,一直重传失败(3次),会抛出上传失败的回调
*/
xs_int32 xs_iot_report(xs_int32 devId, xs_iotReportMsgType_en msgType, const xs_char* payload, xs_uint32 payloadLen, xs_uint32* serviceId);
参数格式说明
设备上报的payload参数为json格式,目前支持两种上报格式:
格式一:key/value/time格式:注意需要包含上报的参数的key以及value和time字段,举例如下:
{
"VoiceDetectionSensitivity": {
"value": 2,
"time":"1732691271662"
},
"SoundDetectionSensitivity": {
"value": 3,
"time":"1732691271662"
}
}
注意value值需要和物模型定义的格式保持一致,time字段为参数修改时的utc时间戳(毫秒)
格式二(建议采用):精简格式,支持按照 属性:值的格式进行上报,格式如下:
{
"VoiceDetectionSensitivity": 2,
"SoundDetectionSensitivity": 3,
"time": "1732691271662"
}
上面两种上报格式是相同的效果。
注意:
如果设备参数之间有互斥行为(比如人脸检测功能和车牌检测功能不能同时打开),设备自行处理互斥行为,并将修改后的其他参数值通过上述接口一并上报到平台。
另外,设备绑定成功或设备重启后,建议将所有属性打包一起上报到服务器,后续通过增量方式上报更新
事件
SDK支持通过下面2种方式上报自定义事件消息 (例如开锁消息,传感器消息等),平台会保存用户上报的消息列表。
方式一:
xs_iot_report 接口:和上报接口和物模型属性的上报接口相同,区别是 上报的时候 msgType 值为 XS_IOT_MSG_POST_TSL_MSG
typedef enum {
...
XS_IOT_MSG_POST_TSL_MSG = 4, //上报自定义物模型IOT事件消息
} xs_iotReportMsgType_en;
上报数据的格式(payload)举例说明如下:
{
"LockAllEvent": [{
"value": {
"lockEvent": [-59],
"type": 9
},
"time": "1736919345687"
}]
}
其中,"LockAllEvent"为用户在控制台自定义的物模型消息类型(event Identifier),"value" 和 "time"为必填项,value的值为用户定义的消息参数结构体,time为事件发生的utc毫秒时间戳。
方式二:
xs_iot_report_event 接口:对xs_iot_report 接口进行了二次封装,达到和 xs_iot_report 接口相同的效果,区别是 xs_iot_report_event 是一次只能上报一种类型的事件,但是使用起来更加简单方便。
/**
* @brief 上报自定义事件消息到云端
* @param [IN] devId: xs_iot_open 接口返回的 deviceId
* @param [IN] eventId: 物模型中定义的事件类型, eventIdentifier
* @param [IN] utcms: utc时间戳,毫秒,如果填0, SDK内部会使用当前系统时间
* @param [IN] payload: 消息内容,物模型中定义的带结束符(\0)的json格式字符串,格式参考文档定义
* @param [IN] payloadLen: 消息长度,不能超过4096字节
* @return 0:成功, 其他值:错误码
* @note
* 1. 使用xs_iot_report 接口(msgType = XS_IOT_MSG_POST_TSL_MSG)也可以达到和此接口相同的效果,区别是使用此接口上报更加简单一些
* 2. 其他注意事项同 xs_iot_report 接口
*/
xs_int32 xs_iot_report_event(xs_int32 devId, const xs_char* eventId, xs_uint64 utcms, const xs_char* payload, xs_uint32 payloadLen, xs_uint32* serviceId);
上报方式示例:
/*测试上报物模型自定义的事件消息*/
void testReportTslEvent()
{
/*此处模拟上报物模型自定义事件消息*/
char* eventId = "LockAllEvent"; /*物模型中定义的event Identifier*/
char* payload = (char*)malloc(512);
strcpy(payload, "{\"lockEvent\":[-59],\"type\":9}"); /*事件内容*/
xs_uint32 serviceId = 0;
xs_iot_report_event(g_devId, eventId, getCurrentUtcMs(), payload, strlen(payload), &serviceId);
free(payload);
}
其他视频相关的智能报警事件的上报主要是通过 StreamSDK 接口进行上报,可以参考 StreamSDK 的报警推送接口 xs_stream_postIntelligentAlarm
服务
物模型服务的回调函数如下,通过此回调可以控制设备 PTZ 操作,SD 卡格式化,容量查询、设备抓图等操作,具体支持的服务种类以用户定义的物模型模板为准:
/**
* @brief 设置物模型服务的回调,注意:回调完成后,SDK内部会用free函数释放response
* @param [IN] devId: 设备ID,xs_iot_open接口返回的ID,目前仅支持主设备
* @param [IN] serviceid: 物模型中定义的服务类型ID
* @param [IN] serviceidLen: serviceid的长度
* @param [IN] request: 物模型服务对应的json参数信息,格式参考物模型定义中的inputData
* @param [IN] request_len: 参数信息的长度
* @param [OUT] response: 返回的response,格式参考物模型定义中的outputData,如 果没有返回值,则不需要处理此字段
* @param [OUT] responseLen: 返回的response的长度
* @return 0:成功, 其他值:错误码
*/
typedef xs_int32(*xs_serviceCallback)(xs_int32 devId, const xs_char *serviceid, const xs_uint32 serviceidLen,
const xs_char *request, const xs_uint32 request_len,
xs_char **response, xs_uint32 *responseLen);
用法示例:
/*处理物模型服务的消息回调,设备按照物模型中定义的Id 和参数进行解析*/
static xs_int32 handleServiceCallback(xs_int32 devId, const xs_char *serviceid, const xs_uint32 serviceidLen,
const xs_char *request, const xs_uint32 request_len,
xs_char **response, xs_uint32 *responseLen)
{
LOG_PRINT("handle service callback| devId:%d | serviceId:%s | request:%s\n",
devId, serviceid, request);
/* 此处需解析serviceId以及对应的输入参数
* 以开始操作PTZ转动为例(StartPTZAction), 设备收到的回调 中:
* serviceId= "StartPTZAction", request = "{\"ActionType\":1,\"Speed\":2}"
*/
return XSIOT_EC_SUCCESS;
}
*注意:返回值中 response 如果不为 NULL,SDK 内部会调用 free 函数将其释放
OTA 固件在线升级
OTA固件升级功能,一般按照如下步骤操作:
- 设备上报版本号和对应模块信息
- 控制台配置升级包信息,和测试设备信息,并上传升级包到控制台
- APP检测到升级,点击升级按钮触发升级
- 设备收到固件升级的回调通知(upgradeCb 回调)
- 设备开始下载升级包、并安装,升级过程中需要上报下载和升级进度。
详细描述如下: