应用开发

更新时间:2022-11-24 09:20:24下载pdf

为了更高效的进行产品开发,涂鸦提供了一套标准的应用模板,应用模板包含了 DP 上报、数据下发、KV 数据存储等,您可以基于应用模板快速完成底层基础能力,专注于开发自身应用代码,更快完成产品开发。

应用模板说明

应用模板包含在 OpenCPU SDK 内,您在获取到 SDK 后,解压开发后即可看到应用模板的代码(apps 文件夹下的 tuyaos_demo_nb_sample 文件包)。
应用开发

文件说明

apps 文件夹下的应用模板文件结构说明如下:

文件夹名称 作用 备注
tuyaos_demo_nb_sample OpenCPU 应用模板,帮助快速开发上层代码
文件名称 作用 备注
tuya_device.c 存放应用开发代码
tuya_device.h 存放宏定义、产品信息及公共头文件等

编译说明

获取到 OpenCPU SDK 解压后在根目录执行编译命令:

./build_app.sh ./apps/tuyaos_demo_nb_sample mt2625gl_common 1.0.0

编译成功以后,会出现“NB”字样:

应用开发
编译后的文件输出在此路径下:

TuyaOS\vendor\mtk2625_SDK280\mt2625_os\project\mt2625_evb\apps\tuya_alpha\output\mt2625gl_common

应用开发

应用模板功能介绍

应用开发

重点函数介绍

  • pre_init
    此阶段对应初始化 NBIOT SDK 之前需要做的一些工作,用户可以根据自己的需求来实现,也可以不实现,不实现便不会执行,该函数主要用于一些外设的基本配置与需要上电快速启动的一些功能,例如:唤醒引脚初始化、ADC 初始化、快速点亮 LED 灯或者使能外设等操作。注意:请不要在此函数中使用较长时间延时。

  • device_init
    此阶段用于初始化产品功能,需要配置 PRODUCT_KEY 与一些必要的回调注册,下面以一种经典的场景举例介绍该函数的使用方法:

    int device_init(void)
    {
        int ret = OPRT_OK;
        // 配置产品 PID
        tuya_user_api_set_product_key(PRODUCT_KEY);
        // 设置事件捕获回调函数
        tuya_user_api_event_loop_set_cb(tuya_event_process_cb, NULL);
        //启动事件捕获任务
        tuya_user_api_event_loop_start();
        // 设置云端下发数据点回调函数
        tuya_user_api_dp_write_default_cb(tuya_dp_write_cb);
        // 设置记录型数据点上报结果回调函数
        tuya_user_api_dp_report_record_ack_register_cb(dp_report_notify_callback);
        // 设置心跳时间
        tuya_user_api_lifetime_set(600);
        // 设置记录型数据在弱网条件下的上报时间间隔
        tuya_user_api_record_dp_lifetime_set(600);
        /*
        此处可创建用户任务
        */
        return ret;
    }
    
  • tuya_user_api_event_loop_set_cb(tuya_event_process_cb, NULL)

    • 该函数用于配置事件捕获的回调,其中回调函数 tuya_event_process_cb 主要处理判断 SDK 返回的事件 ID,包含以下各种状态:

      typedef enum {
          SYSTEM_EVENT_ID_CARD,               //设备识别到 SIM 卡正常
          SYSTEM_EVENT_NETWORK_READY,        //成功附着基站
          SYSTEM_EVENT_NETWORK_DISCONNECT,   //网络断开
          SYSTEM_EVENT_GOING_SLEEP,           //正在进入睡眠
          SYSTEM_EVENT_GOING_REBOOT,          //设备正在重启
          EVENT_LWM2M_CONNECTED,              //已连接 LWM2M 服务器
          EVENT_LWM2M_READY,                  //LWM2M 网络服务已可用
          EVENT_LWM2M_UPDATE_SUCCESS,        //数据上报成功
          EVENT_LWM2M_RESPONSE_SUCCESS,      //数据响应成功
          EVENT_LWM2M_RESTART,                //LWM2M 重连
          EVENT_DEVICE_INFO_RESET,           //设备信息重置
          EVENT_DEVICE_BIND_ON,              //设备已绑定
          EVENT_DEVICE_UNBIND_ON,            //设备未绑定
          EVENT_DEVICE_DEACTIVE,             //设备重置 
          EVENT_POWERKEY_PRESS,              //POWER 按键按下
          EVENT_SCHEMA_COMPLETE_ON,          //Schema 文件完整
          EVENT_ELOG_SWITCH,                 //ELOG 开关
          SYSTEM_EVENT_MAX
      } system_event_id_t;
      
    • 这些状态可供用户判断处理,建议将此消息发送到用户的任务中处理,例如:SYSTEM_EVENT_ID_CARD(设备识别到 SIM 卡正常)、SYSTEM_EVENT_NETWORK_DISCONNECT(网络断开)等,可以作为用户网络指示灯的信号。

    • SDK 开始会初始化主事件,并默认注册主事件处理函数。

    • 主要包括事件见 tuya_comm.h 文件 system_event_id_t 枚举。这里讲几个重要的枚举。

    • 当设备读到卡后,响应 SYSTEM_EVENT_ID_CARD 此事件。

    • 当网络注册上基站后,响应 SYSTEM_EVENT_NETWORK_READY 此事件。

    • 当 ISP 模式(代理服务器模式)时,设备会先与代理服务器通讯,通讯正常,则设备响应 EVENT_LWM2M_READY 事件。

    • 当设备登录上代理服务器,则响应 EVENT_LWM2M_CONNECTED 事件。
      当设备网络注销,响应 SYSTEM_EVENT_NETWORK_DISCONNECT 事件。

  • tuya_user_api_fota_notify_register
    该接口用于固件升级过程中电量查询与升级状态回调,用户需要自己实现电量采集接口,根据实际场景返回电量状态:
    typedef enum {
    BATTERY_LEVEL_LOW = 0,
    BATTERY_LEVEL_NORMAL = 1,
    } battery_state_t;
    当电量为低的时候,固件不会进行更新,且会上报当前状态至服务器,并且会通知状态至手机 App。

  • tuya_user_api_mf_test_cb_reg(tuya_user_prod_test)
    产测相关功能需要涂鸦产测相关的夹具并且需要符合涂鸦产测协议,详情可咨询涂鸦相关人员。
    该接口可供用户进行产测回调注册,原型为:

    /*********************************************************************************
    * @功能    		用户产测接口回调注册
    * @参数    	  	user_test_callback :回调函数
    * @参数    	  	cmd  : 子命令
    * @参数    	  	data : 子命令负载指针
    * @参数    	  	len  : 子命令负载长度
    * @参数    	  	ret_data : 返回结果指针
    * @参数    	  	ret_len  : 返回结果长度
    * @返回值:  		0:函数执行正常;其它:函数执行异常
    *********************************************************************************/
    void tuya_user_api_mf_test_cb_reg(int (*user_test_callback)(IN USHORT_T cmd, IN UCHAR_T *data,IN UINT_T len, OUT UCHAR_T *ret_data,OUT USHORT_T *ret_len));
    

    产测回调函数实现举例:

    int tuya_user_prod_test(USHORT_T cmd, UCHAR_T *data, UINT_T len, OUT UCHAR_T *ret_data, OUT USHORT_T *ret_len)
    {
    switch (cmd){
            // LED 灯测试
            case 0x0001:
                    USER_API_LOGI("user prod test, val:%d", data[0]);
                    /*点亮 LED 灯*/
                    *ret_len = sprintf((char *)ret_data, "%s", "{\"ret\":true}");
            break;
    /*
            其他产测场景
    */
    }
    }
    
  • multi_dps_report_demo
    该函数演示了如何进行多个不同类型 DP 的组合上报,其中调用了各个类型 DP 的编码接口:

    tuya_user_api_lwdp_encode_string:编码字符串类型数据
    tuya_user_api_lwdp_encode_bool:编码布尔型数据
    tuya_user_api_lwdp_encode_int:编码整型数据
    tuya_user_api_lwdp_encode_enum:编码枚举类型数据
    tuya_user_api_lwdp_encode_map:编码 map 类型数据
    更多接口请查看 tuya_user_api.h
    
  • tuya_dp_write_cb
    该函数演示了下行数据的解码处理,其中使用了各个类型 DP 的解码接口:

    tuya_user_api_lwdp_decode_string:解码字符串类型数据
    tuya_user_api_lwdp_decode_bool:解码布尔型数据
    tuya_user_api_lwdp_decode_int:解码整型数据
    tuya_user_api_lwdp_decode_enum:解码枚举类型数据
    tuya_user_api_lwdp_decode_map:解码 map 类型数据
    

    使用方法举例:

    说明:其中 tuya_user_api_lwdp_object_new 所创建的 OBJ_SIZE 要大于等于真实的 DP 点数量,不然的话会出现上报异常,同时确保上报的 DP 与真实的一一对应,避免创建与上报的 DP 数量不一致。上报以后调用释放接口:tuya_user_api_lwdp_object_free(OBJ_SIZE, dataP);

    void dev_state_report(void)
    {
        USER_API_LOGD("###### dev_state_report ######");
    #define OBJ_SIZE 6
        uint8_t i = 0;
        lwdp_object_t* dataP = tuya_user_api_lwdp_object_new(OBJ_SIZE);
    
        if (dataP == NULL) {
            USER_API_LOGE("dataP == NULL");
            return;
        }
        dataP[i].id = DPID_RSSI;
        tuya_user_api_lwdp_encode_int(tuya_user_api_rssi_get(), &dataP[i++]);
    
        dataP[i].id = DPID_HEARTBEAT_INTERVAL;
        tuya_user_api_lwdp_encode_int(tuya_user_api_get_dev_lifetime(), &dataP[i++]);
    
        dataP[i].id = DPID_HEARTBEAT_TOTAL;
        tuya_user_api_lwdp_encode_int(packet_send_sum, &dataP[i++]);
    
        dataP[i].id = DPID_HEARTBEAT_SUCCESS;
        tuya_user_api_lwdp_encode_int(packet_send_succeed, &dataP[i++]);
    
        tuya_user_api_get_system_runtime(&on_time, NULL);
        dataP[i].id = DPID_POWON_TIME;
        tuya_user_api_lwdp_encode_int(on_time, &dataP[i++]);
    
        dataP[i].id = DPID_POWON_RST;
        tuya_user_api_lwdp_encode_int(tuya_user_api_get_powerOn_result(), &dataP[i++]);
    
        tuya_user_api_dp_report(true, i, dataP);
        tuya_user_api_lwdp_object_free(OBJ_SIZE, dataP);
    #undef OBJ_SIZE   
    }