The Challenge
Standard motion sensors generate too many false positives (pets, sunlight, shadows F***** moths and spiders). The goal of this project was to create a "Confirmation Logic" in Node-RED that requires input from multiple sources before triggering a high-priority alarm.
System Architecture
- Input: PIR Sensors (HC-SR501), Door/Window Contacts (Wired/Shelly), Router Presence (FritzBox).
- Logic: Node-RED flow running on Docker.
- Output: Telegram Bot (Critical Alerts), Ip Speaker for Alarm sound and Light control (via Node-Red controlling Shellys.
Logic Snapshot
The system uses a "state machine" approach. It doesn't alarm immediately; it enters a "Pre-Alarm" state to check for corroborating evidence and the presence of trusted devices/people in the house.
var devices = context.get("devices") || {};
var deviceName = msg.payload.NewHostName || "Unknown Device";
var isOnline = msg.payload.NewActive === "1" || msg.payload.NewActive === 1;
var wasOnline = devices[deviceName] || false;
// Update device list
if (isOnline) {
devices[deviceName] = true;
} else {
delete devices[deviceName];
}
context.set("devices", devices);
// Get current device count
var allDevices = Object.keys(devices);
var armSystem = allDevices.length === 0; // Arm only when all devices leave
var messages = [];
// ā
Goodbye message only when a device actually leaves
if (!isOnline && wasOnline) {
var message = `š Goodbye *${deviceName}*!`;
if (!armSystem) {
var remainingDevice = allDevices.join(", ");
message += `\nš System will NOT arm because *${remainingDevice}* is still home.`;
} else {
message += `\nš *All devices have left! Arming the system in 30 seconds...*`;
messages.push({ payload: 911 }); // Send arm signal
}
messages.push({
payload: {
chatId: "Your Telegram Chat ID",
type: "message",
content: message,
parse_mode: "Markdown"
}
});
}
// ā
**NEW: Welcome message when a device connects**
if (isOnline && !wasOnline) {
messages.push({
payload: {
chatId: "Your Telegram Chat ID",
type: "message",
content: `š Welcome back *${deviceName}*! \nš I disabled the alarm for you.`,
parse_mode: "Markdown"
}
});
messages.push({ payload: 912 }); // Send disarm signal
}
return messages.length > 0 ? messages : null;
// Output 1: CRITICAL ALARM
} else if (pirActive) {
return [null, msg]; // Output 2: Warning / Record Cam
}
}
return null;
Visuals
The flow handles arming, disarming, and snapshot capture from the door camera.