简体中文
简体中文
English
联系我们
注册
登录
layout空间导航

4.x SDK 开发指南

更新时间:2022-05-09 01:32:28下载pdf

本文介绍了涂鸦 IPC 嵌入式 SDK 的开发流程,从运行 SDK Demo 开始,将开发中所需要的资料串联。您可根据实际需要进行具体功能的开发,可查看对应方案的开发说明,适用于开发者快速入门。

名词解释

名词 说明
配网 网络连接的过程,建立设备、手机 App、涂鸦 IoT 之间的通信链路。
产品ID 即 PID(Product ID),PID关联了产品具有的功能点,用来标示某一类产品。同一种类型的 IPC 设备共享同一个 PID。
UUID 即通用唯一识别码(Universally Unique Identifier),由计算机随机生成的数字,保证所有 UUID 都具有唯一性。
AUTHKEY 设备的授权值,在涂鸦 IoT 上已注册能够使用涂鸦云服务的服务码。
P2P ID 点对点服务ID,3.0.0 版本以上 SDK 不需要填写 P2P ID,涂鸦 IoT 自动进行分配。
Token 在扫描二维码配网的过程中,由涂鸦 IoT 生成的标识码,具有 10 分钟的有效期。
DP 即功能点(Date Point),设备功能与涂鸦 IoT 交互的。
Chromecast 谷歌电视棒或谷歌Home Hub 实时视频传输服务。
Echo Show 亚马逊 Echo Show 音响实时视频传输服务。
IFTTT 与其他品牌商建立设备联动的服务,例如梅赛德斯奔驰。
OTA 即设备固件在线升级( Over the Air)。

SDK 目录

涂鸦 IPC 嵌入式 SDK 文件目录如下:

.
└── tuya_ipc_sdk
	├── include
	│   ├── base_hwl.h
	│   ├── cJSON.h
	│   ├── tuya_cloud_base_defs.h
	│   ├── tuya_cloud_com_defs.h
	│   ├── tuya_cloud_error_code.h
	│   ├── tuya_cloud_types.h
	│   ├── tuya_cloud_wifi_defs.h
	│   ├── tuya_g711_utils.h
	│   ├── tuya_iot_config.h
	│   ├── tuya_ipc_ai_detect_storage.h
	│   ├── tuya_ipc_ai_face_db.h
	│   ├── tuya_ipc_ai_face_detect.h
	│   ├── tuya_ipc_api.h
	│   ├── tuya_ipc_chromecast.h
	│   ├── tuya_ipc_cloud_storage.h
	│   ├── tuya_ipc_echo_show.h
	│   ├── tuya_ipc_img_defs.h
	│   ├── tuya_ipc_img_proc.h
	│   ├── tuya_ipc_media.h
	│   ├── tuya_ipc_mqt_proccess.h
	│   ├── tuya_ipc_p2p.h
	│   ├── tuya_ipc_ptz.h
	│   ├── tuya_ipc_qrcode_proc.h
	│   ├── tuya_ipc_skill.h
	│   ├── tuya_ipc_stream_storage.h
	│   ├── tuya_ipc_video_msg.h
	│   ├── tuya_ipc_video_proc.h
	│   ├── tuya_ipc_webrtc.h
	│   ├── tuya_ipc_wifi_migrate.h
	│   ├── tuya_ring_buffer.h
	│   ├── uni_network.h
	│   └── wifi_hwl.h
	└── libs
		├── libmbedtls.a
		└── libtuya_ipc.a

业务流程

获取到 SDK 后,您首先需要进行SDK服务注册。注册操作通过SDK配网模组建立,服务通道建立成功,用户可以将设备的音视频信息按照格式要求送入SDK开辟的缓存中,至此用户无需关心后续的操作。

可通过App端进行操控设备。基于原始的的音视频数据,SDK结合手机端App可以实现设备的存储功能、点对点传输服务以及其他的第三方接入功能,例如亚马逊 EchoShow 和谷歌 ChromeCast 接入功能。

4.x SDK 开发指南

快速体验

您可以根据以下流程快速体验涂鸦 IPC SDK 功能:

  1. 登录 涂鸦 IoT 平台创建产品。
  2. 获取涂鸦 IPC SDK 包。
  3. 在 App Store 等应用市场下载涂鸦智能 app。
  4. 在 Linux 系统中做简单适配。
  5. 运行 Demo,手机移动端直观体验。

第一步:创建产品

创建产品的详细步骤可参考 选品类创建产品

  1. 登录 涂鸦 IoT 平台
  2. 选择 安防监控 > 云台摄像机,选择自定义方案,输入输入产品名称和型号等信息。
    4.x SDK 开发指南
  3. 根据产品所需,添加功能点。
    4.x SDK 开发指南
  4. 硬件开发 阶段,选择芯片平台和模组名称。
    4.x SDK 开发指南
  5. 根据页面提示,您可以获取免费的激活码。
    4.x SDK 开发指南
  6. 选择了激活码后,等待生成免费授权码。
  7. 短信收到后,点击订单详情。
    4.x SDK 开发指南
  8. 产品创建成功,并获得10组试用的授权信息。

第二步:获取 IPC SDK

请登录 GitHub 下载 SDK。

第三步:运行 Demo

通过运行 Demo,您可以快速体验涂鸦 IPC SDK 功能。

  1. 按照 Demo 使用说明,下载Demo 代码到本地。

    #git clone https://github.com/tuya/tuya-iotos-embeded-multimedia-demo.git
    
  2. 将下载的 SDK 解压到demo_for_ipc/sdk目录下,生成可执行程序。

    #cd demo_for_ipc
    #make APP_NAME=demo
    
  3. 手机安装涂鸦智能App,选择添加摄像机,生成二维码。将二维码通过微信“扫一扫”功能。

    {“s”:“Tuya-Test”,“p”:“88888888”,“t”:“AYm1YVV5jupJcF”}

    该 Token 有 10 分钟的有效期。

  4. 执行虚拟机,体验 Demo。

    #cd output
    #./tuya_ipc_demo -m 2 -p [PID] -u [UUID] -a [AUTHKEY] -r "[./]" -t "[TOKEN]"
    
    4.x SDK 开发指南
  5. 通过如下指令体验不同的功能,例如虚拟设备执行过程中,运行以下命令:

    #start
    

    随后,可以在消息中心产看得到一条移动侦测的上报。

    4.x SDK 开发指南

    其他模拟指令说明如下表:

    指令 指令说明
    start 模拟移动侦测事件触发
    stop 模拟停止移动侦测事件
    status 获取设备激活状态
    bell 模拟门铃事件上报

SDK 配网开发

涂鸦 IPC SDK 搭建了一套完整的用以引导设备配网的函数框架,本章节阐述配网的流程以及各框架函数的用途。建议您按照文档介绍,在对应的框架函数下,实现各功能点的具体操作。

填写基本参数

  • 分别修改 DB 文件、OTA 文件、本地录像文件的保存路径,宏定义如下:

    #define IPC_APP_STORAGE_PATH "/tmp/"
    #define IPC_APP_UPGRADE_FILE "/tmp/upgrade.file"
    #define IPC_APP_SD_BASE_PATH "/tmp/"
    

    说明:DB 文件中保存设备的配网信息,需要保存至掉电不丢失的路径下 DB 文件与本地录像文件保存路径需要检查结尾是否有/

  • 修改PID、UUID、AUTHKEY的宏定义:

    说明:PID 需要联系涂鸦项目经理获取,UUID、AUTHKEY 可以在 IoT平台创建产品(PID)后申请获取。

  • 修改嵌入式软件版本号的宏定义:

    #define IPC_APP_VERSION "1.2.3"
    

    说明:版本号必需按照格式:xx.xx.xx 进行填写,不超过20位字符。

Wi-Fi 快联配网

4.x SDK 开发指南

开发流程

  • IPC_APP_Init_SDK 函数中,选择:WIFI_INIT_AUTO 配网模式,token参数填NULL。

  • SDK跳转至:hwl_wf_wk_mode_get函数,如下所示:

    说明:需要在函数内根据实际情况,实现Wi-Fi模组状态的获取操作。

    OPERATE_RET hwl_wf_wk_mode_get(OUT WF_WK_MD_E *mode)
    {
       if(NULL == mode)
     {
       return OPRT_INVALID_PARM;
      }
    
  • SDK跳转至:hwl_wf_all_ap_scan 函数扫描信道,需要往AP_IF_S 结构体传入Wi-Fi扫描信道结果,函数如下所示。

    说明:需要在函数内根据实际情况,实现Wi-Fi模组信道扫描的操作。

    OPERATE_RET hwl_wf_all_ap_scan(OUT AP_IF_S **ap_ary,OUT UINT_T *num)
    {
     if(NULL == ap_ary || NULL == num)
     {
      return OPRT_INVALID_PARM;
     }
    
     static AP_IF_S s_aps[MAX_AP_SEARCH];
    
     memset(s_aps, 0, sizeof(s_aps));
     *ap_ary = s_aps;
     *num = 0;
    
  • SDK跳转至:hwl_wf_sniffer_set 函数,需要往其中传入Wi-Fi接收到的空口包信号,函数如下所示。

    说明:需要在函数内根据实际情况,实现Wi-Fi模组sniffer状态数据的获取操作。

    #define MAX_REV_BUFFER 512
    BYTE_T rev_buffer[MAX_REV_BUFFER];
    
    int skipLen = 26;/* Radiotap default length is 26 */
    
    while((s_pSnifferCall != NULL) && (TRUE == s_enable_sniffer))
    {
     int rev_num = recvfrom(sock, rev_buffer, MAX_REV_BUFFER, 0, NULL, NULL);
     ieee80211_radiotap_header *pHeader = (ieee80211_radiotap_header *)rev_buffer;
     skipLen = pHeader->it_len;
    
  • 当SDK判断Wi-Fi输入的空口包数据正确,调用函数:hwl_wf_wk_mode_set,将Wi-Fi状态设置为station模式。

    说明:需要在函数内根据实际情况,实现开启Wi-Fi模组不同模式的操作。

    case WWM_SNIFFER:
    {
    #ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
        exec_cmd(tmpCmd);
    #endif
        snprintf(tmpCmd, 100, "iwconfig %s mode Monitor", WLAN_DEV);
        exec_cmd(tmpCmd);
    #ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
        exec_cmd(tmpCmd);
    
  • SDK跳转至:hwl_wf_station_connect函数进行联网操作。

    说明:需要在函数内根据实际情况,实现Wi-Fi模组的联网操作。

    OPERATE_RET hwl_wf_station_connect(IN CONST CHAR_T *ssid,IN CONST CHAR_T passwd)
    {
     if(sniffer_set_done)
     {
      sniffer_set_done = FALSE;
      IPC_APP_Notify_LED_Sound_Status_CB(IPC_REV_WIFI_CFG);
      usleep(10001000);
     }
    
     IPC_APP_Notify_LED_Sound_Status_CB(IPC_CONNECTING_WIFI);
    
      //TODO
      //Add a blocking operation for the Wi-Fi connection here.
    
      sleep(2);
    
       return OPRT_OK;
    }
    
  • 配网成功后,调用:hwl_wf_station_stat_get,通知SDK已获取到IP地址。

    说明:此接口为高频接口,需要按照实时状态返回。

    OPERATE_RET hwl_wf_station_stat_get(OUT WF_STATION_STAT_E *stat)
    {
     if(NULL == stat)
     {
      return OPRT_INVALID_PARM;
     }
     *stat = WSS_GOT_IP; //Be sure to return in real time//Reservedreturn OPRT_OK;
    }
    

二维码配网

  • IPC_APP_Init_SDK 函数中,选择:WIFI_INIT_AUTO 配网模式,token参数填NULL

  • SDK跳转至:hwl_wf_wk_mode_get函数。

    说明:需要在函数内根据实际情况,实现Wi-Fi模组状态的获取操作。

    OPERATE_RET hwl_wf_wk_mode_get(OUT WF_WK_MD_E *mode)
    {
       if(NULL == mode)
     {
       return OPRT_INVALID_PARM;
      }
    
  • SDK跳转至:hwl_wf_sniffer_set 函数,获取二维码的扫描结果,函数如下所示:

    说明:需要在函数内根据实际情况,在__tuya_linux_get_snap_qrcode中调用zbar库实现二维码的识别操作。

    #define MAX_REV_BUFFER 512
    BYTE_T rev_buffer[MAX_REV_BUFFER];
    
    int skipLen = 26;/* Radiotap default length is 26 */
    
    while((s_pSnifferCall != NULL) && (TRUE == s_enable_sniffer))
    {
     int rev_num = recvfrom(sock, rev_buffer, MAX_REV_BUFFER, 0, NULL, NULL);
     ieee80211_radiotap_header *pHeader = (ieee80211_radiotap_header *)rev_buffer;
     skipLen = pHeader->it_len;
    
  • 当SDK获取到二维码的解析结果,调用函数:hwl_wf_wk_mode_set,将Wi-Fi状态设置为station模式。

    说明:需要在函数内根据实际情况,实现开启Wi-Fi模组不同模式的操作。

    case WWM_SNIFFER:
    {
    #ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
        exec_cmd(tmpCmd);
    #endif
        snprintf(tmpCmd, 100, "iwconfig %s mode Monitor", WLAN_DEV);
        exec_cmd(tmpCmd);
    #ifndef WIFI_CHIP_7601
        snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
        exec_cmd(tmpCmd);
    
  • SDK跳转至:hwl_wf_station_connect函数进行联网操作,具体如下所示。

    说明:需要在函数内根据实际情况,实现Wi-Fi模组的联网操作。

    OPERATE_RET hwl_wf_station_connect(IN CONST CHAR_T *ssid,IN CONST CHAR_T passwd)
    {
     if(sniffer_set_done)
     {
      sniffer_set_done = FALSE;
      IPC_APP_Notify_LED_Sound_Status_CB(IPC_REV_WIFI_CFG);
      usleep(10001000);
     }
    
     IPC_APP_Notify_LED_Sound_Status_CB(IPC_CONNECTING_WIFI);
    
      //TODO
      //Add a blocking operation for the Wi-Fi connection here.
    
      sleep(2);
    
       return OPRT_OK;
    }
    
  • 配网成功后,调用:hwl_wf_station_stat_get,通知SDK已获取到IP地址。

    说明:此接口为高频接口,需要按照实时状态返回。

    OPERATE_RET hwl_wf_station_stat_get(OUT WF_STATION_STAT_E *stat)
    {
     if(NULL == stat)
     {
      return OPRT_INVALID_PARM;
     }
     *stat = WSS_GOT_IP; //Be sure to return in real time//Reservedreturn OPRT_OK;
    }
    

AP配网

  • IPC_APP_Init_SDK 函数中,选择:WIFI_INIT_AP 配网模式,Token参数填NULL。

  • SDK跳转至:hwl_wf_wk_mode_get函数,如下所示:

    说明:需要在函数内根据实际情况,实现Wi-Fi模组状态的获取操作。

    OPERATE_RET hwl_wf_wk_mode_get(OUT WF_WK_MD_E *mode)
    {
       if(NULL == mode)
     {
       return OPRT_INVALID_PARM;
      }
    
  • SDK跳转至:hwl_wf_ap_start函数开启AP模式。

    说明:需要在函数内根据WF_AP_CFG_IF_S结构体参数信息,打开AP模式。

    OPERATE_RET hwl_wf_ap_start(IN CONST WF_AP_CFG_IF_S *cfg)
    {
     if(NULL == cfg)
      {
      return OPRT_INVALID_PARM;
     }
    
     printf("Start AP SSID:%s \r\n", cfg->ssid);
     //Reservedreturn OPRT_OK;
    }
    
  • SDK接收到AP模式的配网信息,调用函数:hwl_wf_wk_mode_set,将Wi-Fi状态设置为station模式。

    说明:需要在函数内根据实际情况,实现开启Wi-Fi模组不同模式的操作。

    case WWM_STATION:
     {
    #ifndef WIFI_CHIP_7601
      snprintf(tmpCmd, 100, "ifconfig %s down", WLAN_DEV);
      exec_cmd(tmpCmd);
    #endif
      snprintf(tmpCmd, 100, "iwconfig %s mode Managed", WLAN_DEV);
      exec_cmd(tmpCmd);
    #ifndef WIFI_CHIP_7601
      snprintf(tmpCmd, 100, "ifconfig %s up", WLAN_DEV);
      exec_cmd(tmpCmd);
    #endif
    
  • SDK跳转至:hwl_wf_station_connect函数进行联网操作,具体如下所示:

    说明:需要在函数内根据实际情况,实现Wi-Fi模组的联网操作

    OPERATE_RET hwl_wf_station_connect(IN CONST CHAR_T *ssid,IN CONST CHAR_T passwd)
    {
     if(sniffer_set_done)
     {
      sniffer_set_done = FALSE;
      IPC_APP_Notify_LED_Sound_Status_CB(IPC_REV_WIFI_CFG);
      usleep(10001000);
     }
    
     IPC_APP_Notify_LED_Sound_Status_CB(IPC_CONNECTING_WIFI);
    
      //TODO
      //Add a blocking operation for the Wi-Fi connection here.
    
      sleep(2);
    
       return OPRT_OK;
    }
    
  • 配网成功后,调用:hwl_wf_station_stat_get,通知SDK已获取到IP地址:

    说明:此接口为高频接口,需要按照实时状态返回。

    OPERATE_RET hwl_wf_station_stat_get(OUT WF_STATION_STAT_E *stat)
    {
     if(NULL == stat)
     {
      return OPRT_INVALID_PARM;
     }
     *stat = WSS_GOT_IP; // Be sure to return in real time// Reservedreturn OPRT_OK;
    }
    

有线配网(局域网发现)

  • 设备端调用:IPC_APP_Init_SDK函数进行SDK初始化。

  • SDK调用:hwl_wf_get_ip函数,获取设备IP地址,设备在检测到已连接路由器时,返回获取到的IP地址,函数如下所示:

    说明:需要在函数内根据实际情况,开发设备获取IP地址的具体操作

    OPERATE_RET hwl_wf_get_ip(IN CONST WF_IF_E wf,OUT NW_IP_S *ip)
    {
     if(NULL == ip)
     {
      return OPRT_INVALID_PARM;
     }
    
  • SDK调用:hwl_wf_get_mac函数,获取设备Mac地址,函数如下所示:

    说明:需要在函数内根据实际情况,开发设备获取Mac地址的具体操作

    OPERATE_RET hwl_wf_get_mac(IN CONST WF_IF_E wf,INOUT NW_MAC_S *mac)
    {
     if(NULL == mac)
     {
      return OPRT_INVALID_PARM;
     }
    
  • SDK将获取到的设备IP地址与Mac地址通过路由器发送广播包,手机连上路由器Wi-Fi并接收到广播信息后,向服务器获取token,获取成功后给到设备端进行联网,至此,配网操作完成。

有线配网(手机扫设备二维码)

  • 确认已下载带有wired属性涂鸦SDK且涂鸦UUID经过后台打标处理。

  • 调用:IPC_APP_Init_SDK函数进行SDK初始化,入参WIFI_INIT_MODE_E 选择:WIFI_INIT_NULL,token填写NULL。

  • 设备调用:tuya_ipc_set_region函数,设置设备的国家码,函数如下所示:

    说明:国家码需要按照设备实际出货的区域来设定,否则容易出现设备跟其他国家区域服务器交互的异常问题

    #if defined(QRCODE_ACTIVE_MODE) && (QRCODE_ACTIVE_MODE==1)
       tuya_ipc_set_region(REGION_CN);
       p_token = NULL;
    #endif
    
  • 设备调用:tuya_ipc_get_qrcode函数,获取二维码URL信息,函数如下所示:

    说明:每个UUID的URL链接固定不变,带屏幕的设备可将URL链接转换成二维码来显示,不带屏幕的设备可以直接将短链接打印贴出。

    #if defined(QRCODE_ACTIVE_MODE) && (QRCODE_ACTIVE_MODE==1)/* demo: how to get qrcode from tuya server for display */
     sleep(2);
     CHAR_T info[32] = {0};
     tuya_ipc_get_qrcode(NULL,info, 32);
     printf("###info:%s\n", info);
    #endif
    
  • 手机点击右上角扫描图标,扫描二维码激活设备。

音视频开发

实时预览开发

SDK初始化时,将默认创建10秒音视频数据缓存,您将设备采集到的音视频数据送入ringbuffer即可。

SDK库文件已实现数据的发送,您不需要再做对应开发。

开发流程

  • 确认IPC_APP_Set_Media_Info函数中视频参数信息。

    说明:GOP推荐:FPS参数的2~3倍,码率上限1.5Mbps,分辨率推荐16:9,支持H264、H265编码格式。

    s_media_info.channel_enable[E_CHANNEL_VIDEO_MAIN] = TRUE; /* Whether to enable local HD video streaming /
    s_media_info.video_fps[E_CHANNEL_VIDEO_MAIN] = 30; / FPS /
    s_media_info.video_gop[E_CHANNEL_VIDEO_MAIN] = 30; / GOP /
    s_media_info.video_bitrate[E_CHANNEL_VIDEO_MAIN] = TUYA_VIDEO_BITRATE_1M; / Rate limit /
    s_media_info.video_width[E_CHANNEL_VIDEO_MAIN] = 640; / Single frame resolution of width*/
    s_media_info.video_height[E_CHANNEL_VIDEO_MAIN] = 360;/* Single frame resolution of height /
    s_media_info.video_freq[E_CHANNEL_VIDEO_MAIN] = 90000; / Clock frequency /
    s_media_info.video_codec[E_CHANNEL_VIDEO_MAIN] = TUYA_CODEC_VIDEO_H264; / Encoding format */
    
  • 确认IPC_APP_Set_Media_Info函数中音频参数信息。

    说明:音频支持PCM、G711U、G711A格式,上传最大长度:1400字节,支持8K、16K音频,App下发音频长度固定为:320字节。

    s_media_info.channel_enable[E_CHANNEL_VIDEO_SUB] = TRUE; /* Whether to enable local SD video stream /
    s_media_info.video_fps[E_CHANNEL_VIDEO_SUB] = 30; / FPS /
    s_media_info.video_gop[E_CHANNEL_VIDEO_SUB] = 30; / GOP /
    s_media_info.video_bitrate[E_CHANNEL_VIDEO_SUB] = TUYA_VIDEO_BITRATE_512K; / Rate limit /
    s_media_info.video_width[E_CHANNEL_VIDEO_SUB] = 640; / Single frame resolution of width /
    s_media_info.video_height[E_CHANNEL_VIDEO_SUB] = 360;/ Single frame resolution of height /
    s_media_info.video_freq[E_CHANNEL_VIDEO_SUB] = 90000; / Clock frequency /
    s_media_info.video_codec[E_CHANNEL_VIDEO_SUB] = TUYA_CODEC_VIDEO_H264; / Encoding format */
    
  • 将摄像机采集到的音视频数据通过函数:tuya_ipc_ring_buffer_append_data传入ringbuffer中,函数如下所示。

    /* append new frame into a ring buffer*/
    OPERATE_RET tuya_ipc_ring_buffer_append_data(CHANNEL_E channel, UCHAR_T *addr, UINT_T size, MEDIA_FRAME_TYPE_E type, UINT64_T pts);
    
  • 在TUYA_APP_Enable_Speaker_CB函数中实现喇叭的开关控制,函数如下所示。

    VOID TUYA_APP_Enable_Speaker_CB(BOOL_T enabled)
    {
     printf("enable speaker %d \r\n", enabled);
     //TODO/* Developers need to turn on or off speaker hardware operations.
     If IPC hardware features do not need to be explicitly turned on, the function can be left blank. */
    }
    
  • 在TUYA_APP_Rev_Audio_CB函数中实现音频数据的播放操作,函数如下所示。

    VOID TUYA_APP_Rev_Audio_CB(IN CONST MEDIA_FRAME_S *p_audio_frame,
                  TUYA_AUDIO_SAMPLE_E audio_sample,
                  TUYA_AUDIO_DATABITS_E audio_databits,
                  TUYA_AUDIO_CHANNEL_E audio_channel)
    {
     printf("rev audio cb len:%u sample:%d db:%d channel:%d\r\n", p_audio_frame->size, audio_sample, audio_databits, audio_channel);
     //PCM-Format 8K 16Bit MONO//TODO/*Developers need to implement the operations of voice playback */
    }
    
  • App默认下发G711U格式音频,设备端如需以PCM格式播放,需要调用函数:tuya_g711_decode对下发的音频做转码处理,函数如下所示。

    说明:函数参数:

    • 1:TUYA_G711_MU_LAW
    • 2:被解析数据的地址
    • 3:被解析数据的长度
    • 4:数据解析后输出的地址
    • 5:数据解析后的长度
    int tuya_g711_decode(unsigned char type, unsigned short *src, unsigned int srcLen, unsigned char *drc, unsigned int *pOut);
    

本地录像开发

涂鸦SDK库文件已集成本地存储功能,您仅需要将音视频送入ringbuffer,且完成本地存储的设置即可。

因此,本节将主要介绍如何开发本地存储录像的开启与设置。

同步时间开发

  • 在mqtt上线后,调用IPC_APP_Sync_Utc_Time函数与服务器同步时间。判断mqtt上线回调函数:__IPC_APP_Get_Net_Status_cb,如下所示:

    说明

    • 开启本地录像前必须先同步时间,避免时间不正确,找不到回放视频问题。
    • 同步时间,偶尔会出现失败现象,需要多调用几次,直到成功。
    STATIC VOID __IPC_APP_Get_Net_Status_cb(IN CONST BYTE_T stat)
    {
     PR_DEBUG("Net status change to:%d", stat);
     switch(stat)
     {
    #if defined(WIFI_GW) && (WIFI_GW == 1)
       case STAT_CLOUD_CONN: //for Wi-Fi ipc
       case STAT_MQTT_ONLINE: //for low-power Wi-Fi ipc
    #endif
    #if defined(WIFI_GW) && (WIFI_GW==0)
       case GB_STAT_CLOUD_CONN: //for wired ipc
    #endif
    {
       IPC_APP_Notify_LED_Sound_Status_CB(IPC_MQTT_ONLINE);
       PR_DEBUG("mqtt is online\r\n");
       s_mqtt_status = 1;
       break;
    
  • 设备端调用接口:IPC_APP_Sync_Utc_Time同步服务器时间,函数如下所示:

    说明

    • 时区设定:仅在设备第一次配网前,更改手机自身时区,引导设备配网,新时区会生效(即:若设备已配网成功,修改手机时区,新时区不会生效)。
    • 以手机自身的时区时间为准,与账号的区域和app显示的时区无关。
    OPERATE_RET IPC_APP_Sync_Utc_Time(VOID)
    {
      TIME_T time_utc;
      INT_T time_zone;
      PR_DEBUG("Get Server Time ");
      OPERATE_RET ret = tuya_ipc_get_service_time_force(&time_utc, &time_zone);
    
       if(ret != OPRT_OK)
       {
        return ret;
       }
       //The API returns OK, indicating that UTC time has been successfully obtained.
       //If it return not OK, the time has not been fetched.
    
       PR_DEBUG("Get Server Time Success: %lu %d", time_utc, time_zone);
       return OPRT_OK;
    }
    
  • 调用接口:tuya_ipc_check_in_dls做夏令时的判断,判断结果为true,则时区+1。

    说明:夏令时具有周期性变化的属性,设备端需要周期性判断夏令时是否发生变化。

    /*
    \fn OPERATE_RET tuya_ipc_check_in_dls(IN TIME_T time_utc, OUT BOOL * pIsDls)
    \brief check if specified utc time is in daylight saving time夏令时
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_check_in_dls(IN TIME_T time_utc, OUT BOOL_T * pIsDls);
    
  • 夏令时判断范例代码:

    TIME_T time_utc;
    tuya_ipc_get_utc_time(&time_utc);
    BOOL_T isDls = FALSE;
    tuya_ipc_check_in_dls(time_utc,&isDls);
    if (TRUE == isDls)
    {
     time_utc += 3600;
    }
    

本地存储开发

  • 调用TUYA_APP_Init_Stream_Storage函数进行本地存储初始化,App下发指令,开启事件录像或全时录像,函数如下所示。

    说明

    • 连续存储开启后,无需做其他操作,SDK自动将录像保存至SD卡,设备启动后,本地存储初始化仅需要调用一次。
    • 本地存储仅支持SD卡使用FAT32格式,若检测到SD卡格式异常,可以通过 DP 上报SD卡格式异常信息。
    • 用户在App点击SD卡设置时,会有弹窗提醒SD卡异常,引导客户对SD卡进行格式化。
    OPERATE_RET TUYA_APP_Init_Stream_Storage(IN CONST CHAR_T *p_sd_base_path)
    {
     STATIC BOOL_T s_stream_storage_inited = FALSE;
     if(s_stream_storage_inited == TRUE)
     {
      PR_DEBUG("The Stream Storage Is Already Inited");
      return OPRT_OK;
     }
    
  • 若已开启事件存储,当设备需要进行录像时,调用函数:tuya_ipc_ss_start_event开启录像,调用:tuya_ipc_ss_stop_event关闭录像,单个事件录像最长时间10分钟,超过10分钟若没有调用:tuya_ipc_ss_stop_event,则SDK会自动关闭录像。

  • 按照实际情况,在tuya_ipc_sd_get_status函数中实现SD卡的检测,函数如下所示。

    说明:当检测SD卡格式异常,例如:NTFS格式的SD卡时,返回abnormal状态,其余都返回normal状态

    E_SD_STATUS tuya_ipc_sd_get_status(VOID)
    {
     FILE *fp = fopen(LINUX_SD_DEV_FILE, "rb");
     if(!fp)
     {
      return SD_STATUS_NOT_EXIST;
     }
     fclose(fp);
    

功能点开发

DP 主要用以控制设备的各项功能,您需要根据服务器下发的 DP 与 DP 的值,设置设备并将设置后的状态上报服务器,在tuya_ipc_utils.h文件中对通用 DP 进行了具体说明,您可以根据已有demo代码来进行开发与设置。若有定制化 DP 加入,则仿照已有的相同数据类型的 DP 代码进行添加与设置即可。

DP 数据保存与读取

  • 需要在以下两个函数: __tuya_app_write_INT与__tuya_app_write_STR中实现 DP 数据保存的具体操作,函数如下所示。

    STATIC VOID __tuya_app_write_INT(CHAR_T *key, INT_T value)
    {
     //TODO
      CHAR_T tmp_cmd[128] = {0};
      snprintf(tmp_cmd, 128, "mkdir -p /tmp/tuya.cfgs/;echo %d > /tmp/tuya.cfgs/%s", value, key);
      printf("write int exc: %s \r\n", tmp_cmd);
      system(tmp_cmd);
    }
    
    STATIC VOID __tuya_app_write_STR(CHAR_T *key, CHAR_T *value)
    {
     //TODO
     CHAR_T tmp_cmd[256] = {0};
     snprintf(tmp_cmd, 256, "echo %s > /tmp/tuya.cfgs/%s", value, key);
     printf("write STR exc: %s \r\n", tmp_cmd);
     system(tmp_cmd);
    }
    
  • 需要在以下两个函数: __tuya_app_read_INT与__tuya_app_read_STR中实现 DP 数据读取的具体操作,函数如下所示。

    STATIC INT_T __tuya_app_read_INT(CHAR_T *key)
    {
     //TODO
     CHAR_T tmp_file[64] = {0};
     snprintf(tmp_file, 64, "cat /tmp/tuya.cfgs/%s", key);
     printf("read int exc: %s \r\n", tmp_file);
     FILE *p_file = popen(tmp_file, "r");
    
    STATIC INT_T __tuya_app_read_STR(CHAR_T *key, CHAR_T *value, INT_T value_size)
    {
     //TODOmemset(value, 0, value_size);
     CHAR_T tmp_file[64] = {0};
     snprintf(tmp_file, 64, "cat /tmp/tuya.cfgs/%s", key);
     printf("read str exc: %s \r\n", tmp_file);
     FILE *p_file = popen(tmp_file, "r");
    

OSD水印功能开发

  • OSD 水印 DP:104
  • 根据服务器下发的 DP 值,给视频加上或取消时间水印,水印位置与内容由设备端控制

PIR功能开发

  • PIR DP :152
  • 根据服务器下发的 DP 值,控制设备PIR功能的开关以及灵敏度,当PIR被触发时,调用:tuya_ipc_notify_door_bell_press函数,将摄像机采集到的图像上报服务器。

    说明:PIR上报的频率建议:大于30秒做一次检测并上报

移动侦测开发

SDK提供了控制移动侦测功能开关控制、灵敏度控制、定时控制、间歇控制以及数据上报的函数,4.4.6 SDK库文件已实现移动侦测。

以及移动追踪功能的判断,您可以调用SDK API接口完成功能移动侦测以及移动追踪功能的开发。

移动侦测开发流程(通用)

  • 移动侦测开关DP:134;移动侦测灵敏度DP:106

  • 当摄像机移动侦测功能已被打开,发现画面有变化时,调用函数:tuya_ipc_notify_motion_detect上报图片,函数如下所示。

    说明:移动侦测消息上报,需要选择对应的图片数据类型。

    /*
    \fn OPERATE_RET tuya_ipc_notify_motion_detect
    \brief send a motion-detecttion alarm to tuya cloud and APP
    \param[in] snap_buffer: address of current snapshot
    \param[in] snap_size: size fo snapshot, in Byte
    \param[in] type: snapshot file type, jpeg or png
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_notify_motion_detect(IN CONST CHAR_T *snap_buffer, IN CONST UINT_T snap_size, IN CONST NOTIFICATION_CONTENT_TYPE_E type);
    

移动侦测开发流程(SDK集成)

  • 调用函数:Tuya_Ipc_Motion_Init,进行移动侦测功能初始化,函数如下所示:

    /*********************************************************************************
    * Init input config.
    **********************************************************************************/
    OPERATE_RET Tuya_Ipc_Motion_Init(TUYA_MOTION_TRACKING_CFG mt_cfg);
    
  • 初始化参数结构体TUYA_MOTION_TRACKING_CFG信息说明如下所示:

    typedef struct _TUYA_MOTION_TRACKING_CFG
    {
      INT_T frame_w;  //视频宽度
      INT_T frame_h;  //视频长度
      INT_T y_thd;  //移动侦测评判阈值,默认30,阈值范围推荐540:范围1255,值越小,越灵敏
      INT_T sensitivity;  //移动侦测灵敏度,设置1~7,值越大,越灵敏
      TUYA_RPERCENT_ECT roi;  //移动侦测区域设置,设置参考TUYA_RECT结构体
      INT_T tracking_enable;  //运动跟踪开关,只开移动侦测设置为:0,开启运动跟踪设置为:1
    }TUYA_MOTION_TRACKING_CFG;
    
  • 初始化参数结构体TUYA_RECT说明如下所示:

    typedef struct _TUYA_RECT
    {
      INT_T left;  //区域坐标的x值占x轴的百分比(值需要取整),例:x坐标点为128,10%
      INT_T top;  //区域坐标的y值占y轴的百分比(值需要取整),例:y坐标点为72,10%
      INT_T right;  //移动侦测区域长度所占x轴的百分比(值需要取整),例:x方向长度为256,20%
      INT_T bottom;  //移动侦测区域长度所占y轴的百分比(值需要取整),例:y方向长度为144,20%
    }TUYA_AI_RECT;
    
  • 结构体TUYA_RECT,图例示意如下所示:

    4.x SDK 开发指南
  • 初始化函数:Tuya_Ipc_Motion_Init调用后,若需要修改移动侦测的参数,调用函数:Tuya_Ipc_Set_Motion进行修改。

    /*********************************************************************************
    * Set config dynamically.
    **********************************************************************************/
    OPERATE_RET Tuya_Ipc_Set_Motion(TUYA_MOTION_TRACKING_CFG mt_cfg);
    
  • 获取移动侦测的参数函数:Tuya_Ipc_Get_Motion,函数如下所示:

    /*********************************************************************************
    * Get config dynamically.
    **********************************************************************************/
    void Tuya_Ipc_Get_Motion(TUYA_MOTION_TRACKING_CFG *mt_cfg);
    
  • 设备每隔一段时间调用接口Tuya_Ipc_Motion,将采集到的YUV数据传入,当SDK判断两张图片间存在差异,需要触发移动报警,则返回值1,若无,则返回值0。函数如下所示:

    说明

    • 传入的图片信息必须是:YUV420格式,移动追踪功能调优,建议取5次移动追踪判断结果的平均值作为舵机转动的目标角度,减少设备追踪不上事物移动的情况。
    • 函数:Tuya_Ipc_Motion调用的频率由设备测试调优的实际需求而定,参数说明如下:
      • 1:传入图片信息
      • 2:返回1,则移动侦测触发成功
      • 3:若打开了移动追踪功能,则输出物体移动后以图像中心为中心轴坐标系的物体(x,y)像素坐标点
    /*********************************************************************************
    * Execute Motion Detect \ Motion Tracking.
    * in_data       Input YUV.
    * motion_flag     Return the value of Motion Detect.
               0 for no moving; 1 for moving exist.
    * motion_point   Return the center point coordinate of the largest moving object.
               Both values(x, y) are 0 for no moving; otherwise, moving exist.
               Return values(0, 0) when tracking_enable==0
    **********************************************************************************/
    OPERATE_RET Tuya_Ipc_Motion(UCHAR_T *in_data, INT_T *motion_flag, TUYA_POINT * motion_point);
    
  • 若函数:Tuya_Ipc_Motion判断两张图片间的差异需要触发移动追踪,则输出物体移动后,以图像中心为中心轴坐标系的物体(x,y)像素坐标点,图例示意如下所示:

    说明:设备需根据(x,y)像素坐标点计算出舵机转向的角度并控制舵机转动。

    4.x SDK 开发指南
  • 若在OTA中,需要优化内存资源,可调用函数:Tuya_Ipc_Motion_Release退出移动侦测以及移动追踪功能,函数如下所示:

    /*********************************************************************************
    * release.
    **********************************************************************************/
    void Tuya_Ipc_Motion_Release();
    

间歇移动侦测

  • 间歇移动侦测 DP:133
  • 根据服务器下发的 DP 值,间歇地开启移动侦测功能,例如:接收到133 DP 值为5,则每间隔5分钟开启移动侦测,移动侦测每次开启时间为5分钟。

图像缩放开发(SDK集成)

图像缩放功能目的在于调整图像的分辨率,将采集到的图像调整至需要的目标分辨率。

图像缩放开发流程

  • 调用函数: Tuya_Ipc_Img_Resize,传入图片信息,参数信息,图片输出的地址信息,函数如下所示:

    说明:参数说明如下:

    • 1:传入图片地址,
    • 2:传入图片参数信息,
    • 3:图片输出地址。
    • 传入图片信息必须是:YUV420格式
    /*********************************************************************************
    * YUV420 image scale interface
    * in_data  input YUV420
    * paras   scale struct
    * out_data  output YUV420
    **********************************************************************************/
    OPERATE_RET Tuya_Ipc_Img_Resize(UCHAR_T *in_data, TUYA_IMG_RESIZE_PARA paras, UCHAR_T *out_data);
    
  • 结构体TUYA_IMG_RESIZE_PARA说明如下所示:

    typedef struct _TUYA_IMG_RESIZE_PARA
    {
        INT_T srcWidth;  //传入图像的宽度
        INT_T srcHeight;  //传入图像的高度
        INT_T dstWidth;  //输出图像的宽度
        INT_T dstHeight;  //输出图像的高度
        IMG_TYPE img_type;  //缩放方式
        IMG_RESIZE_TYPE resize_type;
    }TUYA_IMG_RESIZE_PARA;
    
  • 选择加密方式结构体IMG_RESIZE_TYPE说明如下所示:

    typedef enum
    {
       LINEAR,  //速度快但质量差
       CUBIC,  //速度慢但质量高
    }IMG_RESIZE_TYPE;
    

PTZ摇头机功能开发

设备接收到服务端DP的控制指令后,控制PTZ摇头机转动

PTZ摇头机通用控制开发

  • 云台 DP 控制说明如下表所示,根据服务器下发的DP值控制设备方向,控制逻辑:接收到119转动方向 DP 后,
    开始转动,直到接收到116 停止转动DP,停止舵机转动。
摇头机 DP DP 说明
119 云台转动控制 0-右上,1-右,2-右下,3-下,4-左下,5-左,6-左上,7-上
116 云台转动停止,BOOL类型
161 移动跟踪使能开关,bool类型,true 开启,false 不开启
178 收藏点操作,string型,type:1 添加,type:2 删除,不同类型跟的数据串不同

PTZ摇头机预设位控制开发

  • 预设位控制功能 DP :

    #define TUYA_DP_PRESET_SET               178            /* 收藏点操作,string型,type:1 添加,type:2 删除,不同类型跟的数据串不同 */
    
  • 预设备添加收藏点前,需要上报179 DP ,eum:2 非巡航模式

  • 设备接收到服务器下发的 DP 数据,增加预设点函数:tuya_ipc_preset_add,具体如下所示:

    error_num = tuya_ipc_preset_add(&node[num]);
    
    snprintf(respond_add,128,"{\"type\":%d,\"data\":{\"seq\":%d,\"pan\":%d,\"tilt\": %d,\"zoom\": 0 }}",
    type-valueint,error_num,node[num].ptz.pan,node[num].ptz.tilt);
    
  • S_PRESET_POSITION 结构体

    说明

    • id[32]:服务器下发的ID值,可以不做处理
    • name[32]:增加收藏点时,name[32]下发收藏点名字,可以做对应存储
    • mpId:设备增加对应收藏点后,需要填入收藏点的序号,从1开始
    • ptz:填入设备收藏点的具体p与t坐标,若是定焦设备,z坐标值为0
    typedef struct
    {
       CHAR_T id[32]; //id in server
        CHAR_T name[32]; //preset point name
       INT_T mpId; //index ID
       S_PRESET_PTZ ptz; //ptz for preset position
    } S_PRESET_POSITION;
    
    typedef struct
    {
     INT_T pan;  //横向
     INT_T tilt;  //竖直
     INT_T zoom;  //定焦设备该值为0
    }S_PRESET_PTZ;
    
  • 调用tuya_ipc_preset_add_pic函数,传入图片地址以及图片大小,函数如下所示。

    /*
    \fn OPERATE_RET tuya_ipc_preset_add_pic(CHAR_T *addr, UINT_T size)
    \brief upload a snapshot for current preset position
    \param[in] addr/size: address and size of the picture to be uploaded
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_preset_add_pic(CHAR_T *addr, UINT_T size);
    
  • 设备上电后,调用接口:tuya_ipc_preset_get与服务器同步已存在的预设位收藏点信息

    /*
    \fn OPERATE_RET tuya_ipc_preset_get(S_PRESET_CFG *preset_cfg)
    \brief get all preset positions stored in tuya cloud.
    \param[in out] preset_cfg
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_preset_get(S_PRESET_CFG *preset_cfg);
    
  • 服务器下发删除预设位指令,设备端删除相关信息后,调用函数:tuya_ipc_preset_del,回传服务器下发的ID值:

    //删除预设位,error需要0与1交替
    if(tmp == 0)
    {
     tmp = 1;
    }
    else if(tmp == 1)
    {
     tmp = 0;
    }
    
    tuya_ipc_preset_del(devId->valuestring);
    
    snprintf(respond_del,128,"{"type":%d,"data":{"error":%d}}",type->valueint,tmp);
    

AP预览功能开发

开启AP预览

  • PID增加231、232、233、234 DP

  • APP操作页面输入 AP 信息(包含:ssid 与 passwd),通过232 DP 下发信息给到设备端,即触发handle_DP_AP_SWITCH函数,函数如下所示:

    STATIC VOID handle_DP_AP_SWITCH(IN TY_OBJ_DP_S *p_dp_json)
    {
      CHAR_T resp[32] = {0};
      INT_T ap_enable = IPC_APP_set_ap_mode((cJSON *)p_dp_json->value.dp_str);
      if(ap_enable < 0)
      {
         snprintf(resp, 32, "{"ap_enable":0,"errcode":0}");
      }
      else
      {
         snprintf(resp, 32, "{"ap_enable":%d,"errcode":0}",ap_enable);
      }
      respone_dp_str(TUYA_DP_AP_SWITCH, resp);
      if(ap_enable >= 0)
      {
        change_ap_process();
      }
    }
    
  • 在函数IPC_APP_set_ap_mode中,可以获取到下发的 AP信息,设备需要调用tuya_ipc_save_ap_info接口,将AP信息(ssid 与 passwd)保存至涂鸦数据库,设备回复232 DP 内容:"{"ap_enable":1,"errcode":0}",回复231 DP 内容:"{"is_ap":1,"ap_ssid":"xxx","password":"xxx"}"IPC_APP_set_ap_mode函数如下所示:

    说明:设备回复232 DP 后,需要主动回复231 DP ,刷新设备在服务器状态

    INT_T IPC_APP_set_ap_mode(IN cJSON *p_ap_info)
    {
      if (NULL == p_ap_info)
     {
      return 0;
     }
    
     INT_T ap_onoff = -1;
    
     printf("%s %d handle_DP_AP_SWITCH:%s rn",FUNCTION,LINE, (char *)p_ap_info);
    
     cJSON * pJson = cJSON_Parse((CHAR_T *)p_ap_info);
    
  • DP 上报完成后,Wi-Fi切换模式,从station 状态切换至AP状态,手机寻找对应ssid连接,重新点击设备列表设备,即可进行AP预览。

  • 若设备已开启AP热点,拔电重启,SDK初始化函数:IPC_APP_Init_SDK 入参:WIFI_INIT_MODE_E需要选择:WIFI_INIT_AP,token填NULL,需要调用接口:tuya_ipc_set_ap_info传入AP热点信息,函数如下所示:

    说明:设备拔电重启后,AP预览,设备无法连接外网, P2P的初始化,需要脱离MQTT上线的前置条件,即SDK初始化后,开始初始化P2P

    /*
    \fn OPERATE_RET tuya_ipc_set_ap_info(IN CONST CHAR_T *ssid, IN CONST CHAR_T *passwd)
    \brief set ap info when start SDK
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_set_ap_info(IN CONST CHAR_T *ssid, IN CONST CHAR_T *passwd);
    

设备时间获取

设备连接app后,app通过233 DP 下发UTC时间信息,通过234下发时区信息,设备需要调用接口:tuya_ipc_set_service_time与接口:uni_set_time_zone将UTC时间信息以及时区信息设置到SDK中,函数如下所示。

说明:时区设置传入值,例:-5:00 (纽约非夏令时)。

/*
\fn OPERATE_RET tuya_ipc_set_service_time(IN TIME_T new_time_utc)
\brief set time of tuya SDK
\return OPERATE_RET
*/
OPERATE_RET tuya_ipc_set_service_time(IN TIME_T new_time_utc);

/*
\Function: uni_set_time_zone
\Input: time_zone->"+/-hh:mm"
\Output: none
\ Return: none
*/
OPERATE_RET uni_set_time_zone(IN CONST CHAR_T *time_zone)

关闭AP预览

  • 手机点击 结束AP模式handle_DP_AP_SWITCH函数被触发,Wi-Fi AP模式关闭并触发tuya_ipc_reconnect_wifi函数,设备重连Wi-Fi,函数如下所示:

    if(cur_mode == WWM_SOFTAP)
    {
      hwl_wf_ap_stop();
      tuya_ipc_reconnect_wifi();
    }
    
  • 若设备已关闭AP热点,拔电重启,SDK初始化函数:IPC_APP_Init_SDK 入参:WIFI_INIT_MODE_E需按照原有的入参填入,token填NULL,仍需要调用接口:tuya_ipc_set_ap_info传入上一次AP热点信息

    说明:设备若没有启动过AP预览功能,则不需要传入上一次AP热点信息,若有启动过,则之后的每一次启动,都需要调用tuya_ipc_set_ap_info传入上一次AP热点信息

日志上报后台开发

  • 设备启动应用前,判断SD卡中是否存在标志位信息,若存在,将应用的输出日志重定向到SD卡,若不存在,则将应用的输出日志重定向到目录:/tmp/log.txt

    说明:设备端开发涂鸦SDK,禁止连接第三方或私有服务器,否则存在不符合海外法规风险,设备端DNS必须需要设定为自动获取,否则存在设备联网异常风险。

  • 调用函数:tuya_ipc_set_log_attr控制日志输出,SDK默认日志输出级别:4,设置数值越少,日志输出则越少,trace级别:5。函数调用位置如下所示:

    tuya_ipc_init_sdk(&env);
    tuya_ipc_set_log_attr(5,NULL);
    tuya_ipc_start_sdk(init_mode, p_token);
    

门铃功能开发

本章节主要介绍门铃产品特性功能的开发,包含:低功耗休眠功能、门铃触发功能。若所开发产品不是门铃,可忽略本章节。

设备进入休眠状态

  • 增加 DP :149

    说明:149 DP 数值:0 设备进入休眠状态 1 设备进入唤醒状态
    #define TUYA_DP_DOOR_SLEEP “149” /* 设备休眠开关,BOOL类型,true未休眠,false休眠 */

  • 进入低功耗状态:

    1. 调用函数:tuya_ipc_book_wakeup_topic 通知服务器,设备将要准备进入睡眠状态
    2. 通过:tuya_ipc_get_mqtt_socket_fd获取对应的socket fd 信息
    3. 通过:tuya_ipc_get_wakeup_data 获取app唤醒的数据,设备低功耗芯片与服务器取得通信后,判断是否有接收到唤醒数据来唤醒设备
    4. 通过:tuya_ipc_get_heartbeat_data获取设备休眠时,与服务器建立连接的保活包,设备休眠时,保活包的发送频率建议为30S~120S
    5. 上报 DP :149,通知服务器设备进入休眠
    6. 设备进入休眠状态,只留下低功耗芯片与网络保持心跳包通信

设备进入唤醒状态

  • 设备判断唤醒数据成功后,启动设备并回复149 DP ,回复值:1

  • 若是通过手动按门铃方式唤醒设备,则:

    • 门铃呼叫(图片):设备回复149 dp(低功耗-唤醒状态)点与函数tuya_ipc_door_bell_press,函数入参如下所示:

      说明

      • 参数1:DOORBELL_NORMALL,
      • 2:图片地址,
      • 3:图片大小
      • 4:图片类型
      /*
      \fn OPERATE_RET tuya_ipc_door_bell_press
      \brief send a doorbell pressing message to tuya cloud and APP
      \param[in] doorbell_type: DOORBELL_NORMAL or DOORBELL_AC
      \param[in] snap_buffer: address of current snapshot
      \param[in] snap_size: size fo snapshot, in Byte
      \param[in] type: snapshot file type, jpeg or png
      \return OPERATE_RET
      */
      OPERATE_RET tuya_ipc_door_bell_press(IN CONST DOORBELL_TYPE_E doorbell_type, IN CONST CHAR_T *snap_buffer, IN CONST UINT_T snap_size, IN CONST NOTIFICATION_CONTENT_TYPE_E type);
      
    • 门铃呼叫(P2P):设备回复149dp(低功耗-唤醒状态)点,函数tuya_ipc_door_bell_press,以及函数:tuya_ipc_notify_with_event,函数入参如下所示:

      说明

      • 1:DOORBELL_AC
      • 2:NULL
      • 3:空
      • 4:NULL
      /*
      \fn OPERATE_RET tuya_ipc_door_bell_press
      \brief send a doorbell pressing message to tuya cloud and APP
      \param[in] doorbell_type: DOORBELL_NORMAL or DOORBELL_AC
      \param[in] snap_buffer: address of current snapshot
      \param[in] snap_size: size fo snapshot, in Byte
      \param[in] type: snapshot file type, jpeg or png
      \return OPERATE_RET
      */
      OPERATE_RET tuya_ipc_door_bell_press(IN CONST DOORBELL_TYPE_E doorbell_type, IN CONST CHAR_T *snap_buffer, IN CONST UINT_T snap_size, IN CONST NOTIFICATION_CONTENT_TYPE_E type);
      

      说明

      • 1:图片地址
      • 2:图片size
      • 3:图片type
      • 4:NOTIFICATION_NAME_DOORBELL
      /*
      \fn OPERATE_RET tuya_ipc_notify_with_event
      \brief send a editable alarm to tuya cloud and App
      \param[in] snap_buffer: address of current snapshot
      \param[in] snap_size: size fo snapshot, in Byte
      \param[in] type: snapshot file type, jpeg or png
      \param[in] name: editable event type, NOTIFICATION_NAME_E
      \return OPERATE_RET
      */
      
      OPERATE_RET tuya_ipc_notify_with_event(IN CONST CHAR_T *snap_buffer, IN CONST UINT_T snap_size, IN CONST NOTIFICATION_CONTENT_TYPE_E type, IN CONST NOTIFICATION_NAME_E name);
      
  • App操作函数查询接口:

    • 获取音视频开启、关闭信息回调函数:__TUYA_APP_p2p_event_cb
    • 获取设备连接数信息查询函数:tuya_ipc_get_client_conn_info

低功耗设备功能启动优化

  • mqtt上线回调函数:__IPC_APP_Get_Net_Status_cb 可以使用STAT_MQTT_ONLINE判定mqtt是否上线成功,成功后可往下执行剩余操作。
  • Wi-Fi连通外网后,可另起线程,进行P2P 初始化,提高设备接入外网效率。
  • 设备只需检测到SD卡挂载成功,即可进行本地录像初始化,SDK带有时间修复机制,会自动检测并修复时间戳异常的数据。
  • 带有Echo与Chromecast增值服务的设备,Echo 或 Chromecast 启动时,会调用对应的回调接口。TUYA_APP_Echoshow_StartTUYA_APP_Chromecast_Start,设备收到start 回调时不能休眠,直到收到停止回调TUYA_APP_Echoshow_StopTUYA_APP_Chromecast_Stop时才能休眠。
  • 使用本地存储事件录像功能,调用函数:tuya_ipc_ss_stop_event后,设备需要稍等2~3秒,直至录像数据已经保存至SD卡再进入休眠。
  • 本地存储调用了event stop 接口后,需要调用tuya_ipc_ss_get_status 获取本地录像的状态,当状态是:E_STORAGE_STOP 时,设备再进入休眠。tuya_ipc_ss_get_status接口只能用来获取状态,不能设置状态。
  • 使用云存储功能,调用函数tuya_ipc_cloud_storage_event_delete后,需要调用:tuya_ipc_cloud_storage_get_event_status_by_id 查询云存储数据上传的状态,查询状态不为:EVENT_ONGOINGEVENT_READY时,设备才可进入休眠状态,否则容易出现云存储数据丢失的情况,具体说明如下所示。
    typedef enum
    {
      EVENT_NONE,    //没有云存储事件发生或云存储事件传输完成
      EVENT_ONGOING,  //云存储事件正在进行
      EVENT_READY,   //云存储事件进行的临界点,出现在刚调用add 接口时
      EVENT_INVALID  //云存储功能没有初始化成功
    }EVENT_STATUS_E;
    
  • 云存储可调用接口:tuya_ipc_cloud_storage_set_pre_record_time 设置取预录制的时间,获取更往前的预录制视频数据。
  • 提高P2P线程、本地存储线程的优先级(提高线程优先级存在一定风险,设备端需要仔细确认其他线程基本功能不受影响。

OTA功能开发

OTA作为设备升级与维护的最重要途径之一,将在本章节进行具体介绍。当有固件需要升级时,SDK将通过回调的形式告知设备,进行OTA操作。

OTA开发流程

  • OTA请求回调函数:IPC_APP_Upgrade_Inform_cb(),包含:固件下载的 URL(下载链接)以及 Size(文件的大小),函数如下所示:

    VOID IPC_APP_Upgrade_Inform_cb(IN CONST FW_UG_S *fw)
    {
      PR_DEBUG("Rev Upgrade Info");
      PR_DEBUG("fw->fw_url:%s", fw->fw_url);
      PR_DEBUG("fw->fw_md5:%s", fw->fw_md5);
      PR_DEBUG("fw->sw_ver:%s", fw->sw_ver);
      PR_DEBUG("fw->file_size:%u", fw->file_size);
    
  • 释放(优化)系统(内存)资源:调用tuya_ipc_ss_set_write_mode,关闭本地录像功能,然后调用:tuya_ipc_ss_uninit()tuya_ipc_tranfser_close函数,uninitquit函数主要用以SDK本地存储与P2P功能的反初始化,尽可能释放内存资源。

    说明:内存资源优化需要在tuya_ipc_upgrade_sdk函数前进行(如下所示)。

    VOID IPC_APP_Upgrade_Inform_cb(IN CONST FW_UG_S *fw)
    {
      PR_DEBUG("Rev Upgrade Info");
      PR_DEBUG("fw->fw_url:%s", fw->fw_url);
      PR_DEBUG("fw->fw_md5:%s", fw->fw_md5);
      PR_DEBUG("fw->sw_ver:%s", fw->sw_ver);
      PR_DEBUG("fw->file_size:%u", fw->file_size);
    
      FILE *p_upgrade_fd = fopen(s_mgr_info.upgrade_file_path, "w+b");
      //此处优化内存资源
      tuya_ipc_upgrade_sdk(fw, __IPC_APP_get_file_data_cb, __IPC_APP_upgrade_notify_cb, p_upgrade_fd);
    
  • 开始下载固件,回调函数:__IPC_APP_get_file_data_cb,函数如下所示:

    说明:函数中有入参与出参,入参主要提供给您使用,出参由您获取到数据后,需要返回是否已完成数据的写入,写入成功返回0。

    OPERATE_RET __IPC_APP_get_file_data_cb(IN CONST FW_UG_S *fw, IN CONST UINT_T total_len,IN CONST UINT_T offset,
    IN CONST BYTE_T *data,IN CONST UINT_T len,OUT UINT_T *remain_len, IN PVOID_T pri_data)
    {
       PR_DEBUG("Rev File Data");
      PR_DEBUG("total_len:%d fw_url:%s", total_len, fw->fw_url);
      PR_DEBUG("Offset:%d Len:%d", offset, len);
    
  • 函数:tuya_ipc_upgrade_sdk如下所示:

    说明:第一个回调给到SDK与App,用以显示OTA升级整体进度。固件下载完成后,第二个回调会有反馈。

    VOID IPC_APP_Upgrade_Inform_cb(IN CONST FW_UG_S *fw)
    {
      PR_DEBUG("Rev Upgrade Info");
      PR_DEBUG("fw->fw_url:%s", fw->fw_url);
      PR_DEBUG("fw->fw_md5:%s", fw->fw_md5);
      PR_DEBUG("fw->sw_ver:%s", fw->sw_ver);
      PR_DEBUG("fw->file_size:%u", fw->file_size);
    
      FILE *p_upgrade_fd = fopen(s_mgr_info.upgrade_file_path, "w+b");
      //此处优化内存资源
      tuya_ipc_upgrade_sdk(fw, __IPC_APP_get_file_data_cb, __IPC_APP_upgrade_notify_cb, p_upgrade_fd);
    
  • 在函数:__IPC_APP_upgrade_notify_cb中替换新固件,函数如下所示:

    说明:固件下载完成后,需要客户在函数中实现固件的具体替换过程,替换成功后,需要在此函数内进行设备的重启操作固件替换前,需要备份db文件,固件替换成功后,对比db文件替换固件前后的md5值,若相同,则可以直接重启,若不相同,则将备份的db文件替换现有的db文件再重启设备。

    VOID __IPC_APP_upgrade_notify_cb(IN CONST FW_UG_S *fw, IN CONST INT_T download_result, IN PVOID_T pri_data)
    {
      FILE *p_upgrade_fd = (FILE *)pri_data;
      fclose(p_upgrade_fd);
    
      PR_DEBUG("Upgrade Finish");
      PR_DEBUG("download_result:%d fw_url:%s", download_result, fw->fw_url);
    
      if(download_result == 0)
      {
      /* The developer needs to implement the operation of OTA upgrade,
      when the OTA file has been downloaded successfully to the specified path. [ p_mgr_info->upgrade_file_path ]*/
      }
      //TODO
      //reboot system
    }
    
  • 若OTA升级失败,需要在函数:__IPC_APP_upgrade_notify_cb中加入重启操作。

    说明:反初始化的操作不可逆,若OTA失败,设备必须进行重启。

  • 固件升级时,手机App进度显示会暂停在92%~98%之间,此时,固件已完成下载,App正在等待设备重启并上报新固件版本号,版本号上报成功后,App将显示 升级成功

  • App等待设备替换固件与上报新版本号的时间为1分钟,若设备流程超过此时间,需要告知项目经理PID 后台进行配置。

OTA自定义进度上报开发

  • OTA请求回调函数:IPC_APP_Upgrade_Inform_cb(),包含:固件下载的URL(下载链接)以及size(文件的大小)。

  • 释放(优化)系统(内存)资源:调用tuya_ipc_ss_set_write_mode,关闭本地录像功能,然后调用:tuya_ipc_ss_uninit()tuya_ipc_tranfser_quit函数,uninitquit函数主要用以SDK本地存储与P2P功能的反初始化,尽可能释放内存资源。

    说明:设备端可根据实际启用的SDK接口,做对应的反初始化,优化内存空间。

  • 设备端通过URL开始下载固件,调用tuya_ipc_upgrade_progress_report函数,上报OTA下载的进度,函数如下所示:

    说明:上报的进度值建议小于99%。

    /*
    \fn OPERATE_RET tuya_ipc_upgrade_progress_report
    \brief send a upgrade progress to tuya cloude and app
    \param[in] percent: upgrade progress percent , valid value [0,100]
    \return SUCCESS – OPERATE_RET , FAIL – COMM ERROR
    */
    OPERATE_RET tuya_ipc_upgrade_progress_report(IN UINT_T percent);
    
  • 固件升级时,手机App进度显示会暂停在98%,此时,固件已完成下载,App正在等待设备重启并上报新固件版本号,版本号上报成功后,App将显示 升级成功

  • App等待设备替换固件与上报新版本号的时间为1分钟,若设备流程超过此时间,需要告知项目经理PID 后台进行配置。

云存储功能开发

SDK库文件已集成云存储功能,在购买云存储服务后,SDK将ringbuffer中的音视频信息发送至涂鸦 IoT 保存,保存时间根据所购买的云存储服务而定。

开发流程

  • 每个UUID都有一次体验低价购买云存储服务的权限。

  • 成功购买服务后,调用云存储初始化函数:TUYA_APP_Enable_CloudStorage

  • SDK默认对数据采用软件加密的方式,加密接口:OpensslAES_CBC128_encrypt 使用AES CBC方式。若软件加密给MCU带来较大的负载,可改用硬件加密方式,使用soc硬件加密通道,加密方式:PKCS5/PKCS7,如下所示:

    填充类型 说明
    不填充 有些块在加密模式下不需要填充,或者明文都是块长度的整数倍。
    ISO10126 假设块长度为 64 bit,数据为 FF FF FF FF FF FF FF FF FF,则填充后为 FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07。
    PKCS5/PKCS7 假设块长度为 64 bit,数据为 FF FF FF FF FF FF FF FF FF,则填充后为 FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07。PKCS5要求块大小的8字节,后续扩充为16字节,PKCS7块大小范围为1~255字节。
    OAEP/PKCS1 为RSA算法提供的。
  • 事件云存储录像:当摄像机发现画面变化时,必须调用tuya_ipc_cloud_storage_event_add函数,SDK才会将音视频信息上传至涂鸦 IoT ,当发现画面静止时,调用:tuya_ipc_cloud_storage_event_delete终止云存储事件录像。tuya_ipc_cloud_storage_event_add接口调用成功,返回event ID用以调用tuya_ipc_cloud_storage_event_delete函数。若tuya_ipc_cloud_storage_event_add接口调用失败,返回:INVALID_EVENT_ID。云存储录像最终以列表的形式展现,函数如下所示:

    说明:调用tuya_ipc_cloud_storage_event_add

    • 1:图片地址
    • 2:图片size
    • 3:EVENT_TYPE_MOTION_DETECT
    • 4:300(单个云存储事件最大长度300秒)
    • 开启标记,最长时间为5分钟,5分钟后若没有调用tuya_ipc_cloud_storage_event_delete,SDK将自动结束事件。
    /*
    \fn OPERATE_RET tuya_ipc_cloud_storage_event_add
    \brief add a new event
    \param[in] snapshot_buffer snapshot_size of current evnet
    \param[in] type event type
    \param[in] max_duration max duration of the event, not bigger than MAX_CLOUD_EVENT_DURATION
    \ event will be automaticly stopped when times up, if it’s not stopped by delete API
    \return EVENT_ID unique evnet id
    /
    EVENT_ID tuya_ipc_cloud_storage_event_add(CHAR_T *snapshot_buffer, UINT_T snapshot_size, ClOUD_STORAGE_EVENT_TYPE_E type, UINT_T max_duration);
    
    /*
    \fn OPERATE_RET tuya_ipc_cloud_storage_event_delete
    \brief delete(stop) specified event
    \return OPERATE_RET
    */
    OPERATE_RET tuya_ipc_cloud_storage_event_delete(EVENT_ID event_id);
    

Echo show 与 chromecast 功能

Echo show 与 chromecast 功能是将摄像机采集到的音视频数据显示在亚马逊或谷歌的智能设备上。本章节将介绍具体开发流程。此类功能的开发需要您自行搭建测试环境。

  • 确认PID以及UUID是否都完成增值服务打标。

  • 设备端在所有需要启动功能确认初始化成功后,调用接口 tuya_ipc_upload_skills上报技能值函数如下所示。

    说明:SDK使用第一路音频发送音频数据(支持PCM),设备端不需要另起音频通道。

    /*very important! After all module inited, update skill to tuya cloud */
    tuya_ipc_upload_skills();
    
  • 谷歌推流开始时,__TUYA_APP_p2p_event_cb 收到回调:TRANS_STREAMING_VIDEO_START,函数如下所示:

    说明:在低功耗设备应用时,建议收到start回调后,设备不进入休眠状态,直到收到stop回调。

    case TRANS_STREAMING_VIDEO_START:
    {
      TRANSFER_SOURCE_TYPE_E *pSrcType = (TRANSFER_SOURCE_TYPE_E *)args;
      PR_DEBUG("streaming start type %d",*pSrcType);
      break;
    }
    
  • 谷歌推流结束时,__TUYA_APP_p2p_event_cb 收到回调:TRANS_STREAMING_VIDEO_STOP,函数如下所示:

    case TRANS_STREAMING_VIDEO_STOP:
    {
      TRANSFER_SOURCE_TYPE_E *pSrcType = (TRANSFER_SOURCE_TYPE_E *)args;
      PR_DEBUG("streaming stop type %d",*pSrcType);
      break;
    }
    
  • 亚马逊推流开始时,__TUYA_APP_p2p_event_cb 收到回调:TRANS_LIVE_VIDEO_START,type:3,函数如下所示:

    case TRANS_LIVE_VIDEO_START:
    {
      C2C_TRANS_CTRL_VIDEO_START * parm = (C2C_TRANS_CTRL_VIDEO_START *)args;
      PR_DEBUG("chn[%u] type[%d]video start",parm->channel,parm->type);
      break;
    }
    
  • 亚马逊推流结束时,__TUYA_APP_p2p_event_cb 收到回调:TRANS_LIVE_VIDEO_STOP,type:3,函数如下所示:

    case TRANS_LIVE_VIDEO_STOP:
    {
      C2C_TRANS_CTRL_VIDEO_STOP * parm = (C2C_TRANS_CTRL_VIDEO_STOP *)args;
      PR_DEBUG("chn[%u] type[%d] video stop",parm->channel,parm->type);
      break;
    }
    

设备解绑与复位

本章节主要简述设备通过App解绑与按复位键,这两种复位方式,开发中的流程与区别。

设备解绑开发流程

  • App点击 删除设备 按键,SDK将清除DB文件中的配网信息并执行回调函数:IPC_APP_Reset_System_CB重启设备,函数如下所示。

    说明:需要在函数内,实现设备的重启与对 DP 数据文件进行重置操作,不需要删除DB文件。

    VOID IPC_APP_Reset_System_CB(GW_RESET_TYPE_E type)
    {
      printf("reset ipc success. please restart the ipc %d\n", type);
      IPC_APP_Notify_LED_Sound_Status_CB(IPC_RESET_SUCCESS);
      //TODO
      /* Developers need to restart IPC operations */
    }
    

设备复位开发流程

  • 设备检测到复位键被按下,存在复位操作,删除三个db文件:tuya_user.db_baktuya_user.dbtuya_enckey.db
  • 设备对 DP 数据文件进行重置操作并重启。

相关文档