Hier anbei mal ein Skript für die X-Sense Rauchmelder bei auslösen eines Alarms.
<?php
################################################################################
# Script: Rauchmelder.Brandalarm.Logik.ips.php
# Version: 1.0.20260510
# Author: ChatGPT / angepasst für IP-Symcon
#
# Zentrale Brandalarm- und CO-Alarm-Logik für X-Sense Rauchmelder per MQTT.
#
# Aufgabe:
# Dieses Skript überwacht alle eingebundenen X-Sense Rauchmelder, erkennt
# Rauchalarm, Testalarm, Wartungszustände und Diagnosemeldungen und steuert
# darauf basierend Benachrichtigungen, Licht, Rollläden und optionale Sirenen.
#
# Hintergrund:
# Die X-Sense Rauchmelder liefern ihre Zustände über MQTT/Zigbee2MQTT nach
# IP-Symcon. Dieses Skript bündelt die Alarm- und Wartungslogik zentral, damit
# Brandalarm, Eskalation, Quittierung und Diagnose einheitlich verarbeitet werden.
#
# Funktionen:
# - sucht Rauchmelder automatisch unter definierten Root-Kategorien
# - erkennt aktiven Rauchalarm über Smoke Status
# - unterstützt Testmodus mit frei definierbarem Testmelder
# - setzt zentrale Status-, Quellen-, Zeit- und Diagnosevariablen
# - sendet WebFront Push-Benachrichtigungen
# - sendet Pushover-Nachrichten mit Tag-/Nacht-Priorität
# - schaltet bei Alarm nachts definierte Lichtgruppen ein
# - öffnet bei Alarm definierte Rollläden
# - unterstützt optionale Sirenen
# - ermöglicht Quittierung über Sonoff SNZB-01P
# - startet Testmodus über Sonoff SNZB-01P Long-Press
# - führt eine Alarmhistorie mit maximal 50 Einträgen
# - überwacht Offline-, Batterie- und EndOfLife-/Fault-Zustände
# - erkennt aktiven CO-Alarm über CO Status
# - setzt getrennte CO-Alarm-Status-, Quellen-, Zeit- und Historienvariablen
# - führt getrennte Eskalationslogik für Rauchalarm und CO-Alarm aus
#
# Das Skript arbeitet mit:
# - $searchRootIDs -> Suchbereiche für Rauchmelder
# - $varBrandalarmAktivID -> Brandalarm aktiv
# - $varBrandalarmQuelleID -> auslösender Rauchmelder
# - $varBrandalarmZeitID -> Zeitpunkt des Alarms
# - $varBrandalarmStatusID -> aktueller Brandalarm-Status
# - $varBrandalarmAnzahlID -> Anzahl aktiver Rauchmelder
# - $varBrandalarmEskalationID -> Eskalationsstatus
# - $varBrandalarmTimerphaseID -> interne Timerphase
# - $varBrandalarmWartungID -> Wartungstext
# - $varBrandalarmTestmodusID -> Testmodus
# - $varBrandalarmTestmelderID -> Name des Testmelders
# - $varSicherheitsalarmQuittiertID -> gemeinsame Quittierung für Rauch- und CO-Alarm
# - $varSonoffActionID -> Action-Variable des Sonoff-Tasters
# - $varRMGesamtstatusID -> Rauchmelder-Gesamtstatus
# - $varRMBatterieID -> Batteriewarnungen
# - $varRMEndOfLifeID -> EndOfLife-/Fault-Meldungen
# - $varRMOfflineID -> Offline-Meldungen
# - $varRMLetzterTestID -> letzter Testzeitpunkt
# - $varBrandalarmHistorieID -> Alarmhistorie
# - $webfrontID -> WebFront-Instanz
# - $pushoverID -> Pushover-Instanz
# - $varIsDayID -> Tag-/Nacht-Erkennung
# - $lichtIDs -> Lichtgruppen für Nachtalarm
# - $rollladenIDs -> Rollläden für Alarmöffnung
# - $sirenenIDs -> optionale Sirenen
# - $varCOAlarmAktivID -> CO-Alarm aktiv
# - $varCOAlarmQuelleID -> auslösender CO-Melder
# - $varCOAlarmZeitID -> Zeitpunkt des CO-Alarms
# - $varCOAlarmStatusID -> aktueller CO-Alarm-Status
# - $varCOAlarmAnzahlID -> Anzahl aktiver CO-Melder
# - $varCOAlarmEskalationID -> CO-Eskalationsstatus
# - $varCOAlarmTimerphaseID -> interne CO-Timerphase
# - $varCOAlarmHistorieID -> CO-Alarmhistorie
#
# Ablauf:
# 1. Rauchmelder unterhalb der Suchbereiche automatisch suchen
# 2. Smoke-, Online-, Batterie- und EndOfLife-Zustände auslesen
# 3. Testmodus bei Bedarf in die Alarmlogik einrechnen
# 4. Bei erkanntem Alarm eine kurze Stabilitätsprüfung starten
# 5. Nach bestätigtem Alarm Statusvariablen setzen und Push senden
# 6. Licht, Rollläden und optionale Sirenen auslösen
# 7. Nach definierter Zeit Eskalation prüfen
# 8. Alarmende erkennen und Zustände zurücksetzen
# 9. Wartungs- und Diagnosevariablen aktualisieren
# 10. CO-Alarm erkennen, Status setzen und Sicherheitsaktionen auslösen
# 11. CO-Eskalation getrennt von Rauchalarm prüfen
# 12. CO-Alarmende erkennen und CO-Zustände zurücksetzen
#
# Besonderheiten:
# - Alarm wird nicht sofort ausgelöst, sondern nach kurzer Prüfzeit bestätigt
# - Eskalation erfolgt bei mehreren gleichzeitig aktiven Rauchmeldern
# - Lichtautomatik wird nur nachts ausgeführt
# - Rollläden werden unabhängig von Tag/Nacht immer geöffnet
# - Testmodus löst dieselbe Logik aus, verwendet aber reduzierte Push-Priorität
# - Quittierung verhindert weitere Eskalationsmeldungen, solange Alarm aktiv ist
# - CO-Alarm wird separat zum Rauchalarm geführt
# - Rauchalarm und CO-Alarm verwenden getrennte Timerphasen
# - ein gemeinsamer ScriptTimer wird über Fälligkeiten koordiniert
# - dadurch überschreiben sich Rauch- und CO-Timer nicht gegenseitig
# - eine gemeinsame Quittierung gilt für Rauchalarm und CO-Alarm
#
# Voraussetzungen:
# - IP-Symcon mit eingebundenen X-Sense Rauchmeldern
# - MQTT-/Zigbee2MQTT-Variablen mit passenden Variablennamen
# - zentrale Statusvariablen für Brandalarm und Rauchmelderdiagnose
# - WebFront-Instanz für Push-Benachrichtigungen
# - optional Pushover-Modul
# - optional Sonoff SNZB-01P für Quittierung und Testmodus
#
# Hinweis:
# Dieses Skript wird durch Variablenereignisse, TimerEvents und manuelle
# Ausführung verwendet.
#
# Es erfolgt keine automatische Ausführung ohne Event.
################################################################################
################################################################################
# ID-DOKUMENTATION
#
# $searchRootIDs
# -> Root-Kategorien, unter denen nach Rauchmeldern gesucht wird
#
# $varBrandalarmAktivID
# -> Boolean-Variable für aktiven Brandalarm
#
# $varBrandalarmQuelleID
# -> String-Variable für den ersten auslösenden Rauchmelder
#
# $varBrandalarmZeitID
# -> String-Variable für den Zeitpunkt der Alarmauslösung
#
# $varBrandalarmStatusID
# -> String-Variable für den aktuellen Brandalarm-Status
#
# $varBrandalarmAnzahlID
# -> Integer-Variable für die Anzahl aktiver Rauchmelder
#
# $varBrandalarmEskalationID
# -> Boolean-Variable für Eskalation bei mehreren aktiven Rauchmeldern
#
# $varBrandalarmTimerphaseID
# -> String-Variable für interne Rauchalarm-Timerphasen
#
# Rauchalarm-Timerphasen:
# - ALARM_PRUEFUNG -> Rauchalarm wird nach Verzögerung erneut geprüft
# - ESKALATION -> Rauchalarm-Eskalation wird nach Verzögerung geprüft
#
# Hinweis:
# Die Timerphase wird als Kombination aus Phase und Fälligkeit gespeichert.
#
# Format:
# PHASE|UnixTimestamp
#
# Beispiel:
# ALARM_PRUEFUNG|1760000000
# ESKALATION|1760000030
#
# $varBrandalarmWartungID
# -> String-Variable für zusammengefassten Wartungsstatus
#
# $varBrandalarmTestmodusID
# -> Boolean-Variable zum Aktivieren des Testmodus
#
# $varBrandalarmTestmelderID
# -> String-Variable für den Namen des simulierten Testmelders
#
# $varSicherheitsalarmQuittiertID
# -> Boolean-Variable für gemeinsam quittierten Rauch- oder CO-Alarm
#
# $varSonoffActionID
# -> String-Variable für Action-Werte des Sonoff SNZB-01P
#
# Sonoff-Aktionen:
# - single -> Sicherheitsalarm quittieren
# - long -> Testmodus starten
#
# $varRMGesamtstatusID
# -> String-Variable für den Rauchmelder-Gesamtstatus
#
# $varRMBatterieID
# -> String-Variable für Rauchmelder mit Batteriewarnung
#
# $varRMEndOfLifeID
# -> String-Variable für Rauchmelder mit EndOfLife-/Fault-Zustand
#
# $varRMOfflineID
# -> String-Variable für Rauchmelder ohne Verbindung
#
# $varRMLetzterTestID
# -> Integer-Variable mit Unix-Zeitstempel des letzten Testalarms
#
# $varRMLetzterTestTextID
# -> String-Variable mit lesbarem Zeitpunkt des letzten Testalarms
#
# $varBrandalarmHistorieID
# -> String-Variable für Alarmhistorie mit maximal 50 Einträgen
#
# $webfrontID
# -> WebFront-ID für PushNotification
#
# $pushoverID
# -> Pushover-Instanz-ID für externe Push-Nachrichten
#
# $varIsDayID
# -> Boolean-Variable für Tag-/Nacht-Erkennung
#
# Tag-/Nacht-Erkennung:
# - true -> Tag
# - false -> Nacht
#
# $lichtIDs
# -> Liste der Lichtgruppen, die nachts bei Brandalarm eingeschaltet werden
#
# $rollladenIDs
# -> Liste der Rollläden, die bei Brandalarm geöffnet werden
#
# $sirenenIDs
# -> optionale Liste von Sirenen-Schaltvariablen
#
# $varCOAlarmAktivID
# -> Boolean-Variable für aktiven CO-Alarm
#
# $varCOAlarmQuelleID
# -> String-Variable für den ersten auslösenden CO-Melder
#
# $varCOAlarmZeitID
# -> String-Variable für den Zeitpunkt der CO-Alarmauslösung
#
# $varCOAlarmStatusID
# -> String-Variable für den aktuellen CO-Alarm-Status
#
# $varCOAlarmAnzahlID
# -> Integer-Variable für die Anzahl aktiver CO-Melder
#
# $varCOAlarmEskalationID
# -> Boolean-Variable für CO-Eskalation
#
# $varCOAlarmTimerphaseID
# -> String-Variable für interne CO-Alarm-Timerphasen
#
# CO-Timerphasen:
# - CO_ESKALATION -> CO-Eskalation wird nach Verzögerung geprüft
#
# Hinweis:
# Die CO-Timerphase wird ebenfalls als Kombination aus Phase und Fälligkeit gespeichert.
#
# Format:
# PHASE|UnixTimestamp
#
# Beispiel:
# CO_ESKALATION|1760000030
#
# $varCOAlarmHistorieID
# -> String-Variable für CO-Alarmhistorie mit maximal 50 Einträgen
################################################################################
################################################################################
# FUNKTIONSWEISE BRANDALARM-LOGIK
#
# Dieses Skript:
# - wertet Rauchmelderzustände zentral aus
# - erkennt Alarm, Testalarm und Wartungszustände
# - setzt zentrale Statusvariablen
# - löst Benachrichtigungen und Sicherheitsaktionen aus
#
# Verhalten bei Alarm:
# - Alarm wird erkannt
# - kurze Stabilitätsprüfung wird gestartet
# - nach Bestätigung wird Brandalarm aktiv gesetzt
# - Quelle, Zeit, Anzahl und Status werden gespeichert
# - Push- und Pushover-Nachrichten werden versendet
# - nachts wird Licht eingeschaltet
# - Rollläden werden geöffnet
# - Eskalation wird verzögert geprüft
#
# Verhalten bei Eskalation:
# - mehrere aktive Rauchmelder lösen Eskalation aus
# - Eskalationsstatus wird gesetzt
# - zusätzliche Push-Nachrichten werden versendet
# - Alarmhistorie wird ergänzt
#
# Verhalten bei Quittierung:
# - Alarm bleibt aktiv
# - Quittierstatus wird gesetzt
# - Eskalationsmeldungen werden unterdrückt
# - Sirenen werden ausgeschaltet
#
# Verhalten bei Alarmende:
# - Brandalarm wird zurückgesetzt
# - Quelle, Zeit, Anzahl und Timerphase werden geleert
# - Eskalation und Quittierung werden zurückgesetzt
# - Push-Nachricht "Alarm beendet" wird gesendet
################################################################################
################################################################################
# AUFRUF
#
# Dieses Skript wird:
# -> per Änderungsereignis, TimerEvent oder manuell ausgeführt
#
# Verwendung:
# - bei Änderung von Smoke Status / Smoke
# - bei Änderung von Online Status / Connectivity
# - bei Änderung von Battery Status / Battery
# - bei Änderung von End of Life / Problem
# - bei Änderung der Sonoff SNZB-01P Action-Variable
# - zur manuellen Diagnose und Statusaktualisierung
################################################################################
################################################################################
# KONFIGURATION
#
# Zentrale Parameter:
#
# - $alarmVerzoegerungSekunden -> Verzögerung bis zur Alarmbestätigung
# - $eskalationSekunden -> Verzögerung bis zur Eskalationsprüfung
# - $nachtPrioritaet -> Pushover-Priorität bei Nacht
# - $tagPrioritaet -> Pushover-Priorität bei Tag
#
# Hinweis:
# Neue Rauchmelder müssen nicht einzeln eingetragen werden, solange sie unterhalb
# der Suchbereiche liegen und die erwarteten Variablennamen besitzen.
################################################################################
// -----------------------------------------------------------------------------
// KONFIGURATION
// -----------------------------------------------------------------------------
$searchRootIDs = [
54758, // KG
58743, // EG
49801 // OG
];
// Brandalarm
$varBrandalarmAktivID = 14820;
$varBrandalarmQuelleID = 19189;
$varBrandalarmZeitID = 18951;
$varBrandalarmStatusID = 26445;
$varBrandalarmAnzahlID = 44964;
$varBrandalarmEskalationID = 48844;
$varBrandalarmTimerphaseID = 40877;
$varBrandalarmWartungID = 21483;
$varBrandalarmHistorieID = 43084;
// CO-Alarm
$varCOAlarmAktivID = 49273;
$varCOAlarmQuelleID = 10951;
$varCOAlarmZeitID = 40864;
$varCOAlarmStatusID = 35766;
$varCOAlarmEskalationID = 28782;
$varCOAlarmTimerphaseID = 20674;
$varCOAlarmHistorieID = 28410;
$varCOAlarmAnzahlID = 14148;
// Testmodus
$varBrandalarmTestmodusID = 50536;
$varBrandalarmTestmelderID = 18184;
// gemeinsame Quittierung für Rauch- und CO-Alarm
$varSicherheitsalarmQuittiertID = 25578;
// Sonoff SNZB-01P Aktion
$varSonoffActionID = 17763;
// Diagnose / Sammelstatus
$varRMGesamtstatusID = 47942;
$varRMBatterieID = 15758;
$varRMEndOfLifeID = 42441;
$varRMOfflineID = 15404;
$varRMLetzterTestID = 45872;
$varRMLetzterTestTextID = 47476;
// Push
$webfrontID = 10436;
$pushoverID = 36786;
// Tag-/Nacht-Erkennung
// true = Tag
// false = Nacht
$varIsDayID = 42475;
// Pushover Priorität
$tagPrioritaet = 1;
$nachtPrioritaet = 2;
// Zeiten
$alarmVerzoegerungSekunden = 5;
$eskalationSekunden = 30;
$coEskalationSekunden = 30;
// -----------------------------------------------------------------------------
// LICHT
// -----------------------------------------------------------------------------
$lichtIDs = [
[
"name" => "Gruppe EG Flur",
"instanzID" => 26675,
"statusID" => 58122,
"helligkeitID" => 52325
],
[
"name" => "Gruppe EG Haupt-Flur",
"instanzID" => 39396,
"statusID" => 48479,
"helligkeitID" => 31879
],
[
"name" => "Gruppe EG Wohnzimmer",
"instanzID" => 47571,
"statusID" => 21397,
"helligkeitID" => 29467
],
[
"name" => "Gruppe EG Küche",
"instanzID" => 14068,
"statusID" => 34672,
"helligkeitID" => 56904
]
];
// -----------------------------------------------------------------------------
// ROLLLÄDEN
// 100 = offen
// 0 = geschlossen
// -----------------------------------------------------------------------------
$rollladenIDs = [
[
"name" => "Fenster EG Küche Vorne",
"levelID" => 33230
],
[
"name" => "Fenster EG Küche Links",
"levelID" => 12237
],
[
"name" => "Fenster EG Wohnzimmer Rechts",
"levelID" => 53796
],
[
"name" => "Fenster EG Wohnzimmer Links",
"levelID" => 13381
],
[
"name" => "Fenster EG Wohnzimmer Garten",
"levelID" => 24436
]
];
// -----------------------------------------------------------------------------
// OPTIONAL: SIRENEN
// -----------------------------------------------------------------------------
$sirenenIDs = [
];
// -----------------------------------------------------------------------------
// X-SENSE VARIABLENNAMEN
// -----------------------------------------------------------------------------
$smokeNames = ["Smoke Status", "Smoke", "Rauch erkannt"];
$coNames = ["CO Status", "CO", "CO erkannt"];
$onlineNames = ["Online Status", "Connectivity", "Erreichbar"];
$batteryNames = ["Battery Status", "Battery", "Batteriewarnung"];
$endlifeNames = ["End of Life", "Problem", "Fehler / EndOfLife"];
// -----------------------------------------------------------------------------
// HILFSFUNKTIONEN
// -----------------------------------------------------------------------------
function RM_GetChildByNames(int $parentID, array $names)
{
foreach (IPS_GetChildrenIDs($parentID) as $childID) {
if (in_array(IPS_GetName($childID), $names)) {
return $childID;
}
}
return false;
}
function RM_FindDevicesRecursive(int $rootID, array $smokeNames, array $coNames)
{
$found = [];
foreach (IPS_GetChildrenIDs($rootID) as $childID) {
$object = IPS_GetObject($childID);
$smokeID = RM_GetChildByNames($childID, $smokeNames);
$coID = RM_GetChildByNames($childID, $coNames);
if ($smokeID !== false || $coID !== false) {
$found[] = $childID;
continue;
}
if ($object['ObjectType'] == 0 || $object['ObjectType'] == 1) {
$found = array_merge(
$found,
RM_FindDevicesRecursive($childID, $smokeNames, $coNames)
);
}
}
return $found;
}
function RM_Scan(
array $searchRootIDs,
array $smokeNames,
array $coNames,
array $onlineNames,
array $batteryNames,
array $endlifeNames
) {
$devices = [];
foreach ($searchRootIDs as $rootID) {
$devices = array_merge(
$devices,
RM_FindDevicesRecursive($rootID, $smokeNames, $coNames)
);
}
$devices = array_unique($devices);
$result = [
"alarm" => false,
"quelle" => "",
"anzahl" => 0,
"aktiv" => [],
"coalarm" => false,
"coquelle" => "",
"coanzahl" => 0,
"coaktiv" => [],
"offline" => [],
"batterie" => [],
"endlife" => [],
"anzahlMelder" => count($devices),
"testmodus" => false
];
foreach ($devices as $deviceID) {
$name = IPS_GetName($deviceID);
$smokeID = RM_GetChildByNames($deviceID, $smokeNames);
$coID = RM_GetChildByNames($deviceID, $coNames);
$onlineID = RM_GetChildByNames($deviceID, $onlineNames);
$batteryID = RM_GetChildByNames($deviceID, $batteryNames);
$endlifeID = RM_GetChildByNames($deviceID, $endlifeNames);
if ($smokeID !== false && GetValueBoolean($smokeID)) {
$result["alarm"] = true;
$result["anzahl"]++;
$result["aktiv"][] = $name;
if ($result["quelle"] == "") {
$result["quelle"] = $name;
}
}
if ($coID !== false && GetValueBoolean($coID)) {
$result["coalarm"] = true;
$result["coanzahl"]++;
$result["coaktiv"][] = $name;
if ($result["coquelle"] == "") {
$result["coquelle"] = $name;
}
}
if ($onlineID !== false && !GetValueBoolean($onlineID)) {
$result["offline"][] = $name;
}
if ($batteryID !== false && GetValueBoolean($batteryID)) {
$result["batterie"][] = $name;
}
if ($endlifeID !== false && GetValueBoolean($endlifeID)) {
$result["endlife"][] = $name;
}
}
if (
$GLOBALS['varBrandalarmTestmodusID'] > 0 &&
GetValueBoolean($GLOBALS['varBrandalarmTestmodusID'])
) {
$testmelder = "Test Rauchmelder";
if (
$GLOBALS['varBrandalarmTestmelderID'] > 0 &&
GetValueString($GLOBALS['varBrandalarmTestmelderID']) != ""
) {
$testmelder = GetValueString($GLOBALS['varBrandalarmTestmelderID']);
}
$result["testmodus"] = true;
$result["alarm"] = true;
$result["anzahl"]++;
$result["aktiv"][] = $testmelder;
if ($result["quelle"] == "") {
$result["quelle"] = $testmelder;
}
}
return $result;
}
function RM_Push(int $webfrontID, string $titel, string $text)
{
if ($webfrontID > 0) {
@WFC_PushNotification($webfrontID, $titel, $text, "", 0);
}
}
function RM_Pushover(int $instanceID, string $titel, string $text, int $priority = -1)
{
if ($instanceID > 0) {
@TUPO_SendMessage($instanceID, $titel, $text, $priority);
}
}
function RM_SetValueIfValid(int $id, $value)
{
if ($id > 0) {
SetValue($id, $value);
}
}
function RM_AddHistorie(int $id, string $text)
{
if ($id <= 0) {
return;
}
$alt = GetValueString($id);
$neu = date("d.m.Y H:i:s") . " | " . $text;
if ($alt != "") {
$neu .= "\n" . $alt;
}
$lines = explode("\n", $neu);
$lines = array_slice($lines, 0, 50);
SetValueString($id, implode("\n", $lines));
}
function RM_GetBoolIfValid(int $id, bool $default = false)
{
if ($id > 0) {
return GetValueBoolean($id);
}
return $default;
}
function RM_GetAlarmPriority(
int $varIsDayID,
int $tagPrioritaet,
int $nachtPrioritaet
) {
if ($varIsDayID > 0) {
if (GetValueBoolean($varIsDayID)) {
return $tagPrioritaet;
}
return $nachtPrioritaet;
}
return $nachtPrioritaet;
}
function RM_SwitchEmergencyLights(array $lichtIDs, int $varIsDayID)
{
$lichtAutomatikAktiv = true;
if ($varIsDayID > 0) {
$lichtAutomatikAktiv = !GetValueBoolean($varIsDayID);
}
if (!$lichtAutomatikAktiv) {
return;
}
foreach ($lichtIDs as $licht) {
if (isset($licht["helligkeitID"]) && $licht["helligkeitID"] > 0) {
@RequestAction($licht["helligkeitID"], 100);
}
if (isset($licht["statusID"]) && $licht["statusID"] > 0) {
@RequestAction($licht["statusID"], true);
}
}
}
function RM_OpenShutters(array $rollladenIDs)
{
foreach ($rollladenIDs as $rollladen) {
if (isset($rollladen["levelID"]) && $rollladen["levelID"] > 0) {
@RequestAction($rollladen["levelID"], 100);
}
}
}
function RM_StopSirens(array $sirenenIDs)
{
foreach ($sirenenIDs as $id) {
@RequestAction($id, false);
}
}
function RM_StartSirens(array $sirenenIDs)
{
foreach ($sirenenIDs as $id) {
@RequestAction($id, true);
}
}
// -----------------------------------------------------------------------------
// TIMER-HILFSFUNKTIONEN
// -----------------------------------------------------------------------------
function RM_SetTimerPhase(int $id, string $phase, int $delaySeconds)
{
if ($id <= 0) {
return;
}
$due = time() + $delaySeconds;
SetValueString($id, $phase . "|" . $due);
}
function RM_ClearTimerPhase(int $id)
{
if ($id > 0) {
SetValueString($id, "");
}
}
function RM_GetTimerPhaseName(int $id): string
{
if ($id <= 0) {
return "";
}
$value = GetValueString($id);
if ($value == "") {
return "";
}
$parts = explode("|", $value);
return $parts[0] ?? "";
}
function RM_GetTimerPhaseDue(int $id): int
{
if ($id <= 0) {
return 0;
}
$value = GetValueString($id);
if ($value == "") {
return 0;
}
$parts = explode("|", $value);
return isset($parts[1]) ? (int)$parts[1] : 0;
}
function RM_IsTimerPhaseDue(int $id, string $phase): bool
{
if ($id <= 0) {
return false;
}
if (RM_GetTimerPhaseName($id) !== $phase) {
return false;
}
$due = RM_GetTimerPhaseDue($id);
if ($due <= 0) {
return true;
}
return time() >= $due;
}
function RM_RefreshScriptTimer(int $scriptID, array $timerPhaseIDs)
{
$nextDue = null;
foreach ($timerPhaseIDs as $id) {
if ($id <= 0) {
continue;
}
$phase = RM_GetTimerPhaseName($id);
$due = RM_GetTimerPhaseDue($id);
if ($phase == "" || $due <= 0) {
continue;
}
if ($nextDue === null || $due < $nextDue) {
$nextDue = $due;
}
}
if ($nextDue === null) {
IPS_SetScriptTimer($scriptID, 0);
return;
}
$seconds = max(1, $nextDue - time());
IPS_SetScriptTimer($scriptID, $seconds);
}
// -----------------------------------------------------------------------------
// TIMER-AUFRUF
// -----------------------------------------------------------------------------
if ($_IPS['SENDER'] == "TimerEvent") {
$scan = RM_Scan(
$searchRootIDs,
$smokeNames,
$coNames,
$onlineNames,
$batteryNames,
$endlifeNames
);
// ------------------------------------------------------------------------
// Rauchalarm bestätigen
// ------------------------------------------------------------------------
if (RM_IsTimerPhaseDue($varBrandalarmTimerphaseID, "ALARM_PRUEFUNG")) {
RM_ClearTimerPhase($varBrandalarmTimerphaseID);
if ($scan["alarm"] && !GetValueBoolean($varBrandalarmAktivID)) {
SetValueBoolean($varBrandalarmAktivID, true);
SetValueString($varBrandalarmQuelleID, $scan["quelle"]);
SetValueString($varBrandalarmZeitID, date("d.m.Y H:i:s"));
if ($scan["testmodus"]) {
RM_SetValueIfValid(
$varRMLetzterTestID,
time()
);
RM_SetValueIfValid(
$varRMLetzterTestTextID,
date("d.m.Y H:i:s") . " | " . $scan["quelle"]
);
}
RM_SetValueIfValid($varBrandalarmAnzahlID, $scan["anzahl"]);
RM_SetValueIfValid($varSicherheitsalarmQuittiertID, false);
RM_SetValueIfValid(
$varBrandalarmStatusID,
$scan["testmodus"]
? "TESTMODUS: Alarm aktiv: " . $scan["quelle"]
: "ALARM aktiv: " . $scan["quelle"]
);
RM_Push(
$webfrontID,
$scan["testmodus"] ? "🧪 Rauchalarm Test" : "🚨 Rauchalarm!",
"Ausgelöst durch: " . $scan["quelle"]
);
$alarmPriority = RM_GetAlarmPriority(
$varIsDayID,
$tagPrioritaet,
$nachtPrioritaet
);
RM_Pushover(
$pushoverID,
$scan["testmodus"] ? "🧪 Rauchalarm Test" : "🚨 Rauchalarm!",
"Ausgelöst durch: " . $scan["quelle"],
$scan["testmodus"] ? -1 : $alarmPriority
);
RM_AddHistorie(
$varBrandalarmHistorieID,
($scan["testmodus"] ? "TEST" : "ALARM") . " | " . $scan["quelle"]
);
RM_SwitchEmergencyLights($lichtIDs, $varIsDayID);
RM_OpenShutters($rollladenIDs);
RM_StartSirens($sirenenIDs);
RM_SetTimerPhase(
$varBrandalarmTimerphaseID,
"ESKALATION",
$eskalationSekunden
);
}
}
// ------------------------------------------------------------------------
// Rauchalarm Eskalation
// ------------------------------------------------------------------------
if (RM_IsTimerPhaseDue($varBrandalarmTimerphaseID, "ESKALATION")) {
RM_ClearTimerPhase($varBrandalarmTimerphaseID);
if ($scan["alarm"] && GetValueBoolean($varBrandalarmAktivID)) {
RM_SetValueIfValid($varBrandalarmAnzahlID, $scan["anzahl"]);
if (!RM_GetBoolIfValid($varSicherheitsalarmQuittiertID, false)) {
if ($scan["anzahl"] >= 2) {
RM_SetValueIfValid($varBrandalarmEskalationID, true);
RM_SetValueIfValid(
$varBrandalarmStatusID,
$scan["testmodus"]
? "TESTMODUS: Eskalation mehrere Rauchmelder aktiv"
: "ESKALATION: mehrere Rauchmelder aktiv"
);
RM_Push(
$webfrontID,
$scan["testmodus"]
? "🧪 Test Eskalation"
: "🔥 BRANDALARM ESKALATION!",
$scan["anzahl"] . " Rauchmelder aktiv: " . implode(", ", $scan["aktiv"])
);
RM_Pushover(
$pushoverID,
$scan["testmodus"]
? "🧪 Test Eskalation"
: "🔥 BRANDALARM ESKALATION!",
$scan["anzahl"] . " Rauchmelder aktiv: " . implode(", ", $scan["aktiv"]),
$scan["testmodus"] ? -1 : $nachtPrioritaet
);
RM_AddHistorie(
$varBrandalarmHistorieID,
"ESKALATION | " . $scan["anzahl"] . " Rauchmelder"
);
} else {
RM_SetValueIfValid(
$varBrandalarmStatusID,
$scan["testmodus"]
? "TESTMODUS: Alarm weiterhin aktiv: " . GetValueString($varBrandalarmQuelleID)
: "ALARM weiterhin aktiv: " . GetValueString($varBrandalarmQuelleID)
);
RM_Push(
$webfrontID,
$scan["testmodus"]
? "🧪 Rauchalarm Test weiterhin aktiv"
: "⚠️ Rauchalarm weiterhin aktiv",
"Quelle: " . GetValueString($varBrandalarmQuelleID)
);
$alarmPriority = RM_GetAlarmPriority(
$varIsDayID,
$tagPrioritaet,
$nachtPrioritaet
);
RM_Pushover(
$pushoverID,
$scan["testmodus"]
? "🧪 Rauchalarm Test weiterhin aktiv"
: "⚠️ Rauchalarm weiterhin aktiv",
"Quelle: " . GetValueString($varBrandalarmQuelleID),
$scan["testmodus"] ? -1 : $alarmPriority
);
}
} else {
RM_SetValueIfValid(
$varBrandalarmStatusID,
"Alarm quittiert - weiterhin aktiv: " . GetValueString($varBrandalarmQuelleID)
);
}
}
}
// ------------------------------------------------------------------------
// CO-Alarm Eskalation
// ------------------------------------------------------------------------
if (RM_IsTimerPhaseDue($varCOAlarmTimerphaseID, "CO_ESKALATION")) {
RM_ClearTimerPhase($varCOAlarmTimerphaseID);
if ($scan["coalarm"] && RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid($varCOAlarmAnzahlID, $scan["coanzahl"]);
if (!RM_GetBoolIfValid($varSicherheitsalarmQuittiertID, false)) {
RM_SetValueIfValid($varCOAlarmEskalationID, true);
RM_SetValueIfValid(
$varCOAlarmStatusID,
"CO ALARM ESKALATION: " . implode(", ", $scan["coaktiv"])
);
RM_Push(
$webfrontID,
"☠️ CO-ALARM ESKALATION!",
$scan["coanzahl"] . " CO-Melder aktiv: " . implode(", ", $scan["coaktiv"])
);
RM_Pushover(
$pushoverID,
"☠️ CO-ALARM ESKALATION!",
$scan["coanzahl"] . " CO-Melder aktiv: " . implode(", ", $scan["coaktiv"]),
$nachtPrioritaet
);
RM_AddHistorie(
$varCOAlarmHistorieID,
"CO-ESKALATION | " . $scan["coanzahl"] . " CO-Melder"
);
} else {
RM_SetValueIfValid(
$varCOAlarmStatusID,
"CO Alarm quittiert - weiterhin aktiv: " . GetValueString($varCOAlarmQuelleID)
);
}
}
}
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
return;
}
// -----------------------------------------------------------------------------
// NORMALER AUFRUF
// -----------------------------------------------------------------------------
$scan = RM_Scan(
$searchRootIDs,
$smokeNames,
$coNames,
$onlineNames,
$batteryNames,
$endlifeNames
);
// -----------------------------------------------------------------------------
// SONOFF SNZB-01P AUSWERTUNG
// -----------------------------------------------------------------------------
if ($_IPS['SENDER'] == "Variable") {
if ($_IPS['VARIABLE'] == $varSonoffActionID) {
$action = GetValueString($varSonoffActionID);
// --------------------------------------------------------------------
// SINGLE = Sicherheitsalarm quittieren
// --------------------------------------------------------------------
if ($action == "single") {
if (
GetValueBoolean($varBrandalarmAktivID) ||
RM_GetBoolIfValid($varCOAlarmAktivID, false)
) {
RM_SetValueIfValid($varSicherheitsalarmQuittiertID, true);
RM_SetValueIfValid($varBrandalarmStatusID, "Sicherheitsalarm quittiert");
if ($varCOAlarmStatusID > 0 && RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid($varCOAlarmStatusID, "CO Alarm quittiert");
}
RM_Pushover(
$pushoverID,
"🔕 Sicherheitsalarm quittiert",
"Alarm wurde manuell quittiert.",
-1
);
RM_AddHistorie(
$varBrandalarmHistorieID,
"QUITTIERT"
);
if ($varCOAlarmHistorieID > 0 && RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_AddHistorie(
$varCOAlarmHistorieID,
"CO QUITTIERT"
);
}
RM_StopSirens($sirenenIDs);
}
return;
}
// --------------------------------------------------------------------
// LONG = Testmodus starten
// --------------------------------------------------------------------
if ($action == "long") {
SetValueString($varBrandalarmTestmelderID, "SNZB-01P Test");
SetValueBoolean($varBrandalarmTestmodusID, true);
RM_Pushover(
$pushoverID,
"🧪 Rauchalarm Test",
"Testmodus über Sonoff SNZB-01P gestartet.",
-1
);
$scan = RM_Scan(
$searchRootIDs,
$smokeNames,
$coNames,
$onlineNames,
$batteryNames,
$endlifeNames
);
}
}
}
RM_SetValueIfValid($varBrandalarmAnzahlID, $scan["anzahl"]);
RM_SetValueIfValid($varCOAlarmAnzahlID, $scan["coanzahl"]);
// -----------------------------------------------------------------------------
// CO-ALARM
// -----------------------------------------------------------------------------
if ($scan["coalarm"]) {
if (!RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid($varCOAlarmAktivID, true);
RM_SetValueIfValid($varCOAlarmQuelleID, $scan["coquelle"]);
RM_SetValueIfValid($varCOAlarmZeitID, date("d.m.Y H:i:s"));
RM_SetValueIfValid($varCOAlarmAnzahlID, $scan["coanzahl"]);
RM_SetValueIfValid($varCOAlarmEskalationID, false);
RM_SetValueIfValid($varSicherheitsalarmQuittiertID, false);
RM_SetValueIfValid(
$varCOAlarmStatusID,
"CO ALARM aktiv: " . $scan["coquelle"]
);
RM_Push(
$webfrontID,
"☠️ CO-ALARM!",
"Kohlenmonoxid erkannt: " . $scan["coquelle"]
);
$alarmPriority = RM_GetAlarmPriority(
$varIsDayID,
$tagPrioritaet,
$nachtPrioritaet
);
RM_Pushover(
$pushoverID,
"☠️ CO-ALARM!",
"Kohlenmonoxid erkannt: " . $scan["coquelle"],
$alarmPriority
);
RM_AddHistorie(
$varCOAlarmHistorieID,
"CO-ALARM | " . $scan["coquelle"]
);
RM_SwitchEmergencyLights($lichtIDs, $varIsDayID);
RM_OpenShutters($rollladenIDs);
RM_StartSirens($sirenenIDs);
RM_SetTimerPhase(
$varCOAlarmTimerphaseID,
"CO_ESKALATION",
$coEskalationSekunden
);
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
}
return;
}
// -----------------------------------------------------------------------------
// CO-ALARM BEENDET
// -----------------------------------------------------------------------------
if (!$scan["coalarm"] && RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid($varCOAlarmAktivID, false);
RM_SetValueIfValid($varCOAlarmQuelleID, "");
RM_SetValueIfValid($varCOAlarmZeitID, "");
RM_SetValueIfValid($varCOAlarmAnzahlID, 0);
RM_SetValueIfValid($varCOAlarmEskalationID, false);
RM_ClearTimerPhase($varCOAlarmTimerphaseID);
RM_SetValueIfValid(
$varCOAlarmStatusID,
"CO Alarm beendet"
);
RM_Push(
$webfrontID,
"✅ CO Alarm beendet",
"CO Werte wieder normal."
);
RM_Pushover(
$pushoverID,
"✅ CO Alarm beendet",
"CO Werte wieder normal.",
-1
);
RM_AddHistorie(
$varCOAlarmHistorieID,
"CO-ALARM ENDE"
);
RM_StopSirens($sirenenIDs);
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
}
// -----------------------------------------------------------------------------
// AUFRÄUMEN BEI NORMALZUSTAND
// -----------------------------------------------------------------------------
if (
!$scan["alarm"] &&
!$scan["coalarm"] &&
!GetValueBoolean($varBrandalarmAktivID) &&
!RM_GetBoolIfValid($varCOAlarmAktivID, false)
) {
SetValueString($varBrandalarmQuelleID, "");
SetValueString($varBrandalarmZeitID, "");
RM_SetValueIfValid($varBrandalarmAnzahlID, 0);
RM_SetValueIfValid($varBrandalarmEskalationID, false);
RM_ClearTimerPhase($varBrandalarmTimerphaseID);
RM_SetValueIfValid($varCOAlarmQuelleID, "");
RM_SetValueIfValid($varCOAlarmZeitID, "");
RM_SetValueIfValid($varCOAlarmAnzahlID, 0);
RM_SetValueIfValid($varCOAlarmEskalationID, false);
RM_ClearTimerPhase($varCOAlarmTimerphaseID);
RM_SetValueIfValid($varSicherheitsalarmQuittiertID, false);
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
}
// -----------------------------------------------------------------------------
// RAUCHALARM ERKANNT
// -----------------------------------------------------------------------------
if ($scan["alarm"]) {
if (!GetValueBoolean($varBrandalarmAktivID)) {
RM_SetValueIfValid(
$varBrandalarmStatusID,
$scan["testmodus"]
? "TESTMODUS aktiv, prüfe Stabilität..."
: "Alarm erkannt, prüfe Stabilität..."
);
RM_SetTimerPhase(
$varBrandalarmTimerphaseID,
"ALARM_PRUEFUNG",
$alarmVerzoegerungSekunden
);
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
return;
}
RM_SetValueIfValid($varBrandalarmAnzahlID, $scan["anzahl"]);
if (
$scan["anzahl"] >= 2 &&
$varBrandalarmEskalationID > 0 &&
!GetValueBoolean($varBrandalarmEskalationID) &&
!RM_GetBoolIfValid($varSicherheitsalarmQuittiertID, false)
) {
SetValueBoolean($varBrandalarmEskalationID, true);
RM_SetValueIfValid(
$varBrandalarmStatusID,
$scan["testmodus"]
? "TESTMODUS: Eskalation mehrere Rauchmelder aktiv"
: "ESKALATION: mehrere Rauchmelder aktiv"
);
RM_Push(
$webfrontID,
$scan["testmodus"] ? "🧪 Test: mehrere Rauchmelder" : "🔥 Mehrere Rauchmelder!",
$scan["anzahl"] . " Rauchmelder aktiv: " . implode(", ", $scan["aktiv"])
);
$alarmPriority = RM_GetAlarmPriority(
$varIsDayID,
$tagPrioritaet,
$nachtPrioritaet
);
RM_Pushover(
$pushoverID,
$scan["testmodus"] ? "🧪 Test: mehrere Rauchmelder" : "🔥 Mehrere Rauchmelder!",
$scan["anzahl"] . " Rauchmelder aktiv: " . implode(", ", $scan["aktiv"]),
$scan["testmodus"] ? -1 : $alarmPriority
);
RM_AddHistorie(
$varBrandalarmHistorieID,
"ESKALATION | " . $scan["anzahl"] . " Rauchmelder"
);
}
return;
}
// -----------------------------------------------------------------------------
// RAUCHALARM BEENDET
// -----------------------------------------------------------------------------
if (!$scan["alarm"] && GetValueBoolean($varBrandalarmAktivID)) {
SetValueBoolean($varBrandalarmAktivID, false);
SetValueString($varBrandalarmQuelleID, "");
SetValueString($varBrandalarmZeitID, "");
RM_SetValueIfValid($varBrandalarmAnzahlID, 0);
RM_SetValueIfValid($varBrandalarmEskalationID, false);
RM_SetValueIfValid($varBrandalarmStatusID, "Alarm beendet");
RM_ClearTimerPhase($varBrandalarmTimerphaseID);
if (!RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid($varSicherheitsalarmQuittiertID, false);
}
RM_RefreshScriptTimer(
$_IPS['SELF'],
[
$varBrandalarmTimerphaseID,
$varCOAlarmTimerphaseID
]
);
RM_Push(
$webfrontID,
"✅ Rauchalarm beendet",
"Alle Rauchmelder wieder frei."
);
RM_Pushover(
$pushoverID,
"✅ Rauchalarm beendet",
"Alle Rauchmelder wieder frei.",
-1
);
RM_AddHistorie(
$varBrandalarmHistorieID,
"ENDE"
);
RM_StopSirens($sirenenIDs);
return;
}
// -----------------------------------------------------------------------------
// WARTUNG / DIAGNOSE
// -----------------------------------------------------------------------------
$wartung = [];
if (count($scan["offline"]) > 0) {
$wartung[] = "Offline: " . implode(", ", $scan["offline"]);
}
if (count($scan["batterie"]) > 0) {
$wartung[] = "Batterie prüfen: " . implode(", ", $scan["batterie"]);
}
if (count($scan["endlife"]) > 0) {
$wartung[] = "EndOfLife/Fault: " . implode(", ", $scan["endlife"]);
}
// ---------------------------------------------------------------------------
// Diagnosevariablen
// ---------------------------------------------------------------------------
RM_SetValueIfValid(
$varRMOfflineID,
count($scan["offline"]) > 0
? implode(", ", $scan["offline"])
: "Keine Rauchmelder offline"
);
RM_SetValueIfValid(
$varRMBatterieID,
count($scan["batterie"]) > 0
? implode(", ", $scan["batterie"])
: "Alle Batterien OK"
);
RM_SetValueIfValid(
$varRMEndOfLifeID,
count($scan["endlife"]) > 0
? implode(", ", $scan["endlife"])
: "Keine Fault-/EndOfLife-Melder"
);
// ---------------------------------------------------------------------------
// CO Status
// ---------------------------------------------------------------------------
if (!$scan["coalarm"] && !RM_GetBoolIfValid($varCOAlarmAktivID, false)) {
RM_SetValueIfValid(
$varCOAlarmStatusID,
"Kein CO Alarm"
);
}
// ---------------------------------------------------------------------------
// Gesamtstatus
// ---------------------------------------------------------------------------
if (
count($scan["offline"]) == 0 &&
count($scan["batterie"]) == 0 &&
count($scan["endlife"]) == 0
) {
RM_SetValueIfValid(
$varRMGesamtstatusID,
"🟢 Alle Rauchmelder OK"
);
RM_SetValueIfValid(
$varBrandalarmStatusID,
"Alles normal"
);
RM_SetValueIfValid(
$varBrandalarmWartungID,
"Alle " . $scan["anzahlMelder"] . " Rauchmelder normal"
);
} else {
$status = [];
if (count($scan["offline"]) > 0) {
$status[] = "🔴 Offline";
}
if (count($scan["batterie"]) > 0) {
$status[] = "🟠 Batterie";
}
if (count($scan["endlife"]) > 0) {
$status[] = "⚫ Fault";
}
RM_SetValueIfValid(
$varRMGesamtstatusID,
implode(" | ", $status)
);
RM_SetValueIfValid(
$varBrandalarmStatusID,
"Wartung erforderlich"
);
RM_SetValueIfValid(
$varBrandalarmWartungID,
implode(" | ", $wartung)
);
}
Dokumentation dazu:
<?php
################################################################################
# Dokumentation: Rauchmelder Brandalarm Logik
# Version: 1.0.20260511
# Author: ChatGPT / angepasst für IP-Symcon
#
# Übersicht:
# Dokumentation der zentralen Brandalarm- und Sicherheitslogik für
# X-Sense Rauchmelder in IP-Symcon.
#
# Die Rauchmelder werden über MQTT eingebunden und automatisch überwacht.
################################################################################
################################################################################
# UNTERSTÜTZTE HARDWARE
#
# Rauchmelder:
# - X-Sense XS0B-MR
# - X-Sense XP0A-MR
#
# Anbindung:
# - MQTT
# - Zigbee2MQTT
#
# Alarmquittierung / Testmodus:
# - Sonoff SNZB-01P
#
# Unterstützte Aktionen:
# - single
# - long
################################################################################
################################################################################
# HAUPTFUNKTIONEN
#
# Das Skript erkennt automatisch:
#
# - Rauchalarm
# - Mehrfachauslösung
# - Offline-Melder
# - niedrige Batterien
# - EndOfLife / Fault-Zustände
#
# Zusätzlich verarbeitet das System:
#
# - Push-Benachrichtigungen
# - Pushover-Alarme
# - Lichtsteuerungen
# - Rollladenöffnungen
# - Alarmhistorien
# - Nachtlogik
# - Alarmquittierungen
################################################################################
################################################################################
# RAUCHALARM-ERKENNUNG
#
# Das Skript überwacht automatisch alle gefundenen Rauchmelder.
#
# Verwendete Variablen:
#
# Smoke Status
# -> Rauchalarm aktiv
#
# Online Status
# -> Melder online/offline
#
# Battery Status
# -> Batteriewarnung
#
# End of Life
# -> Fault / Gerätefehler
#
#
# Verhalten bei Rauchalarm:
#
# Rauch erkannt
# -> Stabilitätsprüfung
# -> Alarm aktiv
# -> Push / Pushover
# -> Licht nachts einschalten
# -> Rollläden öffnen
# -> Eskalation starten
################################################################################
################################################################################
# STABILITÄTSPRÜFUNG
#
# Vor echter Alarmierung wird geprüft:
#
# Alarm weiterhin nach 5 Sekunden aktiv?
#
# Dadurch werden reduziert:
#
# - MQTT-Fehler
# - kurze Fehltrigger
# - Kommunikationsspitzen
################################################################################
################################################################################
# ESKALATIONSLOGIK
#
# Nach erfolgreicher Alarmierung startet ein Eskalationstimer:
#
# 30 Sekunden
#
#
# Verhalten:
#
# Ein Rauchmelder aktiv:
# -> Alarm weiterhin aktiv
#
# Zwei oder mehr Rauchmelder aktiv:
# -> ESKALATION
#
#
# Zusätzlich:
#
# - kritische Pushs
# - Historieneintrag
# - Eskalationsstatus
################################################################################
################################################################################
# TAG- / NACHTLOGIK
#
# Verwendete Variable:
#
# Is Day
# -> Variable aus Location Control
#
#
# Verhalten tagsüber:
#
# - kein Licht
# - normale Alarmierung
# - Rollläden öffnen
#
#
# Verhalten nachts:
#
# - Licht einschalten
# - kritische Alarmierung
# - Rollläden öffnen
################################################################################
################################################################################
# TIMERLOGIK
#
# Rauchalarm und CO-Alarm verwenden getrennte Timerphasen.
#
# Beide Systeme teilen sich jedoch nur einen einzigen ScriptTimer.
#
#
# Hintergrund:
#
# IP-Symcon erlaubt pro Skript nur einen aktiven ScriptTimer.
#
#
# Lösung:
#
# Die Timerphasen speichern:
#
# - Phase
# - Fälligkeit
#
#
# Format:
#
# PHASE|UnixTimestamp
#
#
# Beispiel:
#
# ALARM_PRUEFUNG|1760000000
# CO_ESKALATION|1760000030
#
#
# Vorteile:
#
# - Rauchalarm und CO-Alarm blockieren sich nicht gegenseitig
# - beliebig erweiterbar
# - stabil bei parallelen Alarmen
# - saubere Eskalationssteuerung
################################################################################
################################################################################
# TIMERPHASEN
#
# Rauchalarm:
#
# ALARM_PRUEFUNG
# -> Stabilitätsprüfung nach Raucherkennung
#
# ESKALATION
# -> Eskalationsprüfung bei weiterhin aktivem Alarm
#
#
# CO-Alarm:
#
# CO_ESKALATION
# -> Eskalationsprüfung bei weiterhin aktivem CO-Alarm
################################################################################
################################################################################
# LICHTSTEUERUNG
#
# Nachts werden definierte Lichtgruppen aktiviert.
#
# Verhalten:
#
# - Licht EIN
# - Helligkeit 100 %
#
#
# Aktuell eingebunden:
#
# - EG Flur
# - EG Haupt-Flur
# - EG Wohnzimmer
# - EG Küche
################################################################################
################################################################################
# ROLLLADENSTEUERUNG
#
# Bei Brandalarm werden definierte Rollläden geöffnet.
#
# Verhalten:
#
# 100 % = offen
#
#
# Zweck:
#
# - Fluchtwege
# - Sichtbarkeit
# - Feuerwehrzugang
################################################################################
################################################################################
# SIRENENLOGIK
#
# Optional können externe Sirenen eingebunden werden.
#
# Verhalten:
#
# Alarm aktiv:
# -> Sirenen EIN
#
# Alarm quittiert:
# -> Sirenen AUS
#
# Alarm beendet:
# -> Sirenen AUS
#
#
# Hinweis:
#
# Licht und Rollläden bleiben auch nach Quittierung aktiv,
# damit Fluchtwege weiterhin sichtbar bleiben.
################################################################################
################################################################################
# ALARMQUITTIERUNG
#
# Über den Sonoff SNZB-01P kann ein Alarm quittiert werden.
#
#
# SINGLE:
#
# -> Alarm quittieren
#
# Wirkung:
# - Sirenen AUS
# - Eskalation stoppen
# - Alarm bleibt sichtbar
# - Licht bleibt aktiv
# - Rollläden bleiben offen
#
#
# LONG:
#
# -> Testmodus starten
#
# Wirkung:
# - vollständiger Funktionstest
# - ohne echten Rauchalarm
################################################################################
################################################################################
# TESTMODUS
#
# Der Testmodus simuliert einen echten Rauchalarm.
#
# Folgende Funktionen werden vollständig getestet:
#
# - Push
# - Pushover
# - Lichtsteuerung
# - Rollladenöffnung
# - Eskalation
# - Historie
################################################################################
################################################################################
# TESTALARM-PROTOKOLLIERUNG
#
# Der letzte erfolgreiche Testalarm wird gespeichert.
#
# Verwendete Variablen:
#
# Rauchmelder Letzter Test
# -> Unix-Zeitstempel
#
# Rauchmelder Letzter Test Text
# -> lesbarer Zeitstempel mit Quelle
#
#
# Beispiel:
#
# 11.05.2026 20:15:22 | SNZB-01P Test
################################################################################
################################################################################
# WARTUNGSÜBERWACHUNG
#
# Das Skript überwacht automatisch:
#
# Rauchmelder Erreichbarkeit:
# Online Status = false
#
# Rauchmelder Batteriestatus:
# Battery Status = true
#
# Rauchmelder Faultstatus:
# End of Life = true
################################################################################
################################################################################
# SAMMELSTATUS
#
# Die Variable:
#
# Rauchmelder Gesamtstatus
#
# zeigt:
#
# - Gesamtstatus
# - Offline-Zustände
# - Batterieprobleme
# - Fault-Zustände
################################################################################
################################################################################
# ALARMHISTORIE
#
# Alle wichtigen Ereignisse werden gespeichert.
#
# Beispiele:
#
# 10.05.2026 23:14 | ALARM | Rauchmelder EG Flur
# 10.05.2026 23:15 | ESKALATION | 2 Rauchmelder
# 10.05.2026 23:16 | QUITTIERT
# 10.05.2026 23:18 | ENDE
################################################################################
################################################################################
# PUSH-BENACHRICHTIGUNGEN
#
# Unterstützt:
#
# WebFront Push:
# - WFC_PushNotification
#
# Pushover:
# - TUPO_SendMessage
################################################################################
################################################################################
# PRIORITÄTEN
#
# Tagsüber:
# -> Priorität 1
#
# Nachts:
# -> Priorität 2
#
#
# Zweck:
#
# - lautere Warnung
# - Wiederholung
# - höhere Sichtbarkeit
################################################################################
################################################################################
# AUTOMATISCHE RÜCKSETZUNG
#
# Nach Alarmende werden automatisch zurückgesetzt:
#
# - Brandalarm Aktiv
# - Eskalation
# - Quittierung
# - Timerphase
# - Alarmquelle
# - Alarmzeit
################################################################################
################################################################################
# EMPFOHLENE STRUKTUR
#
# Gewerke
# └── Sicherheit
# └── Brandalarm
# ├── Brandalarm Aktiv
# ├── Brandalarm Eskalation
# ├── Brandalarm Quittiert
# ├── Brandalarm Status
# ├── Brandalarm Historie
# ├── Brandalarm Wartung
# ├── Rauchmelder Erreichbarkeit
# ├── Rauchmelder Batteriestatus
# ├── Rauchmelder Faultstatus
# ├── Rauchmelder Gesamtstatus
# └── Rauchmelder Letzter Test
################################################################################
################################################################################
# EMPFOHLENE EVENTS
#
# Rauchmelder:
#
# Bei Änderung:
# - Smoke Status
# - Online Status
# - Battery Status
# - End Of Life
#
# -> Skript ausführen
#
#
# Sonoff SNZB-01P:
#
# Bei Änderung:
# - Action
#
# -> Skript ausführen
#
#
# Wartungsprüfung:
#
# täglich
#
# -> Skript ausführen
################################################################################
################################################################################
# SICHERHEITSKONZEPT
#
# Das System reduziert Fehlalarme durch:
#
# - Stabilitätsprüfung
# - Quittierungslogik
# - Eskalationslogik
#
#
# Echter Alarm wird maximal sichtbar durch:
#
# - Lichtsteuerung
# - Rollladenöffnung
# - Pushs
# - Pushover
# - Historie
# - Eskalation
################################################################################
################################################################################
# ERWEITERUNGSMÖGLICHKEITEN
#
# Später möglich:
#
# - TTS / Sprachdurchsagen
# - Wasseralarm
# - Kameraintegration
# - Feuerwehrmodus
# - Außensirenen
# - Alarmzentrale
# - Notfallbeleuchtung
# - Anwesenheitslogik
# - Alarmweiterleitung
################################################################################
################################################################################
# CO-ALARM
#
# Zusätzlich zum Rauchalarm unterstützt das System CO-Alarm-Erkennung.
#
# Verwendete Variablen:
#
# CO Status
# -> Kohlenmonoxid erkannt
#
#
# Verhalten bei CO-Alarm:
#
# CO erkannt
# -> CO Alarm aktiv
# -> Push / Pushover
# -> Licht nachts einschalten
# -> Rollläden öffnen
# -> Sirenen aktivieren
# -> CO-Eskalation starten
#
#
# Unterschiede zum Rauchalarm:
#
# - keine Stabilitätsprüfung
# - sofortige Alarmierung
# - eigene Historie
# - eigener Statusbereich
# - eigene Eskalationslogik
################################################################################
Angelegte Variablen:
Angelegte Events:

