跳转到内容

功率阈值逻辑

功率阈值逻辑

本节介绍如何设计和实现功率阈值逻辑,实现对设备能耗的智能监控。学习完成后,您将能够:

  • 设计多级功率阈值架构
  • 实现阈值触发和自动响应
  • 结合时间条件优化控制策略
  • 构建灵活的阈值配置管理系统
功率值
│ CRITICAL: 2000W ──┼────────────────────── 过载保护,立即断电
│ │
│ WARNING: 1500W ───┼──────────────── 告警通知,关注负载
│ │
│ NORMAL: 800W ─────┼─────────── 正常运行范围
│ │
│ LOW: 50W ─────────┼───── 待机/低功耗
│ │
│ OFF: 5W ──────────┼─ 设备关闭/断电
└──────────────────────────────────────────► 时间
// Function: 多级阈值检测引擎
// 支持灵活的阈值配置
// 阈值配置 (可从 Flow/Global Context 动态加载)
var thresholds = context.get("powerThresholds") || {
device: {
"shellyplus1pm-LINE1": {
critical: { max: 2000, action: "shutdown" },
warning: { max: 1500, action: "notify" },
normal: { min: 50, max: 1500 },
standby: { max: 50 }
},
"tasmota-socket1": {
critical: { max: 2500, action: "shutdown" },
warning: { max: 2000, action: "notify" },
normal: { min: 100, max: 2000 },
standby: { max: 100 }
}
},
default: {
critical: { max: 2000, action: "shutdown" },
warning: { max: 1500, action: "notify" },
normal: { min: 10, max: 1500 },
standby: { max: 10 }
}
};
// 获取设备 ID
var deviceId = msg.payload.device || "unknown";
// 获取当前功率
var power = msg.payload.power;
if (power === undefined || power === null) {
return null;
}
// 获取设备阈值配置
var deviceThreshold = thresholds.device[deviceId] || thresholds.default;
// 获取上次状态
var lastState = context.get("powerState_" + deviceId) || "unknown";
// 判断当前状态
var currentState;
if (power > deviceThreshold.critical.max) {
currentState = "critical";
} else if (power > deviceThreshold.warning.max) {
currentState = "warning";
} else if (power >= deviceThreshold.normal.min) {
currentState = "normal";
} else if (power >= deviceThreshold.standby.max) {
currentState = "standby";
} else {
currentState = "off";
}
// 状态变化检测
var stateChanged = (currentState !== lastState);
if (stateChanged) {
context.set("powerState_" + deviceId, currentState);
node.status({
fill: currentState === "critical" ? "red" :
currentState === "warning" ? "yellow" : "green",
shape: "dot",
text: currentState
});
}
// 构建结果
msg.payload = {
device: deviceId,
power: power,
state: currentState,
state_changed: stateChanged,
previous_state: lastState,
threshold_config: deviceThreshold,
action_required: currentState === "critical" || currentState === "warning",
timestamp: Date.now()
};
// 触发告警的附加信息
if (currentState === "critical" && deviceThreshold.critical.action === "shutdown") {
msg.shutdown = true;
}
if (currentState === "warning") {
msg.alert = true;
}
return msg;
// Function: 时间感知的阈值调整
var now = new Date();
var hour = now.getHours();
// 按时间段调整阈值 (白天/夜晚)
var timeConfig = {
// 工作时间 (08:00-20:00): 正常阈值
workday: {
warning: 2000,
critical: 2500
},
// 非工作时间 (20:00-08:00): 更敏感的阈值
night: {
warning: 500, // 夜间设备应低功耗
critical: 1000 // 超过 1000W 可能异常
}
};
// 判断当前时段
var isNight = (hour >= 20 || hour < 8);
var config = isNight ? timeConfig.night : timeConfig.workday;
var power = msg.payload.power;
var state = "normal";
if (power > config.critical) {
state = "critical";
} else if (power > config.warning) {
state = "warning";
}
// 夜间模式下异常更敏感
if (isNight && state === "warning") {
// 夜间告警升级
msg.severity = "high";
} else {
msg.severity = "normal";
}
msg.payload = {
power: power,
state: state,
period: isNight ? "night" : "workday",
thresholds: config,
severity: msg.severity,
timestamp: Date.now()
};
return msg;
// Function: 累计电量控制
// 当日用电量超过设定值时触发
var todayKwh = msg.payload.today_kwh || 0;
var deviceId = msg.payload.device || "unknown";
// 每日用电量上限配置 (kWh)
var DAILY_LIMIT = {
"shellyplus1pm-LINE1": 10,
"shellyplus1pm-LINE2": 5,
"default": 8
};
var limit = DAILY_LIMIT[deviceId] || DAILY_LIMIT.default;
// 检测日期变更,重置累计
var today = new Date().toISOString().split('T')[0];
var lastDate = context.get("lastDate_" + deviceId);
if (lastDate !== today) {
context.set("lastDate_" + deviceId, today);
context.set("dailyAlert_" + deviceId, false);
}
if (todayKwh > limit) {
var alreadyAlerted = context.get("dailyAlert_" + deviceId) || false;
if (!alreadyAlerted) {
context.set("dailyAlert_" + deviceId, true);
msg.payload = {
device: deviceId,
type: "daily_limit",
current_kwh: todayKwh,
limit_kwh: limit,
exceeded_by: (todayKwh - limit).toFixed(2),
message: "设备 " + deviceId + " 今日用电量 " + todayKwh +
"kWh 已超过限额 " + limit + "kWh",
timestamp: Date.now()
};
return msg;
}
}
return null; // 未超过限额或已告警

通过 Node-RED Dashboard 动态调整阈值

Section titled “通过 Node-RED Dashboard 动态调整阈值”
// Function: 接收 Dashboard 滑条/输入组件传来的阈值更新
// 输入: {"device":"shellyplus1pm-LINE1","threshold":"warning","value":1800}
var config = msg.payload;
if (config.device && config.threshold && config.value) {
var thresholds = context.get("powerThresholds") || {};
if (!thresholds.device) {
thresholds.device = {};
}
if (!thresholds.device[config.device]) {
thresholds.device[config.device] = {};
}
thresholds.device[config.device][config.threshold] = {
max: Number(config.value),
action: config.threshold === "critical" ? "shutdown" : "notify"
};
context.set("powerThresholds", thresholds);
node.log("Threshold updated: " + config.device +
" " + config.threshold + " = " + config.value + "W");
msg.payload = {
status: "ok",
message: "阈值已更新"
};
return msg;
}
Terminal window
# 1. 模拟功率过载
mosquitto_pub -t "tele/tasmota/socket1/SENSOR" \
-m '{"ENERGY":{"Power":2100,"Voltage":223,"Current":9.4}}'
# 2. 检查是否触发 critical 状态和 shutdown 动作
# Node-RED Debug 面板应显示 state: "critical"
# 3. 恢复模拟正常值
mosquitto_pub -t "tele/tasmota/socket1/SENSOR" \
-m '{"ENERGY":{"Power":800,"Voltage":223,"Current":3.6}}'
# 4. 状态应恢复为 normal

取决于设备类型和场景:

  • 照明回路: 500-1000W
  • 办公设备: 1500-2000W
  • 空调/电机: 2000-3500W
  • 建议先采集一周数据后根据实际值调整阈值

Q2: 如何避免功率瞬态波动导致误触发?

Section titled “Q2: 如何避免功率瞬态波动导致误触发?”

在 Function 中引入去抖逻辑:连续 N 次超过阈值才触发动作,或使用阈值持续时间判定(如超过阈值持续 30 秒)。

推荐做法:

  • 使用多级阈值(正常/警告/严重)分级响应
  • 结合时间条件调整阈值灵敏度
  • 实现去抖逻辑避免瞬态误触发
  • 阈值配置可从 Dashboard 动态调整

避免做法:

  • 单一固定阈值不适用于所有场景
  • 忽略设备启动电流(瞬时峰值)
  • 无去抖逻辑导致频繁告警
  • 阈值硬编码在 Function 中
  1. 多级阈值提供 normal/warning/critical 分级响应
  2. 时间感知根据白天/夜间调整阈值灵敏度
  3. 累计电量控制防止单日过度用电
  4. 去抖逻辑避免瞬态波动误触发
  5. 阈值可通过 Node-RED Dashboard 动态调整