前言
前面我们对荣事达暖风机进行了拆机改装,确认了改装后的硬件系统;下面我们要创建嵌入式软件系统,让改装后的智能暖风机活起来。
1.创建产品
- 首先进入涂鸦IoT智能平台,创建一个暖风机产品。点击创建产品 >小家电 >取暖器。
- 选择自定义方案,自定义产品名称,通讯协议选择WIFI+蓝牙,点击创建产品。
- 添加DP点,本案例中添加了标准功能:“开关”、“目标温度”、“当前温度”、“档位”、“摇头”,添加了自定义功能:“灯光”、“定时开启”、“定时关闭”、“倒计时时间”;功能点可以根据需求自行增减,功能点名称以及属性也可根据需求自行修改。
- 选择设备面板,可以选择自己喜欢的模板或者自己自定义面板,调试阶段推荐选择开发调试面板,便于测试。
- 选择硬件开发平台,可以根据需要自行选择开发平台。
- 至此,产品创建阶段已经基本完成,此时可以通过“涂鸦智能”app和虚拟设备体验dp数据的接收和发送。
2.暖风机的嵌入式系统搭建
前面已经创建了产品,app端的控制界面已经有了,为了实现app和暖风机的智能交互,此时就需要建立暖风机设备的嵌入式系统。
建立嵌入式开发环境
本案例是基于BK7231N平台进行的SOC开发,开发所用的涂鸦通用SDK编译需要linux环境,首先要安装linux开发环境,然后从涂鸦仓库拉取包含SDK环境的demo例程。
$ cd "your directory"
$ git clone https://github.com/tuya/tuya-iotos-embeded-sdk-wifi-ble-bk7231n
在自己建立的目录中git下来demo,里面有附带有SDK环境,同时“apps”目录中也有几个应用案例,我们就使用apps/tuya_demo_template这个demo为开发模板,在此基础上增减代码,实现一个嵌入式系统框架。
搭建一个能够配网连接APP的嵌入式系统框架
实现暖风机的智能化首先要搭建一个简易的嵌入式框架,可以实现APP和设备之间的连接与通信,之后我们再模块化的实现暖风机的功能。
- 在现有的demo基础上搭建系统框架
当前tuya_demo_template应用程序的文件组成如下:
├── src
| └── tuya_device.c //应用层入口文件
|
├── include //头文件目录
| └── tuya_device.h
|
└── output //编译产物
- 更改tuya_device.h中代码,按照创建的产品中的PID去填写。
- 创建一个C文件,做为dp点触发的主要应用函数
创建后的demo文件组成如下:
├── src
├── tuya_dp_process.c
| └── tuya_device.c //应用层入口文件
|
├── include //头文件目录
├── tuya_dp_process.h
| └── tuya_device.h
|
└── output //编译产物
- tuya_dp_process.h中定义功能点的DP_ID和不同DP类型的属性结构体,如枚举型、数值型。
#ifndef __TUYA_DP_PROCESS_H__
#define __TUYA_DP_PROCESS_H__
/* Includes ------------------------------------------------------------------*/
#include "tuya_cloud_types.h"
#include "tuya_iot_com_api.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Exported types ------------------------------------------------------------*/
typedef UINT8_T DP_ID_T;
typedef struct {
DP_ID_T dp_id;
bool power;
}DP_BOOL_T;
typedef struct {
DP_ID_T dp_id;
INT_T value;
}DP_VALUE_T;
/* Exported constants --------------------------------------------------------*/
extern DP_BOOL_T switch_s;
extern DP_VALUE_T led_s;
extern DP_VALUE_T mode_s;
extern DP_VALUE_T temper_s;
extern DP_BOOL_T shake_s;
extern DP_VALUE_T set_temper_s;
extern DP_BOOL_T time_to_open_s;
extern DP_BOOL_T time_to_close_s;
extern DP_VALUE_T shutdown_time_s;
/* Exported macro ------------------------------------------------------------*/
#define DP_SWITCH 1
#define DP_TEMPER 3
#define DP_SHAKE 8
#define DP_MODE 5
#define DP_LED 101
#define DP_SET_TEMP 2
#define DP_TIME_ON 102
#define DP_TIME_OFF 103
#define DP_SHUTDOWN_TIME 104
/* Exported functions ------------------------------------------------------- */
VOID_T deal_dp_proc(IN CONST TY_OBJ_DP_S *root);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __TUYA_DP_PROCESS */
- tuya_dp_process.c中实现deal_dp_proc函数原型,用于实现设备接收到不同dp数据后的动作。
/* Includes ------------------------------------------------------------------*/
#include "uni_log.h"
#include "tuya_cloud_wifi_defs.h"
#include "tuya_os_adapter.h"
#include "tuya_cloud_error_code.h"
#include <string.h>
#include <stdlib.h>
/* Private includes ----------------------------------------------------------*/
#include "tuya_dp_process.h"
#include "tuya_device.h"
/* Private typedef -----------------------------------------------------------*/
DP_BOOL_T switch_s = {
.dp_id = DP_SWITCH,
.power = FALSE,
};
DP_VALUE_T led_s = {
.dp_id = DP_LED,
.value = 0,
};
DP_VALUE_T mode_s = {
.dp_id = DP_MODE,
.value = 0,
};
DP_VALUE_T temper_s = {
.dp_id = DP_TEMPER,
.value = 0,
};
DP_BOOL_T shake_s = {
.dp_id = DP_SHAKE,
.power = FALSE,
};
DP_VALUE_T set_temper_s = {
.dp_id = DP_SET_TEMP,
.value = 0,
};
DP_BOOL_T time_to_open_s = {
.dp_id = DP_TIME_ON,
.power = FALSE,
};
DP_BOOL_T time_to_close_s = {
.dp_id = DP_TIME_OFF,
.power = FALSE,
};
DP_VALUE_T shutdown_time_s = {
.dp_id = DP_SHUTDOWN_TIME,
.value = 0,
};
/* Private functions ---------------------------------------------------------*/
VOID_T deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{
UCHAR_T dpid;
dpid = root->dpid;
switch (dpid){
case DP_SWITCH:
{
PR_NOTICE("set switch %d",root->value.dp_bool);
}
break;
case DP_TEMPER:
{
PR_NOTICE("set switch %d",root->value.dp_value);
}
break;
case DP_SHAKE:
{
PR_NOTICE("shake %d",root->value.dp_bool);
}
break;
case DP_MODE:
{
PR_NOTICE("mode %d",root->value.dp_enum);
}
break;
case DP_LED:
{
PR_NOTICE("led color %d",root->value.dp_value);
}
break;
case DP_SET_TEMP:
{
PR_NOTICE("set temperature %d",root->value.dp_value);
}
break;
case DP_TIME_ON:
{
PR_NOTICE("time on %d",root->value.dp_value);
}
break;
case DP_TIME_OFF:
{
PR_NOTICE("time_off %d",root->value.dp_value);
}
break;
case DP_SHUTDOWN_TIME:
{
PR_NOTICE("shutdown time %d",root->value.dp_value);
}
break;
default:
break;
}
}
- 更改tuya_device.c中代码。
填充dp数据上报函数
VOID_T hw_report_all_dp_status(VOID_T)
{
OPERATE_RET op_ret = OPRT_OK;
INT_T dp_cnt = 0;
dp_cnt = 9;
GW_WIFI_NW_STAT_E wifi_state = 0xFF;
/* 没有连接到路由器,退出 */
op_ret = get_wf_gw_nw_status(&wifi_state);
if (OPRT_OK != op_ret) {
PR_ERR("get wifi state err");
return;
}
if (wifi_state <= STAT_AP_STA_DISC || wifi_state == STAT_STA_DISC) {
return;
}
TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(dp_cnt*SIZEOF(TY_OBJ_DP_S));
if(NULL == dp_arr) {
PR_ERR("malloc failed");
return;
}
memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));
/* */
dp_arr[0].dpid = switch_s.dp_id;
dp_arr[0].type = PROP_BOOL;
dp_arr[0].time_stamp = 0;
dp_arr[0].value.dp_bool = switch_s.power;
dp_arr[1].dpid = temper_s.dp_id;
dp_arr[1].type = PROP_VALUE;
dp_arr[1].time_stamp = 0;
dp_arr[1].value.dp_value = temper_s.value;
dp_arr[2].dpid = shake_s.dp_id;
dp_arr[2].type = PROP_BOOL;
dp_arr[2].time_stamp = 0;
dp_arr[2].value.dp_bool = shake_s.power;
dp_arr[3].dpid = mode_s.dp_id;
dp_arr[3].type = PROP_ENUM;
dp_arr[3].time_stamp = 0;
dp_arr[3].value.dp_enum = mode_s.value;
dp_arr[4].dpid = led_s.dp_id;
dp_arr[4].type = PROP_ENUM;
dp_arr[4].time_stamp = 0;
dp_arr[4].value.dp_enum = led_s.value;
dp_arr[5].dpid = set_temper_s.dp_id;
dp_arr[5].type = PROP_VALUE;
dp_arr[5].time_stamp = 0;
dp_arr[5].value.dp_value = set_temper_s.value;
dp_arr[6].dpid = time_to_open_s.dp_id;
dp_arr[6].type = PROP_BOOL;
dp_arr[6].time_stamp = 0;
dp_arr[6].value.dp_bool = time_to_open_s.power;
dp_arr[7].dpid = time_to_close_s.dp_id;
dp_arr[7].type = PROP_BOOL;
dp_arr[7].time_stamp = 0;
dp_arr[7].value.dp_bool = time_to_close_s.power;
dp_arr[8].dpid = shutdown_time_s.dp_id;
dp_arr[8].type = PROP_VALUE;
dp_arr[8].time_stamp = 0;
dp_arr[8].value.dp_value = shutdown_time_s.value;
op_ret = dev_report_dp_json_async(NULL , dp_arr, dp_cnt);
Free(dp_arr);
dp_arr = NULL;
if(OPRT_OK != op_ret) {
PR_ERR("dev_report_dp_json_async relay_config data error,err_num",op_ret);
}
return;
}
- 调用dp点执行函数,用于app端下发dp数据后,设备端的动作响应处理
/**
* @Function: dev_obj_dp_cb
* @Description: obj dp info cmd callback, tuya cloud dp(data point) received
* @Input: dp:obj dp info
* @Output: none
* @Return: none
* @Others: app send data by dpid control device stat
*/
VOID dev_obj_dp_cb(IN CONST TY_RECV_OBJ_DP_S *dp)
{
PR_DEBUG("dp->cid:%s dp->dps_cnt:%d",dp->cid,dp->dps_cnt);
UCHAR_T i = 8;
for(i = 0;i < dp->dps_cnt;i++) {
deal_dp_proc(&(dp->dps[i]));
dev_report_dp_json_async(get_gw_cntl()->gw_if.id, dp->dps, dp->dps_cnt);
}
}
此时一个简单的软件框架就搭建好了,软件思想是app下发dp数据,设备端会有对应的打印信息,接下来是编译及烧录。
程序的编译和烧录
-
在SDK根目录下执行以下命令开始编译:
sh build_app.sh apps/tuya_demo_template tuya_demo_template 1.0.0
-
固件烧录授权相关信息请参考:WiFi + BLE 系列模组烧录授权
-
设备连接与实验
烧录后打开涂鸦智能app搜索设备进行连接,设备名称是创建产品时的产品名称。连接成功后app端发送dp数据,设备的串口2将打印对应的输出信息。
系统框架建立完成
此时设备已经和app端进行了连接实现了通信,后面就可以逐个实现暖风机的各个功能。
具体的功能实现过程将在后续的文章详细介绍。
技术支持
您可以通过以下方法获得涂鸦的支持: