Skip to content

场景联动 Export (LinkEdge)

场景联动 Export 是 driver-box 的核心业务逻辑组件,提供强大的规则引擎功能。它支持基于设备点位、时间计划、日期条件等触发场景联动,执行设备控制、场景嵌套等动作。原名 LinkEdge,实际是通用的场景联动引擎。

  • 多类型触发器: 支持设备点位触发、定时调度、设备事件触发
  • 丰富条件判断: 数值比较、时间窗口、日期区间、周期性条件
  • 灵活动作执行: 设备点位控制、场景嵌套调用、延时执行
  • 静默期控制: 防止场景频繁触发
  • 执行状态反馈: 全部成功/部分成功/全部失败
  • 持久化配置: JSON 文件存储场景配置
  • 嵌套场景支持: 支持最多 10 层场景嵌套
graph TD
    A[设备数据变化] --> B[点位触发器检测]
    C[定时任务] --> D[调度触发器执行]
    E[手动触发] --> F[场景执行引擎]
    
    B --> F
    D --> F
    
    F --> G[条件评估]
    G --> H{条件满足?}
    H -->|否| I[结束]
    H -->|是| J[执行动作]
    
    J --> K[设备点位控制]
    J --> L[嵌套场景调用]
    J --> M[延时等待]
    
    K --> N[按连接分组写入]
    N --> O[并发执行]
    O --> P[执行结果统计]
    
    L --> F
    M --> J

一个完整的自动化规则,包含:

  • 触发器: 定义何时触发场景
  • 条件: 定义触发后需要满足的条件
  • 动作: 定义满足条件后执行的动作

当指定设备的点位值满足条件时触发:

{
"type": "devicePoint",
"deviceID": "sensor_001",
"devicePoint": "temperature",
"condition": ">",
"value": "30"
}

基于 Cron 表达式的定时触发:

{
"type": "schedule",
"cron": "0 */5 * * * *" // 每5分钟
}

预留的设备事件触发(当前未实现)

支持的操作符:

  • eq: 等于 (==)
  • ne: 不等于 (!=)
  • gt: 大于 (>)
  • ge: 大于等于 (>=)
  • lt: 小于 (<)
  • le: 小于等于 (<=)
  • 执行时间窗口: 在指定时间范围内可执行
  • 日期区间: 在指定日期范围内可执行
  • 静默期: 防止过于频繁的触发
  • 年份: 指定年份执行
  • 月份: 指定月份执行
  • 日期: 指定日期执行
  • 星期: 指定星期执行
  • 时间段: 指定时间段执行

点位值持续满足条件一段时间后才触发:

{
"type": "devicePoint",
"deviceID": "motion_sensor",
"devicePoint": "detected",
"condition": "eq",
"value": "true",
"duration": 30 // 持续30秒
}

场景配置存储在 res/linkedge/{id}.json

{
"id": "scene_001",
"name": "温度过高报警",
"description": "温度超过30度时启动风扇",
"enable": true,
"silentPeriod": 60,
"trigger": [...],
"condition": [...],
"action": [...],
"executeTime": "2023-01-01T10:00:00Z"
}
字段类型说明
idstring场景唯一标识符
namestring场景名称
enablebool是否启用
silentPeriodint静默期(秒),防止频繁触发
triggerarray触发器列表
conditionarray执行条件列表
actionarray执行动作列表
executeTimedatetime最后执行时间
graph TD
    A[加载配置目录] --> B[扫描 JSON 文件]
    B --> C[解析场景配置]
    C --> D[注册触发器]
    D --> E[启动定时任务]
    E --> F[设置点位监听]
    F --> G[就绪状态]
graph TD
    A[触发事件] --> B[加载场景配置]
    B --> C[检查启用状态]
    C --> D{启用?}
    D -->|否| E[结束]
    D -->|是| F[静默期检查]
    F --> G{可触发?}
    G -->|否| E
    G -->|是| H[条件评估]
    H --> I{条件满足?}
    I -->|否| E
    I -->|是| J[执行动作序列]
    J --> K[按设备分组]
    K --> L[并发写入]
    L --> M[统计执行结果]
    M --> N[触发后续场景]
    N --> O[更新执行时间]
// 先检查持续时间条件
err := s.checkListTimeCondition(conditions)
if err != nil {
return err
}
  • 设备点位条件:实时查询设备影子值
  • 时间窗口条件:检查当前时间是否在范围内
  • 日期区间条件:支持跨年处理
  • 周期性条件:年/月/日/周/时间段匹配

支持字符串和数值类型的比较:

  • 字符串:仅支持 eqne
  • 数值:支持所有比较操作符
switch action.Type {
case model.ActionTypeDevicePoint:
// 单点位设置(兼容旧版本)
if action.DevicePoint != "" && action.Value != "" {
// ...
}
// 多点位设置
if len(action.Points) != 0 {
for _, point := range action.Points {
actions[deviceID] = append(actions[deviceID], plugin.PointData{
PointName: point.Point,
Value: point.Value,
})
}
}
}

支持场景间的调用,形成复杂的自动化链:

case model.ActionTypeLinkEdge:
go s.triggerLinkEdge(action.ID, depth+1)

嵌套深度限制: 最大 10 层,防止无限递归

动作间支持延时:

{
"type": "devicePoint",
"sleep": "5s" // 执行后等待5秒
}
  1. 设备分组: 按连接键分组,减少连接建立开销
  2. 并发写入: 每组设备使用独立 goroutine
  3. 离线跳过: 自动跳过离线设备,避免阻塞
  4. 错误隔离: 单个设备失败不影响其他设备
type IService interface {
Create(model.Config) error // 创建场景
Update(model.Config) error // 更新场景
Delete(id string) error // 删除场景
Trigger(id string) error // 手动触发
Get(id string) (model.Config, error) // 获取场景
GetList(tag ...string) ([]model.Config, error) // 列表查询
Preview(model.Config) error // 预览执行
}
  • EVT_TRIGGER: 场景执行结果事件
    • ExecuteResultAllSuccess: 全部成功
    • ExecuteResultPartSuccess: 部分成功
    • ExecuteResultAllFail: 全部失败
触发器: 温度 > 30°C
条件: 工作时间 (9:00-18:00)
动作: 启动空调制冷,设置温度为 25°C
触发器: 运动检测到人
条件: 夜间时段 (22:00-06:00) AND 持续30秒
动作: 开启警报灯,发送通知
触发器: 定时调度 (工作日 18:00)
条件: 办公室无人 (人员传感器全为0)
动作: 关闭所有非必要设备电源
场景A: 检测到火灾 → 触发场景B和场景C
场景B: 启动消防系统
场景C: 疏散广播 + 电梯归首层
  • 嵌套深度: 限制 10 层防止栈溢出
  • 并发控制: 设备级并发,避免连接风暴
  • 条件缓存: 场景配置内存缓存,减少 IO
  • 静默期: 防止高频触发导致系统负载过高
错误场景处理方式
场景配置无效记录错误,跳过执行
设备离线跳过该设备,继续其他设备
条件评估失败终止场景执行
动作执行失败记录错误,统计失败数量
嵌套过深抛出错误,停止嵌套
静默期内触发拒绝执行,等待下次机会
  • 按设备分组,减少连接开销
  • 合理使用延时控制执行顺序
  • 谨慎使用场景嵌套,避免循环调用