跳转到内容

场景自动化与调度

场景自动化与调度

本节介绍智能家居系统的场景自动化和定时调度功能。学习完成后,您将能够:

  • 设计智能家居场景模式和触发条件
  • 实现 Node-RED 场景编排逻辑
  • 配置定时调度和自动化规则
  • 评估场景自动化方案的技术边界

在开始本节之前,请确保:

  • 已完成 Node-RED 基础学习
  • 已完成 MQTT 通信配置
  • 了解 IF-THEN 规则引擎的基本概念
// Node-RED 场景配置
const scenes = {
// 离家模式
"away": {
name: "离家",
icon: "🏃",
actions: [
{topic: "home/light/livingroom/set", payload: '{"state":"OFF"}'},
{topic: "home/light/bedroom/set", payload: '{"state":"OFF"}'},
{topic: "home/light/kitchen/set", payload: '{"state":"OFF"}'},
{topic: "home/climate/livingroom/mode/set", payload: '"off"'},
{topic: "home/climate/bedroom/mode/set", payload: '"off"'},
{topic: "home/curtain/livingroom/set", payload: '{"position":0}'},
{topic: "home/curtain/bedroom/set", payload: '{"position":0}'},
{topic: "home/alarm/set", payload: '{"mode":"away"}'},
{topic: "home/panel/display", payload: '{"scene":"away"}', delay: 500}
],
reversed: "home" // 反向模式
},
// 回家模式
"home": {
name: "回家",
icon: "🏠",
actions: [
{topic: "home/light/livingroom/set", payload: '{"state":"ON"}'},
{topic: "home/light/livingroom/brightness/set", payload: '50'},
{topic: "home/climate/livingroom/mode/set", payload: '"cool"'},
{topic: "home/climate/livingroom/temperature_set", payload: '26'},
{topic: "home/curtain/livingroom/set", payload: '{"position":50}'},
{topic: "home/alarm/set", payload: '{"mode":"disarm"}'},
{topic: "home/panel/display", payload: '{"scene":"home"}', delay: 500}
],
reversed: "away"
},
// 睡眠模式
"sleep": {
name: "睡眠",
icon: "🌙",
actions: [
{topic: "home/light/livingroom/set", payload: '{"state":"OFF"}'},
{topic: "home/light/bedroom/set", payload: '{"state":"OFF","brightness":10}'},
{topic: "home/light/nightlight/set", payload: '{"state":"ON"}'},
{topic: "home/curtain/bedroom/set", payload: '{"position":100}'},
{topic: "home/climate/bedroom/mode/set", payload: '"sleep"'},
{topic: "home/climate/bedroom/temperature_set", payload: '24'},
{topic: "home/alarm/set", payload: '{"mode":"sleep"}'},
{topic: "home/panel/display", payload: '{"scene":"sleep"}', delay: 500}
],
reversed: null
},
// 阅读模式
"reading": {
name: "阅读",
icon: "📚",
actions: [
{topic: "home/light/livingroom/set", payload: '{"state":"ON"}'},
{topic: "home/light/livingroom/brightness/set", payload: '100'},
{topic: "home/light/livingroom/color_temp/set", payload: '4000'}, // 暖白光
{topic: "home/curtain/livingroom/set", payload: '{"position":100}'},
{topic: "home/climate/livingroom/mode/set", payload: '"cool"'},
{topic: "home/panel/display", payload: '{"scene":"reading"}', delay: 500}
],
reversed: null
}
};
{
"id": "scene_executor",
"nodes": [
// 场景触发源
{"id":"scene_trigger_mqtt","type":"mqtt in",
"topic":"home/scene/+/trigger","server":"localhost"},
{"id":"scene_trigger_dashboard","type":"ui_button",
"group":"scene_group","label":"场景"},
{"id":"scene_trigger_schedule","type":"inject",
"crontab":"0 22 * * *","payload":"sleep","topic":"scene"},
// 场景解析
{"id":"scene_parser","type":"function","func":`
var scenes = global.get("scenes") || {};
var sceneName = msg.payload;
if (typeof sceneName === 'string' && scenes[sceneName]) {
var scene = scenes[sceneName];
var sequence = [];
// 生成动作序列
scene.actions.forEach(function(action, index) {
var delay = action.delay || 0;
sequence.push({
topic: action.topic,
payload: action.payload,
delay: delay + index * 200 // 每个动作间隔 200ms
});
});
// 记录场景执行
node.log(`触发场景: ${scene.name} (${sceneName})`);
return {
payload: {
scene: sceneName,
name: scene.name,
icon: scene.icon,
sequence: sequence,
timestamp: Date.now()
}
};
}
return null;
`},
// 顺序执行
{"id":"scene_delay","type":"delay",
"timeoutType":"delay","delayType":"fixed"},
{"id":"scene_mqtt_out","type":"mqtt out","qos":1}
]
}
// Node-RED 自动化规则引擎
// 规则定义
const rules = [
// 规则 1: 温度 > 30°C → 自动开空调
{
id: "rule_high_temp",
name: "高温自动空调",
condition: (data) => data.temperature > 30,
action: {
topic: "home/climate/livingroom/mode/set",
payload: '"cool"'
}
},
// 规则 2: 温度 > 28°C 且 湿度 > 70% → 除湿模式
{
id: "rule_high_humidity",
name: "高湿除湿",
condition: (data) => data.temperature > 28 && data.humidity > 70,
action: {
topic: "home/climate/livingroom/mode/set",
payload: '"dry"'
}
},
// 规则 3: 光照 < 50 lux 且 时间 > 18:00 → 自动开灯
{
id: "rule_dark_evening",
name: "傍晚自动开灯",
condition: (data) => {
var now = new Date();
var hour = now.getHours();
return data.lux < 50 && hour >= 18;
},
action: {
topic: "home/light/livingroom/set",
payload: '{"state":"ON","brightness":30}'
}
},
// 规则 4: 无人移动 30 分钟 → 自动进入节能模式
{
id: "rule_no_motion",
name: "无人节能",
condition: (data) => {
var timeSinceMotion = Date.now() - (global.get('lastMotion') || Date.now());
return timeSinceMotion > 1800000; // 30分钟
},
action: {
topic: "home/scene/livingroom/trigger",
payload: '"away"'
}
},
// 规则 5: 有人移动 + 光照不足 → 自动开夜灯
{
id: "rule_motion_nightlight",
name: "夜间感应灯",
condition: (data) => {
var now = new Date();
var hour = now.getHours();
return data.motion && (hour >= 22 || hour <= 5) && data.lux < 10;
},
action: {
topic: "home/light/nightlight/set",
payload: '{"state":"ON","brightness":20}'
}
}
];
// Node-RED 定时调度
// 使用 inject 节点的 cron 表达式
[
// 工作日 7:00 → 起床场景
{"id":"timer_wakeup","type":"inject",
"crontab":"0 7 * * 1-5",
"payload":"{\"scene\":\"home\",\"params\":{\"brightness\":60}}",
"topic":"home/scene/livingroom/trigger"},
// 工作日 8:30 → 离家场景
{"id":"timer_leave","type":"inject",
"crontab":"30 8 * * 1-5",
"payload":"\"away\"",
"topic":"home/scene/livingroom/trigger"},
// 工作日 17:30 → 回家场景
{"id":"timer_return","type":"inject",
"crontab":"30 17 * * 1-5",
"payload":"\"home\"",
"topic":"home/scene/livingroom/trigger"},
// 每天 22:00 → 睡眠场景
{"id":"timer_sleep","type":"inject",
"crontab":"0 22 * * *",
"payload":"\"sleep\"",
"topic":"home/scene/livingroom/trigger"},
// 周末 9:00 → 起床
{"id":"timer_weekend","type":"inject",
"crontab":"0 9 * * 6,0",
"payload":"{\"scene\":\"home\"}",
"topic":"home/scene/livingroom/trigger"}
]
// ESP32 面板上的场景选择界面
void create_scene_selection() {
lv_obj_t* scenePage = lv_obj_create(screen);
lv_obj_set_size(scenePage, LV_PCT(100), LV_PCT(100));
// 场景标题
lv_obj_t* title = lv_label_create(scenePage);
lv_label_set_text(title, "选择场景模式");
lv_obj_set_style_text_font(title, &lv_font_montserrat_20, 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 20);
// 场景按钮网格 (2x2)
const char* scenes[][2] = {
{"🏃 离家", "away"},
{"🏠 回家", "home"},
{"🌙 睡眠", "sleep"},
{"📚 阅读", "reading"}
};
int btnWidth = 120;
int btnHeight = 80;
int startX = (TFT_WIDTH - btnWidth * 2) / 3;
int startY = 80;
int gapX = (TFT_WIDTH - btnWidth * 2) / 3;
int gapY = 30;
for (int i = 0; i < 4; i++) {
int row = i / 2;
int col = i % 2;
int x = startX + col * (btnWidth + gapX);
int y = startY + row * (btnHeight + gapY);
lv_obj_t* btn = lv_btn_create(scenePage);
lv_obj_set_size(btn, btnWidth, btnHeight);
lv_obj_set_pos(btn, x, y);
lv_obj_set_style_radius(btn, 16, 0);
// 不同的场景颜色
lv_palette_t colors[] = {LV_PALETTE_TEAL, LV_PALETTE_GREEN,
LV_PALETTE_INDIGO, LV_PALETTE_ORANGE};
lv_obj_set_style_bg_color(btn, lv_palette_main(colors[i]), 0);
lv_obj_t* label = lv_label_create(btn);
lv_label_set_text(label, scenes[i][0]);
lv_obj_center(label);
// 绑定场景触发
lv_obj_add_event_cb(btn, [](lv_event_t* e) {
const char* scene = (const char*)lv_event_get_user_data(e);
mqttClient.publish("home/scene/livingroom/trigger", scene);
}, LV_EVENT_CLICKED, (void*)scenes[i][1]);
}
}
自动化类型功能买家价值
场景模式一键多设备联动”一键切换整个家居状态”
定时调度按时间自动执行”每天7点自动起床场景”
条件触发传感器 → 自动化”温度过高自动开空调”
缺席检测无运动自动节能”离家自动关灯关空调”
场景反转离/回家场景互逆”离家关闭的设备回家自动开启”

本节介绍了智能家居场景自动化和定时调度:

  1. 场景模式:离家、回家、睡眠、阅读等预设场景
  2. 场景执行流程:节点触发 → 动作序列 → MQTT 控制
  3. 自动化规则:IF-THEN 规则引擎基于传感器数据触发
  4. 定时调度:cron 表达式实现每日/工作日/周末定时触发
  5. 面板场景 UI:LVGL 场景选择界面,一键触发场景