安防能力

更新时间:2023-02-01 04:04:02下载pdf

TuyaOS 提供了家庭安防能力,支持布防、撤防、报警等安防功能。本文将介绍基于 TuyaOS 网关开发框架如何快速开发安防网关产品。

背景信息

网关支持三种布撤防模式:在家布防、离家布防、撤防,终端用户可以通过安防遥控器或者 App 自由切换其模式。

网关布防还有以下两个功能:

  • 延迟布防:终端用户可以根据自己进入或离开防区来设置延迟时间,满足安防系统延迟生效的需求。

  • 布防忽略:终端用户切换到在家布防或者离家布防时,如果网关检查到传感设备状态异常,会触发布防忽略告警。此时,用户有三个选择:

    • 选择一:忽略该设备继续执行布防操作,在布防期间该传感设备仍上报异常状态但不触发报警。
    • 选择二:取消布防操作,网关恢复到切换前的布撤防状态。
    • 选择三:解除传感设备异常状态后,继续执行布防操作,在布防期间该传感设备上报异常触发报警。

网关有以下三种报警状态:

  • 布防报警:网关处于布防模式,终端用户设置的布防传感设备(如门磁、人体感应等传感器)触发报警时,网关报警。
  • 环境报警:网关处于任何布撤防模式,环境传感设备(如水浸报警器、燃气报警器、烟雾报警器、一氧化碳传感器等)触发报警时,网关报警。
  • 主动报警:网关处于任何布撤防模式,终端用户通过 App、SOS 紧急按钮、安防遥控器等方式主动触发报警,网关报警。

涂鸦 IoT 开发平台 上创建网关产品可以选择安防标准功能点,其定义如下:

DP ID 功能点名称 数据类型 功能点属性
4 报警声开关 布尔型(Bool) -
32 主机状态 枚举型(Enum) [“normal”,“alarm”]
34 重启 布尔型(Bool) -
45 主动报警 字符型(String) -

实现原理

家庭安防的布撤防模式其实可以理解成一种特殊的联动,当布防设备满足报警条件时,则触发报警。

TuyaOS 提供了安防回调接口,您无需关注具体的实现方式,只需要在回调中专注于应用业务的处理,比如根据布撤防以及报警状态播放音频片段或者控制 LED 指示灯。

实现方法

TuyaOS 开启安防功能比较简单,只需要调用 tuya_iot_gw_home_security_start 接口就可以。

该接口要求在 TuyaOS 初始化和网关预初始化 之间被调用,否则会导致安防功能不能正常工作。

为满足不同的开发需求,TuyaOS 提供了两种安防注册方式,您可以自由选择其中的一种:

  • 方式一:启动安防服务 tuya_iot_gw_home_security_start 接口的参数为 NULL 时,TuyaOS 内部实现了安防回调接口和网关安防功能点处理,另外提供一个更直观的通知回调,通过 tuya_iot_gw_home_security_reg_ops_cb 接口注册。选择这种方式开发门槛低,但受到 TuyaOS 限制。
  • 方式二:启动安防服务 tuya_iot_gw_home_security_start 接口的参数非 NULL 时,您需要实现安防回调接口,把它作为参数。这种方式的开发门槛相对高一些,但灵活性也更高。

实现示例

实现方式 1:

#include "tuya_home_security_api.h"

/**
 * @brief 报警回调
 *
 * @param[in] volume 音量
 * @param[in] time   报警时长
 */
STATIC VOID __home_security_alarm_cb(INT_T volume, UINT_T time)
{
    PR_DEBUG("home security alarm cb, volume: %d, time: %d", volume, time);
}

/**
 * @brief 报警消音回调
 *
 * @param[in] mute_on TRUE 为消音,FALSE 为播放
 */
STATIC VOID __home_security_alarm_mute_cb(INT_T mute_on)
{
    PR_DEBUG("home security alarm mute cb, mute_on: %d", mute_on);
}

/**
 * @brief 报警取消回调
 */
STATIC VOID __home_security_alarm_cancel_cb(VOID)
{
    PR_DEBUG("home security alarm cancel cb");
}

/**
 * @brief 进入撤防模式回调
 *
 * @param[in] volume 音量
 */
STATIC VOID __home_security_disarmed_cb(INT_T volume)
{
    PR_DEBUG("home security disarmed cb, volume: %d", volume);
}

/**
 * @brief 进入离家布防模式回调
 *
 * @param[in] volume 音量
 */
STATIC VOID __home_security_away_and_armed_cb(INT_T volume)
{
    PR_DEBUG("home security away armed cb, volume: %d", volume);
}

/**
 * @brief 进入在家布防模式回调
 *
 * @param[in] volume 音量
 */
STATIC VOID __home_security_home_and_armed_cb(INT_T volume)
{
    PR_DEBUG("home security home armed cb, volume: %d", volume);
}

/**
 * @brief 布防忽略回调
 *
 * @param[in] volume 音量
 */
STATIC VOID __home_security_arm_ignore_cb(INT_T volume)
{
    PR_DEBUG("home security arm ignore cb, volume: %d", volume);
}

/**
 * @brief 布防延迟回调
 *
 * @param[in] volume 音量
 * @param[in] time   延迟时间,单位是秒
 */
STATIC VOID __home_security_arm_countdown_cb(INT_T volume, UINT_T time)
{
    PR_DEBUG("home security arm delay cb, volume: %d, time: %d", volume, time);
}

/**
 * @brief 报警延迟回调
 *
 * @param[in] volume 音量
 * @param[in] time   延迟时间,单位是秒
 */
STATIC VOID __home_security_alarm_countdown_cb(INT_T volume, UINT_T time)
{
    PR_DEBUG("home security alarm delay cb, volume: %d, time: %d", volume, time);
}

OPERATE_RET demo_home_security(VOID)
{
    OPERATE_RET rt = OPRT_OK;
    TY_HOME_SECURITY_OPS_CB_S security_alarm_ops_cb = {
        .alarm_cb           = __home_security_alarm_cb,
        .alarm_mute_cb      = __home_security_alarm_mute_cb,
        .alarm_cancel_cb    = __home_security_alarm_cancel_cb,
        .disarmed_cb        = __home_security_disarmed_cb,
        .away_and_armed_cb  = __home_security_away_and_armed_cb,
        .home_and_armed_cb  = __home_security_home_and_armed_cb,
        .arm_ignore_cb      = __home_security_arm_ignore_cb,
        .arm_countdown_cb   = __home_security_arm_countdown_cb,
        .alarm_countdown_cb = __home_security_alarm_countdown_cb,
    };

    // TuyaOS 初始化
    TUYA_CALL_ERR_RETURN(tuya_iot_init("./"));

    // 注册回调
    TUYA_CALL_ERR_RETURN(tuya_iot_gw_home_security_reg_ops_cb(&security_alarm_ops_cb));
	// 启动安防服务
    TUYA_CALL_ERR_RETURN(tuya_iot_gw_home_security_start(NULL));

    // 网关预初始化
	tuya_iot_sdk_pre_init(TRUE);

    return OPRT_OK;
}

实现方式 2:

#include "tuya_home_security_api.h"

/**
 * @brief 离线时,存储 DP 数据回调
 * @note 网关离线时,上报的 DP 数据会通过该回调通知应用,应该可以把 DP 数据存储到文件中,待联网后再上报。
 *       如果您的产品不需要用到该功能,可以不做处理。
 *
 * @param[in] dev_id 设备唯一的 ID,表示该 DP 数据是哪个设备上报的
 * @param[in] dps    DP 数据数组
 * @param[in] dp_cnt DP 数据数组的长度
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
STATIC OPERATE_RET __home_security_save_dp_cb(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dps, IN CONST UINT_T dp_cnt)
{
    return OPRT_OK;
}

/**
 * @brief 切换布撤防模式回调
 *
 * @param[in] mode_str "0" 表示撤防,"1" 表示在家布防,"2" 表示离家布防
 * @param[in] time     延迟时间
 * @param[in] is_sound TRUE 表示播放音频,FALSE 表示不播放音频
 */
STATIC VOID __home_security_set_mode_cb(IN CONST CHAR_T *mode_str, IN CONST UINT_T time, BOOL_T is_sound)
{
    return;
}

/**
 * @brief 报警延迟状态回调
 *
 * @param[in] status 延迟状态:开始、延迟中、结束
 */
STATIC VOID __home_security_alarm_delay_status_cb(IN ALARM_DELAY_STATE status)
{
    return;
}

/**
 * @brief 安防事件回调
 *
 * @param[in] event 事件:DISARMED_EVENT(已进入撤防状态)
 *                       ARMED_EVENT(已进入布防状态)
 *                       BYPASS_EVNET(布防忽略)
 *                       WARING_COUNTDOWN(报警延迟)
 * @param[in] data  数据。
 *                  event = WARING_COUNTDOWN 时,data 的数据类型为 UINT_T,表示延迟时间。
 *                  event 为其他值,data 为 NULL。
 */
STATIC VOID __home_security_event_cb(IN SECURITY_EVENT_E event, PVOID_T data)
{
    return;
}

/**
 * @brief 取消报警回调
 */
STATIC VOID __home_security_cancel_alarm_cb(VOID)
{
    return;
}

/**
 * @brief 设备触发报警回调
 *
 * @param[in] cid     触发报警条件的设备 ID
 * @param[in] dp_info 触发报警条件的设备 DP
 * @param[in] type    设备类型。NO_ENV_DEV:普通传感设备,ENV_DEV:环境传感设备
 */
STATIC VOID __home_security_device_alarm_cb(IN CONST CHAR_T *cid, IN ty_cJSON *dp_info, SECURITY_DEV_TYPE_E type)
{
    return;
}

/**
 * @brief 报警回调
 *
 * @param[in] alarm_on   报警状态。TRUE:报警,FALSE:正常
 * @param[in] alarm_info 报警信息。
 */
STATIC VOID __home_security_enter_alarm_cb(IN BOOL_T alarm_on, IN CHAR_T *alarm_info)
{
    return;
}

/**
 * @brief 安防 DP 处理
 */
STATIC OPERATE_RET __home_security_dp_obj_cmd(IN TY_OBJ_DP_S dp)
{
    BYTE_T dpid = dp.dpid;
    switch (dpid) {
        case 4: {
            // 报警声开关
            break;
        }
        case 32: {
            // 设备触发报警
            break;
        }
        case 34: {
            // 重启
            break;
        }
        case 45: {
            // App 触发报警
            break;
        }
        default: {
            break;
        }
    }

    return OPRT_OK;
}

/**
 * @brief 网关 DP 处理回调
 */
VOID __gw_dp_cmd_obj(IN CONST TY_RECV_OBJ_DP_S *dp)
{
    UINT_T i = 0;

    PR_DEBUG("gw obj dp cmd");

    // 直接把接收到的数据上报作为应答
    dev_report_dp_json_async(dp->cid, dp->dps, dp->dps_cnt);

    for (i = 0; i < dp->dps_cnt; i++) {
        __home_security_dp_obj_cmd(dp->dps[i]);
    }
}

OPERATE_RET demo_home_security(VOID)
{
    OPERATE_RET rt = OPRT_OK;
    TY_GW_HOME_SECURITY_APP_CBS_S security_app_cbs = {
        .gw_offline_dp_save_cb                  = __home_security_save_dp_cb,
        .gw_home_security_if_cb                 = __home_security_set_mode_cb,
        .gw_home_security_alarm_delay_status_cb = __home_security_alarm_delay_status_cb,
        .gw_home_security_event_cb              = __home_security_event_cb,
        .gw_home_security_cancel_alarm          = __home_security_cancel_alarm_cb,
        .gw_home_security_alarm_dev_new_cb      = __home_security_device_alarm_cb,
        .gw_home_security_enter_alarm_cb        = __home_security_enter_alarm_cb,
    };

    TY_GW_DP_CBS_S dp_cbs = {
        .obj   = __gw_dp_cmd_obj,
    };

    // TuyaOS 初始化
    TUYA_CALL_ERR_RETURN(tuya_iot_init("./"));

    // 注册接收网关 DP
    TUYA_CALL_ERR_RETURN(tuya_gw_user_dp_reg(&dp_cbs));

	// 启动安防服务,要求在 TuyaOS 初始化和网关预初始化之间
    TUYA_CALL_ERR_RETURN(tuya_iot_gw_home_security_start(&security_app_cbs));

    // 网关预初始化
	tuya_iot_sdk_pre_init(TRUE);

    return OPRT_OK;
}

数据类型

ALARM_DELAY_STATE

typedef enum  {
    ALARM_DELAY_DONOT_CREATE=0, // 延迟开始
    ALARM_DELAY_COUNTDOWN,      // 延迟中
    ALARM_DELAY_END,            // 延迟完成
} ALARM_DELAY_STATE;

ALARM_INFO_S

typedef struct {
    CHAR_T alarm_mode[ALARM_SECURITY_MODE_STR_LEN_MAX+1];  // 布撤防模式,"0" 表示撤防,"1" 表示在家布防,"2" 表示离家布防
    BOOL_T alarm_status; // 报警状态,TRUE 表示报警,FALSE 表示正常
    BOOL_T enable_countdown_status; // 是否处于延迟状态,TRUE 表示处于延迟状态,FALSE 表示处于非延迟状态
} ALARM_INFO_S;

SECURITY_EVENT_E

typedef enum {
    DISARMED_EVENT,     // 已进入撤防状态
    ARMED_EVENT,        // 已进入布防状态,在家布防或离家布防
    BYPASS_EVNET,       // 布防忽略
    WARING_COUNTDOWN,   // 报警延迟
} SECURITY_EVENT_E;

SECURITY_DEV_TYPE_E

typedef enum  {
    NO_ENV_DEV,   // 非环境传感设备,如门磁、人体感应等传感器
    ENV_DEV,      // 环境传感设备,如水浸报警器、烟雾报警器等
} SECURITY_DEV_TYPE_E;

TY_HOME_SECURITY_OPS_CB_S

typedef struct {
    VOID (*alarm_cb)(INT_T volume, UINT_T time); // 报警回调
    VOID (*alarm_mute_cb)(INT_T mute_on); // 报警消音回调
    VOID (*alarm_cancel_cb)(VOID); // 报警取消回调
    VOID (*disarmed_cb)(INT_T volume);  // 进入撤防模式回调
    VOID (*away_and_armed_cb)(INT_T volume); // 进入离家布防模式回调
    VOID (*home_and_armed_cb)(INT_T volume); // 进入在家布防模式回调
    VOID (*arm_ignore_cb)(INT_T volume); // 布防忽略回调
    VOID (*arm_countdown_cb)(INT_T volume, UINT_T countdown_time); // 布防延迟回调
    VOID (*alarm_countdown_cb)(INT_T volume, UINT_T countdown_time); // 报警延迟回调
    VOID (*alarm_door_cb)(INT_T volume); // 已废弃
    VOID (*alarm_devname_cb)(INT_T volume, CHAR_T *name); // 已废弃
} TY_HOME_SECURITY_OPS_CB_S;

TY_GW_HOME_SECURITY_APP_CBS_S

typedef struct {
    GW_OFFLINE_DP_SAVE gw_offline_dp_save_cb; // 离线存储 DP 数据回调
    GW_HOME_SECURITY_IF_CB gw_home_security_if_cb; // 切换布撤防模式回调
    GW_HOME_SECURITY_ALARM_DELAY_STATUS_CB gw_home_security_alarm_delay_status_cb; // 报警延迟状态回调
    GW_HOME_SECURITY_EVENT_CB gw_home_security_event_cb; // 安防事件回调
    GW_HOME_SECURITY_CANCEL_ALARM_CB gw_home_security_cancel_alarm; // 取消报警回调
    GW_HOME_SECURITY_ALARM_DEV_NEW_CB gw_home_security_alarm_dev_new_cb; // 设备触发报警回调
	GW_HOME_SECURITY_ENTER_ALARM_CB gw_home_security_enter_alarm_cb; // 报警回调
} TY_GW_HOME_SECURITY_APP_CBS_S;

回调接口

GW_OFFLINE_DP_SAVE

/**
 * @brief 离线时,存储 DP 数据回调
 * @note 网关离线时,上报的 DP 数据会通过该回调通知应用,应该可以把 DP 数据存储到文件中,待联网后再上报。
 *       如果您的产品不需要用到该功能,可以不做处理。
 *
 * @param[in] dev_id 设备唯一的 ID,表示该 DP 数据是哪个设备上报的
 * @param[in] dps    DP 数据数组
 * @param[in] dp_cnt DP 数据数组的长度
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
typedef OPERATE_RET (*GW_OFFLINE_DP_SAVE)(IN CONST CHAR_T *dev_id, IN CONST TY_OBJ_DP_S *dp_data, IN CONST UINT_T cnt);

GW_HOME_SECURITY_IF_CB

/**
 * @brief 切换布撤防模式回调
 *
 * @param[in] mode_str "0" 表示撤防,"1" 表示在家布防,"2" 表示离家布防
 * @param[in] time     延迟时间
 * @param[in] is_sound TRUE 表示播放音频,FALSE 表示不播放音频
 */
typedef VOID (*GW_HOME_SECURITY_IF_CB)(IN CONST CHAR_T *mode_str, IN CONST UINT_T time, BOOL_T is_sound);

GW_HOME_SECURITY_ALARM_DELAY_STATUS_CB

/**
 * @brief 报警延迟状态回调
 *
 * @param[in] status 延迟状态:开始、延迟中、结束
 */
typedef VOID (*GW_HOME_SECURITY_ALARM_DELAY_STATUS_CB)(IN ALARM_DELAY_STATE alarm_status);

GW_HOME_SECURITY_EVENT_CB

/**
 * @brief 安防事件回调
 *
 * @param[in] event 事件:DISARMED_EVENT(已进入撤防状态)
 *                       ARMED_EVENT(已进入布防状态)
 *                       BYPASS_EVNET(布防忽略)
 *                       WARING_COUNTDOWN(报警延迟)
 * @param[in] data  数据。
 *                  event = WARING_COUNTDOWN 时,data 的数据类型为 UINT_T,表示延迟时间。
 *                  event 为其他值,data 为 NULL。
 */
typedef VOID (*GW_HOME_SECURITY_EVENT_CB)(IN SECURITY_EVENT_E security_event_status, PVOID_T data);

GW_HOME_SECURITY_CANCEL_ALARM_CB

/**
 * @brief 取消报警回调
 */
typedef VOID (*GW_HOME_SECURITY_CANCEL_ALARM_CB)(VOID);

GW_HOME_SECURITY_ALARM_DEV_NEW_CB

/**
 * @brief 设备触发报警回调
 *
 * @param[in] cid     触发报警条件的设备 ID
 * @param[in] dp_info 触发报警条件的设备 DP
 * @param[in] type    设备类型。NO_ENV_DEV:普通传感设备,ENV_DEV:环境传感设备
 */
typedef VOID (*GW_HOME_SECURITY_ALARM_DEV_NEW_CB)(IN CONST CHAR_T *cid, IN ty_cJSON *dp_inf, SECURITY_DEV_TYPE_E dev_type);

GW_HOME_SECURITY_ENTER_ALARM_CB

/**
 * @brief 报警回调
 *
 * @param[in] alarm_on   报警状态。TRUE:报警,FALSE:正常
 * @param[in] alarm_info 报警信息。
 */
typedef VOID (*GW_HOME_SECURITY_ENTER_ALARM_CB)(IN BOOL_T alarm_status, IN CHAR_T *alarm_info);

API 说明

开启安防服务

/**
 * @brief 开启安防服务
 * @note 该接口要求在 TuyaOS 和网关初始化之间调用
 *
 * @param[in] iot_alarm_cbs 参考 TY_GW_HOME_SECURITY_APP_CBS_S
 *            如果参数为空,您可以调用 `tuya_iot_gw_home_security_reg_ops_cb` 接口注册另外更简易的回调
 *            如果参数非空,您需要实现回调接口
 *
 * @return OPRT_OK 成功,其他错误码请参考 tuya_error_code.h
 */
OPERATE_RET tuya_iot_gw_home_security_start(TY_GW_HOME_SECURITY_APP_CBS_S *iot_alarm_cbs);

注册安防回调

/**
 * @brief 注册安防回调
 *
 * @param[in] cbs 参考 TY_HOME_SECURITY_OPS_CB_S
 *
 * @return OPRT_OK 成功,其他错误码请参考 tuya_error_code.h
 */
OPERATE_RET tuya_iot_gw_home_security_reg_ops_cb(TY_HOME_SECURITY_OPS_CB_S *cbs);

设置布撤防模式

/**
 * @brief 设置布撤防模式
 *
 * @param[in] mode_str  "0": 撤防, "1": 在家布防, "2": 离家布防
 * @param[in] node_id   执行布撤防的设备 ID,通常为 NULL,表示网关
 * @param[in] delay_str 延迟时间,格式为 json 字符串。例如:"{\"1\":1000}", 表示模式为在家布防,延迟 1000 秒
 *
 * @return OPRT_OK 成功,其他错误码请参考 tuya_error_code.h
 */
OPERATE_RET tuya_iot_home_secruity_info_set(IN CONST CHAR_T *mode_str, IN CONST CHAR_T *node_id, IN CONST CHAR_T *delay_str);

获取布撤防/报警状态

/**
 * @brief 获取布撤防/报警信息
 *
 * @param[out] alarm_info 参考 ALARM_INFO_S
 *
 * @return OPRT_OK 成功,其他错误码请参考 tuya_error_code.h
 */
OPERATE_RET tuya_iot_home_secruity_get_alarm_info(OUT ALARM_INFO_S *alarm_info);