Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Umfassendes Alarmanlagen-Skript

NEWS

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    18
    1
    600

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    9.0k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.3k

Umfassendes Alarmanlagen-Skript

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
javascriptsecurity
145 Beiträge 27 Kommentatoren 32.4k Aufrufe 52 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • andreaskosA Offline
    andreaskosA Offline
    andreaskos
    schrieb am zuletzt editiert von andreaskos
    #103

    Lieber @Freaknet und @Schmakus und alle anderen Leser,

    ich habe eben die Funktion eingebaut, einzelne Melder aus der Aussenhülle von der Überwachung ausnehmen zu können. Die Funktion ist mehr oder weniger ungetestet und ich würde euch bitten hier Feedback zu geben, um das Skript fehlerfrei zu bekommen und auch als neue Version oben im ersten Thread updaten zu können.

    Neue Datenpunkte
    Unter "Input" ist nun ein neuer Knoten namens "IgnoreOpen" zu finden. Unterhalb diesem können per Flag die einzelnen Melder inaktiv geschaltet werden.
    true = wird mitüberwacht
    false = von der Überwachung ausgenommen

    Unter "Output" ist ein Text-Datenpunkt, der die Liste der offenen Melder mit gesetztem IgnoreOpen-Flag beinhaltet. Diese Melder kommen nicht in die Liste der ganz regulär offenen Melder.
    Diesen Datenpunkt könnte man verwenden, um sich zu warnen, wenn zum Zeitpunkt des Scharf-Schaltens (oder ein paar Millisekunden später) hier Text enthalten ist.

    ACHTUNG
    Die Einstellung der IgnoreOpen-Flags wird (derzeit) nicht automatisch zurück gesetzt, etwa beim Scharf-Schalten. Das bedeutet, man muss selbst drauf achten, dass ein Melder nicht ewig auf Inaktiv bleibt, weil man vergessen hat das Flag wieder auf true zu stellen.

    /*
    ########################################################################################################################
    # ALARMSYSTEM
    #
    # Das Skript bildet eine einfache Alarmanlage nach mit der Schaltmöglichkeit
    # für intern und extern.
    # Datenpunkte für Inputs und Outputs werden angelegt.
    # Nähere Beschreibung siehe im ioBroker-Forum unter
    # https://forum.iobroker.net/topic/32885/umfassendes-alarmanlagen-skript
    # Änderungshistorie:
    # 2020-05-01    Andreas Kos     Erstellt
    # 2020-05-02    Andreas Kos     Schaltwunsch mit Number-Datenpunkt Input.SwitchNumber (Idee von @Homer.J.)
    #                               Schaltstatus mit Number-Datenpunkt Output.ActiveNumber (Idee von @Homer.J.)
    # 2020-05-03    Andreas Kos     Korrekturen, u.a. für Melderauswertung (chage: "ne") & AlarmText
    # 2020-05-04    Andreas Kos     - Melder werden aus den Functions (Aufzählungen, enums) dafür geholt. Auch beim Unscharf-
    #                                 schalten, dadurch ist kein Neustarten des Skripts notwendig bei
    #                                 Änderungen an diesen Aufzählungen.
    #                               - Eine Schaltung von einem scharf-Zustand auf einen anderen
    #                                 wird verhindert. ZB von scharf intern auf scharf extern.
    #                                 Es muss immer unscharf dazwischen geschaltet werden.
    # 2020-05-09    Andreas Kos     Zusätzliche Objekte mit JSON-Strings für:
    #                               - den auslösenden Melder
    #                               - alle offenen Melder
    #                               - alle offenen Melder der Außenhaut
    #                               - alle offenen Melder des Innenraums
    #                               Die JSON-String beinhalten das auslösende Objekt, sowie (falls vorhanden)
    #                               das Parent und das ParentsParent-Objekt mit allen in ioBroker verfügbaren Eigenschaften.
    #                               Kleinere Verbesserungen, z.B. bezüglich setzen der AlarmTexte.
    # 2020-05-12    Andreas Kos     Setzen des Datenpunkts idReady zur Bereitschaftsanzeige neu gemacht.
    # 2021-06-13    Andreas Kos     Einbau der Funktion zum Ausnehmen einzelner Melder der Aussenhülle
    #                               von der Melder-Überwachung. Soll zum Kippen von Fenstern dienen u.ä.
    ########################################################################################################################
    */
    
    // EINBRUCHSMELDER
    // Jeder Melder muss ein State sein, der bei Auslösung true liefert und in Ruhe (geschlossen) false.
    // Die Melder sind in Arrays zusammengefasst, d.h. sie müssen jeweils mit Beistrich voneinander getrennt werden.
    // Die Namen der Melder sollten gut gepflegt sein für eine sinnvolle Verwendung (Attribut name bei den Objekten)
    
    // Melder der Außenhaut
    // Dies können Öffnungskontakte sein von Fenster und Türen in den Außenmauern des Objekts.
    // EINGABE: In der Aufzählung "alarmanlage_aussenhaut" die States einfügen.
    
    // Melder des Innenraums
    // Dies können Bewegungsmelder sein aus dem Inneren.
    // EINGABE: In der Aufzählung "alarmanlage_innenraum" die States einfügen.
    
    // Verzögerte Melder
    // Diese kommen in den Gruppen oben auch vor. Sie bewirken eine Aktivierung der Eingangsverzögerung
    // bei scharf geschalteter Anlage und erlauben während der Ausgangsverzögerung nach dem
    // Scharfschalten das Haus zu verlassen.
    // EINGABE: In der Aufzählung "alarmanlage_verzoegert" die States einfügen.
    
    
    // EINSTELLUNGEN
    const entryDelay =                30;         // Eingangsverzögerung in Sekunden (sollte maximal 60s sein)
    const exitDelay =                 30;         // Ausgangsverzögerung in Sekunden (sollte maximal 60s sein)
    const alarmDurationAccoustical =  180;         // Dauer des akkustischen Alarms in Sekunden (ACHTUNG: in Ö sind maximal 180s erlaubt!)
    const alarmDurationOptical =      -1;         // Dauer des optischen Alarm in Sekunden, -1 für unendlich
    
    // TEXTE FÜR SCHALTZUSTAND
    // Diese Text geben Auskunft über den Zustand der Anlage.
    // Sie werden in den Datenpunkt "javascript.X.Output.StatusText" geschrieben.
    const textStatusInactive =        "unscharf";
    const textStatusActiveInternal =  "scharf intern";
    const textStatusActiveExternal =  "scharf extern";
    const textActiveExternalDelayed = "scharf extern verzögert";
    const textEntryDelayActive =      "Eingangsverzögerung aktiv";
    const textExitDelayActive =       "Ausgangsverzögerung aktiv";
    
    // TEXTE FÜR ALARMIERUNG UND FEHLER
    // Diese Text geben im unscharfen Zustand der Anlage Auskunft über die Bereitschaft
    // zum Scharfschalten (nur möglich, wenn alle Melder geschlossen - in Ruhe - sind) und
    // Fehler bei der Scharfschaltung bzw. bei scharfer Anlage über den Zustand Frieden oder Alarm.
    // Sie werden in den Datenpunkt "javascript.X.Output.AlarmText" geschrieben.
    const textAlarmInactive =         "Alles OK";
    const textAlarmActive =           "Alarm!!";
    const textReady =                 "Bereit";
    const textNotReady =              "Nicht bereit";
    const textError =                 "Fehler bei der Scharfschaltung";
    
    // EXPERTEN-EINSTELLUNGEN
    const pathToCreatedStates = "Alarmanlage";    // Beispiel: States werden erzeugt unter javascript.X.Alarmanlage
    const seperator = ", ";                       // Trenn-String, der zwischen den Meldernamen verwendet wird, im Datenpunkt "OpenDetectors"
    const loglevel = 2;                           // 0 bis 3. 0 ist AUS, 3 ist maximales Logging
                                                // Empfehlung für Nachvollziehbarkeit aller Handlungen ist 2 (Ereignisliste)
    const functionOuterSkin = "alarmanlage_aussenhaut";
    const functionIndoor = "alarmanlage_innenraum";
    const functionDelayedDetectors = "alarmanlage_verzoegert";
    
    /*
       ###############################################################################
                        DO NOT CHANGE ANYTHING BELOW THIS LINE
                             AB HIER NICHTS MEHR ÄNDERN
       ###############################################################################
    */
    
    // ===============================================================================
    // Variablen
    // ===============================================================================
    
    // Arrays für die Melder
    var detectorsOuterSkin = [];
    var detectorsIndoor = [];
    var detectorsDelayed = [];
    
    // Array für die IgnoreOpen-Melder (beinhaltet nur Flags).
    // Das Array ist inital deckungsgleich mit detectorsOuterSkin, da diese
    // nur aus dieser Function kommen können.
    // Dieses Array ist 2-Dimensional: [Melder-ID, IgnoreOpen-Zustands-ID]
    var detectorsIgnoreOpen = [];
    
    // Javascript-Instanz mit der das Alarmanlagen-Skript ausgeführt wird
    var javascriptInstance = instance;
    
    // States, die erzeugt werden für Status-Ausgaben
    var idActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Active";
    var idActiveExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveExternal";
    var idActiveInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveInternal";
    var idActiveNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveNumber";
    var idAlarm = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Alarm";
    var idAlarmAccoustical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmAccoustical";
    var idAlarmOptical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmOptical";
    var idReady = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Ready";
    var idEntryDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.EntryDelayActive";
    var idExitDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ExitDelayActive";
    var idAlarmingDetector = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetector";
    var idAlarmingDetectorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetectorJSON";
    var idOpenDetectors = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectors";
    var idOpenDetectorsJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsJSON";
    var idOpenDetectorsOuterSkinJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsOuterSkinJSON";
    var idOpenDetectorsIndoorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIndoorJSON";
    var idOpenDetectorsWithIgnoreOpenFlagSet = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIgnoreOpen";
    
    var idStatusText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.StatusText";
    var idAlarmText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmText";
    var idError = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Error";
    
    // States, die erzeugt werden für Eingaben
    var idSwitchExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternal";
    var idSwitchInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchInternal";
    var idSwitchExternalDelayed = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternalDelayed";
    var idSwitchNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchNumber";
    
    // Sonstige globale Variablen, die gebraucht werden
    var timerExitDelay = null;
    var timerTexts = null;
    
    // ===============================================================================
    // Precode
    // ===============================================================================
    
    // Logging
    if (loglevel >= 1) log ("Alarmsystem started.");
    
    getAllDetectors();
    
    // States erzeugen
    myCreateState(idActive, "boolean", false, "Switch Status Total", false, "info.status");
    myCreateState(idActiveExternal, "boolean", false, "Switch Status External", false, "info.status");
    myCreateState(idActiveInternal, "boolean", false, "Switch Status Internal", false, "info.status");
    myCreateState(idAlarm, "boolean", false, "Alarm Status", false, "sensor.alarm");
    myCreateState(idAlarmAccoustical, "boolean", false, "Accoustical Alarm Status", false, "sensor.alarm");
    myCreateState(idAlarmOptical, "boolean", false, "Optical Alarm Status", false, "sensor.alarm");
    myCreateState(idReady, "boolean", false, "Alarmsystem Ready", false, "info.status");
    myCreateState(idError, "boolean", false, "Error Switching Active", false, "info.status");
    myCreateState(idEntryDelayActive, "boolean", false, "Entry Delay Active Status", false, "info.status");
    myCreateState(idExitDelayActive, "boolean", false, "Exit Delay Active Status", false, "info.status");
    myCreateState(idAlarmingDetector, "string", "", "Alarming Detector", false, "text");
    myCreateState(idAlarmingDetectorJSON, "string", "", "Alarming Detector JSON", false, "json");
    myCreateState(idOpenDetectors, "string", "", "Open Detectors", false, "info.name");
    myCreateState(idOpenDetectorsJSON, "string", "", "Open Detectors JSON", false, "json");
    myCreateState(idOpenDetectorsOuterSkinJSON, "string", "", "Open Detectors Outer Skin JSON", false, "json");
    myCreateState(idOpenDetectorsIndoorJSON, "string", "", "Open Detectors Indoor JSON", false, "json");
    myCreateState(idOpenDetectorsWithIgnoreOpenFlagSet, "string", "", "Open Detectors with IgnoreOpen-Flag set", false, "text");
    myCreateState(idStatusText, "string", "", "Status Text", false, "text");
    myCreateState(idAlarmText, "string", "", "Alarm Text", false, "text");
    myCreateState(idSwitchExternal, "boolean", false, "Enable Surveillance External", true, "switch");
    myCreateState(idSwitchInternal, "boolean", false, "Enable Surveillance Internal", true, "switch");
    myCreateState(idSwitchExternalDelayed, "boolean", false, "Enable Surveillance External Delayed", true, "switch");
    
    myCreateMultiState (idActiveNumber, "number", 0, "Switch Status Number", false, 0, 4,"0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+"; 2:"+textStatusActiveExternal+"; 3:"+textExitDelayActive+"; 4:"+textEntryDelayActive);
    myCreateMultiState (idSwitchNumber, "number", 0, "Switch by Number", true, 0, 3, "0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+" ; 2:"+textStatusActiveExternal+" ; 3:"+textActiveExternalDelayed);
    
    // Erzeugen der Datenpunkte für die IgnoreOpen-Einstellung
    myCreateIgnoreOpenDPs();
    
    // Melder nach dem Starten checken
    checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
    
    // ===============================================================================
    // ON-Subscribtions
    // ===============================================================================
    
    // Auf Schaltstellen EXTERN verzögert reagieren (schalten EIN/AUS)
    on ({id: idSwitchExternalDelayed, change: "any"}, function(obj){
        if (loglevel >= 3) log ("Switching External Delayed, Value: " + getState(obj.id).val);
        if (getState(obj.id).val) { // Einschalten, scharf extern VERZÖGERT
            if (loglevel >= 2) log ("Switching required: Delayed External Active");
                if (getState(idActive).val) {
                    if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                    setState(idError, true);
                } else {
                    setState(idExitDelayActive, true);
                    if (timerExitDelay) clearTimeout(timerExitDelay);
                    timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                }
        }
        else { // Ausschalten, unscharf SOFORT
            if (loglevel >= 2) log ("Switching required: Inactive");
            switchInactive();
        }
    });
    
    // Auf Schaltstellen EXTERN sofort reagieren (schalten EIN/AUS)
    on ({id: idSwitchExternal, change: "any"}, function(obj){
        if (loglevel >= 3) log ("Switching External Immediately, Value: " + getState(obj.id).val);
        if (getState(obj.id).val) { // Einschalten, scharf extern
            if (loglevel >= 2) log ("Switching required: External Active");
            if (getState(idActive).val) {
                if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                setState(idError, true);
            } else {
                switchActiveExternal();
            }
        }
        else { // Ausschalten, unscharf
            if (loglevel >= 2) log ("Switching required: Inactive");
            switchInactive();
        }
    });
    
    // Auf Schaltstellen INTERN sofort reagieren (schalten EIN/AUS)
    on ({id: idSwitchInternal, change: "any"}, function(obj){
        if (loglevel >= 3) log ("Switching Internal, Value: " + getState(obj.id).val);
        if (getState(obj.id).val) { // Einschalten, scharf intern
            if (loglevel >= 2) log ("Switching required: Internal Active");
            if (getState(idActive).val) {
                if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                setState(idError, true);
            } else {
                switchActiveInternal();
            }
        }
        else { // Ausschalten, unscharf
            switchInactive();
            if (loglevel >= 2) log ("Switching required: Inactive");
        }
    });
    
    // Auf Schaltstelle mit Datenpunkt SwitchNumber reagieren
    // Folgende Reaktionen:
    //      0 ... unscharf schalten
    //      1 ... scharf intern schalten
    //      2 ... scharf extern schalten
    //      3 ... verzögert scharf extern schalten
    on ({id: idSwitchNumber, change: "any"}, function(obj){
        if (loglevel >= 3) log ("Switching Number, Value: " + obj.state.val);
        switch (obj.state.val) {
            case 0:
                if (loglevel >= 2) log ("Switching required: Inactive");
                switchInactive();
                break;
            case 1:
                if (loglevel >= 2) log ("Switching required: Internal Active");
                if (getState(idActive).val) {
                    if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                    setState(idError, true);
                } else {
                    switchActiveInternal();
                }
                break;
            case 2:
                if (loglevel >= 2) log ("Switching required: External Active");
                if (getState(idActive).val) {
                    if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                    setState(idError, true);
                } else {
                    switchActiveExternal();
                }
                break;
            case 3:
                if (loglevel >= 2) log ("Switching required: Delayed External Active");
                if (getState(idActive).val) {
                    if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                    setState(idError, true);
                } else {
                    setState(idExitDelayActive, true);
                    if (timerExitDelay) clearTimeout(timerExitDelay);
                    timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                }
                break;
            default:
                if (loglevel >= 3) log ("idSwitchNumber has unknown number!");
        }
    });
    
    // Auf Fehler bei der Scharfschaltung reagieren
    on ({id: idError, val: true, change: "any"}, function(obj){
        if (loglevel >= 1) log ("Error when switching to active.");
        setState(idAlarmText, textError);
    });
    
    // Auf Eingangsverzögerung reagieren
    on({id: idEntryDelayActive, val: true, change: "ne"}, function (obj) {
        if (loglevel >= 2) log ("Entry Delay is active (" + entryDelay + " seconds)");
        setState(idStatusText, textEntryDelayActive);
        setStateDelayed(idAlarmAccoustical, true, entryDelay * 1000);
        setStateDelayed(idAlarmOptical, true, entryDelay * 1000);
    });
    
    // Auf Ausgangsverzögerung reagieren
    on({id: idExitDelayActive, val: true, change: "ne"}, function (obj) {
        if (loglevel >= 2) log ("Exit Delay is active (" + exitDelay + " seconds)");
        setState(idStatusText, textExitDelayActive);
    });
    
    // Auf Akustischen Alarm reagieren
    on ({id: idAlarmAccoustical, val: true, change: "ne"}, function(obj){
        if (loglevel >= 1) log ("ALARM is active!");
        setState(idEntryDelayActive, false);
        setState(idAlarmText, textAlarmActive);
        setState(idAlarm, true);
        setStateDelayed(idAlarmAccoustical, false, alarmDurationAccoustical * 1000);
        if (getState(idActiveExternal).val) setState(idStatusText, textStatusActiveExternal);
        if (getState(idActiveInternal).val) setState(idStatusText, textStatusActiveInternal);
    });
    
    // Auf Optischen Alarm reagieren
    on ({id: idAlarmOptical, val: true, change: "ne"}, function(obj){
        if (alarmDurationOptical >= 0)
            setStateDelayed(idAlarmOptical, false, alarmDurationOptical * 1000);
    });
    
    // Melderauswertung
    on( {id: detectorsOuterSkin.concat(detectorsIndoor), change: "ne"}, function(obj){
        detectorSurveillance(obj);
    });
    
    // Status in Active.Number schreiben
    on ({id: [idActiveInternal, idActiveExternal, idEntryDelayActive, idExitDelayActive], change: "ne"}, function(obj){
        if (loglevel >= 3) log ("on for writing ActiveNumber, Trigger: " + obj.id);
        setActiveNumber();
    });
    
    // Texte korrekt setzen
    on ({id: [idAlarm, idActive, idOpenDetectors], change: "any"}, function (obj) {
        // Das Timeout ggf. abbrechen
        if (timerTexts) clearTimeout(timerTexts);  
        // Nach einem Timeout den Check anfangen
        timerTexts = setTimeout(setTexts, 200);
    });
    
    
    
    // ===============================================================================
    // Funktionen
    // ===============================================================================
    // Funktion     checkIfIgnoreOpenFlagSet
    // =====================================
    // Parameter:       Prüft, ob das IgnoreOpen-Flag für einen Melder gesetzt ist.
    // Übergabewert:    Melder-ID
    // Rückgabewert:    Flag-Zustand
    function checkIfIgnoreOpenFlagSet(id){
        var i=0;
        while (i<detectorsIgnoreOpen.length){
            if ( detectorsIgnoreOpen[i][0] == id )
                if (getState(detectorsIgnoreOpen[i][1]).val)
                    return true;
            i++;
        }
        return false;
    }
    
    // Function setTexts
    // =================
    // Parameter:       keiner
    // Funktion:        Abhängig von den Zuständen scharf/unscharf und
    //                  Alarm / Kein Alarm werden Texte für
    //                  den AlarmText richtig gesetzt. Auch der Datenpunkt idReady wird hier gesetzt.
    // Rückgabewert:    keiner
    function setTexts(){    
        var textListOfDetectors = getState(idOpenDetectors).val;
        if (textListOfDetectors.length > 0) {
            if (!getState(idActive).val)
                // Offene Melder gefunden und unscharf
                setState(idAlarmText, textNotReady);
                setState(idReady, false);
            return false;
        } else {
            if (getState(idActive).val && !getState(idAlarm).val)
                // kein offener Melder gefunden und scharf und kein Alarm
                setState(idAlarmText, textAlarmInactive);
            else if (!getState(idActive).val)
                // kein offener Melder gefunden und unscharf
                setState(idAlarmText, textReady);
                setState(idReady, true);
            return true;
        }
    }
    
    // Function getAllDetectors
    // ========================
    // Parameter:       keiner
    // Funktion:        Über die Funktion getDetectorsFromFunction werden
    //                  alle Melder von den Functions geholt und in die
    //                  globalen Variablen dafür geschrieben.
    // Rückgabewert:    keiner
    function getAllDetectors(){
        var i=0;
        detectorsOuterSkin = getDetectorsFromFunction(functionOuterSkin);
        detectorsIgnoreOpen = [];
        while (i<detectorsOuterSkin.length) {
            detectorsIgnoreOpen.push([detectorsOuterSkin[i++]]);
        }
        detectorsIndoor = getDetectorsFromFunction(functionIndoor);
        detectorsDelayed = getDetectorsFromFunction(functionDelayedDetectors);
    }
    
    // Function getDetectorsFromFunction
    // =================================
    // Parameter:       functionString
    //                  Name der Function, in der die Melder enthalen sind.
    // Funktion:        Alle Teilnehmer der übergebenen Function werden
    //                  in ein Array geschrieben.
    // Rückgabewert:    Array der Melder-IDs
    function getDetectorsFromFunction( functionString ) {
        if (loglevel >= 3) log ("Function getDetectorsFromFunction");
        var detectors = [];
        $('state(functions='+functionString+')').each(function(id, i) {
            detectors.push(id);
            if (loglevel >= 3) log ("This detector was added to surveillance from function "+functionString+": " + id);
        });
        return detectors;
    }
    
    // Function detectorSurveillance
    // =============================
    // Parameter:       obj
    //                  Objekt des auslösenden Melders
    // Funktion:        Abhängig vom Schaltzustand werden die Melder überprüft.
    //                  Bei unscharf wird nur die Liste der offenen Melder und die
    //                  Bereitschaft der Anlage zum Scharfschalten gepfelgt.
    //                  Bei scharf geschalteter Anlage ist es anders:
    //                  Es wird geprüft, ob der auslösende Melder in den Außenhaut- oder
    //                  Innenraum-Meldern enthalten ist und ob dieser ein verzögerter Melder ist.
    //                  Abhängig davon wird entweder sofort oder verzögert Alarm ausgelöst.
    // Rückgabewert:    keiner
    function detectorSurveillance (obj) {
        var active = getState(idActive).val;
        var activeExternal = getState(idActiveExternal).val;
        var activeInternal = getState(idActiveInternal).val;
        var ready;
        var ignoreOpenSet;
        
        if (loglevel >= 2) log ("Surveillance of detectors started, triggering detector: " + obj.common.name);
    
        // Alle offenen Melder feststellen
        ready = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
    
        // Auslösenden Melder schreiben
        setState(idAlarmingDetector, obj.common.name);
        setState(idAlarmingDetectorJSON, JSON.stringify(  getDetectorObject(obj.id)  ));
    
        // Prüfen, wie der der Schaltzustand ist
        // bei unscharf
        if (!active) {
            if (loglevel >= 2) log ("Alarmsystem is Inactive");
        }
        // bei scharf intern
        if (activeInternal) {
            if (loglevel >= 2) log ("Alarmsystem is Internal Active");
            if (detectorsOuterSkin.indexOf(obj.id) != -1) {
                if (loglevel >= 3) log ("Detector is part of Outer Skin");
                if (detectorsDelayed.indexOf(obj.id) != -1) {
                    if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                    if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                    else {
                        if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                        setState(idAlarmAccoustical, true);
                        setState(idAlarmOptical, true);
                    }
                } else {
                    if (loglevel >= 3) log ("Detector is not delayed");
                    setState(idAlarmAccoustical, true);
                    setState(idAlarmOptical, true);
                }
            }
        }
        // bei scharf extern
        if (activeExternal) {
            if (loglevel >= 2) log ("Alarmsystem is External Active");
            // Prüfen, ob er der Melder das IgnoreOpen-Flag gesetzt hat.
            ignoreOpenSet = checkIfIgnoreOpenFlagSet(obj.id);
            if (loglevel >= 2) log ("Detector has IgnoreOpen-Flag set true!");
            if (ignoreOpenSet)  return;
            if (detectorsOuterSkin.concat(detectorsIndoor).indexOf(obj.id) != -1) {
                if (loglevel >= 3) log ("Detector is part of Outer Skin or Indoor");
                if (detectorsDelayed.indexOf(obj.id) != -1) {
                    if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                    if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                    else {
                        if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                        setState(idAlarmAccoustical, true);
                        setState(idAlarmOptical, true);
                    }
                } else {
                    if (loglevel >= 3) log ("Detector is not delayed");
                    if (loglevel >= 2) log ("System is ALARMING now!");
                    setState(idAlarmAccoustical, true);
                    setState(idAlarmOptical, true);
                }
            }
        }
    }
    
    // Function myCreateState
    // =======================
    // Parameter:       id      ... id des neu anzulegenden Datenpunkts
    //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
    //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
    //                  descr   ... Name als String
    //                  writeaccess Schreibrechte true oder false
    // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
    //                  Parametern angelegt.
    // Rückgabewert:    keiner
    function myCreateState(id, typ, val, descr, writeaccess, role) {
        if (loglevel >= 3) log ("Function myCreateState for " + id);
        createState(id, val,    {read: !writeaccess, 
                                write: writeaccess, 
                                name: descr,
                                type: typ,
                                def: val,
                                role: role ? role : "state"
        });
    }
    
    // Function myCreateMultiState
    // ===========================
    // Parameter:       id      ... id des neu anzulegenden Datenpunkts
    //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
    //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
    //                  descr   ... Name als String
    //                  min     ... Minimalwert
    //                  max     ... Maximalwert
    //                  list    ... Liste mit Werten und Bezeichnern im Format "0:Text0; 1:Text1; 2:Text2"
    //                  writeaccess Schreibrechte true oder false
    // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
    //                  Parametern angelegt.
    // Rückgabewert:    keiner
    function myCreateMultiState(id, typ, val, descr, writeaccess, minimum, maximum, list, role) {
        if (loglevel >= 3) log ("Function myCreateMultiState for " + id);
        createState(id, val, {  read: true, 
                                write: writeaccess, 
                                name: descr,
                                type: typ,
                                def: val,
                                min: minimum, 
                                max: maximum, 
                                states: list,
                                role: role ? role : "state"
        });
    }
    // Funktion myCreateIgnoreOpenDPs
    // ==============================
    // Parameter:       Keine
    // Funktion:        Erzeugt die Datenpunkte für die Ignoge-Open-Melder.
    //                  Dafür werden die Namen aus dem detectorsOuterSkin-Array geholt.
    //                  Die IDs der Ignore-Open Datenpunkte für jeden Melder werden auch in
    //                  das Array detectorsIgnoreOpen geschrieben. Dieses wird damit 3-Dimensional.
    // Rückgabewert:    Keiner.
    function myCreateIgnoreOpenDPs(){
        var detectorName;
        var idBase = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.IgnoreOpen.";
        var i=0;
        while (i<detectorsOuterSkin.length) {
            detectorName = getObject(detectorsOuterSkin[i]).common.name.replace(/\./g,"_");
            myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
            detectorsIgnoreOpen[i].push(idBase + detectorName);
            i++;
        }
    }
    
    // Function switchActiveExternal
    // =============================
    // Parameter:       keiner
    // Funktion:        Nach Prüfung auf Bereitschaft zum externen Scharfschalten, wird 
    //                  scharf geschaltet oder ein Fehler angezeigt.
    // Rückgabewert:    keiner
    function switchActiveExternal () {
        if (loglevel >= 3) log ("Function switchActiveExternal");
        setState(idExitDelayActive, false);
        var ok = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
        if (ok) {
            setState(idActiveExternal, true);
            setState(idActive, true);
            setState(idStatusText, textStatusActiveExternal);
            setState(idAlarmText, textAlarmInactive);
            setState(idAlarmingDetector,"");
            setState(idError, false);
            if (loglevel >= 2) log ("Switched to External Active");
        } else {
            if (loglevel >= 2) log ("NOT ready to switch to External Active!");
            setState(idError, true);
        }
    }
    
    // Function switchActiveInternal
    // =============================
    // Parameter:       keiner
    // Funktion:        Nach Prüfung auf Bereitschaft zum internen Scharfschalten, wird 
    //                  scharf geschaltet oder ein Fehler angezeigt.
    // Rückgabewert:    keiner
    function switchActiveInternal () {
        if (loglevel >= 3) log ("Function switchActiveInternal");
        var ok = checkDetectors(detectorsOuterSkin);
        if (ok) {
            setState(idActiveInternal, true);
            setState(idActive, true);
            setState(idStatusText, textStatusActiveInternal);
            setState(idAlarmText, textAlarmInactive);
            setState(idAlarmingDetector,"");
            setState(idError, false);
            if (loglevel >= 2) log ("Switched to Internal Active");
        } else {
            if (loglevel >= 2) log ("NOT ready to switch to Internal Active!");
            setState(idError, true);
        }
    ;}
    
    // Function switchInactive
    // =============================
    // Parameter:       keiner
    // Funktion:        Es wird unscharf geschaltet und die ganze Anlage resetiert.
    // Rückgabewert:    keiner
    function switchInactive () {
        if (loglevel >= 3) log ("Function switchInactive");
        if (timerExitDelay) clearTimeout(timerExitDelay);
        setState(idEntryDelayActive, false);
        setState(idExitDelayActive, false);
        setState(idActiveExternal, false);
        setState(idActiveInternal, false);
        setState(idActive, false);
        setState(idError, false);
        clearStateDelayed(idAlarmAccoustical);
        clearStateDelayed(idAlarmOptical);
        setState(idAlarmAccoustical, false);
        setState(idAlarmOptical, false);
        setState(idAlarm, false);
        setState(idAlarmText, textAlarmInactive);
        setState(idStatusText, textStatusInactive);
        checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
        if (loglevel >= 2) log ("Switched to Inactive");
        getAllDetectors();
    }
    
    // Function setActiveNumber
    // =======================
    // Parameter:       keine
    // Funktion:        Prüft ob intern scharf, extern scharf oder unscharf ist und
    //                  ob jeweils Eingangs- oder Ausgangsverzögerung aktiv ist.
    //                  Abhängig davon wird der Datenpunt "Output.ActiveNumber"
    //                  wie folgt gesetzt:
    //                    0 ... unscharf
    //                    1 ... intern scharf
    //                    2 ... extern scharf
    //                    3 ... Eingangsverzögerung aktiv
    //                    4 ... Ausgangsverzögerung aktiv
    // Rückgabewert:    keiner
    function setActiveNumber () {
        if (loglevel >= 3) log ("Function setActiveNumber");
        var internal = getState(idActiveInternal).val;
        var external = getState(idActiveExternal).val;
        var entry = getState(idEntryDelayActive).val;
        var exit = getState(idExitDelayActive).val;
        if (!external && !internal) {
            if (exit)
                setState(idActiveNumber, 4);
            else
                setState(idActiveNumber, 0);
        }
        if (internal) setState(idActiveNumber, 1);
        if (external){
            if (entry)
                setState(idActiveNumber, 3);
            else
                setState(idActiveNumber, 2);
        }
    }
    
    // Function checkDetectors
    // =======================
    // Parameter:       detectors
    //                  Array mit Melder-IDs
    // Funktion:        Alle Melder aus dem Array werden geprüft und alle offenen
    //                  Melder werden in einen Datenpunkt geschrieben als String.
    //                  Das Trennzeichen zwischen den Meldernamen ist die globale
    //                  Variable "seperator".
    // Rückgabewert:    true, wenn alle Melder in Ruhe sind
    //                  false, wenn ein oder mehr Melder ausgelöst sind
    function checkDetectors ( detectors ) {
        if (loglevel >= 3) log ("Function checkDetectors");
        var i=0;
        var textListOfDetectors="";
        var textListOfDetectorsIgnoreOpen="";
        var objOpenDetectors = {
            title: "All open detectors",
            zone: null,
            listOfDetectors:    []
        };
        var objOpenDetectorsOuterSkin = {
            title: "Open detectors outer skin",
            zone: functionOuterSkin,
            listOfDetectors:    []
        };
        var objOpenDetectorsIndoor = {
            title: "Open detectors indoor",
            zone: functionIndoor,
            listOfDetectors:    []
        };
        while(i < detectors.length) {
            if (getState(detectors[i]).val) {
                if (checkIfIgnoreOpenFlagSet(detectors[i])) {
                    if (textListOfDetectorsIgnoreOpen.length > 0) textListOfDetectorsIgnoreOpen += seperator;
                    textListOfDetectorsIgnoreOpen += getObject(detectors[i]).common.name;
                }
                else {
                    if (textListOfDetectors.length > 0) textListOfDetectors += seperator;
                    textListOfDetectors += getObject(detectors[i]).common.name;
                }
                var detObj = getDetectorObject(detectors[i]);
                objOpenDetectors.listOfDetectors.push(detObj);
                if (detectorsOuterSkin.indexOf(detectors[i]) != -1) objOpenDetectorsOuterSkin.listOfDetectors.push(detObj);
                if (detectorsIndoor.indexOf(detectors[i]) != -1) objOpenDetectorsIndoor.listOfDetectors.push(detObj);
            }
            i++;
        }
        if (loglevel >= 3) log ("Open Detectors found: " + (textListOfDetectors.length ? textListOfDetectors : "none"));
        
        // Datenpunkte schreiben
        setState(idOpenDetectors, textListOfDetectors);
        setState(idOpenDetectorsWithIgnoreOpenFlagSet, textListOfDetectorsIgnoreOpen);
        setState(idOpenDetectorsJSON, JSON.stringify(objOpenDetectors));
        setState(idOpenDetectorsOuterSkinJSON, JSON.stringify(objOpenDetectorsOuterSkin));
        setState(idOpenDetectorsIndoorJSON, JSON.stringify(objOpenDetectorsIndoor));
    
        if (textListOfDetectors.length > 0) {
            return false;
        } else {
            return true;
        }
    }
    
    // Function getDetectorObject
    // ==========================
    // Parameter:       id
    //                  id eines Melder-States
    // Funktion:        Vom Melder mit der id wird das Objekt über getObjekt(id) geholt,
    //                  sowie von seinem Parent und ParentsParent.
    //                  Alle Objekte kommen in ein großes Objekt und werden zurück gegeben.
    // Rückgabewert:    Das Objekt des Melders samt Parent und ParentsParent (sofern es welche gibt)
    function getDetectorObject (id) {
        if (loglevel >= 3) log ("Function getDetectorObject for id: " + id);
        // ioBroker Parent-Datenpunkt (z.B. Kanal), kann auch null sein (zB bei KNX)
        var idParent = id.substr(0, id.lastIndexOf("."));
        // ioBroker ParentsParent-Datenpunkt (z.B. Gerät), kann auch null sein (zB bei KNX)
        var idParentsParent = idParent.substr(0, idParent.lastIndexOf("."));
    
        // Objekte dazu holen
        var obj    = getObject(id);
        var objParent = getObject(idParent);
        var objParentsParent = getObject(idParentsParent);
    
        // Alle Objekte in ein großes Objekt sammeln
        var detectorsObj = {
            id:             id,
            self:           obj,
            parent:         objParent,
            parentsparent:  objParentsParent
        };
    
        // Rückgeben
        return detectorsObj;
    }
    
    
    

    Ich hoffe, es funktioniert einigermaßen. Bitte mal testen.
    Danke und LG
    Andreas

    BBTownB SchmakusS 2 Antworten Letzte Antwort
    0
    • andreaskosA andreaskos

      Lieber @Freaknet und @Schmakus und alle anderen Leser,

      ich habe eben die Funktion eingebaut, einzelne Melder aus der Aussenhülle von der Überwachung ausnehmen zu können. Die Funktion ist mehr oder weniger ungetestet und ich würde euch bitten hier Feedback zu geben, um das Skript fehlerfrei zu bekommen und auch als neue Version oben im ersten Thread updaten zu können.

      Neue Datenpunkte
      Unter "Input" ist nun ein neuer Knoten namens "IgnoreOpen" zu finden. Unterhalb diesem können per Flag die einzelnen Melder inaktiv geschaltet werden.
      true = wird mitüberwacht
      false = von der Überwachung ausgenommen

      Unter "Output" ist ein Text-Datenpunkt, der die Liste der offenen Melder mit gesetztem IgnoreOpen-Flag beinhaltet. Diese Melder kommen nicht in die Liste der ganz regulär offenen Melder.
      Diesen Datenpunkt könnte man verwenden, um sich zu warnen, wenn zum Zeitpunkt des Scharf-Schaltens (oder ein paar Millisekunden später) hier Text enthalten ist.

      ACHTUNG
      Die Einstellung der IgnoreOpen-Flags wird (derzeit) nicht automatisch zurück gesetzt, etwa beim Scharf-Schalten. Das bedeutet, man muss selbst drauf achten, dass ein Melder nicht ewig auf Inaktiv bleibt, weil man vergessen hat das Flag wieder auf true zu stellen.

      /*
      ########################################################################################################################
      # ALARMSYSTEM
      #
      # Das Skript bildet eine einfache Alarmanlage nach mit der Schaltmöglichkeit
      # für intern und extern.
      # Datenpunkte für Inputs und Outputs werden angelegt.
      # Nähere Beschreibung siehe im ioBroker-Forum unter
      # https://forum.iobroker.net/topic/32885/umfassendes-alarmanlagen-skript
      # Änderungshistorie:
      # 2020-05-01    Andreas Kos     Erstellt
      # 2020-05-02    Andreas Kos     Schaltwunsch mit Number-Datenpunkt Input.SwitchNumber (Idee von @Homer.J.)
      #                               Schaltstatus mit Number-Datenpunkt Output.ActiveNumber (Idee von @Homer.J.)
      # 2020-05-03    Andreas Kos     Korrekturen, u.a. für Melderauswertung (chage: "ne") & AlarmText
      # 2020-05-04    Andreas Kos     - Melder werden aus den Functions (Aufzählungen, enums) dafür geholt. Auch beim Unscharf-
      #                                 schalten, dadurch ist kein Neustarten des Skripts notwendig bei
      #                                 Änderungen an diesen Aufzählungen.
      #                               - Eine Schaltung von einem scharf-Zustand auf einen anderen
      #                                 wird verhindert. ZB von scharf intern auf scharf extern.
      #                                 Es muss immer unscharf dazwischen geschaltet werden.
      # 2020-05-09    Andreas Kos     Zusätzliche Objekte mit JSON-Strings für:
      #                               - den auslösenden Melder
      #                               - alle offenen Melder
      #                               - alle offenen Melder der Außenhaut
      #                               - alle offenen Melder des Innenraums
      #                               Die JSON-String beinhalten das auslösende Objekt, sowie (falls vorhanden)
      #                               das Parent und das ParentsParent-Objekt mit allen in ioBroker verfügbaren Eigenschaften.
      #                               Kleinere Verbesserungen, z.B. bezüglich setzen der AlarmTexte.
      # 2020-05-12    Andreas Kos     Setzen des Datenpunkts idReady zur Bereitschaftsanzeige neu gemacht.
      # 2021-06-13    Andreas Kos     Einbau der Funktion zum Ausnehmen einzelner Melder der Aussenhülle
      #                               von der Melder-Überwachung. Soll zum Kippen von Fenstern dienen u.ä.
      ########################################################################################################################
      */
      
      // EINBRUCHSMELDER
      // Jeder Melder muss ein State sein, der bei Auslösung true liefert und in Ruhe (geschlossen) false.
      // Die Melder sind in Arrays zusammengefasst, d.h. sie müssen jeweils mit Beistrich voneinander getrennt werden.
      // Die Namen der Melder sollten gut gepflegt sein für eine sinnvolle Verwendung (Attribut name bei den Objekten)
      
      // Melder der Außenhaut
      // Dies können Öffnungskontakte sein von Fenster und Türen in den Außenmauern des Objekts.
      // EINGABE: In der Aufzählung "alarmanlage_aussenhaut" die States einfügen.
      
      // Melder des Innenraums
      // Dies können Bewegungsmelder sein aus dem Inneren.
      // EINGABE: In der Aufzählung "alarmanlage_innenraum" die States einfügen.
      
      // Verzögerte Melder
      // Diese kommen in den Gruppen oben auch vor. Sie bewirken eine Aktivierung der Eingangsverzögerung
      // bei scharf geschalteter Anlage und erlauben während der Ausgangsverzögerung nach dem
      // Scharfschalten das Haus zu verlassen.
      // EINGABE: In der Aufzählung "alarmanlage_verzoegert" die States einfügen.
      
      
      // EINSTELLUNGEN
      const entryDelay =                30;         // Eingangsverzögerung in Sekunden (sollte maximal 60s sein)
      const exitDelay =                 30;         // Ausgangsverzögerung in Sekunden (sollte maximal 60s sein)
      const alarmDurationAccoustical =  180;         // Dauer des akkustischen Alarms in Sekunden (ACHTUNG: in Ö sind maximal 180s erlaubt!)
      const alarmDurationOptical =      -1;         // Dauer des optischen Alarm in Sekunden, -1 für unendlich
      
      // TEXTE FÜR SCHALTZUSTAND
      // Diese Text geben Auskunft über den Zustand der Anlage.
      // Sie werden in den Datenpunkt "javascript.X.Output.StatusText" geschrieben.
      const textStatusInactive =        "unscharf";
      const textStatusActiveInternal =  "scharf intern";
      const textStatusActiveExternal =  "scharf extern";
      const textActiveExternalDelayed = "scharf extern verzögert";
      const textEntryDelayActive =      "Eingangsverzögerung aktiv";
      const textExitDelayActive =       "Ausgangsverzögerung aktiv";
      
      // TEXTE FÜR ALARMIERUNG UND FEHLER
      // Diese Text geben im unscharfen Zustand der Anlage Auskunft über die Bereitschaft
      // zum Scharfschalten (nur möglich, wenn alle Melder geschlossen - in Ruhe - sind) und
      // Fehler bei der Scharfschaltung bzw. bei scharfer Anlage über den Zustand Frieden oder Alarm.
      // Sie werden in den Datenpunkt "javascript.X.Output.AlarmText" geschrieben.
      const textAlarmInactive =         "Alles OK";
      const textAlarmActive =           "Alarm!!";
      const textReady =                 "Bereit";
      const textNotReady =              "Nicht bereit";
      const textError =                 "Fehler bei der Scharfschaltung";
      
      // EXPERTEN-EINSTELLUNGEN
      const pathToCreatedStates = "Alarmanlage";    // Beispiel: States werden erzeugt unter javascript.X.Alarmanlage
      const seperator = ", ";                       // Trenn-String, der zwischen den Meldernamen verwendet wird, im Datenpunkt "OpenDetectors"
      const loglevel = 2;                           // 0 bis 3. 0 ist AUS, 3 ist maximales Logging
                                                  // Empfehlung für Nachvollziehbarkeit aller Handlungen ist 2 (Ereignisliste)
      const functionOuterSkin = "alarmanlage_aussenhaut";
      const functionIndoor = "alarmanlage_innenraum";
      const functionDelayedDetectors = "alarmanlage_verzoegert";
      
      /*
         ###############################################################################
                          DO NOT CHANGE ANYTHING BELOW THIS LINE
                               AB HIER NICHTS MEHR ÄNDERN
         ###############################################################################
      */
      
      // ===============================================================================
      // Variablen
      // ===============================================================================
      
      // Arrays für die Melder
      var detectorsOuterSkin = [];
      var detectorsIndoor = [];
      var detectorsDelayed = [];
      
      // Array für die IgnoreOpen-Melder (beinhaltet nur Flags).
      // Das Array ist inital deckungsgleich mit detectorsOuterSkin, da diese
      // nur aus dieser Function kommen können.
      // Dieses Array ist 2-Dimensional: [Melder-ID, IgnoreOpen-Zustands-ID]
      var detectorsIgnoreOpen = [];
      
      // Javascript-Instanz mit der das Alarmanlagen-Skript ausgeführt wird
      var javascriptInstance = instance;
      
      // States, die erzeugt werden für Status-Ausgaben
      var idActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Active";
      var idActiveExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveExternal";
      var idActiveInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveInternal";
      var idActiveNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveNumber";
      var idAlarm = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Alarm";
      var idAlarmAccoustical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmAccoustical";
      var idAlarmOptical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmOptical";
      var idReady = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Ready";
      var idEntryDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.EntryDelayActive";
      var idExitDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ExitDelayActive";
      var idAlarmingDetector = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetector";
      var idAlarmingDetectorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetectorJSON";
      var idOpenDetectors = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectors";
      var idOpenDetectorsJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsJSON";
      var idOpenDetectorsOuterSkinJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsOuterSkinJSON";
      var idOpenDetectorsIndoorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIndoorJSON";
      var idOpenDetectorsWithIgnoreOpenFlagSet = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIgnoreOpen";
      
      var idStatusText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.StatusText";
      var idAlarmText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmText";
      var idError = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Error";
      
      // States, die erzeugt werden für Eingaben
      var idSwitchExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternal";
      var idSwitchInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchInternal";
      var idSwitchExternalDelayed = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternalDelayed";
      var idSwitchNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchNumber";
      
      // Sonstige globale Variablen, die gebraucht werden
      var timerExitDelay = null;
      var timerTexts = null;
      
      // ===============================================================================
      // Precode
      // ===============================================================================
      
      // Logging
      if (loglevel >= 1) log ("Alarmsystem started.");
      
      getAllDetectors();
      
      // States erzeugen
      myCreateState(idActive, "boolean", false, "Switch Status Total", false, "info.status");
      myCreateState(idActiveExternal, "boolean", false, "Switch Status External", false, "info.status");
      myCreateState(idActiveInternal, "boolean", false, "Switch Status Internal", false, "info.status");
      myCreateState(idAlarm, "boolean", false, "Alarm Status", false, "sensor.alarm");
      myCreateState(idAlarmAccoustical, "boolean", false, "Accoustical Alarm Status", false, "sensor.alarm");
      myCreateState(idAlarmOptical, "boolean", false, "Optical Alarm Status", false, "sensor.alarm");
      myCreateState(idReady, "boolean", false, "Alarmsystem Ready", false, "info.status");
      myCreateState(idError, "boolean", false, "Error Switching Active", false, "info.status");
      myCreateState(idEntryDelayActive, "boolean", false, "Entry Delay Active Status", false, "info.status");
      myCreateState(idExitDelayActive, "boolean", false, "Exit Delay Active Status", false, "info.status");
      myCreateState(idAlarmingDetector, "string", "", "Alarming Detector", false, "text");
      myCreateState(idAlarmingDetectorJSON, "string", "", "Alarming Detector JSON", false, "json");
      myCreateState(idOpenDetectors, "string", "", "Open Detectors", false, "info.name");
      myCreateState(idOpenDetectorsJSON, "string", "", "Open Detectors JSON", false, "json");
      myCreateState(idOpenDetectorsOuterSkinJSON, "string", "", "Open Detectors Outer Skin JSON", false, "json");
      myCreateState(idOpenDetectorsIndoorJSON, "string", "", "Open Detectors Indoor JSON", false, "json");
      myCreateState(idOpenDetectorsWithIgnoreOpenFlagSet, "string", "", "Open Detectors with IgnoreOpen-Flag set", false, "text");
      myCreateState(idStatusText, "string", "", "Status Text", false, "text");
      myCreateState(idAlarmText, "string", "", "Alarm Text", false, "text");
      myCreateState(idSwitchExternal, "boolean", false, "Enable Surveillance External", true, "switch");
      myCreateState(idSwitchInternal, "boolean", false, "Enable Surveillance Internal", true, "switch");
      myCreateState(idSwitchExternalDelayed, "boolean", false, "Enable Surveillance External Delayed", true, "switch");
      
      myCreateMultiState (idActiveNumber, "number", 0, "Switch Status Number", false, 0, 4,"0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+"; 2:"+textStatusActiveExternal+"; 3:"+textExitDelayActive+"; 4:"+textEntryDelayActive);
      myCreateMultiState (idSwitchNumber, "number", 0, "Switch by Number", true, 0, 3, "0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+" ; 2:"+textStatusActiveExternal+" ; 3:"+textActiveExternalDelayed);
      
      // Erzeugen der Datenpunkte für die IgnoreOpen-Einstellung
      myCreateIgnoreOpenDPs();
      
      // Melder nach dem Starten checken
      checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
      
      // ===============================================================================
      // ON-Subscribtions
      // ===============================================================================
      
      // Auf Schaltstellen EXTERN verzögert reagieren (schalten EIN/AUS)
      on ({id: idSwitchExternalDelayed, change: "any"}, function(obj){
          if (loglevel >= 3) log ("Switching External Delayed, Value: " + getState(obj.id).val);
          if (getState(obj.id).val) { // Einschalten, scharf extern VERZÖGERT
              if (loglevel >= 2) log ("Switching required: Delayed External Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      setState(idExitDelayActive, true);
                      if (timerExitDelay) clearTimeout(timerExitDelay);
                      timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                  }
          }
          else { // Ausschalten, unscharf SOFORT
              if (loglevel >= 2) log ("Switching required: Inactive");
              switchInactive();
          }
      });
      
      // Auf Schaltstellen EXTERN sofort reagieren (schalten EIN/AUS)
      on ({id: idSwitchExternal, change: "any"}, function(obj){
          if (loglevel >= 3) log ("Switching External Immediately, Value: " + getState(obj.id).val);
          if (getState(obj.id).val) { // Einschalten, scharf extern
              if (loglevel >= 2) log ("Switching required: External Active");
              if (getState(idActive).val) {
                  if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                  setState(idError, true);
              } else {
                  switchActiveExternal();
              }
          }
          else { // Ausschalten, unscharf
              if (loglevel >= 2) log ("Switching required: Inactive");
              switchInactive();
          }
      });
      
      // Auf Schaltstellen INTERN sofort reagieren (schalten EIN/AUS)
      on ({id: idSwitchInternal, change: "any"}, function(obj){
          if (loglevel >= 3) log ("Switching Internal, Value: " + getState(obj.id).val);
          if (getState(obj.id).val) { // Einschalten, scharf intern
              if (loglevel >= 2) log ("Switching required: Internal Active");
              if (getState(idActive).val) {
                  if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                  setState(idError, true);
              } else {
                  switchActiveInternal();
              }
          }
          else { // Ausschalten, unscharf
              switchInactive();
              if (loglevel >= 2) log ("Switching required: Inactive");
          }
      });
      
      // Auf Schaltstelle mit Datenpunkt SwitchNumber reagieren
      // Folgende Reaktionen:
      //      0 ... unscharf schalten
      //      1 ... scharf intern schalten
      //      2 ... scharf extern schalten
      //      3 ... verzögert scharf extern schalten
      on ({id: idSwitchNumber, change: "any"}, function(obj){
          if (loglevel >= 3) log ("Switching Number, Value: " + obj.state.val);
          switch (obj.state.val) {
              case 0:
                  if (loglevel >= 2) log ("Switching required: Inactive");
                  switchInactive();
                  break;
              case 1:
                  if (loglevel >= 2) log ("Switching required: Internal Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      switchActiveInternal();
                  }
                  break;
              case 2:
                  if (loglevel >= 2) log ("Switching required: External Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      switchActiveExternal();
                  }
                  break;
              case 3:
                  if (loglevel >= 2) log ("Switching required: Delayed External Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      setState(idExitDelayActive, true);
                      if (timerExitDelay) clearTimeout(timerExitDelay);
                      timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                  }
                  break;
              default:
                  if (loglevel >= 3) log ("idSwitchNumber has unknown number!");
          }
      });
      
      // Auf Fehler bei der Scharfschaltung reagieren
      on ({id: idError, val: true, change: "any"}, function(obj){
          if (loglevel >= 1) log ("Error when switching to active.");
          setState(idAlarmText, textError);
      });
      
      // Auf Eingangsverzögerung reagieren
      on({id: idEntryDelayActive, val: true, change: "ne"}, function (obj) {
          if (loglevel >= 2) log ("Entry Delay is active (" + entryDelay + " seconds)");
          setState(idStatusText, textEntryDelayActive);
          setStateDelayed(idAlarmAccoustical, true, entryDelay * 1000);
          setStateDelayed(idAlarmOptical, true, entryDelay * 1000);
      });
      
      // Auf Ausgangsverzögerung reagieren
      on({id: idExitDelayActive, val: true, change: "ne"}, function (obj) {
          if (loglevel >= 2) log ("Exit Delay is active (" + exitDelay + " seconds)");
          setState(idStatusText, textExitDelayActive);
      });
      
      // Auf Akustischen Alarm reagieren
      on ({id: idAlarmAccoustical, val: true, change: "ne"}, function(obj){
          if (loglevel >= 1) log ("ALARM is active!");
          setState(idEntryDelayActive, false);
          setState(idAlarmText, textAlarmActive);
          setState(idAlarm, true);
          setStateDelayed(idAlarmAccoustical, false, alarmDurationAccoustical * 1000);
          if (getState(idActiveExternal).val) setState(idStatusText, textStatusActiveExternal);
          if (getState(idActiveInternal).val) setState(idStatusText, textStatusActiveInternal);
      });
      
      // Auf Optischen Alarm reagieren
      on ({id: idAlarmOptical, val: true, change: "ne"}, function(obj){
          if (alarmDurationOptical >= 0)
              setStateDelayed(idAlarmOptical, false, alarmDurationOptical * 1000);
      });
      
      // Melderauswertung
      on( {id: detectorsOuterSkin.concat(detectorsIndoor), change: "ne"}, function(obj){
          detectorSurveillance(obj);
      });
      
      // Status in Active.Number schreiben
      on ({id: [idActiveInternal, idActiveExternal, idEntryDelayActive, idExitDelayActive], change: "ne"}, function(obj){
          if (loglevel >= 3) log ("on for writing ActiveNumber, Trigger: " + obj.id);
          setActiveNumber();
      });
      
      // Texte korrekt setzen
      on ({id: [idAlarm, idActive, idOpenDetectors], change: "any"}, function (obj) {
          // Das Timeout ggf. abbrechen
          if (timerTexts) clearTimeout(timerTexts);  
          // Nach einem Timeout den Check anfangen
          timerTexts = setTimeout(setTexts, 200);
      });
      
      
      
      // ===============================================================================
      // Funktionen
      // ===============================================================================
      // Funktion     checkIfIgnoreOpenFlagSet
      // =====================================
      // Parameter:       Prüft, ob das IgnoreOpen-Flag für einen Melder gesetzt ist.
      // Übergabewert:    Melder-ID
      // Rückgabewert:    Flag-Zustand
      function checkIfIgnoreOpenFlagSet(id){
          var i=0;
          while (i<detectorsIgnoreOpen.length){
              if ( detectorsIgnoreOpen[i][0] == id )
                  if (getState(detectorsIgnoreOpen[i][1]).val)
                      return true;
              i++;
          }
          return false;
      }
      
      // Function setTexts
      // =================
      // Parameter:       keiner
      // Funktion:        Abhängig von den Zuständen scharf/unscharf und
      //                  Alarm / Kein Alarm werden Texte für
      //                  den AlarmText richtig gesetzt. Auch der Datenpunkt idReady wird hier gesetzt.
      // Rückgabewert:    keiner
      function setTexts(){    
          var textListOfDetectors = getState(idOpenDetectors).val;
          if (textListOfDetectors.length > 0) {
              if (!getState(idActive).val)
                  // Offene Melder gefunden und unscharf
                  setState(idAlarmText, textNotReady);
                  setState(idReady, false);
              return false;
          } else {
              if (getState(idActive).val && !getState(idAlarm).val)
                  // kein offener Melder gefunden und scharf und kein Alarm
                  setState(idAlarmText, textAlarmInactive);
              else if (!getState(idActive).val)
                  // kein offener Melder gefunden und unscharf
                  setState(idAlarmText, textReady);
                  setState(idReady, true);
              return true;
          }
      }
      
      // Function getAllDetectors
      // ========================
      // Parameter:       keiner
      // Funktion:        Über die Funktion getDetectorsFromFunction werden
      //                  alle Melder von den Functions geholt und in die
      //                  globalen Variablen dafür geschrieben.
      // Rückgabewert:    keiner
      function getAllDetectors(){
          var i=0;
          detectorsOuterSkin = getDetectorsFromFunction(functionOuterSkin);
          detectorsIgnoreOpen = [];
          while (i<detectorsOuterSkin.length) {
              detectorsIgnoreOpen.push([detectorsOuterSkin[i++]]);
          }
          detectorsIndoor = getDetectorsFromFunction(functionIndoor);
          detectorsDelayed = getDetectorsFromFunction(functionDelayedDetectors);
      }
      
      // Function getDetectorsFromFunction
      // =================================
      // Parameter:       functionString
      //                  Name der Function, in der die Melder enthalen sind.
      // Funktion:        Alle Teilnehmer der übergebenen Function werden
      //                  in ein Array geschrieben.
      // Rückgabewert:    Array der Melder-IDs
      function getDetectorsFromFunction( functionString ) {
          if (loglevel >= 3) log ("Function getDetectorsFromFunction");
          var detectors = [];
          $('state(functions='+functionString+')').each(function(id, i) {
              detectors.push(id);
              if (loglevel >= 3) log ("This detector was added to surveillance from function "+functionString+": " + id);
          });
          return detectors;
      }
      
      // Function detectorSurveillance
      // =============================
      // Parameter:       obj
      //                  Objekt des auslösenden Melders
      // Funktion:        Abhängig vom Schaltzustand werden die Melder überprüft.
      //                  Bei unscharf wird nur die Liste der offenen Melder und die
      //                  Bereitschaft der Anlage zum Scharfschalten gepfelgt.
      //                  Bei scharf geschalteter Anlage ist es anders:
      //                  Es wird geprüft, ob der auslösende Melder in den Außenhaut- oder
      //                  Innenraum-Meldern enthalten ist und ob dieser ein verzögerter Melder ist.
      //                  Abhängig davon wird entweder sofort oder verzögert Alarm ausgelöst.
      // Rückgabewert:    keiner
      function detectorSurveillance (obj) {
          var active = getState(idActive).val;
          var activeExternal = getState(idActiveExternal).val;
          var activeInternal = getState(idActiveInternal).val;
          var ready;
          var ignoreOpenSet;
          
          if (loglevel >= 2) log ("Surveillance of detectors started, triggering detector: " + obj.common.name);
      
          // Alle offenen Melder feststellen
          ready = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
      
          // Auslösenden Melder schreiben
          setState(idAlarmingDetector, obj.common.name);
          setState(idAlarmingDetectorJSON, JSON.stringify(  getDetectorObject(obj.id)  ));
      
          // Prüfen, wie der der Schaltzustand ist
          // bei unscharf
          if (!active) {
              if (loglevel >= 2) log ("Alarmsystem is Inactive");
          }
          // bei scharf intern
          if (activeInternal) {
              if (loglevel >= 2) log ("Alarmsystem is Internal Active");
              if (detectorsOuterSkin.indexOf(obj.id) != -1) {
                  if (loglevel >= 3) log ("Detector is part of Outer Skin");
                  if (detectorsDelayed.indexOf(obj.id) != -1) {
                      if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                      if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                      else {
                          if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                          setState(idAlarmAccoustical, true);
                          setState(idAlarmOptical, true);
                      }
                  } else {
                      if (loglevel >= 3) log ("Detector is not delayed");
                      setState(idAlarmAccoustical, true);
                      setState(idAlarmOptical, true);
                  }
              }
          }
          // bei scharf extern
          if (activeExternal) {
              if (loglevel >= 2) log ("Alarmsystem is External Active");
              // Prüfen, ob er der Melder das IgnoreOpen-Flag gesetzt hat.
              ignoreOpenSet = checkIfIgnoreOpenFlagSet(obj.id);
              if (loglevel >= 2) log ("Detector has IgnoreOpen-Flag set true!");
              if (ignoreOpenSet)  return;
              if (detectorsOuterSkin.concat(detectorsIndoor).indexOf(obj.id) != -1) {
                  if (loglevel >= 3) log ("Detector is part of Outer Skin or Indoor");
                  if (detectorsDelayed.indexOf(obj.id) != -1) {
                      if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                      if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                      else {
                          if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                          setState(idAlarmAccoustical, true);
                          setState(idAlarmOptical, true);
                      }
                  } else {
                      if (loglevel >= 3) log ("Detector is not delayed");
                      if (loglevel >= 2) log ("System is ALARMING now!");
                      setState(idAlarmAccoustical, true);
                      setState(idAlarmOptical, true);
                  }
              }
          }
      }
      
      // Function myCreateState
      // =======================
      // Parameter:       id      ... id des neu anzulegenden Datenpunkts
      //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
      //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
      //                  descr   ... Name als String
      //                  writeaccess Schreibrechte true oder false
      // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
      //                  Parametern angelegt.
      // Rückgabewert:    keiner
      function myCreateState(id, typ, val, descr, writeaccess, role) {
          if (loglevel >= 3) log ("Function myCreateState for " + id);
          createState(id, val,    {read: !writeaccess, 
                                  write: writeaccess, 
                                  name: descr,
                                  type: typ,
                                  def: val,
                                  role: role ? role : "state"
          });
      }
      
      // Function myCreateMultiState
      // ===========================
      // Parameter:       id      ... id des neu anzulegenden Datenpunkts
      //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
      //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
      //                  descr   ... Name als String
      //                  min     ... Minimalwert
      //                  max     ... Maximalwert
      //                  list    ... Liste mit Werten und Bezeichnern im Format "0:Text0; 1:Text1; 2:Text2"
      //                  writeaccess Schreibrechte true oder false
      // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
      //                  Parametern angelegt.
      // Rückgabewert:    keiner
      function myCreateMultiState(id, typ, val, descr, writeaccess, minimum, maximum, list, role) {
          if (loglevel >= 3) log ("Function myCreateMultiState for " + id);
          createState(id, val, {  read: true, 
                                  write: writeaccess, 
                                  name: descr,
                                  type: typ,
                                  def: val,
                                  min: minimum, 
                                  max: maximum, 
                                  states: list,
                                  role: role ? role : "state"
          });
      }
      // Funktion myCreateIgnoreOpenDPs
      // ==============================
      // Parameter:       Keine
      // Funktion:        Erzeugt die Datenpunkte für die Ignoge-Open-Melder.
      //                  Dafür werden die Namen aus dem detectorsOuterSkin-Array geholt.
      //                  Die IDs der Ignore-Open Datenpunkte für jeden Melder werden auch in
      //                  das Array detectorsIgnoreOpen geschrieben. Dieses wird damit 3-Dimensional.
      // Rückgabewert:    Keiner.
      function myCreateIgnoreOpenDPs(){
          var detectorName;
          var idBase = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.IgnoreOpen.";
          var i=0;
          while (i<detectorsOuterSkin.length) {
              detectorName = getObject(detectorsOuterSkin[i]).common.name.replace(/\./g,"_");
              myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
              detectorsIgnoreOpen[i].push(idBase + detectorName);
              i++;
          }
      }
      
      // Function switchActiveExternal
      // =============================
      // Parameter:       keiner
      // Funktion:        Nach Prüfung auf Bereitschaft zum externen Scharfschalten, wird 
      //                  scharf geschaltet oder ein Fehler angezeigt.
      // Rückgabewert:    keiner
      function switchActiveExternal () {
          if (loglevel >= 3) log ("Function switchActiveExternal");
          setState(idExitDelayActive, false);
          var ok = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
          if (ok) {
              setState(idActiveExternal, true);
              setState(idActive, true);
              setState(idStatusText, textStatusActiveExternal);
              setState(idAlarmText, textAlarmInactive);
              setState(idAlarmingDetector,"");
              setState(idError, false);
              if (loglevel >= 2) log ("Switched to External Active");
          } else {
              if (loglevel >= 2) log ("NOT ready to switch to External Active!");
              setState(idError, true);
          }
      }
      
      // Function switchActiveInternal
      // =============================
      // Parameter:       keiner
      // Funktion:        Nach Prüfung auf Bereitschaft zum internen Scharfschalten, wird 
      //                  scharf geschaltet oder ein Fehler angezeigt.
      // Rückgabewert:    keiner
      function switchActiveInternal () {
          if (loglevel >= 3) log ("Function switchActiveInternal");
          var ok = checkDetectors(detectorsOuterSkin);
          if (ok) {
              setState(idActiveInternal, true);
              setState(idActive, true);
              setState(idStatusText, textStatusActiveInternal);
              setState(idAlarmText, textAlarmInactive);
              setState(idAlarmingDetector,"");
              setState(idError, false);
              if (loglevel >= 2) log ("Switched to Internal Active");
          } else {
              if (loglevel >= 2) log ("NOT ready to switch to Internal Active!");
              setState(idError, true);
          }
      ;}
      
      // Function switchInactive
      // =============================
      // Parameter:       keiner
      // Funktion:        Es wird unscharf geschaltet und die ganze Anlage resetiert.
      // Rückgabewert:    keiner
      function switchInactive () {
          if (loglevel >= 3) log ("Function switchInactive");
          if (timerExitDelay) clearTimeout(timerExitDelay);
          setState(idEntryDelayActive, false);
          setState(idExitDelayActive, false);
          setState(idActiveExternal, false);
          setState(idActiveInternal, false);
          setState(idActive, false);
          setState(idError, false);
          clearStateDelayed(idAlarmAccoustical);
          clearStateDelayed(idAlarmOptical);
          setState(idAlarmAccoustical, false);
          setState(idAlarmOptical, false);
          setState(idAlarm, false);
          setState(idAlarmText, textAlarmInactive);
          setState(idStatusText, textStatusInactive);
          checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
          if (loglevel >= 2) log ("Switched to Inactive");
          getAllDetectors();
      }
      
      // Function setActiveNumber
      // =======================
      // Parameter:       keine
      // Funktion:        Prüft ob intern scharf, extern scharf oder unscharf ist und
      //                  ob jeweils Eingangs- oder Ausgangsverzögerung aktiv ist.
      //                  Abhängig davon wird der Datenpunt "Output.ActiveNumber"
      //                  wie folgt gesetzt:
      //                    0 ... unscharf
      //                    1 ... intern scharf
      //                    2 ... extern scharf
      //                    3 ... Eingangsverzögerung aktiv
      //                    4 ... Ausgangsverzögerung aktiv
      // Rückgabewert:    keiner
      function setActiveNumber () {
          if (loglevel >= 3) log ("Function setActiveNumber");
          var internal = getState(idActiveInternal).val;
          var external = getState(idActiveExternal).val;
          var entry = getState(idEntryDelayActive).val;
          var exit = getState(idExitDelayActive).val;
          if (!external && !internal) {
              if (exit)
                  setState(idActiveNumber, 4);
              else
                  setState(idActiveNumber, 0);
          }
          if (internal) setState(idActiveNumber, 1);
          if (external){
              if (entry)
                  setState(idActiveNumber, 3);
              else
                  setState(idActiveNumber, 2);
          }
      }
      
      // Function checkDetectors
      // =======================
      // Parameter:       detectors
      //                  Array mit Melder-IDs
      // Funktion:        Alle Melder aus dem Array werden geprüft und alle offenen
      //                  Melder werden in einen Datenpunkt geschrieben als String.
      //                  Das Trennzeichen zwischen den Meldernamen ist die globale
      //                  Variable "seperator".
      // Rückgabewert:    true, wenn alle Melder in Ruhe sind
      //                  false, wenn ein oder mehr Melder ausgelöst sind
      function checkDetectors ( detectors ) {
          if (loglevel >= 3) log ("Function checkDetectors");
          var i=0;
          var textListOfDetectors="";
          var textListOfDetectorsIgnoreOpen="";
          var objOpenDetectors = {
              title: "All open detectors",
              zone: null,
              listOfDetectors:    []
          };
          var objOpenDetectorsOuterSkin = {
              title: "Open detectors outer skin",
              zone: functionOuterSkin,
              listOfDetectors:    []
          };
          var objOpenDetectorsIndoor = {
              title: "Open detectors indoor",
              zone: functionIndoor,
              listOfDetectors:    []
          };
          while(i < detectors.length) {
              if (getState(detectors[i]).val) {
                  if (checkIfIgnoreOpenFlagSet(detectors[i])) {
                      if (textListOfDetectorsIgnoreOpen.length > 0) textListOfDetectorsIgnoreOpen += seperator;
                      textListOfDetectorsIgnoreOpen += getObject(detectors[i]).common.name;
                  }
                  else {
                      if (textListOfDetectors.length > 0) textListOfDetectors += seperator;
                      textListOfDetectors += getObject(detectors[i]).common.name;
                  }
                  var detObj = getDetectorObject(detectors[i]);
                  objOpenDetectors.listOfDetectors.push(detObj);
                  if (detectorsOuterSkin.indexOf(detectors[i]) != -1) objOpenDetectorsOuterSkin.listOfDetectors.push(detObj);
                  if (detectorsIndoor.indexOf(detectors[i]) != -1) objOpenDetectorsIndoor.listOfDetectors.push(detObj);
              }
              i++;
          }
          if (loglevel >= 3) log ("Open Detectors found: " + (textListOfDetectors.length ? textListOfDetectors : "none"));
          
          // Datenpunkte schreiben
          setState(idOpenDetectors, textListOfDetectors);
          setState(idOpenDetectorsWithIgnoreOpenFlagSet, textListOfDetectorsIgnoreOpen);
          setState(idOpenDetectorsJSON, JSON.stringify(objOpenDetectors));
          setState(idOpenDetectorsOuterSkinJSON, JSON.stringify(objOpenDetectorsOuterSkin));
          setState(idOpenDetectorsIndoorJSON, JSON.stringify(objOpenDetectorsIndoor));
      
          if (textListOfDetectors.length > 0) {
              return false;
          } else {
              return true;
          }
      }
      
      // Function getDetectorObject
      // ==========================
      // Parameter:       id
      //                  id eines Melder-States
      // Funktion:        Vom Melder mit der id wird das Objekt über getObjekt(id) geholt,
      //                  sowie von seinem Parent und ParentsParent.
      //                  Alle Objekte kommen in ein großes Objekt und werden zurück gegeben.
      // Rückgabewert:    Das Objekt des Melders samt Parent und ParentsParent (sofern es welche gibt)
      function getDetectorObject (id) {
          if (loglevel >= 3) log ("Function getDetectorObject for id: " + id);
          // ioBroker Parent-Datenpunkt (z.B. Kanal), kann auch null sein (zB bei KNX)
          var idParent = id.substr(0, id.lastIndexOf("."));
          // ioBroker ParentsParent-Datenpunkt (z.B. Gerät), kann auch null sein (zB bei KNX)
          var idParentsParent = idParent.substr(0, idParent.lastIndexOf("."));
      
          // Objekte dazu holen
          var obj    = getObject(id);
          var objParent = getObject(idParent);
          var objParentsParent = getObject(idParentsParent);
      
          // Alle Objekte in ein großes Objekt sammeln
          var detectorsObj = {
              id:             id,
              self:           obj,
              parent:         objParent,
              parentsparent:  objParentsParent
          };
      
          // Rückgeben
          return detectorsObj;
      }
      
      
      

      Ich hoffe, es funktioniert einigermaßen. Bitte mal testen.
      Danke und LG
      Andreas

      BBTownB Online
      BBTownB Online
      BBTown
      schrieb am zuletzt editiert von
      #104

      @andreaskos sagte in Umfassendes Alarmanlagen-Skript:

      true = wird mitüberwacht
      false = von der Überwachung ausgenommen

      müßte es nicht logisch bei einem "ignoreOpen" genau anders herum sein?

      ioBroker auf NUC (VM debian v13 (Trixie ), node v22.21.0 npm v10.9.4, js-controller v7.1.0 jsonl/jsonl / HomeMatic CCU-2 (Wired und Funk) / Philips HUE / echo.DOT / Broadlink RM pro / SONOS

      andreaskosA 1 Antwort Letzte Antwort
      0
      • BBTownB BBTown

        @andreaskos sagte in Umfassendes Alarmanlagen-Skript:

        true = wird mitüberwacht
        false = von der Überwachung ausgenommen

        müßte es nicht logisch bei einem "ignoreOpen" genau anders herum sein?

        andreaskosA Offline
        andreaskosA Offline
        andreaskos
        schrieb am zuletzt editiert von
        #105

        @bbtown
        Korrekt - und tatsächlich ist es das auch! 😂
        Es war schön spät...😉

        1 Antwort Letzte Antwort
        0
        • andreaskosA andreaskos

          Lieber @Freaknet und @Schmakus und alle anderen Leser,

          ich habe eben die Funktion eingebaut, einzelne Melder aus der Aussenhülle von der Überwachung ausnehmen zu können. Die Funktion ist mehr oder weniger ungetestet und ich würde euch bitten hier Feedback zu geben, um das Skript fehlerfrei zu bekommen und auch als neue Version oben im ersten Thread updaten zu können.

          Neue Datenpunkte
          Unter "Input" ist nun ein neuer Knoten namens "IgnoreOpen" zu finden. Unterhalb diesem können per Flag die einzelnen Melder inaktiv geschaltet werden.
          true = wird mitüberwacht
          false = von der Überwachung ausgenommen

          Unter "Output" ist ein Text-Datenpunkt, der die Liste der offenen Melder mit gesetztem IgnoreOpen-Flag beinhaltet. Diese Melder kommen nicht in die Liste der ganz regulär offenen Melder.
          Diesen Datenpunkt könnte man verwenden, um sich zu warnen, wenn zum Zeitpunkt des Scharf-Schaltens (oder ein paar Millisekunden später) hier Text enthalten ist.

          ACHTUNG
          Die Einstellung der IgnoreOpen-Flags wird (derzeit) nicht automatisch zurück gesetzt, etwa beim Scharf-Schalten. Das bedeutet, man muss selbst drauf achten, dass ein Melder nicht ewig auf Inaktiv bleibt, weil man vergessen hat das Flag wieder auf true zu stellen.

          /*
          ########################################################################################################################
          # ALARMSYSTEM
          #
          # Das Skript bildet eine einfache Alarmanlage nach mit der Schaltmöglichkeit
          # für intern und extern.
          # Datenpunkte für Inputs und Outputs werden angelegt.
          # Nähere Beschreibung siehe im ioBroker-Forum unter
          # https://forum.iobroker.net/topic/32885/umfassendes-alarmanlagen-skript
          # Änderungshistorie:
          # 2020-05-01    Andreas Kos     Erstellt
          # 2020-05-02    Andreas Kos     Schaltwunsch mit Number-Datenpunkt Input.SwitchNumber (Idee von @Homer.J.)
          #                               Schaltstatus mit Number-Datenpunkt Output.ActiveNumber (Idee von @Homer.J.)
          # 2020-05-03    Andreas Kos     Korrekturen, u.a. für Melderauswertung (chage: "ne") & AlarmText
          # 2020-05-04    Andreas Kos     - Melder werden aus den Functions (Aufzählungen, enums) dafür geholt. Auch beim Unscharf-
          #                                 schalten, dadurch ist kein Neustarten des Skripts notwendig bei
          #                                 Änderungen an diesen Aufzählungen.
          #                               - Eine Schaltung von einem scharf-Zustand auf einen anderen
          #                                 wird verhindert. ZB von scharf intern auf scharf extern.
          #                                 Es muss immer unscharf dazwischen geschaltet werden.
          # 2020-05-09    Andreas Kos     Zusätzliche Objekte mit JSON-Strings für:
          #                               - den auslösenden Melder
          #                               - alle offenen Melder
          #                               - alle offenen Melder der Außenhaut
          #                               - alle offenen Melder des Innenraums
          #                               Die JSON-String beinhalten das auslösende Objekt, sowie (falls vorhanden)
          #                               das Parent und das ParentsParent-Objekt mit allen in ioBroker verfügbaren Eigenschaften.
          #                               Kleinere Verbesserungen, z.B. bezüglich setzen der AlarmTexte.
          # 2020-05-12    Andreas Kos     Setzen des Datenpunkts idReady zur Bereitschaftsanzeige neu gemacht.
          # 2021-06-13    Andreas Kos     Einbau der Funktion zum Ausnehmen einzelner Melder der Aussenhülle
          #                               von der Melder-Überwachung. Soll zum Kippen von Fenstern dienen u.ä.
          ########################################################################################################################
          */
          
          // EINBRUCHSMELDER
          // Jeder Melder muss ein State sein, der bei Auslösung true liefert und in Ruhe (geschlossen) false.
          // Die Melder sind in Arrays zusammengefasst, d.h. sie müssen jeweils mit Beistrich voneinander getrennt werden.
          // Die Namen der Melder sollten gut gepflegt sein für eine sinnvolle Verwendung (Attribut name bei den Objekten)
          
          // Melder der Außenhaut
          // Dies können Öffnungskontakte sein von Fenster und Türen in den Außenmauern des Objekts.
          // EINGABE: In der Aufzählung "alarmanlage_aussenhaut" die States einfügen.
          
          // Melder des Innenraums
          // Dies können Bewegungsmelder sein aus dem Inneren.
          // EINGABE: In der Aufzählung "alarmanlage_innenraum" die States einfügen.
          
          // Verzögerte Melder
          // Diese kommen in den Gruppen oben auch vor. Sie bewirken eine Aktivierung der Eingangsverzögerung
          // bei scharf geschalteter Anlage und erlauben während der Ausgangsverzögerung nach dem
          // Scharfschalten das Haus zu verlassen.
          // EINGABE: In der Aufzählung "alarmanlage_verzoegert" die States einfügen.
          
          
          // EINSTELLUNGEN
          const entryDelay =                30;         // Eingangsverzögerung in Sekunden (sollte maximal 60s sein)
          const exitDelay =                 30;         // Ausgangsverzögerung in Sekunden (sollte maximal 60s sein)
          const alarmDurationAccoustical =  180;         // Dauer des akkustischen Alarms in Sekunden (ACHTUNG: in Ö sind maximal 180s erlaubt!)
          const alarmDurationOptical =      -1;         // Dauer des optischen Alarm in Sekunden, -1 für unendlich
          
          // TEXTE FÜR SCHALTZUSTAND
          // Diese Text geben Auskunft über den Zustand der Anlage.
          // Sie werden in den Datenpunkt "javascript.X.Output.StatusText" geschrieben.
          const textStatusInactive =        "unscharf";
          const textStatusActiveInternal =  "scharf intern";
          const textStatusActiveExternal =  "scharf extern";
          const textActiveExternalDelayed = "scharf extern verzögert";
          const textEntryDelayActive =      "Eingangsverzögerung aktiv";
          const textExitDelayActive =       "Ausgangsverzögerung aktiv";
          
          // TEXTE FÜR ALARMIERUNG UND FEHLER
          // Diese Text geben im unscharfen Zustand der Anlage Auskunft über die Bereitschaft
          // zum Scharfschalten (nur möglich, wenn alle Melder geschlossen - in Ruhe - sind) und
          // Fehler bei der Scharfschaltung bzw. bei scharfer Anlage über den Zustand Frieden oder Alarm.
          // Sie werden in den Datenpunkt "javascript.X.Output.AlarmText" geschrieben.
          const textAlarmInactive =         "Alles OK";
          const textAlarmActive =           "Alarm!!";
          const textReady =                 "Bereit";
          const textNotReady =              "Nicht bereit";
          const textError =                 "Fehler bei der Scharfschaltung";
          
          // EXPERTEN-EINSTELLUNGEN
          const pathToCreatedStates = "Alarmanlage";    // Beispiel: States werden erzeugt unter javascript.X.Alarmanlage
          const seperator = ", ";                       // Trenn-String, der zwischen den Meldernamen verwendet wird, im Datenpunkt "OpenDetectors"
          const loglevel = 2;                           // 0 bis 3. 0 ist AUS, 3 ist maximales Logging
                                                      // Empfehlung für Nachvollziehbarkeit aller Handlungen ist 2 (Ereignisliste)
          const functionOuterSkin = "alarmanlage_aussenhaut";
          const functionIndoor = "alarmanlage_innenraum";
          const functionDelayedDetectors = "alarmanlage_verzoegert";
          
          /*
             ###############################################################################
                              DO NOT CHANGE ANYTHING BELOW THIS LINE
                                   AB HIER NICHTS MEHR ÄNDERN
             ###############################################################################
          */
          
          // ===============================================================================
          // Variablen
          // ===============================================================================
          
          // Arrays für die Melder
          var detectorsOuterSkin = [];
          var detectorsIndoor = [];
          var detectorsDelayed = [];
          
          // Array für die IgnoreOpen-Melder (beinhaltet nur Flags).
          // Das Array ist inital deckungsgleich mit detectorsOuterSkin, da diese
          // nur aus dieser Function kommen können.
          // Dieses Array ist 2-Dimensional: [Melder-ID, IgnoreOpen-Zustands-ID]
          var detectorsIgnoreOpen = [];
          
          // Javascript-Instanz mit der das Alarmanlagen-Skript ausgeführt wird
          var javascriptInstance = instance;
          
          // States, die erzeugt werden für Status-Ausgaben
          var idActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Active";
          var idActiveExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveExternal";
          var idActiveInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveInternal";
          var idActiveNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ActiveNumber";
          var idAlarm = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Alarm";
          var idAlarmAccoustical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmAccoustical";
          var idAlarmOptical = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmOptical";
          var idReady = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Ready";
          var idEntryDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.EntryDelayActive";
          var idExitDelayActive = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.ExitDelayActive";
          var idAlarmingDetector = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetector";
          var idAlarmingDetectorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmingDetectorJSON";
          var idOpenDetectors = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectors";
          var idOpenDetectorsJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsJSON";
          var idOpenDetectorsOuterSkinJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsOuterSkinJSON";
          var idOpenDetectorsIndoorJSON = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIndoorJSON";
          var idOpenDetectorsWithIgnoreOpenFlagSet = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.OpenDetectorsIgnoreOpen";
          
          var idStatusText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.StatusText";
          var idAlarmText = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.AlarmText";
          var idError = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Output.Error";
          
          // States, die erzeugt werden für Eingaben
          var idSwitchExternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternal";
          var idSwitchInternal = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchInternal";
          var idSwitchExternalDelayed = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchExternalDelayed";
          var idSwitchNumber = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.SwitchNumber";
          
          // Sonstige globale Variablen, die gebraucht werden
          var timerExitDelay = null;
          var timerTexts = null;
          
          // ===============================================================================
          // Precode
          // ===============================================================================
          
          // Logging
          if (loglevel >= 1) log ("Alarmsystem started.");
          
          getAllDetectors();
          
          // States erzeugen
          myCreateState(idActive, "boolean", false, "Switch Status Total", false, "info.status");
          myCreateState(idActiveExternal, "boolean", false, "Switch Status External", false, "info.status");
          myCreateState(idActiveInternal, "boolean", false, "Switch Status Internal", false, "info.status");
          myCreateState(idAlarm, "boolean", false, "Alarm Status", false, "sensor.alarm");
          myCreateState(idAlarmAccoustical, "boolean", false, "Accoustical Alarm Status", false, "sensor.alarm");
          myCreateState(idAlarmOptical, "boolean", false, "Optical Alarm Status", false, "sensor.alarm");
          myCreateState(idReady, "boolean", false, "Alarmsystem Ready", false, "info.status");
          myCreateState(idError, "boolean", false, "Error Switching Active", false, "info.status");
          myCreateState(idEntryDelayActive, "boolean", false, "Entry Delay Active Status", false, "info.status");
          myCreateState(idExitDelayActive, "boolean", false, "Exit Delay Active Status", false, "info.status");
          myCreateState(idAlarmingDetector, "string", "", "Alarming Detector", false, "text");
          myCreateState(idAlarmingDetectorJSON, "string", "", "Alarming Detector JSON", false, "json");
          myCreateState(idOpenDetectors, "string", "", "Open Detectors", false, "info.name");
          myCreateState(idOpenDetectorsJSON, "string", "", "Open Detectors JSON", false, "json");
          myCreateState(idOpenDetectorsOuterSkinJSON, "string", "", "Open Detectors Outer Skin JSON", false, "json");
          myCreateState(idOpenDetectorsIndoorJSON, "string", "", "Open Detectors Indoor JSON", false, "json");
          myCreateState(idOpenDetectorsWithIgnoreOpenFlagSet, "string", "", "Open Detectors with IgnoreOpen-Flag set", false, "text");
          myCreateState(idStatusText, "string", "", "Status Text", false, "text");
          myCreateState(idAlarmText, "string", "", "Alarm Text", false, "text");
          myCreateState(idSwitchExternal, "boolean", false, "Enable Surveillance External", true, "switch");
          myCreateState(idSwitchInternal, "boolean", false, "Enable Surveillance Internal", true, "switch");
          myCreateState(idSwitchExternalDelayed, "boolean", false, "Enable Surveillance External Delayed", true, "switch");
          
          myCreateMultiState (idActiveNumber, "number", 0, "Switch Status Number", false, 0, 4,"0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+"; 2:"+textStatusActiveExternal+"; 3:"+textExitDelayActive+"; 4:"+textEntryDelayActive);
          myCreateMultiState (idSwitchNumber, "number", 0, "Switch by Number", true, 0, 3, "0:"+textStatusInactive+"; 1:"+textStatusActiveInternal+" ; 2:"+textStatusActiveExternal+" ; 3:"+textActiveExternalDelayed);
          
          // Erzeugen der Datenpunkte für die IgnoreOpen-Einstellung
          myCreateIgnoreOpenDPs();
          
          // Melder nach dem Starten checken
          checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
          
          // ===============================================================================
          // ON-Subscribtions
          // ===============================================================================
          
          // Auf Schaltstellen EXTERN verzögert reagieren (schalten EIN/AUS)
          on ({id: idSwitchExternalDelayed, change: "any"}, function(obj){
              if (loglevel >= 3) log ("Switching External Delayed, Value: " + getState(obj.id).val);
              if (getState(obj.id).val) { // Einschalten, scharf extern VERZÖGERT
                  if (loglevel >= 2) log ("Switching required: Delayed External Active");
                      if (getState(idActive).val) {
                          if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                          setState(idError, true);
                      } else {
                          setState(idExitDelayActive, true);
                          if (timerExitDelay) clearTimeout(timerExitDelay);
                          timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                      }
              }
              else { // Ausschalten, unscharf SOFORT
                  if (loglevel >= 2) log ("Switching required: Inactive");
                  switchInactive();
              }
          });
          
          // Auf Schaltstellen EXTERN sofort reagieren (schalten EIN/AUS)
          on ({id: idSwitchExternal, change: "any"}, function(obj){
              if (loglevel >= 3) log ("Switching External Immediately, Value: " + getState(obj.id).val);
              if (getState(obj.id).val) { // Einschalten, scharf extern
                  if (loglevel >= 2) log ("Switching required: External Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      switchActiveExternal();
                  }
              }
              else { // Ausschalten, unscharf
                  if (loglevel >= 2) log ("Switching required: Inactive");
                  switchInactive();
              }
          });
          
          // Auf Schaltstellen INTERN sofort reagieren (schalten EIN/AUS)
          on ({id: idSwitchInternal, change: "any"}, function(obj){
              if (loglevel >= 3) log ("Switching Internal, Value: " + getState(obj.id).val);
              if (getState(obj.id).val) { // Einschalten, scharf intern
                  if (loglevel >= 2) log ("Switching required: Internal Active");
                  if (getState(idActive).val) {
                      if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                      setState(idError, true);
                  } else {
                      switchActiveInternal();
                  }
              }
              else { // Ausschalten, unscharf
                  switchInactive();
                  if (loglevel >= 2) log ("Switching required: Inactive");
              }
          });
          
          // Auf Schaltstelle mit Datenpunkt SwitchNumber reagieren
          // Folgende Reaktionen:
          //      0 ... unscharf schalten
          //      1 ... scharf intern schalten
          //      2 ... scharf extern schalten
          //      3 ... verzögert scharf extern schalten
          on ({id: idSwitchNumber, change: "any"}, function(obj){
              if (loglevel >= 3) log ("Switching Number, Value: " + obj.state.val);
              switch (obj.state.val) {
                  case 0:
                      if (loglevel >= 2) log ("Switching required: Inactive");
                      switchInactive();
                      break;
                  case 1:
                      if (loglevel >= 2) log ("Switching required: Internal Active");
                      if (getState(idActive).val) {
                          if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                          setState(idError, true);
                      } else {
                          switchActiveInternal();
                      }
                      break;
                  case 2:
                      if (loglevel >= 2) log ("Switching required: External Active");
                      if (getState(idActive).val) {
                          if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                          setState(idError, true);
                      } else {
                          switchActiveExternal();
                      }
                      break;
                  case 3:
                      if (loglevel >= 2) log ("Switching required: Delayed External Active");
                      if (getState(idActive).val) {
                          if (loglevel >= 3) log ("Alarmsystem already active, switch to inactive first!");
                          setState(idError, true);
                      } else {
                          setState(idExitDelayActive, true);
                          if (timerExitDelay) clearTimeout(timerExitDelay);
                          timerExitDelay = setTimeout(switchActiveExternal, exitDelay * 1000);
                      }
                      break;
                  default:
                      if (loglevel >= 3) log ("idSwitchNumber has unknown number!");
              }
          });
          
          // Auf Fehler bei der Scharfschaltung reagieren
          on ({id: idError, val: true, change: "any"}, function(obj){
              if (loglevel >= 1) log ("Error when switching to active.");
              setState(idAlarmText, textError);
          });
          
          // Auf Eingangsverzögerung reagieren
          on({id: idEntryDelayActive, val: true, change: "ne"}, function (obj) {
              if (loglevel >= 2) log ("Entry Delay is active (" + entryDelay + " seconds)");
              setState(idStatusText, textEntryDelayActive);
              setStateDelayed(idAlarmAccoustical, true, entryDelay * 1000);
              setStateDelayed(idAlarmOptical, true, entryDelay * 1000);
          });
          
          // Auf Ausgangsverzögerung reagieren
          on({id: idExitDelayActive, val: true, change: "ne"}, function (obj) {
              if (loglevel >= 2) log ("Exit Delay is active (" + exitDelay + " seconds)");
              setState(idStatusText, textExitDelayActive);
          });
          
          // Auf Akustischen Alarm reagieren
          on ({id: idAlarmAccoustical, val: true, change: "ne"}, function(obj){
              if (loglevel >= 1) log ("ALARM is active!");
              setState(idEntryDelayActive, false);
              setState(idAlarmText, textAlarmActive);
              setState(idAlarm, true);
              setStateDelayed(idAlarmAccoustical, false, alarmDurationAccoustical * 1000);
              if (getState(idActiveExternal).val) setState(idStatusText, textStatusActiveExternal);
              if (getState(idActiveInternal).val) setState(idStatusText, textStatusActiveInternal);
          });
          
          // Auf Optischen Alarm reagieren
          on ({id: idAlarmOptical, val: true, change: "ne"}, function(obj){
              if (alarmDurationOptical >= 0)
                  setStateDelayed(idAlarmOptical, false, alarmDurationOptical * 1000);
          });
          
          // Melderauswertung
          on( {id: detectorsOuterSkin.concat(detectorsIndoor), change: "ne"}, function(obj){
              detectorSurveillance(obj);
          });
          
          // Status in Active.Number schreiben
          on ({id: [idActiveInternal, idActiveExternal, idEntryDelayActive, idExitDelayActive], change: "ne"}, function(obj){
              if (loglevel >= 3) log ("on for writing ActiveNumber, Trigger: " + obj.id);
              setActiveNumber();
          });
          
          // Texte korrekt setzen
          on ({id: [idAlarm, idActive, idOpenDetectors], change: "any"}, function (obj) {
              // Das Timeout ggf. abbrechen
              if (timerTexts) clearTimeout(timerTexts);  
              // Nach einem Timeout den Check anfangen
              timerTexts = setTimeout(setTexts, 200);
          });
          
          
          
          // ===============================================================================
          // Funktionen
          // ===============================================================================
          // Funktion     checkIfIgnoreOpenFlagSet
          // =====================================
          // Parameter:       Prüft, ob das IgnoreOpen-Flag für einen Melder gesetzt ist.
          // Übergabewert:    Melder-ID
          // Rückgabewert:    Flag-Zustand
          function checkIfIgnoreOpenFlagSet(id){
              var i=0;
              while (i<detectorsIgnoreOpen.length){
                  if ( detectorsIgnoreOpen[i][0] == id )
                      if (getState(detectorsIgnoreOpen[i][1]).val)
                          return true;
                  i++;
              }
              return false;
          }
          
          // Function setTexts
          // =================
          // Parameter:       keiner
          // Funktion:        Abhängig von den Zuständen scharf/unscharf und
          //                  Alarm / Kein Alarm werden Texte für
          //                  den AlarmText richtig gesetzt. Auch der Datenpunkt idReady wird hier gesetzt.
          // Rückgabewert:    keiner
          function setTexts(){    
              var textListOfDetectors = getState(idOpenDetectors).val;
              if (textListOfDetectors.length > 0) {
                  if (!getState(idActive).val)
                      // Offene Melder gefunden und unscharf
                      setState(idAlarmText, textNotReady);
                      setState(idReady, false);
                  return false;
              } else {
                  if (getState(idActive).val && !getState(idAlarm).val)
                      // kein offener Melder gefunden und scharf und kein Alarm
                      setState(idAlarmText, textAlarmInactive);
                  else if (!getState(idActive).val)
                      // kein offener Melder gefunden und unscharf
                      setState(idAlarmText, textReady);
                      setState(idReady, true);
                  return true;
              }
          }
          
          // Function getAllDetectors
          // ========================
          // Parameter:       keiner
          // Funktion:        Über die Funktion getDetectorsFromFunction werden
          //                  alle Melder von den Functions geholt und in die
          //                  globalen Variablen dafür geschrieben.
          // Rückgabewert:    keiner
          function getAllDetectors(){
              var i=0;
              detectorsOuterSkin = getDetectorsFromFunction(functionOuterSkin);
              detectorsIgnoreOpen = [];
              while (i<detectorsOuterSkin.length) {
                  detectorsIgnoreOpen.push([detectorsOuterSkin[i++]]);
              }
              detectorsIndoor = getDetectorsFromFunction(functionIndoor);
              detectorsDelayed = getDetectorsFromFunction(functionDelayedDetectors);
          }
          
          // Function getDetectorsFromFunction
          // =================================
          // Parameter:       functionString
          //                  Name der Function, in der die Melder enthalen sind.
          // Funktion:        Alle Teilnehmer der übergebenen Function werden
          //                  in ein Array geschrieben.
          // Rückgabewert:    Array der Melder-IDs
          function getDetectorsFromFunction( functionString ) {
              if (loglevel >= 3) log ("Function getDetectorsFromFunction");
              var detectors = [];
              $('state(functions='+functionString+')').each(function(id, i) {
                  detectors.push(id);
                  if (loglevel >= 3) log ("This detector was added to surveillance from function "+functionString+": " + id);
              });
              return detectors;
          }
          
          // Function detectorSurveillance
          // =============================
          // Parameter:       obj
          //                  Objekt des auslösenden Melders
          // Funktion:        Abhängig vom Schaltzustand werden die Melder überprüft.
          //                  Bei unscharf wird nur die Liste der offenen Melder und die
          //                  Bereitschaft der Anlage zum Scharfschalten gepfelgt.
          //                  Bei scharf geschalteter Anlage ist es anders:
          //                  Es wird geprüft, ob der auslösende Melder in den Außenhaut- oder
          //                  Innenraum-Meldern enthalten ist und ob dieser ein verzögerter Melder ist.
          //                  Abhängig davon wird entweder sofort oder verzögert Alarm ausgelöst.
          // Rückgabewert:    keiner
          function detectorSurveillance (obj) {
              var active = getState(idActive).val;
              var activeExternal = getState(idActiveExternal).val;
              var activeInternal = getState(idActiveInternal).val;
              var ready;
              var ignoreOpenSet;
              
              if (loglevel >= 2) log ("Surveillance of detectors started, triggering detector: " + obj.common.name);
          
              // Alle offenen Melder feststellen
              ready = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
          
              // Auslösenden Melder schreiben
              setState(idAlarmingDetector, obj.common.name);
              setState(idAlarmingDetectorJSON, JSON.stringify(  getDetectorObject(obj.id)  ));
          
              // Prüfen, wie der der Schaltzustand ist
              // bei unscharf
              if (!active) {
                  if (loglevel >= 2) log ("Alarmsystem is Inactive");
              }
              // bei scharf intern
              if (activeInternal) {
                  if (loglevel >= 2) log ("Alarmsystem is Internal Active");
                  if (detectorsOuterSkin.indexOf(obj.id) != -1) {
                      if (loglevel >= 3) log ("Detector is part of Outer Skin");
                      if (detectorsDelayed.indexOf(obj.id) != -1) {
                          if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                          if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                          else {
                              if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                              setState(idAlarmAccoustical, true);
                              setState(idAlarmOptical, true);
                          }
                      } else {
                          if (loglevel >= 3) log ("Detector is not delayed");
                          setState(idAlarmAccoustical, true);
                          setState(idAlarmOptical, true);
                      }
                  }
              }
              // bei scharf extern
              if (activeExternal) {
                  if (loglevel >= 2) log ("Alarmsystem is External Active");
                  // Prüfen, ob er der Melder das IgnoreOpen-Flag gesetzt hat.
                  ignoreOpenSet = checkIfIgnoreOpenFlagSet(obj.id);
                  if (loglevel >= 2) log ("Detector has IgnoreOpen-Flag set true!");
                  if (ignoreOpenSet)  return;
                  if (detectorsOuterSkin.concat(detectorsIndoor).indexOf(obj.id) != -1) {
                      if (loglevel >= 3) log ("Detector is part of Outer Skin or Indoor");
                      if (detectorsDelayed.indexOf(obj.id) != -1) {
                          if (loglevel >= 3) log ("Detector is part of Delayed Detectors");
                          if(!getState(idAlarm).val) setState(idEntryDelayActive, true);
                          else {
                              if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                              setState(idAlarmAccoustical, true);
                              setState(idAlarmOptical, true);
                          }
                      } else {
                          if (loglevel >= 3) log ("Detector is not delayed");
                          if (loglevel >= 2) log ("System is ALARMING now!");
                          setState(idAlarmAccoustical, true);
                          setState(idAlarmOptical, true);
                      }
                  }
              }
          }
          
          // Function myCreateState
          // =======================
          // Parameter:       id      ... id des neu anzulegenden Datenpunkts
          //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
          //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
          //                  descr   ... Name als String
          //                  writeaccess Schreibrechte true oder false
          // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
          //                  Parametern angelegt.
          // Rückgabewert:    keiner
          function myCreateState(id, typ, val, descr, writeaccess, role) {
              if (loglevel >= 3) log ("Function myCreateState for " + id);
              createState(id, val,    {read: !writeaccess, 
                                      write: writeaccess, 
                                      name: descr,
                                      type: typ,
                                      def: val,
                                      role: role ? role : "state"
              });
          }
          
          // Function myCreateMultiState
          // ===========================
          // Parameter:       id      ... id des neu anzulegenden Datenpunkts
          //                  typ     ... typ des anzulegenden Datenpunkts ("boolean", "string", "number", etc.)
          //                  val     ... Wert, den der Datenpunkt nach dem Anlegen haben soll
          //                  descr   ... Name als String
          //                  min     ... Minimalwert
          //                  max     ... Maximalwert
          //                  list    ... Liste mit Werten und Bezeichnern im Format "0:Text0; 1:Text1; 2:Text2"
          //                  writeaccess Schreibrechte true oder false
          // Funktion:        Mit der Funktion createState wird der neue Datenpunkt mit den übergebenen
          //                  Parametern angelegt.
          // Rückgabewert:    keiner
          function myCreateMultiState(id, typ, val, descr, writeaccess, minimum, maximum, list, role) {
              if (loglevel >= 3) log ("Function myCreateMultiState for " + id);
              createState(id, val, {  read: true, 
                                      write: writeaccess, 
                                      name: descr,
                                      type: typ,
                                      def: val,
                                      min: minimum, 
                                      max: maximum, 
                                      states: list,
                                      role: role ? role : "state"
              });
          }
          // Funktion myCreateIgnoreOpenDPs
          // ==============================
          // Parameter:       Keine
          // Funktion:        Erzeugt die Datenpunkte für die Ignoge-Open-Melder.
          //                  Dafür werden die Namen aus dem detectorsOuterSkin-Array geholt.
          //                  Die IDs der Ignore-Open Datenpunkte für jeden Melder werden auch in
          //                  das Array detectorsIgnoreOpen geschrieben. Dieses wird damit 3-Dimensional.
          // Rückgabewert:    Keiner.
          function myCreateIgnoreOpenDPs(){
              var detectorName;
              var idBase = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.IgnoreOpen.";
              var i=0;
              while (i<detectorsOuterSkin.length) {
                  detectorName = getObject(detectorsOuterSkin[i]).common.name.replace(/\./g,"_");
                  myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
                  detectorsIgnoreOpen[i].push(idBase + detectorName);
                  i++;
              }
          }
          
          // Function switchActiveExternal
          // =============================
          // Parameter:       keiner
          // Funktion:        Nach Prüfung auf Bereitschaft zum externen Scharfschalten, wird 
          //                  scharf geschaltet oder ein Fehler angezeigt.
          // Rückgabewert:    keiner
          function switchActiveExternal () {
              if (loglevel >= 3) log ("Function switchActiveExternal");
              setState(idExitDelayActive, false);
              var ok = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
              if (ok) {
                  setState(idActiveExternal, true);
                  setState(idActive, true);
                  setState(idStatusText, textStatusActiveExternal);
                  setState(idAlarmText, textAlarmInactive);
                  setState(idAlarmingDetector,"");
                  setState(idError, false);
                  if (loglevel >= 2) log ("Switched to External Active");
              } else {
                  if (loglevel >= 2) log ("NOT ready to switch to External Active!");
                  setState(idError, true);
              }
          }
          
          // Function switchActiveInternal
          // =============================
          // Parameter:       keiner
          // Funktion:        Nach Prüfung auf Bereitschaft zum internen Scharfschalten, wird 
          //                  scharf geschaltet oder ein Fehler angezeigt.
          // Rückgabewert:    keiner
          function switchActiveInternal () {
              if (loglevel >= 3) log ("Function switchActiveInternal");
              var ok = checkDetectors(detectorsOuterSkin);
              if (ok) {
                  setState(idActiveInternal, true);
                  setState(idActive, true);
                  setState(idStatusText, textStatusActiveInternal);
                  setState(idAlarmText, textAlarmInactive);
                  setState(idAlarmingDetector,"");
                  setState(idError, false);
                  if (loglevel >= 2) log ("Switched to Internal Active");
              } else {
                  if (loglevel >= 2) log ("NOT ready to switch to Internal Active!");
                  setState(idError, true);
              }
          ;}
          
          // Function switchInactive
          // =============================
          // Parameter:       keiner
          // Funktion:        Es wird unscharf geschaltet und die ganze Anlage resetiert.
          // Rückgabewert:    keiner
          function switchInactive () {
              if (loglevel >= 3) log ("Function switchInactive");
              if (timerExitDelay) clearTimeout(timerExitDelay);
              setState(idEntryDelayActive, false);
              setState(idExitDelayActive, false);
              setState(idActiveExternal, false);
              setState(idActiveInternal, false);
              setState(idActive, false);
              setState(idError, false);
              clearStateDelayed(idAlarmAccoustical);
              clearStateDelayed(idAlarmOptical);
              setState(idAlarmAccoustical, false);
              setState(idAlarmOptical, false);
              setState(idAlarm, false);
              setState(idAlarmText, textAlarmInactive);
              setState(idStatusText, textStatusInactive);
              checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
              if (loglevel >= 2) log ("Switched to Inactive");
              getAllDetectors();
          }
          
          // Function setActiveNumber
          // =======================
          // Parameter:       keine
          // Funktion:        Prüft ob intern scharf, extern scharf oder unscharf ist und
          //                  ob jeweils Eingangs- oder Ausgangsverzögerung aktiv ist.
          //                  Abhängig davon wird der Datenpunt "Output.ActiveNumber"
          //                  wie folgt gesetzt:
          //                    0 ... unscharf
          //                    1 ... intern scharf
          //                    2 ... extern scharf
          //                    3 ... Eingangsverzögerung aktiv
          //                    4 ... Ausgangsverzögerung aktiv
          // Rückgabewert:    keiner
          function setActiveNumber () {
              if (loglevel >= 3) log ("Function setActiveNumber");
              var internal = getState(idActiveInternal).val;
              var external = getState(idActiveExternal).val;
              var entry = getState(idEntryDelayActive).val;
              var exit = getState(idExitDelayActive).val;
              if (!external && !internal) {
                  if (exit)
                      setState(idActiveNumber, 4);
                  else
                      setState(idActiveNumber, 0);
              }
              if (internal) setState(idActiveNumber, 1);
              if (external){
                  if (entry)
                      setState(idActiveNumber, 3);
                  else
                      setState(idActiveNumber, 2);
              }
          }
          
          // Function checkDetectors
          // =======================
          // Parameter:       detectors
          //                  Array mit Melder-IDs
          // Funktion:        Alle Melder aus dem Array werden geprüft und alle offenen
          //                  Melder werden in einen Datenpunkt geschrieben als String.
          //                  Das Trennzeichen zwischen den Meldernamen ist die globale
          //                  Variable "seperator".
          // Rückgabewert:    true, wenn alle Melder in Ruhe sind
          //                  false, wenn ein oder mehr Melder ausgelöst sind
          function checkDetectors ( detectors ) {
              if (loglevel >= 3) log ("Function checkDetectors");
              var i=0;
              var textListOfDetectors="";
              var textListOfDetectorsIgnoreOpen="";
              var objOpenDetectors = {
                  title: "All open detectors",
                  zone: null,
                  listOfDetectors:    []
              };
              var objOpenDetectorsOuterSkin = {
                  title: "Open detectors outer skin",
                  zone: functionOuterSkin,
                  listOfDetectors:    []
              };
              var objOpenDetectorsIndoor = {
                  title: "Open detectors indoor",
                  zone: functionIndoor,
                  listOfDetectors:    []
              };
              while(i < detectors.length) {
                  if (getState(detectors[i]).val) {
                      if (checkIfIgnoreOpenFlagSet(detectors[i])) {
                          if (textListOfDetectorsIgnoreOpen.length > 0) textListOfDetectorsIgnoreOpen += seperator;
                          textListOfDetectorsIgnoreOpen += getObject(detectors[i]).common.name;
                      }
                      else {
                          if (textListOfDetectors.length > 0) textListOfDetectors += seperator;
                          textListOfDetectors += getObject(detectors[i]).common.name;
                      }
                      var detObj = getDetectorObject(detectors[i]);
                      objOpenDetectors.listOfDetectors.push(detObj);
                      if (detectorsOuterSkin.indexOf(detectors[i]) != -1) objOpenDetectorsOuterSkin.listOfDetectors.push(detObj);
                      if (detectorsIndoor.indexOf(detectors[i]) != -1) objOpenDetectorsIndoor.listOfDetectors.push(detObj);
                  }
                  i++;
              }
              if (loglevel >= 3) log ("Open Detectors found: " + (textListOfDetectors.length ? textListOfDetectors : "none"));
              
              // Datenpunkte schreiben
              setState(idOpenDetectors, textListOfDetectors);
              setState(idOpenDetectorsWithIgnoreOpenFlagSet, textListOfDetectorsIgnoreOpen);
              setState(idOpenDetectorsJSON, JSON.stringify(objOpenDetectors));
              setState(idOpenDetectorsOuterSkinJSON, JSON.stringify(objOpenDetectorsOuterSkin));
              setState(idOpenDetectorsIndoorJSON, JSON.stringify(objOpenDetectorsIndoor));
          
              if (textListOfDetectors.length > 0) {
                  return false;
              } else {
                  return true;
              }
          }
          
          // Function getDetectorObject
          // ==========================
          // Parameter:       id
          //                  id eines Melder-States
          // Funktion:        Vom Melder mit der id wird das Objekt über getObjekt(id) geholt,
          //                  sowie von seinem Parent und ParentsParent.
          //                  Alle Objekte kommen in ein großes Objekt und werden zurück gegeben.
          // Rückgabewert:    Das Objekt des Melders samt Parent und ParentsParent (sofern es welche gibt)
          function getDetectorObject (id) {
              if (loglevel >= 3) log ("Function getDetectorObject for id: " + id);
              // ioBroker Parent-Datenpunkt (z.B. Kanal), kann auch null sein (zB bei KNX)
              var idParent = id.substr(0, id.lastIndexOf("."));
              // ioBroker ParentsParent-Datenpunkt (z.B. Gerät), kann auch null sein (zB bei KNX)
              var idParentsParent = idParent.substr(0, idParent.lastIndexOf("."));
          
              // Objekte dazu holen
              var obj    = getObject(id);
              var objParent = getObject(idParent);
              var objParentsParent = getObject(idParentsParent);
          
              // Alle Objekte in ein großes Objekt sammeln
              var detectorsObj = {
                  id:             id,
                  self:           obj,
                  parent:         objParent,
                  parentsparent:  objParentsParent
              };
          
              // Rückgeben
              return detectorsObj;
          }
          
          
          

          Ich hoffe, es funktioniert einigermaßen. Bitte mal testen.
          Danke und LG
          Andreas

          SchmakusS Offline
          SchmakusS Offline
          Schmakus
          Developer
          schrieb am zuletzt editiert von
          #106

          @andreaskos wird getestet! Danke für die Umsetzung

          Dev of LightControl Adapter, Contributor of HUE and DoorBird Adapter

          SchmakusS 1 Antwort Letzte Antwort
          0
          • SchmakusS Schmakus

            @andreaskos wird getestet! Danke für die Umsetzung

            SchmakusS Offline
            SchmakusS Offline
            Schmakus
            Developer
            schrieb am zuletzt editiert von Schmakus
            #107

            @andreaskos: Die States "IgnoreOpen" werden alle mit "Write=false" erstellt. Sollte dies nicht "true" sein?

            myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
            

            Habe es mal selbst geändert.

            Dev of LightControl Adapter, Contributor of HUE and DoorBird Adapter

            andreaskosA 1 Antwort Letzte Antwort
            0
            • SchmakusS Schmakus

              @andreaskos: Die States "IgnoreOpen" werden alle mit "Write=false" erstellt. Sollte dies nicht "true" sein?

              myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
              

              Habe es mal selbst geändert.

              andreaskosA Offline
              andreaskosA Offline
              andreaskos
              schrieb am zuletzt editiert von andreaskos
              #108

              Hi @schmakus

              nein, mit false passt eh, denn grundsätzlich soll ja keiner ignoriert werden.

              Der Fehler lag oben in meinem Post.
              true bedeutet, dass es ignoriert wird.

              Ah - sorry - zu schnell gelesen.
              Hast absolut recht Danke!

              1 Antwort Letzte Antwort
              0
              • F Offline
                F Offline
                Freaknet
                schrieb am zuletzt editiert von
                #109

                @andreaskos und @Schmakus

                Erstmal Danke für die Überarbeitung und die Umsetzung unserer Wünsche :-)
                Find das Klasse und werde das Script gerne mal austesten die Tage :sunglasses:

                Bin jetzt leider nur etwas verwirrt mit der von @Schmakus geposteten Zeile:

                myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
                

                Passt die so wie Sie da steht oder muss ich das "false" in "true" vorher noch ändern?
                Also quasi dann so:

                myCreateState(idBase + detectorName, "boolean", true, "Ignore Open for " + detectorName, true, "switch");
                

                Im Original Script oben steht das ja noch mit "false" drin. Oder ist das Script nochmal angepasst worden @andreaskos?

                Danke für´s kurze Feedback damit ich loslegen kann :+1:

                Gruß Freaknet

                andreaskosA 1 Antwort Letzte Antwort
                0
                • F Freaknet

                  @andreaskos und @Schmakus

                  Erstmal Danke für die Überarbeitung und die Umsetzung unserer Wünsche :-)
                  Find das Klasse und werde das Script gerne mal austesten die Tage :sunglasses:

                  Bin jetzt leider nur etwas verwirrt mit der von @Schmakus geposteten Zeile:

                  myCreateState(idBase + detectorName, "boolean", false, "Ignore Open for " + detectorName, false, "switch");
                  

                  Passt die so wie Sie da steht oder muss ich das "false" in "true" vorher noch ändern?
                  Also quasi dann so:

                  myCreateState(idBase + detectorName, "boolean", true, "Ignore Open for " + detectorName, true, "switch");
                  

                  Im Original Script oben steht das ja noch mit "false" drin. Oder ist das Script nochmal angepasst worden @andreaskos?

                  Danke für´s kurze Feedback damit ich loslegen kann :+1:

                  Gruß Freaknet

                  andreaskosA Offline
                  andreaskosA Offline
                  andreaskos
                  schrieb am zuletzt editiert von
                  #110

                  @freaknet said in Umfassendes Alarmanlagen-Skript:

                  , false,

                  Ich hab noch nichts geändert oder upgedatet seit meiner Überarbeitung des Skripts.
                  Du brauchst nur das zweite, hintere false zu einem true machen, dieses steht für den Write-Access. Das erste, linke kannst du lassen. Das steht für den Default-Wert nach dem ersten Anlegen des Datenpunktes und da passt false grundsätzlich eh.

                  LG
                  Andreas

                  F 1 Antwort Letzte Antwort
                  1
                  • andreaskosA andreaskos

                    @freaknet said in Umfassendes Alarmanlagen-Skript:

                    , false,

                    Ich hab noch nichts geändert oder upgedatet seit meiner Überarbeitung des Skripts.
                    Du brauchst nur das zweite, hintere false zu einem true machen, dieses steht für den Write-Access. Das erste, linke kannst du lassen. Das steht für den Default-Wert nach dem ersten Anlegen des Datenpunktes und da passt false grundsätzlich eh.

                    LG
                    Andreas

                    F Offline
                    F Offline
                    Freaknet
                    schrieb am zuletzt editiert von
                    #111

                    @andreaskos

                    Supi, hatte ich gesehen, dass wenn ich beide auf "true" stelle die Datenpunkte direkt alle beim anlegen auf true angelegt wurden. Hab das dann bereits wieder geändert gehabt, bin dann auch über die Schreibrechte recht schnell dahintergekommen. War am Anfang etwas verwirrt :blush:

                    Bisher scheint das Script genau das zu tun was es soll :-)
                    Jetzt braucht meine Frau Nachts wenn Sie ein Fenster aufmacht bzw. kippt in bestimmten Räumen keine Angst mehr haben dass Sie versehentlich den Alarm auslöst bzw. kann ich Fenster gekippt lassen falls wir mal unterwegs sind.

                    Hab nochmal vielen Dank für die Umsetzung und falls ich noch was entdecke was "noch" nicht klappt meld ich mich.

                    Schönen und angenehmen Start in die neue Woche!

                    Freaknet

                    andreaskosA 1 Antwort Letzte Antwort
                    0
                    • F Freaknet

                      @andreaskos

                      Supi, hatte ich gesehen, dass wenn ich beide auf "true" stelle die Datenpunkte direkt alle beim anlegen auf true angelegt wurden. Hab das dann bereits wieder geändert gehabt, bin dann auch über die Schreibrechte recht schnell dahintergekommen. War am Anfang etwas verwirrt :blush:

                      Bisher scheint das Script genau das zu tun was es soll :-)
                      Jetzt braucht meine Frau Nachts wenn Sie ein Fenster aufmacht bzw. kippt in bestimmten Räumen keine Angst mehr haben dass Sie versehentlich den Alarm auslöst bzw. kann ich Fenster gekippt lassen falls wir mal unterwegs sind.

                      Hab nochmal vielen Dank für die Umsetzung und falls ich noch was entdecke was "noch" nicht klappt meld ich mich.

                      Schönen und angenehmen Start in die neue Woche!

                      Freaknet

                      andreaskosA Offline
                      andreaskosA Offline
                      andreaskos
                      schrieb am zuletzt editiert von
                      #112

                      @freaknet
                      Cool, vielen Dank für's Testen! :-)

                      @Schmakus
                      Kannst du zufällig auch schon ein Feedback geben?

                      LG
                      Andreas

                      andreaskosA H 2 Antworten Letzte Antwort
                      0
                      • andreaskosA andreaskos

                        @freaknet
                        Cool, vielen Dank für's Testen! :-)

                        @Schmakus
                        Kannst du zufällig auch schon ein Feedback geben?

                        LG
                        Andreas

                        andreaskosA Offline
                        andreaskosA Offline
                        andreaskos
                        schrieb am zuletzt editiert von
                        #113

                        Hi zusammen,
                        wenn also nichts dagegen spricht, dann aktualisiere ich wieder den ersten Post oben mit der aktuellen Version mit der eingearbeiteten Änderung für die Ausnahmen.
                        Ja? Noch irgendein Feedback?

                        1 Antwort Letzte Antwort
                        0
                        • J Offline
                          J Offline
                          juggi1962
                          schrieb am zuletzt editiert von
                          #114

                          Hallo an @kosy oder allen Anderen die hier so tolle Arbeit leisten.
                          Bin neu hier und versuche mich gerade an dem tollen Alarmanlagen Skript.
                          Dazu hätte ich zu der letzten Aktualisierung (IgnoreOpen) eine Frage.
                          Wie kann man die Sensoren die jetzt in IgnoreOpen drinn stehen aber mit false auf truhe ändern um sie von der Alarmanlage auszuschließen wenn sie das Fenster offen ist.
                          Wenn ich zb. auf false klick tut sich gar nichts, kann man das nicht da ändern?
                          Sorry wenn meine Frage komisch kling, aber ich bin noch gaaaanz am Anfang.
                          Sonst läuft eh alles.
                          Bitte um Hilfe Gruß aus Tirol.

                          andreaskosA 1 Antwort Letzte Antwort
                          0
                          • andreaskosA andreaskos

                            @freaknet
                            Cool, vielen Dank für's Testen! :-)

                            @Schmakus
                            Kannst du zufällig auch schon ein Feedback geben?

                            LG
                            Andreas

                            H Offline
                            H Offline
                            Holger_B76
                            schrieb am zuletzt editiert von Holger_B76
                            #115

                            Funktioniert

                            andreaskosA 1 Antwort Letzte Antwort
                            1
                            • H Holger_B76

                              Funktioniert

                              andreaskosA Offline
                              andreaskosA Offline
                              andreaskos
                              schrieb am zuletzt editiert von
                              #116

                              @holger_b76 Danke!

                              Ich habe jetzt die Änderungen oben im ersten Post eingearbeitet.
                              Außerdem habe ich das Script auf den aktuellen Javascript-Adapter angepasst und ACK-Flags gesetzt bei createState und setState.
                              Könntet ihr das auch mal ausprobieren? Es ist noch ungetestet... Bitte um euer Feedback!
                              Danke!

                              1 Antwort Letzte Antwort
                              0
                              • J juggi1962

                                Hallo an @kosy oder allen Anderen die hier so tolle Arbeit leisten.
                                Bin neu hier und versuche mich gerade an dem tollen Alarmanlagen Skript.
                                Dazu hätte ich zu der letzten Aktualisierung (IgnoreOpen) eine Frage.
                                Wie kann man die Sensoren die jetzt in IgnoreOpen drinn stehen aber mit false auf truhe ändern um sie von der Alarmanlage auszuschließen wenn sie das Fenster offen ist.
                                Wenn ich zb. auf false klick tut sich gar nichts, kann man das nicht da ändern?
                                Sorry wenn meine Frage komisch kling, aber ich bin noch gaaaanz am Anfang.
                                Sonst läuft eh alles.
                                Bitte um Hilfe Gruß aus Tirol.

                                andreaskosA Offline
                                andreaskosA Offline
                                andreaskos
                                schrieb am zuletzt editiert von
                                #117

                                @juggi1962

                                Sorry für diese reichlich späte Rückmeldung auf deine Frage! Das Verhalten wurde ein paar Posts vorher diskutiert, da lag ein Fehler drin.
                                Versuch es nochmal mit dem aktualisierten Skript ganz oben.

                                Liebe Grüße
                                Andreas

                                1 Antwort Letzte Antwort
                                0
                                • T Offline
                                  T Offline
                                  tritanium
                                  schrieb am zuletzt editiert von
                                  #118

                                  Hallo Andreas, hallo Community,

                                  ich habe mich nun nach vielm Lesen und Testen des Scripts dazu durchgerungen, mal hier zu posten.

                                  Dein Script habe ich eingebaut und es funktioniert auch fehlerfrei.

                                  In den Aufzählungen sind folgende Melder drin:

                                  5c19ff90-f644-45c2-b05e-ff56d21a8d95-grafik.png

                                  Die Datenpunkte (deines Scripts) z.b. "Open Detectors" und auch andere unter "Output" funktionieren scheinbar korrekt, jedenfalls sehe ich bei Statusänderungen der Fenster auch die Datenpunkte sich ändern.
                                  Auch die "IgnoreOpen" funktionieren einwandfrei.

                                  Was mir komisch vorkommt, sind JAVASCRIPT "Warnungen", die ich nicht zuordnen kann und was diese zu bedeuten haben:

                                  8dcc715c-2e5a-45fe-a366-55499f4318d8-grafik.png

                                  Jedesmal, wenn ein Bewegungsmelder (KNX) bewegung dedektiert, kommt dieser "Warnungsblock", oder auch wenn ich ein Fenster öffne, oder schliesse

                                  Muss ich mir Sorgen machen ?? Oder darf ich das ignorieren... bzw. wie lassen sich diese Warnungn, wenn sie nicht tragisch sein sollten, deaktivieren??
                                  Bzw. was muss ich/kann ich tun um diese Warnungen zu beheben ?

                                  Sorry für so blöde Fragen, aber ich weis keinen Rat mehr, da ich kein Javascript behersche und bevor ich das Praktisch verwende, wollte ich sichergehen, das das Script auch korrekt läuft.

                                  Danke jedenfalls im voraus für eure/deine Hilfe :-)

                                  Gruß Michael

                                  andreaskosA 1 Antwort Letzte Antwort
                                  0
                                  • T tritanium

                                    Hallo Andreas, hallo Community,

                                    ich habe mich nun nach vielm Lesen und Testen des Scripts dazu durchgerungen, mal hier zu posten.

                                    Dein Script habe ich eingebaut und es funktioniert auch fehlerfrei.

                                    In den Aufzählungen sind folgende Melder drin:

                                    5c19ff90-f644-45c2-b05e-ff56d21a8d95-grafik.png

                                    Die Datenpunkte (deines Scripts) z.b. "Open Detectors" und auch andere unter "Output" funktionieren scheinbar korrekt, jedenfalls sehe ich bei Statusänderungen der Fenster auch die Datenpunkte sich ändern.
                                    Auch die "IgnoreOpen" funktionieren einwandfrei.

                                    Was mir komisch vorkommt, sind JAVASCRIPT "Warnungen", die ich nicht zuordnen kann und was diese zu bedeuten haben:

                                    8dcc715c-2e5a-45fe-a366-55499f4318d8-grafik.png

                                    Jedesmal, wenn ein Bewegungsmelder (KNX) bewegung dedektiert, kommt dieser "Warnungsblock", oder auch wenn ich ein Fenster öffne, oder schliesse

                                    Muss ich mir Sorgen machen ?? Oder darf ich das ignorieren... bzw. wie lassen sich diese Warnungn, wenn sie nicht tragisch sein sollten, deaktivieren??
                                    Bzw. was muss ich/kann ich tun um diese Warnungen zu beheben ?

                                    Sorry für so blöde Fragen, aber ich weis keinen Rat mehr, da ich kein Javascript behersche und bevor ich das Praktisch verwende, wollte ich sichergehen, das das Script auch korrekt läuft.

                                    Danke jedenfalls im voraus für eure/deine Hilfe :-)

                                    Gruß Michael

                                    andreaskosA Offline
                                    andreaskosA Offline
                                    andreaskos
                                    schrieb am zuletzt editiert von
                                    #119

                                    Hi Michael!

                                    Sorry für die späte Antwort! Freut mich, dass du auch KNX einsetzt! Nur interessehalber: verwendest du den openknx-Adapter oder den knx?

                                    Ich seh mir das an! Melde hier zurück sobald möglich. Bitte gib mir eine Woche dafür. ;-)

                                    LG Andreas

                                    T 1 Antwort Letzte Antwort
                                    0
                                    • andreaskosA andreaskos

                                      Hi Michael!

                                      Sorry für die späte Antwort! Freut mich, dass du auch KNX einsetzt! Nur interessehalber: verwendest du den openknx-Adapter oder den knx?

                                      Ich seh mir das an! Melde hier zurück sobald möglich. Bitte gib mir eine Woche dafür. ;-)

                                      LG Andreas

                                      T Offline
                                      T Offline
                                      tritanium
                                      schrieb am zuletzt editiert von
                                      #120

                                      @andreaskos

                                      Hi Andreas, derzeit verwende ich "noch" den knx Adapter. Eigentlich habe ich nicht geplant zu wechseln, aber man weiss ja nie.
                                      Spielt das denn eine Rolle ??
                                      Gibt es eigentlich eine Möglichkeit dein Script Zonenbasiert zu erweitern ?
                                      Ich würde nämlich gerne den Keller getrennt, vom Wohnraum absichern ...
                                      Spricht Zone Keller, getrennt scharf/unscharf/Meldelinien und Wohnraum (EG,OG,DG) scharf/unscharf/Meldelinien ....
                                      Wenn das ginge, wäre das TOP :-)

                                      Freu mich von dir zu lesen....

                                      andreaskosA 2 Antworten Letzte Antwort
                                      0
                                      • T tritanium

                                        @andreaskos

                                        Hi Andreas, derzeit verwende ich "noch" den knx Adapter. Eigentlich habe ich nicht geplant zu wechseln, aber man weiss ja nie.
                                        Spielt das denn eine Rolle ??
                                        Gibt es eigentlich eine Möglichkeit dein Script Zonenbasiert zu erweitern ?
                                        Ich würde nämlich gerne den Keller getrennt, vom Wohnraum absichern ...
                                        Spricht Zone Keller, getrennt scharf/unscharf/Meldelinien und Wohnraum (EG,OG,DG) scharf/unscharf/Meldelinien ....
                                        Wenn das ginge, wäre das TOP :-)

                                        Freu mich von dir zu lesen....

                                        andreaskosA Offline
                                        andreaskosA Offline
                                        andreaskos
                                        schrieb am zuletzt editiert von andreaskos
                                        #121

                                        @tritanium

                                        Hallo Michael,
                                        also - um es kurz zu machen: Es war ein Fehler im Script! Die Ignore-Open Flags wurden nicht korrekt eingetragen und diese werden aber bei jedem Melder-Event abgefragt.
                                        Die Fehlermeldung ist jetzt weg. Ich habe das Script im ersten Posting ganz oben bereits korrigiert neu reingestellt.

                                        Sorry, dass es so lange gedauert hat!

                                        Liebe Grüße
                                        Andreas

                                        1 Antwort Letzte Antwort
                                        0
                                        • T tritanium

                                          @andreaskos

                                          Hi Andreas, derzeit verwende ich "noch" den knx Adapter. Eigentlich habe ich nicht geplant zu wechseln, aber man weiss ja nie.
                                          Spielt das denn eine Rolle ??
                                          Gibt es eigentlich eine Möglichkeit dein Script Zonenbasiert zu erweitern ?
                                          Ich würde nämlich gerne den Keller getrennt, vom Wohnraum absichern ...
                                          Spricht Zone Keller, getrennt scharf/unscharf/Meldelinien und Wohnraum (EG,OG,DG) scharf/unscharf/Meldelinien ....
                                          Wenn das ginge, wäre das TOP :-)

                                          Freu mich von dir zu lesen....

                                          andreaskosA Offline
                                          andreaskosA Offline
                                          andreaskos
                                          schrieb am zuletzt editiert von
                                          #122

                                          @tritanium

                                          Achja, noch zu der Frage

                                          Gibt es eigentlich eine Möglichkeit dein Script Zonenbasiert zu erweitern ?

                                          Ja, die gibt's! ;-) Einfach das Script ein zweites mal kopieren und laufen lassen für die jeweilige Zone. In den Aufzählungen, die du dort angibst, kannst du dann beispielsweise alle Melder vom Keller reinschmeißen.

                                          T 1 Antwort Letzte Antwort
                                          0
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          890

                                          Online

                                          32.5k

                                          Benutzer

                                          81.6k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe