自制智能镜之——产品创建及开发环境搭建篇(限时活动进行中)

Posted 三明治开发社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自制智能镜之——产品创建及开发环境搭建篇(限时活动进行中)相关的知识,希望对你有一定的参考价值。

(限时活动突击上线!3步学会创建产品,还可获得奖品。跟着下面步骤一起,将创建好的产品PID发至下面官方小助手,领取你的专属惊喜吧!)
在这里插入图片描述

前言


如何给一面普通的镜子赋予更多的功能?本期系列文章将会教给大家怎样通过涂鸦平台及涂鸦wifi模组快速实现一款智能镜产品。

创建产品

  • 首先登录涂鸦智能IoT平台,点击 “创建产品”,在标准类目栏的最下方找到 “找不到品类”,点击进入自定义产品创建页面。

在这里插入图片描述

  • 输入产品名称和描述,通讯协议选择 WIFI+蓝牙,点击 创建产品
    在这里插入图片描述

  • 在功能定义一栏添加DP点,如下图所示,本demo添加了标准功能:“开关”、“灯光开关”、“灯光模式”、“亮度值”、“电量状态”、“人体感应状态”、“人体感应开关”等功能;功能点可以根据需求自行增减,功能点名称以及属性也可根据需求自行修改。
    在这里插入图片描述

  • 进入设备面板,可以选择自己喜欢的模板或者自己自定义面板,调试阶段推荐选择开发调试面板,便于测试。

  • 选择硬件开发平台,可以根据需要自行选择开发平台。注意,需要选择芯片平台并上传固件后,面板才能够使用;固件标识名要和上传的固件名称需保持一致,否则烧录授权时将无法通过。

在这里插入图片描述

  • 至此,产品创建阶段已经基本完成,此时可以通过“涂鸦智能”app和虚拟设备体验dp数据的接收和发送。
    在这里插入图片描述

嵌入式系统搭建

产品创建完毕后,接下来需要实现产品模组固件,首先要做的就是搞定开发环境。

开发环境

本案例是基于BK7231N平台进行的SOC开发,开发所用的涂鸦通用SDK编译需要linux环境,首先要安装linux开发环境,然后从涂鸦仓库拉取包含SDK环境的demo例程。。

  • 下载Tuya IoTOS Embeded WiFi & BLE sdk

    $ 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为开发模板,在此基础上增减代码,实现一个嵌入式系统框架。

实现配网连接涂鸦平台的最简嵌入式系统框架

在正式开始智能镜应用代码开发前,我们可以先搭建一个基本的嵌入式框架,实现设备联网,与平台建立上报下发通道。

  • 在现有的demo基础上搭建系统框架
    当前tuya_demo_template应用程序的文件组成如下:
├── src	
|    └── tuya_device.c            //应用层入口文件
|
├── include				//头文件目录
|    └──  tuya_device.h
|
└── output              //编译产物
  • 将 tuya_demo_template 文件夹更名为 bk7231n_mirror_demo,修改 include 文件夹中的 tuya_device.h 里的 PRODECT_ID 宏定义,修改为我们刚刚创建的智能镜产品的 pid。
    在这里插入图片描述

在这里插入图片描述

  • 创建一个 tuya_app.c 文件,做为智能镜应用代码的主要文件
    创建后的demo文件目录如下:
├── src	
|    └── tuya_device.c            //应用层入口文件
|    └── tuya_app.c            //主要应用文件
|
├── include				//头文件目录
|    └──  tuya_device.h
|    └──  tuya_app.h
|
└── output              //编译产物
  • tuya_app.h中涉及到 DP 点宏定义以及 DP 点上报、下发数据处理函数的声明。
#ifndef __TUYA_APP_H__
#define __TUYA_APP_H__

#include "uni_log.h"
#include "tuya_cloud_error_code.h"
#include "tuya_cloud_com_defs.h"

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

/***********************************************************
*************************variable define********************
***********************************************************/
typedef enum{
    APP_MIRROR_NORMAL,       //normal mode
    APP_MIRROR_PRODTEST      //prodact test mode
}APP_MIRROR_MODE;

#define DPID_SWITCH                      1
#define DPID_SWITCH_LED                  2
#define DPID_LIGHT_MODE                  4
#define DPID_LIGHT_VALUE                 5
#define DPID_BATTERY_STATUS              101
#define DPID_PIR_MODE                    103
#define DPID_PIR_STATE                   105
/********************************************************************************
 * FUNCTION:       app_mirror_init
 * DESCRIPTION:    application initialization
 * INPUT:          mode:application mode
 * OUTPUT:         none
 * RETURN:         none
 * OTHERS:         none
 * HISTORY:        2021-01-12
 *******************************************************************************/
OPERATE_RET app_mirror_init(IN APP_MIRROR_MODE mode);

/********************************************************************************
 * FUNCTION:       deal_dp_proc
 * DESCRIPTION:    deal the data sented by app
 * INPUT:          root:app issued data structure
 * OUTPUT:         none
 * RETURN:         none
 * OTHERS:         none
 * HISTORY:        2021-01-12
 *******************************************************************************/
VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root);

/*********************************************************************************
 * FUNCTION:       app_report_all_dp_status
 * DESCRIPTION:    report all dp date
 * INPUT:          none
 * OUTPUT:         none
 * RETURN:         none
 * OTHERS:         dp_cnt needs to be modified when adding or deleting the dp function
 * HISTORY:        2021-01-12
 *******************************************************************************/
VOID app_report_all_dp_status(VOID);

#ifdef __cplusplus
}
#endif /* __cplusplus */


#endif  /* __TUYA_APP_H__*/
  • tuya_app.c 中需实现下发 dp 点数据处理函数:deal_dp_proc 和 dp 数据上报函数:app_report_all_dp_status 。这里由于涂鸦SDK在上报 dp 数据时会做筛选处理,所有可以一次性把所有dp点全部上报。
//接收下发数据,解析 dp id 和 dp 内容
VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{
    UCHAR_T dpid;

    dpid = root->dpid;
    PR_DEBUG("dpid:%d",dpid);
    
    switch (dpid) {

    case DPID_SWITCH:
    
        //获取dp内容值
        mirror_ctrl_data.Mirror_switch = root->value.dp_bool;
        break;
        
    case DPID_SWITCH_LED:
    
        ......
        break;

    case DPID_LIGHT_MODE:
    
        ......
        break;

    case DPID_LIGHT_VALUE:
    
        ......
        break;

    case DPID_PIR_MODE:
    
        ......
        break;

    default:
        break;
    }
    
    app_report_all_dp_status();

    return;

}

//dp数据上报,判断已经连接涂鸦平台后,上报所有 dp 点。

VOID app_report_all_dp_status(VOID)
{
    OPERATE_RET op_ret = OPRT_OK;

    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;
    }
    
    INT_T dp_cnt = 0;
    dp_cnt = 7;

    if(!mirror_ctrl_data.Wifi_state) {
        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 = DPID_SWITCH;
    dp_arr[0].type = PROP_BOOL;
    dp_arr[0].time_stamp = 0;
    dp_arr[0].value.dp_value = mirror_ctrl_data.Mirror_switch;

    dp_arr[1].dpid = DPID_SWITCH_LED;
    dp_arr[1].type = PROP_BOOL;
    dp_arr[1].time_stamp = 0;
    dp_arr[1].value.dp_value = mirror_ctrl_data.Light_switch;

    dp_arr[2].dpid = DPID_LIGHT_MODE;
    dp_arr[2].type = PROP_ENUM;
    dp_arr[2].time_stamp = 0;
    dp_arr[2].value.dp_value = mirror_ctrl_data.Light_mode;

    dp_arr[3].dpid = DPID_LIGHT_VALUE;
    dp_arr[3].type = PROP_VALUE;
    dp_arr[3].time_stamp = 0;
    dp_arr[3].value.dp_value = mirror_ctrl_data.Light_value;
    
    dp_arr[4].dpid = DPID_BATTERY_STATUS;
    dp_arr[4].type = PROP_ENUM;
    dp_arr[4].time_stamp = 0;
    dp_arr[4].value.dp_value = mirror_ctrl_data.Battery_remain;

    dp_arr[5].dpid = DPID_PIR_MODE;
    dp_arr[5].type = PROP_BOOL;
    dp_arr[5].time_stamp = 0;
    dp_arr[5].value.dp_value = mirror_ctrl_data.PIR_switch;

    dp_arr[6].dpid = DPID_PIR_STATE;
    dp_arr[6].type = PROP_ENUM;
    dp_arr[6].time_stamp = 0;
    dp_arr[6].value.dp_value = mirror_ctrl_data.PIR_state;

    op_ret = dev_report_dp_json_async(NULL,dp_arr,dp_cnt);
    Free(dp_arr);
    if(OPRT_OK != op_ret) {
        PR_ERR("dev_report_dp_json_async relay_config data error,err_num",op_ret);
    }

    PR_DEBUG("dp_query report_all_dp_data");
    return;
}
  • 修改 tuya_device.c 中的几处回调,将上面实现的 dp 上报和下发处理函数填进去。
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 = 0;

    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);
    }
}

VOID hw_report_all_dp_status(VOID)
{
    app_report_all_dp_status();
}

STATIC VOID dev_dp_query_cb(IN CONST TY_DP_QUERY_S *dp_qry) 
{
    PR_NOTICE("Recv DP Query Cmd");

    hw_report_all_dp_status();
}

至此一个基本的配网上报下发接收框架就搭建好了,可以在 dp 下发处理函数中不做任何操作,只执行打印日志,以便测试整个通信链路是否正常。

程序的编译和烧录

  • 在SDK根目录下执行以下命令开始编译:

    sh build_app.sh apps/bk7231n_mirror_demo bk7231n_mirror_demo 1.0.0
    
  • 固件烧录授权相关信息请参考:Wi-Fi + BLE 系列模组烧录授权

  • 设备连接与实验
    烧录授权完成后即可打开涂鸦智能app搜索设备进行配网绑定,绑定完成后就可以用 app 下发指令控制设备了。模组日志将输出在串口2。

系统框架建立完成

此时设备已经和app端进行了连接实现了通信,接下来就可以着手开始实现智能镜的具体功能了。
具体功能实现过程将在后续的文章详细介绍。

后续内容

以上是关于自制智能镜之——产品创建及开发环境搭建篇(限时活动进行中)的主要内容,如果未能解决你的问题,请参考以下文章

自制智能镜之——屏幕显示时间日期篇

自制智能镜之——化妆灯和人体感应篇

自制智能镜之——硬件选型篇

自制智能镜之——功能逻辑分析篇

自制智能镜之——硬件&结构设计篇

智能魔法棒(手势控制器)———嵌入式篇