API文档
本章适用的设备:设备的控制逻辑与WiFi联网功能部署在同一个WiFi芯片上,如果您的设备不属于这种情况,请跳转到WiFi设备开发指导-开发环境准备。
本章先介绍嵌入式WiFi开发者在使用API时需要掌握的基本概念,然后分功能介绍Ablecloud提供给嵌入式WiFi设备的所有的API。
基本概念
开发者通过调用Ablecloud的API可以实现与云端/移动端之间的消息交互,开发者不需要关心交互的消息的完整格式,只需要掌握如下概念:
(1)消息构成
对开发者来说,设备与云端之间的消息由以下部分构成:
名称 | 作用 |
---|---|
MsgSN | 消息的序号(Msg Sequence Number),设备主动上报时填0;设备响应云端指令时必须填写对应的云端指令携带的MsgSN |
MsgCode | 标识payload的类型 |
Payloadlen | 消息携带的payload的长度,以字节为单位 |
payload | 消息体 |
(2)MsgCode
MsgCode用来标识设备与云端交互的消息类型,云端和设备端根据对应的MsgCode区分消息携带的payload的类型。
消息类型表(MsgCode)如下:
MsgCode | 消息类型 | 消息类型说明 |
---|---|---|
2 | AC_CODE_WIFI_CONNECTED | WiFi链接成功通知 |
3 | AC_CODE_WIFI_DISCONNECTED | WiFi断链通知 |
4 | AC_CODE_CLOUD_CONNECTED | 云端链接成功通知 |
5 | AC_CODE_CLOUD_DISCONNECTED | 云端链接断链通知 |
17 | ZC_CODE_OTA_BEGIN | MCU OTA开始通知 |
18 | ZC_CODE_OTA_FILE_BEGIN | MCU OTA文件传输开始通知 |
19 | ZC_CODE_OTA_FILE_CHUNK | MCU OTA文件块到达通知 |
20 | ZC_CODE_OTA_FILE_END | MCU OTA文件传输结束通知 |
21 | ZC_CODE_OTA_END | MCU OTA结束通知 |
63 | ZC_CODE_SUBSCRIBE_REPORT | 请求设备快速上报通知 |
64 | AC_EVENT_BASE | 设备自定义控制消息基址 |
[64,200) | AC_EVENT_CONTROL_AND_RESPONSE | 设备自定义,由服务或APP发给设备的控制消息以及设备的应答消息 |
[200,255] | AC_EVENT_DEVICE_REPORT | 设备自定义,设备上报信息 |
注意: 小于64的MsgCode是AC使用的消息码,开发者不能占用。[64,255]是提供给开发者的设备自定义消息码,开发者使用时需要遵守表中的规则,且要与移动端及UDS协商一致
(3)payload
是由MsgCode定义的消息类型的具体内容。payload的格式可以是二进制,也可以是JSON。
服务器环境配置接口
Ablecloud为开发者提供了用于开发测试的dev环境,以及用于产品正式生产使用的生产环境。通过在ac_cfg.h
中修改CLOUD_ADDR
的值,可以选择不同的环境。
宏CLOUD_ADDR
的取值:
AC_DEV_SERVER :测试环境,对应test.ablecloud.cn
AC_CH_SERVER:生产环境-中国,对应device.ablecloud.cn
AC_US_SERVER:生产环境-美洲,对应usdevice.ablecloud.cn
AC_EU_SERVER:生产环境-欧洲,对应eudevice.ablecloud.cn
AC_EA_SERVER:生产环境-东南亚,对应eadevice.ablecloud.cn
WiFi行为控制接口
进入配网状态
- WiFi设备是通过WiFi模块连接上路由器,再与广域网相连接的,所以WiFi设备要连接到云端,第一步就是连接上路由器。配网即指:利用smartLink、AirKiss等技术,通过路由器、WiFi模块以及连接上路由器的手机APP的协同工作,实现在WiFi模块不知道路由器的SSID和密码的情况下,使WiFi模块获取到路由器的信息、并连接上路由器的过程。
- 配网状态即WiFi模块进入smartLink或AirKiss等状态,准备好开始配网流程的状态。
- WiFi模块进入配网状态后,会等待APP在局域网广播的路由器的SSID和密码,获取到密码后,WiFi模块会连接到路由器并通过DHCP获取到IP地址。
- 配网的功能由WiFi芯片商实现,Ablecloud提供的API会通知WiFi芯片进入配网状态。
- 配网的具体技术细节请参考“SmartLink”和“AirKiss”等
API:
void AC_SendRestMsg(void);
API行为:
- 清除WiFi模块存储的上次连接的路由器的信息
- 重启设备,设备重启后进入配网状态
触发设备进入AP模式
通常WiFi芯片支持Sta模式和AP模式。
AP模式: Access Point,提供无线接入服务,允许其它无线设备接入,提供数据访问。AP和AP之间允许相互连接
Sta模式: Station, 类似于无线终端,Sta本身并不接受无线的接入,它可以连接到AP,通过AP接入广域网或其他网络。
通常,WiFi模块的AP模式用于AP配网:由于部分路由器不支持广播,导致WiFi模块在Sta模式下无法完成配网。转为AP模式,手机APP可以先接入WiFi模块,然后将要连接的路由器的SSID和密码发送给WiFi模块,之后WiFi模块再切换为Sta模式,连接路由器,完成配网流程。
API:
ZC_ErrorCode AC_SendSetApMsg(u8 *pu8ApName,u8 u8Len)
参数
字段 | 类型 | 说明 |
---|---|---|
pu8ApName | u8 * | 存储WiFi模块进入AP模式后的SSID的字符串的首地址 |
u8Len | u8 | WiFi模块进入AP模式后的SSID的长度,不能超过27个字节(超出的部分会被截掉) |
返回值
值 | 意义 |
---|---|
ZC_RET_OK | 配置AP模式成功 |
ZC_PARA_ERROR | 配置AP模式失败,入参无效或内存分配失败 |
API行为:
- 重启WiFi模块
- 重启后,WiFi模块进入AP模式,AP的SSID为入参 pu8ApName
指向的字符串+Mac地址的后四位,密码固定为123456789
重启WiFi模块
API:
void AC_SendRebootMsg(void);
API行为:
- 重启WiFi芯片。重启后,如果Flash中存储了上次连接的路由器的信息,则WiFi模块会直接连接路由器,否则等待APP进行配网
休眠唤醒
如果WiFi芯片具有休眠功能,则这组API会使WiFi芯片进入/切出休眠状态。不同的WiFi芯片,其休眠状态的行为不完全一致。通常来讲,进入休眠状态的WiFi芯片,其射频部分会被关闭,此时设备无法再与外界进行通信。在不需要与外界通信时进入休眠状态,可以降低设备的功耗。
API:
void AC_SendSleepMsg(void);
void AC_SendWakeUpMsg(void);
API行为:
- 第一个API关闭WiFi芯片的射频部分,使设备进入低功耗状态
- 第二个API打开WiFi芯片的射频部分,使设备进入正常工作模式
注意:
如果开启低功耗模式,设备的数据收发会受到影响,使用时请注意。
局域网通信接口
局域网通信加密方式配置接口
接口定义
void AC_SetLocalLevel(PCT_LOCAL_LEVEL Etoken);
参数
字段 | 类型 | 说明 |
---|---|---|
Etoken | PCT_LOCAL_LEVEL | 局域网通信加密方式 |
typedef enum
{
PCT_LOCAL_NONE_TOKEN = 0, /*不加密*/
PCT_LOCAL_STATIC_TOKEN = 1, /*静态加密*/
PCT_LOCAL_DYNAMIC_TOKEN = 2 /*动态加密*/
}PCT_LOCAL_LEVEL;
注意:
一般不建议开发者使用无加密的方式。AC联网SDK默认采用动态加密的方式,如果开发者要使用静态加密,可以在ac_cfg.h
中添加预定义宏LOCAL_STATIC_TOKEN
。所以开发者一般不需要关心这个API。
通知类型消息处理接口
当设备的网络连接状态发生变化,如连接上路由器、连接上云端等,Ablecloud联网模块会通过函数接口通知开发者,开发者可以在该函数接口中添加自己的处理逻辑,如点亮相应的灯,显示WiFi连接状态。
所在文件
ac_hal.c
接口定义
void AC_DealNotifyMessage(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList, u8 *pu8Playload);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到的数据 |
pstruOptList | AC_OptList * | 解析后的option项 |
pu8Playload | u8 * | 指向Playload数据起始位置 |
默认实现
void AC_DealNotifyMessage(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList, u8 *pu8Playload)
{
//deal notify message about state of WiFi connection and cloud connection
switch(pstruMsg->MsgCode)
{
case ZC_CODE_WIFI_CONNECTED://WiFi module disconnect with AP
{
AC_SendDeviceRegsiter(g_u8EqVersion,g_u8ModuleKey,(u8*)&g_u64Domain,g_u8DeviceId);
break;
}
case ZC_CODE_WIFI_DISCONNECTED://WiFi module disconnect with AP
{
ZC_Printf(eLL_Info, eMT_Tbc, "AC_DealNotifyMessage WiFi disconnect\n");
break;
}
case ZC_CODE_CLOUD_CONNECTED://WiFi module connect with cloud
{
#if defined(DEMO_REPORT)
UserCallback_CloudConnect();
#endif
AC_StoreStatus(CLOUDSTATUS,CLOUDCONNECT);
break;
}
case ZC_CODE_CLOUD_DISCONNECTED://WiFi module disconnect with cloud
{
#if defined(DEMO_REPORT)
UserCallback_CloudDisconnect();
#endif
AC_StoreStatus(CLOUDSTATUS,CLOUDDISCONNECT);
break;
}
case ZC_CODE_NTP:
{
AC_HandleNtp((ZC_NTP_TIME*)pu8Playload);
break;
}
case ZC_CODE_LQ://ntp timer
{
AC_HandleLinkQuality((s8)pu8Playload[0]);
break;
}
case ZC_CODE_SUBSCRIBE_REPORT:
{
AC_SendDeviceStatus(pstruOptList);
break;
}
default:
{
ZC_Printf(eLL_Err, eMT_Prot, "AC_DealNotifyMessage error\n");
break;
}
}
}
网络连接状态事件通知
ZC_CODE_WIFI_CONNECTED
,ZC_CODE_WIFI_DISCONNECTED
,ZC_CODE_CLOUD_CONNECTED
,ZC_CODE_CLOUD_DISCONNECTED
分别是WiFi连接上路由器,WiFi与路由器连接断开,WiFI连接上云端,WiFi与云端连接断开的事件通知。
开发者可以在此添加自己的控制逻辑,如点亮LED指示灯。
设备注册接口
设备进行联网注册的逻辑已经由AC联网模块完成,开发者只需要关心是使用MAC地址还是使用自定义ID作为设备的物理ID。
1.如果要使用WiFi模块的MAC作为物理ID,则需要在
ZC_CODE_WIFI_CONNECTED
事件中调用APIAC_SendDeviceRegsiter
时,将最后一个参数置位NULL
2.如果要使用自定义ID作为物理ID,则需要在ZC_CODE_WIFI_CONNECTED
事件中调用APIAC_SendDeviceRegsiter
时,将最后一个参数改为g_u8DeviceId
3.如果使用自定义ID作为物理ID,开发者可以修改ac_cfg.h
中的预定义宏DEVICE_ID
,也可以在调用ZC_Init
之前自行为数组g_u8DeviceId
赋值,作为设备的物理ID
设备属性快速上报请求通知
Ablecloud提供了设备属性快速上报的功能,主要针对以下两种场景:
1.通过云端快速上报设备属性
当有APP打开时,用户有可能想更实时的查看到设备的状态变化,此时需要设备提高上报频率;而当没有APP打开时,设备的上报频率可以降低
2.局域网内快速上报设备属性
在局域网内,当有APP打开时,用户有可能想更实时的收到设备状态的上报消息。
对于场景1,设备上报的频率及持续时间是由APP开发者配置的,对于场景2,设备上报的频率是默认的(3秒一次)。
当需要设备上报属性时,AC联网模块会发送事件ZC_CODE_SUBSCRIBE_REPORT
给UserApp,UserApp需要在该事件通知中构造并上报设备的全量信息。开发示例如下:
void AC_DealNotifyMessage(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList, u8 *pu8Playload)
{
//deal notify message about state of WiFi connection and cloud connection
switch(pstruMsg->MsgCode)
{
.
.
.
.
case ZC_CODE_SUBSCRIBE_REPORT:
{
AC_SendDeviceStatus(pstruOptList);
break;
}
default:
{
ZC_Printf(eLL_Err, eMT_Prot, "AC_DealNotifyMessage error\n");
break;
}
}
}
void AC_SendDeviceStatus(AC_OptList *pstruOptList)
{
u8 DeviceStatus[100] = {0};
/*开发者需要自行构造上报消息的内容*/
AC_SendMessage(MSG_SERVER_CLIENT_GET_LED_STATUS_RSP,0,
(u8*)&DeviceStatus, sizeof(DeviceStatus),
pstruOptList);
}
注意:
1.无论是云端快速上报请求还是局域网快速上报请求,AC联网模块都是通过上述接口通知开发者的,开发者可以通过入参
pstruOptList
是否为空来判断本次上报是发送给云端还是局域网。如果pstruOptList
为空,则本次上报是发送给云端(UDS)的;如果pstruOptList
不为空,则本次上报是发送给局域网内的APP的。
2.对于局域网快速上报,WiFi是通过局域网UDP广播发送给局域网内的所有APP的。
3.上报消息的MsgCode必须不小于200
设备控制消息处理接口
当WiFi模块接收相关的设备自定义控制消息后,会调用该接口。自定义消息的MsgCode必须大于等于64。
所在文件
ac_hal.c
接口定义
void AC_DealEvent(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList , u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到的数据的协议头 |
pstruOptList | AC_OptList * | 解析后的option项。如果该参数为空,则表明是云端发送来的消息;如果该参数不为空,则表明是局域网APP发送来的消息 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload的长度,单位为Byte |
开发示例
void AC_DealEvent(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList, u8 *pu8Payload, u16 u16PayloadLen)
{
//处理设备自定义控制消息
switch(pstruMsg->MsgCode)
{
case MSG_SERVER_CLIENT_SET_LED_ONOFF_REQ:
{
AC_DealLed(pstruMsg, pstruOptList, pu8Payload, u16PayloadLen);
}
break;
}
}
注意:
1.为了更好的体验,我们建议消息处理接口中,开发者在处理完控制逻辑后,将最新的设备状态作为响应信息返回给云端。
2. 开发者在处理完云端下发的指令后,如果要回复响应消息,请在调用AC_BuildMessage
API时,将AC_DealEvent
的入参pstruOptList
传递给AC_BuildMessage
函数。
3.开发者可以通过参数pstruOptList是否为NULL来判断消息来源是云端还是局域网。如果pstruOptList为NULL,则表明是云端消息;如果不为NULL,则表明是局域网消息
OTA接口
对于SoC方案,AC联网模块已经集成了OTA功能,开发者不需要做额外的开发,也不建议开发者修改OTA的流程。
如果开发者希望自行处理OTA的事件通知和数据包,AC联网模块也提供了相关的接口(但是强烈不建议开发者自行修改),在ac_hal.c
文件中的函数AC_DealEvent
中,AC_DealEvent
的接口描述参见上一小节。
void AC_DealEvent(ZC_MessageHead *pstruMsg, AC_OptList *pstruOptList,u8 *pu8Payload, u16 u16PayloadLen)
{
/*deal with message defined by device.*/
switch(pstruMsg->MsgCode)
{
.
.
.
case ZC_CODE_OTA_BEGIN:
{
AC_DealEvent_OtaBegin(pstruMsg, pu8Payload, u16PayloadLen);
break;
}
case ZC_CODE_OTA_FILE_BEGIN:
{
AC_DealEvent_OtaFileBegin(pstruMsg, pu8Payload, u16PayloadLen);
break;
}
case ZC_CODE_OTA_FILE_CHUNK:
{
AC_DealEvent_OtaFileChunk(pstruMsg, pu8Payload, u16PayloadLen);
break;
}
case ZC_CODE_OTA_FILE_END:
{
AC_DealEvent_OtaFileEnd(pstruMsg, pu8Payload, u16PayloadLen);
break;
}
case ZC_CODE_OTA_END:
{
AC_DealEvent_OtaEnd(pstruMsg, pu8Payload, u16PayloadLen);
break;
}
.
.
.
}
}
OTA开始事件处理接口
所在文件
ac_hal.c
接口定义
void AC_DealEvent_OtaBegin(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到数据的协议头 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload数据的长度(单位为byte) |
其中payload是一个ZC_OtaBeginReq
类型的报文,定义如下:
typedef struct
{
u8 u8FileNum;
u8 u8Pad[3];
}ZC_OtaBeginReq;
字段 | 类型 | 说明 |
---|---|---|
u8FileNum | u8 | OTA文件数目 |
u8Pad | u8 | padding,补齐用 |
默认实现
void AC_DealEvent_OtaBegin(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen)
{
ZC_OtaBeginReq struOtaBegin;
if (u16PayloadLen != sizeof(ZC_OtaBeginReq))
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaBegin Err! payload len is invalid %d\n", u16PayloadLen);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
memcpy(&struOtaBegin, pu8Payload, sizeof(ZC_OtaBeginReq));
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaBegin, file num is %d\n", struOtaBegin.u8FileNum);
ZC_CheckResponse(ZC_CODE_ACK, pstruMsg->MsgSN);
return;
}
OTA文件传输开始事件处理接口
所在文件
ac_hal.c
接口定义
void AC_DealEvent_OtaFileBegin(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到数据的协议头 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload数据的长度(单位为byte) |
其中payload是一个ZC_OtaFileBeginReq
类型的报文,定义如下:
typedef struct
{
u8 u8FileType;
u8 u8FileVersion;
u8 u8TotalFileCrc[2];
u32 u32FileTotalLen;
}ZC_OtaFileBeginReq;
字段 | 类型 | 说明 |
---|---|---|
u8FileType | u8 | OTA文件类型 |
u8FileVersion | u8 | OTA版本号 |
u8TotalFileCrc | u8 | OTA文件CRC值 |
u32FileTotalLen | u8 | OTA文件总长度(单位为byte) |
默认实现
void AC_DealEvent_OtaFileBegin(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen)
{
ZC_OtaFileBeginReq struFileBegin;
if (u16PayloadLen != sizeof(ZC_OtaFileBeginReq))
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileBegin Err! payload len is invalid %d\n", u16PayloadLen);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
if (NULL != gpFdFirmware)
{
//fclose(gpFdFirmware);
gpFdFirmware = NULL;
}
//gpFdFirmware = fopen(OtaFileLocalPath, "wb"); /* open the file */
if (NULL == gpFdFirmware)
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileBegin open file failed\n");
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
OtaFileCrcLocal = 0;
memcpy(&struFileBegin, pu8Payload, sizeof(ZC_OtaFileBeginReq));
OtaFileCrcRemote = struFileBegin.u8TotalFileCrc[0]*256+struFileBegin.u8TotalFileCrc[1];
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaFileBegin: \nfileType:\t%d\nfileVersion:\t%d\nCRC:\t%x %x\nfiltLen:\t%d\n",
struFileBegin.u8FileType, struFileBegin.u8FileVersion, struFileBegin.u8TotalFileCrc[0],
struFileBegin.u8TotalFileCrc[1], struFileBegin.u32FileTotalLen);
ZC_CheckResponse(ZC_CODE_ACK, pstruMsg->MsgSN);
return;
}
OTA文件块到达处理接口
所在文件
ac_hal.c
接口定义
void AC_DealEvent_OtaFileChunk(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到数据的协议头 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload数据的长度(单位为byte) |
其中payload是一个ZC_OtaFileChunkReq
类型的报文,定义如下:
typedef struct
{
u32 u32Offset;
}ZC_OtaFileChunkReq;
字段 | 类型 | 说明 |
---|---|---|
u32Offset | u32 | OTA文件块偏移(单位为byte) |
默认实现
void AC_DealEvent_OtaFileChunk(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen)
{
ZC_OtaFileChunkReq struOtaFileChunkReq;
u8 *pOtaFileSegment = NULL;
size_t written = 0;
u16 OtaFileSegmentSize = 0;
if (u16PayloadLen <= sizeof(ZC_OtaFileChunkReq))
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileChunk Err! payload len is invalid %d\n", u16PayloadLen);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
memcpy(&struOtaFileChunkReq, pu8Payload, sizeof(ZC_OtaFileChunkReq));
pOtaFileSegment = pu8Payload + sizeof(ZC_OtaFileChunkReq);
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaFileChunk, offset is %d\n", ZC_HTONL(struOtaFileChunkReq.u32Offset));
if (NULL == gpFdFirmware)
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileChunk Err! Firmware file not exist\n");
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
OtaFileSegmentSize = u16PayloadLen - sizeof(ZC_OtaFileChunkReq);
// written = fwrite(pOtaFileSegment, sizeof(char), OtaFileSegmentSize, gpFdFirmware);
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaFileChunk wrtten block num: %d\n", written);
OtaFileCrcLocal = crc16_ccitt_segment(OtaFileCrcLocal, (const u8*)pOtaFileSegment, OtaFileSegmentSize);
ZC_CheckResponse(ZC_CODE_ACK, pstruMsg->MsgSN);
return;
}
OTA文件传输结束处理接口
所在文件
ac_hal.c
接口定义
void AC_DealEvent_OtaFileEnd(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到数据的协议头 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload数据的长度(单位为byte) |
默认实现
void AC_DealEvent_OtaFileEnd(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen)
{
if (u16PayloadLen != 0)
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileEnd Err! payload len is invalid %d\n", u16PayloadLen);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
if (OtaFileCrcRemote != OtaFileCrcLocal)
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaFileEnd err! CRC failed! local crc is %x, remote crc is %x\n", OtaFileCrcLocal, OtaFileCrcRemote);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
}
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaFileEnd OK\n");
/*todo write OTA segment to local file*/
ZC_CheckResponse(ZC_CODE_ACK, pstruMsg->MsgSN);
return;
}
OTA结束事件处理接口
所在文件
ac_hal.c
接口定义
void AC_DealEvent_OtaEnd(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen);
参数
字段 | 类型 | 说明 |
---|---|---|
pstruMsg | ZC_MessageHead * | 收到数据的协议头 |
pu8Payload | u8 * | 指向Payload数据起始位置 |
u16PayloadLen | u16 | Payload数据的长度(单位为byte) |
默认实现
void AC_DealEvent_OtaEnd(ZC_MessageHead *pstruMsg, u8 *pu8Payload, u16 u16PayloadLen)
{
char cpCmd[200] = {0};
if (u16PayloadLen != 0)
{
ZC_Printf(eLL_Err, eMT_OTA, "AC_DealEvent_OtaEnd Err! payload len is invalid %d\n", u16PayloadLen);
ZC_CheckResponse(ZC_CODE_ERR, pstruMsg->MsgSN);
return;
}
/*todo write OTA segment to local file*/
ZC_CheckResponse(ZC_CODE_ACK, pstruMsg->MsgSN);
ZC_Printf(eLL_Info, eMT_OTA, "AC_DealEvent_OtaEnd OTA chunk finished\n");
/*resource free begin*/
g_struProtocolController.pstruMoudleFun->pfunReleaseSource();
/*resource free end*/
/*todo @developer: developer should add itself code here to release source.*/
ZC_Printf(eLL_Info, eMT_OTA, "WRTnode_FirmwareUpdateFinish Err! TCP OTA should not be executed\n");
sprintf(cpCmd, "mv %s /tmp/AbcloudFirmware.tar.gz", OtaFileLocalPath);
// if (-1 == system(cpCmd))
{
ZC_Printf(eLL_Err, eMT_OTA, "system cmd mv failed\n");
return;
}
// exit(0);
return;
}
强制解绑设备接口
设备与APP用户绑定后,开发者在需要时可以调用API强制解除该绑定关系。
API:
void AC_SendUbindMsg(void);
API行为:
通知Ablecloud联网模块发起设备绑定关系强制解除操作
与云端通信接口
设备与云端的交互流程及代码开发框架具体流程参见WiFi设备开发指导中的“接收云端消息”和“处理云端消息”的描述。这里只描述相关API的具体信息及开发示例。
数据组包发送接口
开发者调用 AC_BuildMessage
API按云端协议格式组包后,调用该API将数据交给Ablecloude的联网模块,Ablecloud会将其发送给云端。
API:
ZC_ErrorCode AC_SendMessage(
u8 u8MsgCode,
u8 u8MsgSN,
u8 *pu8Payload,
u16 u16PayloadLen,
AC_OptList *pstruOptList
)
参数
字段 | 类型 | 说明 |
---|---|---|
u8MsgCode | u8 | 消息类型 |
u8MsgSN | u8 | 消息序列号,设备主动上报时填0,响应时填写对应的云端下发指令的u8MsgSN |
pu8Payload | u8 * | 消息体,设备发送的消息的实际内容。如果不需要发送payload,该参数填NULL |
u16PayloadLen | u16 | 消息实际长度 |
pstruOptList | AC_OptList * | Option项列表,设备主动上报时填NULL,响应时直接将下行控制消息中的pstruOptList填在该处 |
返回值
值 | 意义 |
---|---|
ZC_RET_OK | 发送成功(不代表已经被接收端成功接收) |
ZC_PAYLOAD_LEN_OVERFLOW | 发送失败,发送的消息过长 |
ZC_RET_ERROR | 发送失败,其他原因 |
API行为:
- Ablelcoude联网模块会将数据发送给云端
开发示例
/*上报数据包=code:203 + req:{1,0,0,0}*/
typedef struct tag_STRU_LED_ONOFF
{
u8 u8LedOnOff ; // 0:关,1:开
u8 u8ControlStatus;//0为APP控制开关,1为按键控制开关
u8 u8Pad[2];
}STRU_LED_ONOFF;
void AC_SendStatus2Server(u8 u8control)
{
ZC_ErrorCode ret;
/*上报demo灯的状态*/
STRU_LED_ONOFF struReport;
u16 u16DataLen;
/*读取demo灯状态*/
struReport.u8LedOnOff = GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2);
struReport.u8LedOnOff = struRsp.u8LedOnOff>>2;
struReport.u8ControlStatus = u8control;
/*构造并发送消息*/
ret = AC_SendMessage(203, 0, (u8*)&struReport, sizeof(STRU_LED_ONOFF), NULL);
if (ZC_RET_OK != ret)
{
ZC_Printf("AC_SendStatus2Server Err, AC_SendMessage failed\n");
return;
}
}
JSON格式
用户可调用第三方源码构造JSON格式的消息体。
//请求数据包
{ 203 :[
//关灯
{"switch", 0}
//开灯
{"switch", 1}
]
[
//APP控制开关
{"controltype", 0},
//按键控制开关
{"controltype", 1}
]}
void AC_SendLedStatus2Server(u8 controltype)
{
ZC_ErrorCode ret;
/*上报demo灯的状态*/
cJSON *root;
char *out;
u8 u8LedOnOff;
u16 u16DataLen;
/*JSON协议内存分配*/
root=cJSON_CreateObject();
u8LedOnOff = GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_2);
u8LedOnOff = u8LedOnOff>>2;
/*构造JSON消息体*/
cJSON_AddNumberToObject(root,"action", u8LedOnOff);
cJSON_AddNumberToObject(root,"controltype", controltype);
out=cJSON_Print(root);
cJSON_Delete(root);
/*发送消息*/
ret = AC_SendMessage(203, 0, (u8*)&out, strlen(out), NULL);
if (ZC_RET_OK != ret)
{
/*释放JSON消息*/
free(out);
ZC_Printf("AC_SendLedStatus2Server Err, AC_SendMessage failed\n");
return;
}
/*JSON协议内存释放*/
free(out);
}
NTP时间获取接口
触发获取NTP时间接口
API:
void AC_GetNtpTime(void);
API行为: - 触发AC联网模块到云端服务器获取NTP时间
注意:
获取NTP时间的前提是WiFi模块已经连接上外网
处理NTP结果的接口
开发者调用APIAC_GetNtpTime
触发AC联网模块获取NTP时间后,得到的结果会通过函数AC_HandleNtp
反馈给开发者。开发者可以在该函数中添加自己的处理逻辑。
API:
void AC_HandleNtp(ZC_NTP_TIME* ntp);
参数
typedef struct
{
u16 year;
u8 month;
u8 day;
u8 weekday;
u8 hour;
u8 min;
u8 sec;
u32 ntp_sec;
}ZC_NTP_TIME;
字段 | 类型 | 说明 |
---|---|---|
year | u16 | 年(UTC时间) |
month | u8 | 月(UTC时间) |
day | u8 | 日(UTC时间) |
weekday | u8 | 星期(UTC时间) |
hour | u8 | 时(UTC时间) |
min | u8 | 分(UTC时间) |
sec | u8 | 秒(UTC时间) |
ntp_sec | u32 | 当前时间距1970年1月1日00:00:00的描述(UTC时间) |
注意:
通过NTP获取到的时间是UTC时间,开发者如果需要本地时间,需要根据所在时区自行进行转换。
开发示例
void AC_HandleNtp(ZC_NTP_TIME* ntp)
{
ZC_Printf("ntp time is %d-%d-%d %d:%d:%d weekday is %d\n",ZC_HTONS(ntp->year),
ntp->month,
ntp->day,
ntp->hour,
ntp->min,
ntp->sec,
ntp->weekday);
}
获取信号质量接口
触发获取信号质量接口
API:
void AC_GetLinkQuality(void);
API行为:
- 触发AC联网模块到获取信号质量
处理获取信号的接口
开发者调用APIAC_GetLinkQuality
触发AC联网模块获取获取信号质量,如果模块联网得到的结果会通过函数AC_HandleLinkQuality
反馈给开发者。开发者可以在该函数中添加自己的处理逻辑;如果模块处在断网状态会收到在AC_DealNotifyMessage
收到断网通知消息
API:
void AC_HandleLinkQuality(s8 s8LinkQuality);
参数 取值范围[0,100],该值表征的是当前信号质量在信号质量范围内的百分比。该值越大信号质量最好
开发示例
void AC_HandleLinkQuality(s8 s8LinkQuality)
{
ZC_Printf("Link quality is %d\n",s8LinkQuality);
}
产测接口
Ablecloud针对开发者的产测需求提供了产测服务,具体流程请参见产测服务。
要触发进入产测模式,需要调用APIAC_SetProductTest
。
API:
void AC_SetProductTest();
API行为:
- 触发WiFi扫频,并连接产测路由器(SSID固定为AC_PRODUCT_TEST1或者AC_PRODUCT_TEST2),期间WiFi会自动重启。如果没有SSID为AC_PRODUCT_TEST1或者AC_PRODUCT_TEST2的路由器,则WiFi不会执行任何操作。