1. 概述
微信硬件直连SDK是微信硬件平台对外提供的,能够帮助设备自动登录微信硬件云的设备SDK库,目前仅支持Wi-Fi设备使用。
采用微信硬件直连SDK,能够降低智能设备接入微信硬件云的开发门槛。开发者只需要按照微信硬件云规范的格式生成数据并调用SDK接口上报数据,同时解析和处理服务器返回或推送下来的业务数据即可,设备应用层不需要处理登录、鉴权等网络逻辑。
2. 使用说明
2.1 通信数据流说明
目前设备直连SDK主要为硬件创建了上行和下行的数据通道。设备应用层不需要处理登录,鉴权等网络逻辑,只需要负责按微信硬件云平台的格式生成数据并调用SDK接口上报数据,同时解析和处理服务器返回或推送下来的业务数据即可。本章节将对设备上报的数据格式、服务响应数据格式、服务器推送数据格式进行说明,在下一章节中将对不同平台的SDK使用方式进行说明。
由于微信硬件云提供的业务较多,同时不同业务间的数据格式不一致,为了实现SDK对不同业务之间的兼容性,SDK给微信硬件云平台的各项业务分配了唯一的ID,本文所描述的是微信硬件云平台设备能力项业务,对应的ID为1,厂家在调用接口或收到消息时通过业务ID来使用对应的数据格式解析报文。
设备主动上报数据
在设备联网,并且SDK处于运行状态下时,设备应用层可以通过SDK的发送数据接口上报数据给微信服务器。本章节使用的接口名称只为介绍方便,具体的接口格式请参照各平台SDK的介绍部分。在上报数据接口中需要传入设备所使用的业务ID(如本文描述的设备能力项业务的ID为1),以及要发送的数据内容,注意数据内容的格式要按业务要求进行封装。调用上报数据的接口如果返回值为0表示创建发送任务失败,很可能是没有调用SDK的初始化接口导致,下面以设备能力项业务为例进行说明,上行通道中的数据主要包含两种,一是设备主动上报一些状态,二是设备在收到服务器推送下来的通知后上报响应数据给服务器。设备主动上报的示例格式如下:
{
“msg_type”: “notify”,
“services”: {
“operation_status”: {
“status”: 1
},
“air_conditioner”: {
“tempe_indoor”: 26,
“tempe_outdoor”: 31,
“tempe_target”: 26,
“fan_speed”: 50
……
}
……
}
}
微信硬件云端响应JSON格式包,里面带有本次notify的唯一标识msg_id,设备收到下面的回包时表示服务器已经承接了设备的该项请求,请求的处理结果会通过Notify的方式异步推送下来,并在该Notify的消息中带上对应的msg_id,设备应用层收到该Notify消息时就表示之前自己主动上报的请求已经处理完成了。SDK会通过onResponseCallback(int taskid, int errcode, int funcid, byte[] data);接口将服务器的回包返回给设备应用层,taskid为调用发送数据接口时的返回值,errcode为SDK链路层的错误码,跟业务(body)中的数据无关,成功时为0,funcid为设备能力项业务ID,本例中为1,data即为下面示例中的内容:
{
“error_code”: 0,
“error_msg”: “ok”,
“msg_id”: 1234567890123456
}
标签 | 类型 | 取值限制 | 含义 |
---|
msg_type | string | notify | 消息类型命令字,notify代表通知消息 |
services | string |
| 能力项键值集合,即微信硬件云平台规范的能力项键值 |
operation_status | string |
| 通知微信侧,必须带有运行状态能力项服务 |
status | int8 |
| 通知微信侧,必须带有运行状态能力项属性 |
air_conditioner | string |
| 微信硬件云平台规范的一项能力及其属性值,其他服务及完整的属性参考《产品能力定义指引》 |
error_code | int16 |
| 微信是否成功接收,0代码成功(其他错误码见附录) |
error_msg | string |
| 微信返回成功接收的信息 |
msg_id | int64 | 64位整型 | 消息序列号,用于异步通信,由微信生成,接收方异步接收到Notify时跟本次的Notify对应 |
设备通过onResponseCallback接收到响应以后,只能说明设备的请求服务器已经接收到了,处理结果需要通过异步的方式推送下来onNotifyCallback,并通过onResponseCallback中的msg_id来对应请求,异步推送下来的通知报文如下:
{
“asy_error_code”: 0,
“asy_error_msg”: “ok”,
“msg_id”: 1234567890123456,
“msg_type”: “notify”,
“services”: {
“operation_status”: {
“status”: 1
},
“air_conditioner”: {
“tempe_indoor”: 26,
“tempe_outdoor”: 31,
“tempe_target”: 26,
“fan_speed”: 50
……
}
....
}
}
标签 | 类型 | 取值限制 | 含义 |
---|
asy_error_code | int16 |
| 设备厂商异步设置结果,其他错误请见附录 |
asy_error_msg | string |
| 设备厂商异步查询结果的,消息文本描述 |
msg_id | int64 | 和微信返回请求体里面的msgi_id一致 |
|
msg_type | string | 和请求里面的msg_type一样,为notify |
|
services | string | 和请求里面的services一样 |
|
operation_status | string | 和请求里面的operation_status一样 |
|
status | int8 | 和请求里面的status一样 |
|
●服务器推送控制请求
对于服务器发送过来的请求,SDK会通过onNotifyCallback接口通知设备应用层,如下是微信硬件云推送下来的控制设备的请求:
{
“msg_id”: 1234567890123456,
“user”: “user”,
“msg_type”: “set”,
“services”: {
“air_conditioner”: {
“tempe_indoor”: 26,
“tempe_outdoor”: 31,
“tempe_target”: 26,
“fan_speed”: 50
…..
}
...
}
}
标签 | 类型 | 取值限制 | 含义 |
---|
msg_id | int64 | 64位整型 | 消息序列号,用于异步通信,由微信生成,接收方异步返回的时候带上 |
user | string | 无 | operator操作者唯一标识ID |
msg_type | string | set | 消息类型命令字,set代表设备控制消息 |
services | string |
| 能力项键集合 |
设备应用层收到上述控制命令以后,解析services中的字段,并按要求控制设备,完成控制以后,调用sendDataToServer接口上报结果,上报内容示例如下:
{
“asy_error_code”: 0,
“asy_error_msg”: “ok”,
“msg_id”: 1234567890123456,
“msg_type”: “set”,
“services”: {
“operation_status”: {
“status”: 1
},
…..
}
}
标签 | 类型 | 取值限制 | 含义 |
---|
asy_error_code | int16 |
| 设备厂商异步设置结果,其他错误请见附录 |
asy_error_msg | string |
| 设备厂商异步查询结果的,消息文本描述 |
msg_id | int64 | 和微信返回请求体里面的msgi_id一致 |
|
msg_type | string | 和请求里面的msg_type一样,为set |
|
services | string |
| 能力项键集合(定义详见附录) |
operation_status | string |
| 必须返回运行状态能力项服务 |
status | int8 |
| 必须返回运行状态能力项服务 |
●服务器推送查询请求
在某些情况下,微信硬件云需要查询设备的状态信息,这个时候微信硬件云推送下来的获取设备状态的报文格式如下:
{
“msg_id”: 1234567890123456,
“user”: “user”,
“msg_type”: “get”,
“services”: {
“operation_status”: {
“status”: 0
},
“air_conditioner”: {
“tempe_indoor”: 0,
“tempe_outdoor”: 0,
“tempe_target”: 0,
“fan_speed”: 0
…..
}
...
}
}
设备接收到该请求以后,根据请求的services内容打包数据,并调用sendDataToServer接口上报结果,示例如下:
{
“msg_id”: 1234567890123456,
“user”: “user”,
“msg_type”: “get”,
“services”: {
“operation_status”: {
“status”: 0
},
“air_conditioner”: {
“tempe_indoor”: 26,
“tempe_outdoor”: 31,
“tempe_target”: 26,
“fan_speed”: 50
…..
}
}
}
2.2 Android版本使用说明
目前微信硬件云平台提供了多个平台的直连SDK,设备直连SDK主要为硬件创建了上行和下行的数据通道,设备应用层只需要处理业务流数据,并执行对设备的控制等操作即可。
对于运行于Android系统的设备,微信提供对应的SDK(.so库)且不依赖于设备所使用的Android版本,开发者只需要将SDK动态库和API类文件加载到App中即可,目前文件包括:libwxcloud.so, libstlport_shared.so,/com/tencent/wechat/Cloud.java共3个文件, 注意不得修改包名及方法名否则动态库无法使用,SDK运行中会通过Logcat打印数据,使用过程中遇到问题可以把log导出。详细的工程和代码示例请参考android_demo工程,可以通过Eclipse直接import的方式导入:
动态库和接口文件在工程中的结构如下:
A.加载动态库
由于SDK需要用到网络,如果是新建工程记得在xml中添加网络权限。设备App启动以后,需要加载对应的动态库,如果App有Application入口,可以放在Application入口处:
B.初始化启动SDK
App启动后,通过Cloud.init(deviceLicence);接口初始化并启动SDK,其中deviceLicence为直连设备在微信后台授权注册时由微信生成并返回的设备证书,格式为String,详细信息请通过平台基础消息接口- 设备授权新接口获取, 每个设备都有唯一的一个证书,每个证书只能在一台设备上使用:
C.API接口说明
●初始化启动SDK
接口原型 | public static native boolean init(String deviceLicence); |
参数 | String deviceLicence | 设备证书,由微信后台生成并返回,查看设备授权注册接口 |
返回值 | True/False | 初始化成功/失败 |
●发送数据给服务器
接口原型 | public static native int sendDataToServer(int funcid, String body); |
参数 | int funcid | 微信硬件云平台业务ID,能力服务项业务为1 |
String body | 要发送的数据内容,按业务要求填充报文 |
返回值 | 0/taskid | 返回0表示创建上报任务失败,可能是没有调用初始化接口,非0的话为SDK返回给设备应用层用于标识该任务的taskid,注意固件更新检查有专门API,不通过本API。 |
●检查是否有新固件
接口原型 | public static native int checkUpdate(String body); | 微信硬件平台提供的固件管理业务API |
参数 | String body | 当前的版本信息,按微信硬件平台业务要求填充报文,示例:暂无 |
返回值 | 0/taskid | 返回0表示创建上报任务失败,可能是没有调用初始化接口,非0的话为SDK返回给设备应用层用于标识该任务的taskid。 |
●获取当前证书对应的厂商ID
接口原型 | public static native String getVenderId(); |
参数 | 无 | 调用init接口后可以再调用本接口获取当前Licence对应的VenderID, 之前命名为deviceType |
返回值 | 字符串 | 返回空字符串表示证书无效 |
●获取当前证书对应的设备ID
接口原型 | public static native String getDeviceId(); |
参数 | 无 | 调用init接口后可以再调用本接口获取当前Licence对应的DeviceID |
返回值 | 字符串 | 返回空字符串表示证书无效 |
●关闭微信直连SDK
接口原型 | public static native void release(); |
参数 | 无 |
|
返回值 | 无 |
|
●任务执行结果回调接口
接口原型 | public static void onResponseCallback(int taskid, int errcode, int funcid, byte[] data) |
参数 | int taskid | 该响应对应的任务id |
int errcode | 0的话表示网络链路层正常,非0为失败 |
int funcid | 标识数据是属于微信硬件云平台的哪个业务的。 |
byte[] data | 数据内容 |
返回值 | 无 |
|
●服务器推送消息回调接口
接口原型 | public static void onNotifyCallback(int funcid, byte[] data) |
参数 | int funcid | 标识数据是属于微信硬件云平台的哪个业务的。 |
byte[] data | 数据内容 |
返回值 | 无 |
|
●SDK事件通知回调接口
接口原型 | public static void onEventCallback(int event) |
参数 | int event | 事件类型,取值范围: private static int EVENT_VALUE_LOGIN = 1; private static int EVENT_VALUE_LOGOUT = 2; |
返回值 | 无 |
|
2.3 Linux等C++平台版本
对于运行Linux系统的设备,微信提供对应的C++版本静态库,由于Linux版本众多,编译工具链也不一,对于不在支持列表中的平台,可以下载对应的申请表填写后发到申请表中的邮箱地址进行申请,一般运行环境需要支持-lrt和-lpthread两个外部库。
A.SDK文件组成说明
目前SDK提供的文件主要包括以下几个:
WeChatAPI.h:
SDK提供给设备应用层调用的API接口,包括SDK初始化,回调函数注册,发送数据等接口。
libwxcloud.a:
SDK静态库文件,需要链接到工程中。
B.初始化启动SDK
在设备连接上路由器以后,调用WeChatAPI::instance()->start ()接口完成SDK的初始化,该API返回bool型,false的话一般是设备Licence无效。为了接收相关的回调,需要注册3个回调函数,通过WeChatAPI::instance()->setCallBack,WeChatAPI::instance()->setNotifyCallBack,WeChatAPI::instance()->setSDKEventCallBack这三个函数实现注册。至此在设备证书合法的情况下,SDK就开始正常运行了,示例代码如下:
如果设备需要向服务器发送业务数据,则调用WeChatAPI::instance()->sendDataToServer接口,第一个参数为业务ID(注意固件升级检查不能用此API),可以参考附录最后的表格,目前WeChatAPI::instance()->checkUpdate是微信硬件平台提供的固件管理业务,用于检查是否有新固件。
C.API接口说明
●初始化启动SDK
接口原型 | bool start(const char* devlicence, unsigned int licencelen); |
参数 | const char* devlicence | 设备证书,由微信后台生成并返回,查看设备授权注册接口 |
unsigned int licencelen | 证书长度 |
返回值 | True/False | 初始化成功/失败 |
●发送数据给服务器
接口原型 | int sendDataToServer(unsigned int funcid, const unsigned char* body, unsigned int bodylen); |
参数 | unsigned int funcid, | 微信硬件云平台业务ID,能力服务项业务为1 |
const unsigned char* body | 要发送的数据内容,按业务要求填充报文 |
unsigned int bodylen | 报文长度 |
返回值 | 0/taskid | 返回0表示创建上报任务失败,可能是没有调用初始化接口,非0的话为SDK返回给设备应用层用于标识该任务的taskid,注意固件更新检查有专门API,不通过本API。 |
●检查是否有新固件
接口原型 | int checkUpdate(const unsigned char* body, unsigned int bodylen); | 微信硬件平台提供的固件管理业务API |
参数 | const unsigned char* body, | 当前的版本信息,按微信硬件平台业务要求填充报文,示例:暂无 |
unsigned int bodylen | 数据长度 |
返回值 | 0/taskid | 返回0表示创建上报任务失败,可能是没有调用初始化接口,非0的话为SDK返回给设备应用层用于标识该任务的taskid。 |
●获取当前证书对应的厂商ID
接口原型 | std::string getVenderId(); |
参数 | 无 | 调用init接口后可以再调用本接口获取当前Licence对应的VenderID, 之前命名为deviceType |
返回值 | 字符串 | 返回空字符串表示证书无效 |
●获取当前证书对应的设备ID
接口原型 | std::string getDeviceId(); |
参数 | 无 | 调用init接口后可以再调用本接口获取当前Licence对应的DeviceID |
返回值 | 字符串 | 返回空字符串表示证书无效 |
●关闭微信直连SDK
接口原型 | void release(); |
参数 | 无 |
|
返回值 | 无 |
|
●注册任务执行结果回调接口
接口原型 | void setCallBack(onReceiveResponse _callback); | 所有的task都是通过本接口返回 |
参数 | onReceiveResponse _callback | 回调函数入口地址 |
返回值 | 无 |
|
示例 | void onWeChatCallBack(int taskid, int errcode, unsigned int funcid, const unsigned char* body, unsigned int bodylen) { std::cout << "Receive WeChat CallBack!" << std::endl; std::cout << " taskid = " << taskid << ", errcode = " << errcode << ", funcid = " << funcid << ", body = " << body << ", bodylen = " << bodylen << std::endl; std::cout << "End of WeChat CallBack!" << std::endl; } WeChatAPI::instance()->setCallBack(onWeChatCallBack); |
说明 | 注意不要在onWeChatCallBack做数据处理或阻塞的操作,因为该函数将运行于SDK的线程中,建议将数据拷贝到自己的线程中去处理,taskid为任务ID,errcode为链路层错误码,为0表示正常,funcid为微信业务ID,可参考最后附录,body是具体的数据,bodylen是数据长度。 |
●服务器推送消息回调接口
接口原型 | void setNotifyCallBack(onReceiveNotify _callback); |
参数 | onReceiveNotify _callback | 回调函数入口地址 |
返回值 | 无 |
|
示例 | void onRecevNotify(unsigned int funcid, const unsigned char* _body, unsigned int _bodylen) { std::string body = std::string((const char *)_body, _bodylen); std::cout << "Receive Notify funcid:" << funcid << ", body:" << _body << ", len:" << _bodylen << std::endl; } WeChatAPI::instance()->setNotifyCallBack(onRecevNotify); |
说明 | 注意不要在onRecevNotify做数据处理或阻塞的操作,因为该函数将运行于SDK的线程中,建议将数据拷贝到自己的线程中去处理, funcid为微信业务ID,可参考最后附录,_body是具体的数据,_bodylen是数据长度。 |
●SDK事件通知回调接口
接口原型 | void setSDKEventCallBack(onSDKEventCallback _callback); |
参数 | onSDKEventCallback _callback | 回调函数入口地址 |
返回值 | 无 |
|
示例 | void onHandleEvent (EventValue event_value) { std::cout << "Receive Event:" << event_value << std::endl; switch (event_value) { case EVENT_VALUE_LOGIN: std::cout << "Device login!!" << std::endl; break; case EVENT_VALUE_LOGOUT: std::cout << "Device logout!!" << std::endl; break; default: std::cout << "Unknown event!!" << std::endl; break; } } WeChatAPI::instance()->setSDKEventCallBack(onHandleEvent); enum EventValue { EVENT_VALUE_LOGIN = 1, EVENT_VALUE_LOGOUT = 2 }; |
说明 | 注意不要在onRecevNotify做数据处理或阻塞的操作,因为该函数将运行于SDK的线程中,建议将数据拷贝到自己的线程中去处理,event_value为对应的事件。 |
2.4 嵌入式C版本使用说明
对于运行嵌入式操作系统或者无操作系统的硬件平台,微信提供对应的静态库版本,对于不在支持列表中的平台,可以下载对应的申请表填写后发到申请表中的邮箱地址进行申请。
由于嵌入式平台种类较多,系统的资源和性能各异,微信硬件平台将核心逻辑代码进行了封装,将需要跨平台实现的代码通过外部函数的方式放出来,因此在将静态库添加到项目工程以后,开发者还需要根据airkiss_porting.h中定义的函数原型来实现函数实体,微信硬件平台也提供了几个平台的实现Demo,开发者可以下载下来参考着实现,下面以QCA4004为示例平台进行说明。
A.SDK文件组成说明
目前SDK提供的文件主要包括以下几个:
airkiss_types.h:
SDK使用到的数据类型、数据结构定义头文件。
airkiss_cloudapi.h:
SDK提供给设备应用层调用的API接口,包括SDK初始化,回调函数注册,发送数据等接口。
airkiss_porting.h:
SDK使用到的外部函数的原型,开发者需要根据本文件定义的所有函数原型实现相应的函数,并添加到工程中,否则编译链接静态库的时候会报错找不到函数,如本Demo实现的airkiss_porting_4004.c文件。
libwxcloud.a:
SDK静态库文件,需要链接到工程中。
B.初始化启动SDK
在设备连接上路由器以后,调用airkiss_cloud_init()接口完成SDK的初始化,然后再调用airkiss_regist_callbacks()接口注册相关的回调函数,这两个步骤完成以后,开发者就可以通过airkiss_cloud_sendmessage()接口发送数据给服务器了。如果运行的环境支持多线程,那么开发者可以直接开一个线程来调用airkiss_cloud_loop(),该函数的返回值为下一次期望调用airkiss_cloud_loop()的时间值,单位为毫秒(ms)。对于不支持多线程的系统,开发者可以在程序大循环中调用airkiss_cloud_loop(),然后在函数返回后再去处理数据或运行自己的逻辑代码,示例代码如下所示:
本示例Demo开启了多线程,SDK单独运行一个线程,示例代码如下,其中ak_loop_run_sign是一个全局变量,在设备成功连网以后会进行置位,充当信号的作用,实现比较简单,开发者可以用信号量或其他方式实现:
在设备应用线程中,每隔15s调用airkiss_cloud_sendmessage函数发起一次任务,示例代码如下:
数据内容为测试用,不是实际业务数据。对于不支持多线程的系统则直接可以在airkiss_cloud_loop()函数返回后调用airkiss_cloud_sendmessage函数发送数据。本示例的接收响应回调函数定义如下:
在多线程的环境下,由于ReceiveResponseCB函数实际运行的是SDK的线程,为了SDK运行正常,这里建议开发者只做数据拷贝工作,数据的具体解析和处理逻辑放到别的线程中去执行,如果是单线程的则没有关系。 另外注意body指针指向的内容在函数返回后就会进行释放,所以多线程的话要对数据进行拷贝,不能复制指针。本示例的接收推送消息的回调函数定义如下:
推送消息回调函数的处理方式与接收响应回调函数的处理方式一致。在SDK运行的过程中会发送一些事件消息给应用开发者,目前包括登录态,示例如下:
C.API接口说明
●获取SDK版本信息
接口原型 | const char* airkiss_cloud_version(); |
参数 | 无 |
|
返回值 | 以\0结尾的字符串 | 可以直接打印,反馈问题需提供 |
●初始化SDK
接口原型 | int32_t airkiss_cloud_init(uint8_t *devlicence, uint32_t licencelen, ak_mutex_t* ak_task_mt, ak_mutex_t* ak_mem_mt, void* heap, uint32_t heaplen); |
参数 | uint8_t* devlicence | 设备证书,由微信后台生成并返回,查看设备授权注册接口 |
uint32_t licencelen | licence的有效长度 |
ak_mutex_t* ak_task_mt, ak_mutex_t* ak_mem_mt, | 多线程方式运行SDK时提供常量指针,如本示例中的传入参数为全局变量 |
void* heap | 提供给SDK的堆空间起始地址,为了避免地址对齐问题, 建议定义一个全局的int数组,并把数组地址传入,为保证SDK正常运行,最少4KB,4KB情况下允许同时运行2个任务,8KB运行同时运行4个任务,前提是每个任务的数据不要超过1KB,空间用完启动任务会返回失败,需要等其他任务完成或超时才能继续启动新任务 |
uint32_t heaplen | 堆空间大小,以字节为单位 |
返回值 | 0为成功,非0表示失败 |
|
●注册回调函数
接口原型 | void airkiss_regist_callbacks(airkiss_callbacks_t* _callbacks); |
参数 | airkiss_callbacks_t* _callbacks | 回调函数的结构体指针,如: |
typedef struct { airkiss_onresponse_fn m_respcb; airkiss_onnitify_fn m_notifycb; airkiss_onsdkevent_fn m_eventcb; } airkiss_callbacks_t; | 回调函数实现原型示例及参数赋值见上一小节 |
返回值 | 无 |
|