HeyThings SDK参考手册
版本记录
版本号 | 修改日期 | 修改内容 |
---|---|---|
v0.1 | 2021.03.15 | 整理汇总各模块文档形成参考手册 |
1 HeyThings 设备端软件架构
1.1 名词定义
名词 | 定义 |
---|---|
HeyThings IoT平台 | 基于HeyThings协议的云服务、APP客户端、设备间联动等的HeyThings IoT生态 |
HeyThings SDK | 实现了HeyThings协议的软件开发工具包,开发者在SDK的基础上,可快速完成产品接入 |
物模型 | 产品自身功能的抽象定义,一个设备抽象为具备多个服务的模型,每个服务包含支持的属性(property)、动作(action)、事件(event) |
物模型接口层 | 实现产品物模型的封装和解析接口,作为中间件代理应用层与SDK进行交互 |
产品应用层 | 产品的功能性应用代码,实现产品设备的实际业务操作和状态改变,通过物型接口层与SDK交互 |
1.2 软件架构图
2 产品应用层
产品应用层关注的主要是智能产品本身的功能逻辑、状态与控制等,要把产品本身的功能使用体验开发到极致。智能产品厂商期望能通过简单友好且快速的方式,迅速接入一个IoT生态平台,以便达到更大的经济效益。
3 物模型层
物模型是用来描述设备的互操作抽象的模型,每个设备可以拥有多个服务,每个服务可包含多个属性、动作和事件,通过标准的物模型可以获悉设备的信息、对应的功能属性、支持的动作和事件,从而达到设备自我描述和互操作的目的。
(上图实线框表示必须,虚线框表示可选)
3.1 物模型的内容
- 一个物理设备对应一个抽象模型device,如一个灯对应抽象为light;
- 一个抽象模型拥有多个服务,每个服务是一个独立的有意义的功能组;
- 一个服务包含多个属性properties、动作actions和事件events;
- 每个属性property明确定义属性含义、数据格式、访问方式、取值范围和精度、单位等;
- 每个动作action明确定义动作含义、输入属性列表、输出属性列表,不涉及属性读写或需要同时对多个属性读写才能完成一次有意义的操作时可以用动作来定义;
- 每个事件event明确定义事件含义、变化属性列表,对于简单的状态变化,将直接用属性的notify变化来通知用户,复杂的事件才使用event来表述。
3.2 物模型的描述
HeyThings协议目前的物模型描述框架使用Protobuf。Protocol Buffers(简称Protobuf)是一种序列化框架,与开发语言无关,和平台无关,具有良好的可扩展性,可以用于数据存储、通讯协议。
对一个具体设备的物模型服务,将有对应一份使用protobuf语法进行描述的proto文件,并可生成不同开发语言的序列化和反序列化接口。当模型文件进行更新时,相应的生成的接口也需要同步进行更新。
模型描述proto文件由HeyThings平台提供,以"[服务名].proto"
的方式命名,并由HeyThings平台的工具自动生成对应的序列化接口和物模型接口层代码。
4 HeyThings SDK
HeyThings SDK是HeyThings协议的实现及所提供的开发工具包,开发者使用该SDK,可以快速完成智能产品接入HeyThings IoT平台。
4.1 SDK实现的功能
HeyThings SDK 实现了以下功能:
- 建立与 HeyThings IoT 平台的可靠加密连接
- 负责设备添加、绑定与解绑
- 托管物模型服务,进行属性存储、获取与订阅等
- 控制协议事务转发等
4.2 SDK提供的服务
HeyThings SDK对进行接入产品的开发者提供了以下服务:
- 设备产品名称、固件版本等产品基础信息传入
- 设备配网绑定、连接HeyThings IoT平台等通用基础业务接口
- 设备与HeyThings IoT平台之间物模型数据的双向传输
HeyThings SDK是通用的与具体产品功能无关的基础服务。因此,设备物模型数据的传输是只细化到设备的具体服务编号,服务的属性、动作、事件的编号,及其对应的属性、动作、事件的原始数据。该原始数据,是使用protobuf进行描述的设备物模型进行了protobuf格式序列化后的二进制数据。
SDK提供的物模型接口将由HeyThings工具自动化生成的物模型接口层代码进行调用和再次封装,应用开发者原则上无需直接使用SDK提供的物模型相关接口,而是直接使用物模型接口层的接口及在模型层回调函数中实现函数体内容即可。
4.3 SDK物模型接口
为实现不同平台(Linux、RTOS等)的SDK提供对设备物模型操作的通用性,HeyThings SDK对物模型定义了统一的模型数据交互接口。
- 服务被动操作的接口定义
/**
* @brief 设备属性被动操作回调函数列表
*/
struct hey_properties_callbacks {
/**
* @brief 对端对设备属性进行写入
* @param cb_data [服务注册的回调数据]
* @param n_iid [属性id数量]
* @param iids [属性id列表]
* @param len [写入属性的数据长度]
* @param value [写入属性的原始数据]
* @return int [回调处理结果]
*/
int (*write)(void *cb_data, size_t n_iid, unsigned int *iids,
size_t len, unsigned char *value);
/**
* @brief 对端对设备属性数组添加元素
* @param cb_data [服务注册的回调数据]
* @param iid [被添加元素的数组属性id]
* @param len [添加的属性元素数据长度]
* @param value [添加的属性元素原始数据]
* @return int [添加的元素在数组中的id,负值为错误码]
*/
int (*array_add)(void *cb_data, unsigned int iid,
size_t len, unsigned char *value);
/**
* @brief 对端对设备属性数组删除元素
* @param cb_data [服务注册的回调数据]
* @param iid [被删除元素的数组属性id]
* @param n_id [被删除元素数量]
* @param ids [被删除元素在数组中的id列表]
* @return int [回调处理结果]
*/
int (*array_del)(void *cb_data, unsigned int iid, size_t n_id, unsigned int *ids);
/**
* @brief 对端对设备属性数组更新元素
* @param cb_data [服务注册的回调数据]
* @param iid [被更新元素的数组属性id]
* @param id [被更新元素在数组中的id]
* @param len [更新的属性元素数据长度]
* @param value [更新的属性元素原始数据]
* @return int [回调处理结果]
*/
int (*array_replace)(void *cb_data, unsigned int iid, unsigned int id,
size_t len, unsigned char *value);
};
/**
* @brief 动作类型定义
*/
enum hey_action_type {
HEY_ACTION_ONCE = 0,
HEY_ACTION_IN_ONCE_OUT_STREAM = 1,
HEY_ACTION_IN_STREAM_OUT_ONCE = 2,
HEY_ACTION_IN_STREAM_OUT_STREAM = 3
};
/**
* 流式动作上下文回调函数列表
*/
struct hey_action_ctx_callbacks {
/**
* @brief 对端对设备发起动作交互
* @param cb_data [服务注册的回调数据]
* @param ctx [动作的上下文,SDK生成,应用层负责保存及释放]
* @param len [动作数据长度]
* @param value [动作原始数据]
* @param user_context [自定义上下文,SDK回调时带回,应用层生成及负责释放]
* @return int [回调处理结果]
*/
int (*start)(void *cb_data, struct hey_action_ctx *ctx, size_t len, unsigned char *value,
void **user_context);
/**
* @brief 流式动作交互的消息接收回调
* @param cb_data [服务注册的回调数据]
* @param user_context [start回调中传入的上下文]
* @param len [动作数据长度]
* @param value [动作原始数据]
* @return int [回调处理结果]
*/
int (*message)(void *cb_data, void *user_context, size_t len, unsigned char *value);
/**
* @brief 对端对设备停止动作交互
* @param cb_data [服务注册的回调数据]
* @param user_context [start回调中传入的上下文]
*/
void (*stop)(void *cb_data, void *user_context);
};
/**
* @brief 设备抽象动作定义入口
*/
struct hey_action_entry {
unsigned int iid;
enum hey_action_type type;
const struct hey_action_ctx_callbacks *cbs; // 函数表应使用静态变量定义
};
/**
* @brief 动作交互的消息发送接口
* @param ctx [动作的上下文]
* @param len [动作数据长度]
* @param value [动作原始数据]
* @return int [动作消息发送结果,表示动作消息数据是否成功交付到SDK中]
*/
int hey_action_msg_send(struct hey_action_ctx *ctx,
size_t len, unsigned char *value);
/**
* @brief 主动停止动作交互
* @param ctx [动作的上下文]
* @return int [操作结果]
*/
int hey_action_stop(struct hey_action_ctx *ctx);
/**
* @brief 设备抽象属性
*/
struct hey_schema_properties {
size_t n_iid; // 属性ID数量
unsigned int *iids; // 属性ID列表
const struct hey_properties_callbacks *cbs; // 函数表应使用静态变量定义
size_t len; // 属性数据长度
unsigned char *value; // 属性数据内容
};
/**
* @brief 设备抽象动作
*/
struct hey_schema_actions {
size_t n_iid; // 动作ID数量
struct hey_action_entry *iids; // 动作结构列表
};
/**
* @brief 设备抽象事件
*/
struct hey_schema_events {
size_t n_iid; // 事件ID数量
unsigned int *iids; // 事件ID列表
};
/**
* @brief 设备抽象服务,包含属性、动作、事件
*/
struct hey_schema_service {
struct hey_schema_properties properties;
struct hey_schema_actions actions;
struct hey_schema_events events;
};
/**
* @brief initialize hey schema service
* @param service [schema service]
*/
void hey_schema_service_init(struct hey_schema_service *service);
/**
* @brief 向SDK注册一个设备抽象服务,由SDK负责服务属性等的内部交互管理
* @param siid [待注册的服务编号]
* @param service [待注册的抽象服务]
* @param cb_data [注册回调数据]
* @return hey_service [已注册的服务对象,NULL则为注册失败]
*/
struct hey_service *hey_service_register(unsigned int siid, struct hey_schema_service *service,
void *cb_data);
- 服务主动操作的接口定义
/**
* @brief 属性更新的内容
*/
struct hey_properties_update_content {
size_t n_iid;
unsigned int *iids;
size_t len;
unsigned char *value;
};
/**
* @brief 设备属性改变更新到SDK
* @param service [服务对象]
* @param content [属性更新内容]
* @return int [更新到SDK的结果]
*/
int hey_properties_update(struct hey_service *service,
struct hey_properties_update_content *content);
/**
* @brief 事件通知的内容
*/
struct hey_event_notify_content {
unsigned int iid; // 事件ID
unsigned int importance; // 事件优先级
uint64_t ref_id; // 事件通知关联的UUID
uint64_t timestamp;
size_t len;
unsigned char *value;
void *cb_data;
void (*notify_result_cb)(void *cb_data, int result);
};
/**
* @brief 事件通知
* @param service [服务对象]
* @param content [实际通知的内容]
* @return int64_t [事件通知id,负值为错误码]
*/
int64_t hey_event_notify(struct hey_service *service,
struct hey_event_notify_content *content);
4.4 SDK非模型接口
SDK非模型接口指的是对SDK的初始化和启动、基础信息配置及控制配网绑定等非产品具体功能强相关的接口。在HeyThings平台,配网绑定是对所有产品均为统一的一个实现过程,其交互表现也基本一致,不同产品可能只因实际产品形态的差异而在进入配网模式的操作上略有不同。
同时,为了保证HeyThings产品的状态指示统一性,HeyThings平台也定义了统一的指示灯规范,详见《HeyThings产品状态指示灯规范》。
4.4.1 初始化和启动接口
应用层需要调用SDK的初始化函数来完成SDK的初始化,并调用启动接口让SDK运行起来。SDK内部使用事件驱动模型来处理任务,需要独占一个线程运行,调用启动接口后将不再返回。
初始化函数的参数包括设备产品相关信息和回调函数表。产品相关信息用于SDK托管设备物模型基本信息服务,可以实现让HeyThings平台获取该设备的一些基本信息。回调函数表为SDK运行状态的实时回调及一些关键节点的回调。
- 初始化函数
#define HEY_BRAND_LEN 32
#define HEY_MANUF_LEN 32
#define HEY_MODEL_LEN 32
#define HEY_HARDVER_LEN 32
#define HEY_SOFTVER_LEN 32
enum hey_sdk_state {
HEY_SDK_STATE_INITIAL = 0,
HEY_SDK_STATE_WIFI_CONNECTING = 1,
HEY_SDK_STATE_SERVER_CONNECTING = 2,
HEY_SDK_STATE_SERVER_CONNECTED = 3
};
struct hey_dev_info_config {
unsigned char brand[HEY_BRAND_LEN + 1];
unsigned char manufacture[HEY_MANUF_LEN + 1];
unsigned char model[HEY_MODEL_LEN + 1];
unsigned char hard_version[HEY_HARDVER_LEN + 1];
unsigned char soft_version[HEY_SOFTVER_LEN + 1];
};
struct hey_sdk_callbacks {
void (*state_callback)(enum hey_sdk_state state);
void (*time_synced)(void); // SDK联网后时间同步完成,应用可使用标准C接口获取时间
void (*setup_reset)(void); // 配网功能复位回调
};
struct hey_sdk_config {
struct hey_dev_info_config info;
struct hey_sdk_callbacks *cbs;
};
/**
* @brief heythings sdk initialization
* @param conf [sdk configuration]
* @return int [initialized result]
*/
int hey_sdk_init(struct hey_sdk_config *conf);
- 启动接口
/**
* @brief heythings sdk starts to run, it will not return if it starts successfully.
* @return int [sdk runs result, not 0 means sdk runs failed]
*/
int hey_sdk_run(void);
4.4.2 设备配网接口
- 配网定义
配网是指智能设备在APP等外部交互的协助下获取无线网络配置信息并连接到云端进行绑定的整个过程。
HeyThings SDK提供的配网功能:
- 配网由产品应用层自主控制触发启动及中止
- 产品应用层能够得到配网结果反馈
- 整个配网过程中设备系统无需发生重启
- 配网流程
- 接口定义
enum hey_setup_state {
HEY_SETUP_STATE_INITIAL = 0,
HEY_SETUP_STATE_RUNNING = 1,
HEY_SETUP_STATE_FAILED = 2,
HEY_SETUP_STATE_SUCCESS = 3
};
enum hey_setup_confirm_opinion {
HEY_SETUP_CONFIRM_AGREE = 1,
HEY_SETUP_CONFIRM_DISAGREE = 2
};
struct hey_setup_callbacks {
void (*provision_confirm)(void); // 请求配网授权回调
void (*set_pin)(char **pin, size_t *pin_len); // 设置配网交互过程的PIN
void (*state_callback)(enum hey_setup_state state); // 配网状态回调
};
struct hey_setup_cert_key {
uint8_t *device_cert; // 设备证书
size_t device_cert_len; // 设备证书长度
uint8_t *device_priv_key; // 设备私钥
size_t device_priv_key_len; // 设备私钥长度
uint8_t *product_cert; // 产品证书
size_t product_cert_len; // 产品证书长度
uint8_t *ecdh_priv_key; // ECDH私钥,仅使用ECDH配网的产品才有
size_t ecdh_priv_key_len; // ECDH私钥长度
};
struct hey_setup_config {
uint32_t timeout_seconds;
struct hey_setup_cert_key cert_key;
struct hey_setup_callbacks *cbs;
};
/**
* @brief start a network setup process, only one setup can run at the same time.
* @param conf [network setup parameters]
* @return int [start result,0 means success]
*/
int hey_setup_start(struct hey_setup_config *conf);
/**
* @brief confirms the setup provision to the SDK
* @param opinion [confirm opinion]
*/
void hey_setup_confirm(enum hey_setup_confirm_opinion opinion);
/**
* @brief stop a running network setup process or reset the completed setup
* @return int [reset result,0 means success]
*/
int hey_setup_reset(void);
/**
* @brief get setup state.
* @return enum [setup state]
*/
enum hey_setup_state hey_setup_get_state(void);
4.4.3 特定功能接口
除了SDK的初始化启动、配网接口外,HeyThings SDK还提供了一些特定功能接口,用于完成一些特殊场景功能等,这类接口根据需求在未来可能会有更新迭,将不再一一阐述。
如以下的log上传接口,结合用户体验计划服务,在用户授权的情况下可以开启log上传到云端,方便远程定位调试。
enum hey_log_level{
HEY_LOG_LEVEL_ERR = 3,
HEY_LOG_LEVEL_WARN = 4,
HEY_LOG_LEVEL_NITICE = 5,
HEY_LOG_LEVEL_INFO = 6,
HEY_LOG_LEVEL_DEBUG = 7
};
/**
* @brief Set the log enable
* @param enable [log enable, true or false]
*/
void hey_log_set_enable(bool enable);
/**
* @brief Get the log enable flag
* @return [log enable, true or false]
*/
bool hey_log_get_enable(void);
/**
* @brief start to upload log
*/
void hey_log_upload(void);
/**
* @brief : if log enable, it will be printf to sdk internal log buffer at the same time.
* @param level [log level]
* @param format [log strings to be formatted]
* @param ... [format content]
*/
void hey_log_printf(enum hey_log_level level, const char *format, ...);
5 物模型接口层
物模型接口层是实现产品物模型的封装和解析的接口中间件,将代理应用层与SDK进行交互。
5.1 接口层的作用
产品应用层关注产品功能的实现,HeyThings SDK提供基于设备物模型原始数据的交互服务,为了降低开发者使用SDK的难度,HeyThings将提供一个物模型接口层来完成物模型原始数据到应用层功能的封装和解析。开发者将不需要理解protobuf格式及相关的序列化接口,而是直接以C语言的结构体、函数调用及函数被回调的方式作为模型接口与SDK进行交互。
物模型接口层的交互示意:
5.2 物模型接口定义
物模型的接口是基于C语言语法以枚举、结构体、函数及被回调函数的形式进行定义。
5.2.1 使用枚举类型对应服务属性编号
设备物模型中每个服务下的每一个属性、动作、事件皆有对应的ID编号,同个服务下属性、动作、事件的ID编号是一起统一分配的,互不重复,映射到模型接口层将使用枚举类型进行一一对应。
- 属性的枚举类型定义:
enum [service name]_PROPERTY
{
[service name]_PROPERTY_[property name] = [id],
......
}
- 动作的枚举类型定义:
enum [service name]_ACTION
{
[service name]_ACTION_[action name] = [id],
......
}
- 事件的枚举类型定义:
enum [service name]_EVENT
{
[service name]_EVENT_[event name] = [id],
......
}
5.2.2 使用结构体类型对应属性动作事件表示
对于服务的每个属性、动作、事件,在模型抽象的protobuf格式中是有明确定义的,映射到抽象层将是字符型、整型、结构体等的变量。其中,对于每个独立的抽象服务,其所有属性变量将整合到一个结构体,方便统一的接口调用处理;动作和事件则分别是独立对每一个动作和事件进行结构体定义。
- 属性的结构体定义:
struct [service name]_properties{
[variable type] [property name];
......
};
- 动作的结构体定义:
struct [service name]_[action name]_in{
[variable type] [parameter]
......
};
struct [service name]_[action name]_out{
[variable type] [parameter]
......
};
- 事件的结构体定义:
struct [service name]_[event name]{
[variable type] [parameter]
......
};
动作和事件结构体里面的 [parameter] 是描述该动作或事件的系列参数,可有多个有意义的参数变量或者为一个无意义占位符变量(char place_holder)。
5.2.3 使用函数调用实现对SDK更新内容
设备的属性因外部操作主动发生了变化,或触发了服务事件,则需要把变化的内容更新到SDK,再由SDK负责同步到HeyThings平台的云端、APP端或联动设备端等。这种变化内容将通过函数调用的方式进行更新。
对于设备的属性变化,同一个服务将封装成同一个更新接口,通过参数传递变化的属性数量、属性列表及统一的属性结构体。
对应设备的动作和事件,因其内容结构不统一,将单独为每一个动作和事件抽象封装API接口。
- 服务初始化
/**
* @brief 应用层服务的初始化
* @param properties [服务的所有属性初始值]
*/
int [service name]_service_init(const struct [service name]_properties *properties);
- 属性变化的更新接口函数定义:
/**
* @brief 服务属性变化更新
* @param count [待更新的变化属性数量]
* @param enumerate [待更新的变化属性枚举数组]
* @param properties[待更新的变化属性结构体]
* @return int [更新发送结果]
*/
int [service name]_properties_update(size_t count, unsigned int *enumerate,
struct [service name]_properties *properties);
- 事件触发的通知接口函数定义:
/*
* @brief 事件通知详细参数
*/
struct event_notify_attr {
unsigned int importance; // 事件优先级
uint64_t ref_id; // 事件关联ID
uint64_t timestamp; // 事件发生时刻时间戳
void *cb_data;
};
/**
* @brief 事件触发发送通知
* @param event [通知的事件结构体]
* @param attr [事件通知的详细参数,为NULL则使用默认值进行通知]
* @return int64_t [事件通知id,负值为通知失败,错误码赋值errno]
*/
int64_t [service name]_[event name]_notify(struct [service name]_[event name] *event,
struct event_notify_attr *attr);
5.2.4 使用函数回调实现对应用层发送命令
在HeyThings平台生态里面通过APP触控、语音交互或设备联动等操作将会生成相应的属性设置命令或动作等发送至设备端SDK,SDK将以函数回调的方式把控制命令及内容更新到应用层,由应用层去进行实际属性状态改变或动作的处理。
此处函数回调的函数定义实现在应用层,由开发者填充函数体内容;调用位置在抽象层,无需手动注册函数。带“_cb”后缀的函数即代表该函数为被物模型层进行回调的函数。
- 服务属性操作的被回调函数定义:
/**
* @brief 服务属性写入
* @param count [写入的属性数量]
* @param enumerate [写入的属性枚举数组]
* @param properties[写入的属性结构体]
* @return int [写入结果]
*/
int [service name]_properties_write_cb(size_t count, unsigned int *enumerate,
struct [service name]_properties *properties);
/**
* @brief 服务数组属性添加元素
* @param len [添加的元素数据长度]
* @param value [添加的元素原始数据]
* @return int [添加的元素在数组中的id]
*/
int [service name]_[array property name]_add_cb(size_t len, unsigned char *value);
/**
* @brief 服务数组属性删除元素
* @param n_ids [被删除元素数量]
* @param ids [被删除元素在数组中的id列表]
* @return int [删除结果]
*/
int [service name]_[array property name]_del_cb(size_t n_id, unsigned int *ids);
/**
* @brief 服务数组属性更新元素
* @param id [更新的元素在数组中的id]
* @param len [更新的元素数据长度]
* @param value [更新的元素原始数据]
* @return int [更新结果]
*/
int [service name]_[array property name]_replace_cb(unsigned int id, size_t len,
unsigned char *value);
5.2.5 使用函数调用和回调共同实现动作的交互
物模型的动作(action)分为一次动作交互和流式动作交互。一次动作交互指执行一个仅一次来回交互的动作过程。流式动作交互指执行一个连续多次来回交互的动作过程。
- 一次动作交互
一次动作交互过程由action call发起,对端响应action return结束。在业务应用中,设备端一般是作为被动动作方,即被控制端action call,然后需要响应action return来结束交互过程。
- 回调函数和函数调用定义
/**
* @brief 一次动作交互的回调函数
* @param ctx [单次动作上下文]
* @param action [服务的动作输入结构体]
* @return int [处理结果,0表示应用层处理正常]
*/
int [service name]_[action name]_call_cb(struct hey_action_ctx *ctx,
struct [service name]_[action name]_in *action);
/**
* @brief 一次动作交互的动作响应
* @param ctx [单次动作上下文]
* @param action [服务的动作输出结构体]
* @return int [动作响应发送结果,表示动作响应数据是否成功交付到SDK中]
*/
int [service name]_[action name]_return(struct hey_action_ctx *ctx,
struct [service name]_[action name]_out *action);
- 动作的同步及异步返回
动作中的 “ctx” 为本次动作的上下文信息,代表了本次动作,在进行动作响应action return时需必须使用同一个 “ctx” 作为参数传入,以便完整对应整个动作过程。
在进行同步响应时,可在call_cb回调函数中直接调用return函数进行响应返回。而要进行异步响应时,应用层应在call_cb中先自行保存ctx,然后在应用的异步动作处理完成后,再使用对应保存的ctx调用return函数完成异步响应。
调用return函数进行动作响应后,一次动作的生命周期即结束,ctx的资源被回收,不可再次使用,使用同一ctx重复调用return将无效,也应确保避免这种重复调用。
- 流式动作交互
流式动作交互过程由action start发起,双方可互发action message传送具体数据,然后由action stop结束。在业务应用中,设备端(SDK)一般是作为被动动作方,即被控制端发起action start,然后双方均可互相发送action message,并可以由任意一方发起action stop来结束交互过程。
- 回调函数和函数调用定义
/**
* @brief 流式动作交互开始的回调函数
* @param ctx [本次流式动作的上下文]
* @param action [服务的动作输入结构体]
* @param user_contex [自定义上下文,应用层赋值给SDK,在数据接收时回调回来]
* @return int [处理结果,0表示应用层处理正常]
*/
int [service name]_[action name]_start_cb(struct hey_action_ctx *ctx,
struct [service name]_[action name]_in *action,
void **user_contex);
/**
* @brief 流式动作接收数据的回调函数
* @param user_contex [自定义上下文,在start_cb中传入的]
* @param action [服务的动作输入结构体]
* @return int [处理结果,0表示应用层处理正常]
*/
int [service name]_[action name]_message_cb(void *user_contex,
struct [service name]_[action name]_in *action);
/**
* @brief 流式动作异常结束或对端主动结束的回调函数
* @param user_contex [自定义上下文,在start_cb中传入的]
* @return int [处理结果,0表示应用层处理正常]
*/
int [service name]_[action name]_stop_cb(void *user_contex);
/**
* @brief 流式动作交互的消息发送接口
* @param ctx [连续的动作上下文]
* @param action [服务的动作输出结构体]
* @return int [动作消息发送结果,表示动作消息数据是否成功交付到SDK中]
*/
int [service name]_[action name]_send(struct hey_action_ctx *ctx,
struct [service name]_[action name]_out *action);
/**
* @brief 主动停止流式动作交互
* @param ctx [连续的动作上下文]
* @return int [动作消息发送结果,表示动作消息数据是否成功交付到SDK中]
*/
int [service name]_[action name]_stop(struct hey_action_ctx *ctx);
- 动作的异步返回
动作中的 “ctx” 为本次动作的上下文信息,代表了本次动作,在进行动作响应action send以及结束动作action stop时需必须使用同一个 “ctx” 作为参数传入,以便完整对应整个动作过程。
流式动作是一个持续的多次交互过程,因此在动作开始后基本都是异步响应。应用层应在start_cb中自行保存ctx,然后在处理动作的实时过程中使用对应保存的ctx调用action send函数作动作异步响应。
在流式动作所有操作完成后,可以主动调用action stop结束当次动作。如果是对端主动结束,或者连接异常导致的结束,SDK会回调stop cb,应用需要在stop cb中调用action stop结束动作以便释放动作上下文资源。
调用stop函数后,当次流式动作的生命周期即结束,ctx的资源被回收,不可再次使用,使用同一ctx重复调用action send或action stop将无效,也应确保避免这种重复调用。
6 相关资源
- HeyThings开放平台
产品要接入HeyThings平台,应用开发者需要先在HeyThings开放平台进行开发者账号注册登录,然后创建产品并配置录入产品设备的属性动作事件等信息,开放平台可为开发者提供注册的设备物模型描述文件、物模型接口层代码及SDK。
开发者无需对生成的抽象层接口代码进行修改,只需实现必要的回调函数的函数体内容,以及调用模型接口层的相关API,即可完成与HeyThings SDK的双向交互。注意,所有回调函数的函数体中不能有阻塞式的代码调用,否则会影响SDK的正常运行。
关于HeyThings开放平台的操作详见平台的指引说明。
- 遵循POSIX标准
HeyThings RTOS SDK会对一些芯片平台进行适配,由于嵌入式芯片平台的差异性较大,为让SDK尽可能容易的适用到更多的平台上,SDK的内部实现均遵循POSIX标准。在HeyThings SDK及物模型层提供的接口中,如对返回值没有特别备注说明,其返回值则为POSIX标准的错误码。
关于POSIX接口的使用详见POSIX官方文档。
- 不同平台下的编译调试
HeyThings协议的开源工作目前还在推进中,在未能正式开源前,HeyThings RTOS SDK对开发者将先提供静态库的方式供接入使用。开发者可以在自己熟悉的芯片平台上将HeyThings SDK静态库嵌入到自己的应用程序中,在不改变开发者原有代码框架的情况下通过HeyThings SDK和物模型层的接口接入HeyThings平台。
HeyThings RTOS SDK会为已进行适配的芯片平台提供该平台下的demo,在对应平台下使用的是其平台的编译工具和构建系统。使用HeyThings RTOS SDK前需要满足以下前提条件:
- 相应芯片平台具备以下功能
- 具备TCP/IP协议栈
- 能够进行数据保存读写
- 具备WiFi完整功能接口
- 支持远程OTA功能
- HeyThings已为相应芯片平台推出SDK静态库
- 应用开发者能熟练进行相应芯片平台的开发调试
关于不同芯片平台下源码工程的编译调试详见对应平台官方文档。
如在ESP32芯片平台上,编译构建使用的是官方esp-idf开发框架。而关于esp-idf的基础开发环境搭建及其使用说明请参考ESP官方文档资源,HeyThings将不会对该部分进行介绍和指导,其他芯片平台类似。