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

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

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

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    3.5k

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.
  • Homer.J.H Homer.J.

    @wykat bei dir sind es die Punkte 85-87 die musst du unter Aufzählung erstellen und deine jeweiligen Sensoren reinpacken.
    Hier https://forum.iobroker.net/topic/31657/test-adapter-alarm-1-1-x gibt es aber auch einen leicht zu konfigurierenten Adapter.

    W Offline
    W Offline
    wykat
    schrieb am zuletzt editiert von
    #90

    @Homer-J danke, denk hab's verstanden;
    Das script wird nicht mehr angepasst, aber sensoren werden unter Aufzahlungen (heist bei mir in English ENUM).
    Zuerst war diese option bei mir nicht eingeblendet (ENUM), jetzt ist es da
    Konnte auch unter functions das ENUM 'alarmanlage_aussenhat' erstellen, nur fehlt mir das '+' um etwas zu zufugen. Irgend etwas fehlt da noch. Kann's nur loschen oder andern, nicht editieren.

    c4c3a735-fca2-42b9-83b2-65de650f6e66-image.png

    Homer.J.H 1 Antwort Letzte Antwort
    0
    • W wykat

      @Homer-J danke, denk hab's verstanden;
      Das script wird nicht mehr angepasst, aber sensoren werden unter Aufzahlungen (heist bei mir in English ENUM).
      Zuerst war diese option bei mir nicht eingeblendet (ENUM), jetzt ist es da
      Konnte auch unter functions das ENUM 'alarmanlage_aussenhat' erstellen, nur fehlt mir das '+' um etwas zu zufugen. Irgend etwas fehlt da noch. Kann's nur loschen oder andern, nicht editieren.

      c4c3a735-fca2-42b9-83b2-65de650f6e66-image.png

      Homer.J.H Offline
      Homer.J.H Offline
      Homer.J.
      schrieb am zuletzt editiert von
      #91

      @wykat ändere mal die Ansicht dann muss ein Button editieren da sein und dort wählst du von deinen Sensoren den State aus.

      W 1 Antwort Letzte Antwort
      0
      • Homer.J.H Homer.J.

        @wykat ändere mal die Ansicht dann muss ein Button editieren da sein und dort wählst du von deinen Sensoren den State aus.

        W Offline
        W Offline
        wykat
        schrieb am zuletzt editiert von
        #92

        @Homer-J Hat etwas anders funktioniert :-/.
        Nach einblenden vom Enum und erstellen vom Enum.function.alarmanlage_aussen, Javascript neu gestartet und dann kann im objecten unter function die Enum alarmanlage ausgewahlt werden. Es muss das ganze modul gewahlt werden, nicht der alarm state. Alarm script neu gestartet und sensoren wurde erkannt. Wenn man es weis eigentlich sehr einfach. Keine problemen mit schreibweise.

        Jetzt habe ich leider andere problemen bekommen, ein z-wave modul funktioniert nicht mehr. Value steht jetzt auf 'number' wo es fruher nur boolean angezeigt hat. Werde es einmal ausklinken und wieder neu einbinden. so das es neu installiert wird.

        Beim Homematic sensor wird wahrscheinlich das falsche open/closed gemeldet "Closed(0)". Noch nicht sicher wie ich das andern kann.

        Durch diese 2 fehler kann die alarmanlage dann nicht mehr aktiviert werden, ohne sensoren geht's wieder.

        F 1 Antwort Letzte Antwort
        0
        • W wykat

          @Homer-J Hat etwas anders funktioniert :-/.
          Nach einblenden vom Enum und erstellen vom Enum.function.alarmanlage_aussen, Javascript neu gestartet und dann kann im objecten unter function die Enum alarmanlage ausgewahlt werden. Es muss das ganze modul gewahlt werden, nicht der alarm state. Alarm script neu gestartet und sensoren wurde erkannt. Wenn man es weis eigentlich sehr einfach. Keine problemen mit schreibweise.

          Jetzt habe ich leider andere problemen bekommen, ein z-wave modul funktioniert nicht mehr. Value steht jetzt auf 'number' wo es fruher nur boolean angezeigt hat. Werde es einmal ausklinken und wieder neu einbinden. so das es neu installiert wird.

          Beim Homematic sensor wird wahrscheinlich das falsche open/closed gemeldet "Closed(0)". Noch nicht sicher wie ich das andern kann.

          Durch diese 2 fehler kann die alarmanlage dann nicht mehr aktiviert werden, ohne sensoren geht's wieder.

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

          @andreaskos

          Hey, erstmal Danke für das tolle Script, hat mir ne Menge Arbeit abgenommen, zumal ich von Java-Script 0-Ahnung habe :-)
          Hab auch die Alarmanlage schon ein paar Wochen in Gebrauch und funktioniert 1A.

          Jetzt hätte ich aber ggf. ein Anliegen, falls möglich :blush:
          Wenn nicht umsetzbar oder zu zeitaufwändig ist das aber nicht schlimm.

          Ausgangslage:
          Ich habe div. Sensoren (Aqara 6x BWM, 15x Tür-/Fensterkontakte) in der Alarmanlage integriert.

          Jetzt ist es so, dass in den Sommermonaten oft einzelne Fenster in der Nacht offen sind und dadurch die Alarmanlage nicht aktiv geschaltet werden kann da diese ja auf "true" stehen, bzw. wenn wir Nachts mal ein Fenster öffnen die Alarmanlage anschlägt, ganz zum Leidwesen meiner Frau.
          Die BWM kann ich ja durch den "Alarmanlage_Innenraum" dafür separat deaktivieren, nur geht das schlecht bei der "Alarmanlage_Aussenhaut" mit den Fenstern. Dann brauch ich gleich keine Alarmanlage aktivieren :joy:

          Idee:
          Ich würde für alle Sensoren einen zusätzlichen DP anlegen und mit true/false ausstatten.
          Über diese DP´s würde ich der Alarmanlage gerne sagen, welche Sensoren verwendet werden sollen und welche nicht.
          So könnte ich nach Bedarf einzelne Sensoren deaktivieren und die Alarmanlage würde trotzdem funktionieren.

          Frage:
          Wäre es möglich, in das Script noch eine Funktion/Abfrage einzubauen, so wie in etwa....

          • Wenn DP xyz = true dann verwende den Sensor in Alarmanlage
          • Wenn DP xyz = false dann verwende den Sensor für die Alarmanlage nicht

          Hoffe ich konnte meinen Gedankengang einigermaßen verständlich erklären :worried:

          P.S.: Vielleicht hat ja jemand anderes so ein Problem auf eine andere Weise realisiert oder umgesetzt?
          Über Ideen oder Vorschläge bin ich offen :-)

          Grüße
          Freaknet

          1 Antwort Letzte Antwort
          0
          • L Offline
            L Offline
            LaBamba
            schrieb am zuletzt editiert von LaBamba
            #94

            @homer-j said in Umfassendes Alarmanlagen-Skript:
            Github erlaubt mir nicht das Material Design CSS Version 2 von Uhula zu nutzen.

            1 Antwort Letzte Antwort
            0
            • andreaskosA andreaskos

              Liebe Community!

              Kurzfassung
              Hier stelle ich ein Skript für eine Alarmanlage vor. Einfach die Einstellungen im Skript anpassen und über die erzeugten Datenpunkte (default unter javascript.0.Alarmanlage) steuern.

              LG Andreas

              Langfassung


              Beruflich benutze ich immer wieder mal ioBroker als Smart Home Systemintegrator. Wir errichten mit meiner Firma aber auch ganz normale Alarmanlagen. Hier müssen es (hauptsächlich aus Gründen der Förderung oder Versicherung) oftmals Anlagen sein mit VSÖ-Plakette. Das bedeutet, dass diese nach der ÖNORM-R2 errichtet werden müssen und die verwendeten Komponenten ein Zertfikat benötigen.
              In anderen Fällen - speziell wenn wir das BUS-System KNX verwenden - kommt ein eigenes Sicherheitsmodul von ABB zum Einsatz, das die Alarmanlagen-Funktion abbildet.
              Ich habe mir schon oft gedacht, dass mit ioBroker doch auch eine schöne Alarmanlagen-Funktion umsetzbar wäre. Natürlich, es ist nicht so eine stabile Lösung und schon gar keine zertifizierbare, aber immerhin: in meinen Augen ist eine solche Alarmanlage immer noch besser als gar keine. Ich habe deshalb beschlossen - nur so für mich zum Spaß - einmal eine "echte" Alarmanlage mit ioBroker Javascript nachzubilden. Ich hab die Funktion des ABB-Sicherheitsmoduls als Inspiration genommen und die grundlegenden Funktionen übernommen.
              Bei der Überwachung der Einbruchsmelder erfolgt keine separate Überwachung auf Sabotage. Dies ist in der Ausführung Privat Standard in Österreich laut R2 nicht nötig. In Deutschland ist es denke ich recht ähnlich, da wir ja auch die gleichen Produkte einsetzen, die es ja auch für D gibt, z.B. Jablotron oder Telenot.
              Hier möchte ich das Ergebnis zeigen.

              Aufbau
              Die Alarmanlage besteht aus folgenden Komponenten:

              • Schaltstellen für scharf/unscharf Schaltung
              • Alarmgeber
              • Einbruchsmelder

              Außer den Einbruchsmeldern werden alle Punkte NUR als Datenpunkte angelegt, über die eine weitere Interaktion erfolgen kann. Hierfür bietet ioBroker ja zahlreiche Möglichkeiten wie die Einbindung in eine Visualisierung, die Verwendung in Scripts, Szenen, Blocklys und so weiter.
              Für die Einbruchsmelder werden States aus ioBroker verwendet, die true beim Auslösen sind und false in Ruhe (wenn sie geschlossen sind). Die Namen der Melder sollten sinnvoll vergeben sein, gegebenenfalls daher die name-Attribute der Objekte in ioBroker noch anpassen. Die Melder müssen in Aufzählungen (ENUMs) in ioBroker eingefügt werden. Per default (kann in den Experteneinstellungen im Skript geändert werden) sind das die folgenden Aufzählungen:

              • alarmanlage_aussenhaut
                In dieser Aufzählung befinden sich alle Melder der äußeren Hülle, die überwacht werden soll. Hier gehören Öffnungskontakte, Glasbruchsensoren, Riegelschaltkontakt, etc. hinein.
              • alarmanlage_innenraum
                Hier werden die Melder für die Innenraum-Überwachung zusammengefasst. Das sind im wesentlichen Bewegungsmelder, Näherungssensoren, eventuell auch ganz normale Taster (z.B. für Licht etc.).
              • alarmanlage_verzoegert
                Melder, welche für einen Eingang benötigt werden, der bei Auslösung zu einem verzögerten Alarm führt. Damit kann durch der überwachte Bereich durch die Eingangstür betreten werden und danach (innerhalb der Eingangsverzögerung) unscharf gestellt werden.

              Funktion: scharf/unscharf Schalten
              Grundsätzlich kann die Alarmanlage extern oder intern scharf geschaltet werden. Extern bedeutet, dass sich der Bediener selbst extern aufhält und somit alle verfügbaren Melder verwendet werden.
              Intern bedeutet, dass sich der Bediener intern aufhält und somit nur die Melder zur Überwachung der Außenhaut verwendet werden.
              Die Scharfschaltung für Extern kann auch verzögert erfolgen. Dabei läuft eine Ausgangsverzögerungszeit ab nach dem Schaltbefehl. Nach dem Ende der Verzögerungszeit erfolgt erst die tatsächliche Scharfschaltung.

              Das bedeutet also, dass Melder in Außenhaut oder Innenraum eingeteilt werden. Zusätzlich können Melder aus diesen Gruppen auch als verzögert gelten. Diese drei Gruppen von Meldern müssen in den entsprechenden Aufzählungen enthalten sein.

              ACHTUNG: Scharf (egal, ob extern oder intern) kann nur geschaltet werden, wenn sich alle Melder in Ruhe befinden, also geschlossen sind! Sollte das nicht der Fall sein, so ist die Anlage nicht bereit zur Scharfschaltung. Dies wird in einem eigenen Ready-Datenpunkt angezeigt, sowie im AlarmText.
              Sollte eine Scharfschaltung eingehen, obwohl die Anlage nicht bereit ist, so wird ein Fehler bei der Scharfschaltung durch den Error-Datenpunkt und wieder einem entsprechenden AlarmText angezegt.
              Das kann auch dazu führen, dass bei verzögertem scharf Schalten ein Fehler bei der Scharfschaltung auftritt, den man unter Umständen nicht mehr bemerkt, weil man schon das Haus verlassen hat. Das muss man wissen oder sich einen Hinweis darauf erzeugen, zB durch ein Skript, etwa das Versenden einer Telegram-Meldung im Fehlerfall.

              Funktion: Alarm geben
              Bei scharf gestellter Anlage wird bei Auslösung eines Melders geprüft, welcher Schaltzustand vorherrscht (intern/extern) und welchen Meldergruppen der auslösende Melder zuzuordnen ist. Davon abhängig wird Alarm ausgelöst oder die Eingangsverzögerung gestartet. Nach dieser erfolgt die Alarmierung, sofern nicht zwischenzeitlich unscharf geschaltet wird.

              Bei den Alarmgebern werden drei Datenpunkte angeboten:
              Der AlarmAccoustical ist der akustische Alarm, dieser darf in Ö übrigens 3 Minuten nicht übersteigen. Die Werte bei den Einstellungen werden in Sekunden eingegeben, also maximal 180 Sekunden (keine eingebaute Beschränkung im Skript).
              Der AlarmOptical ist der optische Alarm. Dieser darf so lange dauern, wie gewünscht. Soll er ewig antehen bis zum nächsten unscharf, dann kann die Zahl -1 für die Dauer verwendet werden.
              Der ganz normale Alarm Datenpunkt steht immer auf true, wenn ein Alarm ausgelöst wurde bis zum nächsten unscharf.

              Bedienung oder Verwendung der Input-Datenpunkte
              Über die States im Unterpunkt Input kann die Anlage scharf/unscharf geschaltet werden.
              Mit dem Wert true auf den Datenpunkten erfolgt der Schaltbefehl unmittelbar oder verzögert im Falle von SwitchExternalDelayed.
              Mit dem Wert false wird immer sofort auf unscharf geschaltet.

              Mit unscharf erfolgt auch immer ein Reset der Anlage, d.h. alle Alarme werden beendet und der Status- und Alarmtext entsprechend angepasst.

              Es kann nicht von einem Scharf-Zustand auf einen anderen Scharf-Zustand gewechselt werden, es muss immer dazwischen unscharf geschaltet werden, ansonsten wird ein "Fehler bei der Scharfschaltung" geworfen.

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

              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.

              Verwendung der Output-Datenpunkte
              Über die Output-Datenpunkte können die Alarmgeber angesteuert werden (z.B. über ein zusätliches Script oder Blockly). Es gibt auch eine Menge an weiteren Datenpunkten, die für zusätzliche Funktionen oder Anzeigen in Visualisierungen nützlich sein können. Hier eine Auflistung mit kurzer Erklärung:

              • Active: Schaltzustand der Anlage insgesamt, true=scharf, false=unscharf. [boolean]
              • ActiveInternal: Anlage intern scharf [boolean]
              • ActiveExternal: Anlage extern scharf [boolean]
              • ActiveNumber: gibt Auskunft über den tatsächlichen Zustand mit den Ziffern:
                0 ... unscharf
                1 ... intern scharf
                2 ... extern scharf
                3 ... Eingangsverzögerung aktiv
                4 ... Ausgangsverzögerung aktiv
              • Alarm: true=Alarm ausgelöst, false=kein Alarm [boolean]
              • AlarmAccoustical: Akustischer Alarm aktiv [boolean]
              • AlarmOptical: Optischer Alarm aktiv [boolean]
              • Ready: Anlage bereit zur Scharfschaltung [boolean]
              • EntryDelayActive: Eintrittsverzögerung aktiv [boolean]
              • ExitDelayActive: Ausgangsverzögerung aktiv [boolean]
              • AlarmingDetector: Name des auslösenden Melders [string]
              • AlarmingDetectorJSON: Name und alle weiteren verfügbaren Eigenschaften des auslösenden Melderobjektes und dessen Parent- und ParentsParent-Objekt im JSON-Format. [string]
              • OpenDetectors: Namen aller offenen Melder [string]
              • OpenDetectorsJSON: JSON-String wie beim AlarmingDetector mit Liste aller offenen Melder [string]
              • OpenDetectorsOuterSkingJSON: JSON-String wie beim AlarmingDetector mit Liste aller offenen Melder der Außenhaut [string]
              • OpenDetectorsIndoorJSON: JSON-String wie beim AlarmingDetector mit Liste aller offenen Melder des Innenraums [string]
              • StatusText: Gibt Auskunft über Schaltzustand und aktive Verzögerungen [string]
              • AlarmText: Gibt Auskunft über Alarmzustand und Bereitschaft oder Fehler bei der Scharfschaltung [string]
              • OpenDetectorsIgnoreOpen Liste der offenen Melder mit gesetztem IgnoreOpen-Flag. 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.

              Die Texte, die in den Text-Datenpunkten verwendet werden, können in den Einstellungen im Skript angepasst werden.

              Das Skript

              /*
              ########################################################################################################################
              # 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.ä.
              # 2022-03-20    Andreas Kos	Verbesserung beim Laden der Parents- und Parentsparents-Objekte und
              #                               Umbau auf aktuellen Javascript-Adapter mit Ack-Flags bei createState und setState
              # 2022-12-02    Andreas Kos     Korrektur beim Prüfen der IgnoreOpen-Flags.
              # 2022-12-18    Andreas kos     Korrektur beim Anlegen der States, sodass ein Neustart des Scripts eine weitere
              #                               Funktion der Anlage garantiert, auch, wenn diese zuvor im Zustand "scharf" war.
              ########################################################################################################################
              */
              
              // 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 = 3;                           // 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, true);
                          } else {
                              setState(idExitDelayActive, true, 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, 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, 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, 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, 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, true);
                          } else {
                              setState(idExitDelayActive, true, 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, true);
              });
               
              // 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, true);
                  setStateDelayed(idAlarmAccoustical, true, true, entryDelay * 1000, true);
                  setStateDelayed(idAlarmOptical, true, true, entryDelay * 1000, true);
              });
               
              // 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, true);
              });
               
              // Auf Akustischen Alarm reagieren
              on ({id: idAlarmAccoustical, val: true, change: "ne"}, function(obj){
                  if (loglevel >= 1) log ("ALARM is active!");
                  setState(idEntryDelayActive, false, true);
                  setState(idAlarmText, textAlarmActive, true);
                  setState(idAlarm, true, true);
                  setStateDelayed(idAlarmAccoustical, false, true, alarmDurationAccoustical * 1000, true);
                  if (getState(idActiveExternal).val) setState(idStatusText, textStatusActiveExternal, true);
                  if (getState(idActiveInternal).val) setState(idStatusText, textStatusActiveInternal, true);
              });
               
              // Auf Optischen Alarm reagieren
              on ({id: idAlarmOptical, val: true, change: "ne"}, function(obj){
                  if (alarmDurationOptical >= 0)
                      setStateDelayed(idAlarmOptical, false, true, alarmDurationOptical * 1000, true);
              });
               
              // 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, true);
                          setState(idReady, false, true);
                      return false;
                  } else {
                      if (getState(idActive).val && !getState(idAlarm).val)
                          // kein offener Melder gefunden und scharf und kein Alarm
                          setState(idAlarmText, textAlarmInactive, true);
                      else if (!getState(idActive).val)
                          // kein offener Melder gefunden und unscharf
                          setState(idAlarmText, textReady, true);
                          setState(idReady, true, 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++]]);
                  }
                  addIgnoreOpenFlags();
                  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, true);
                  setState(idAlarmingDetectorJSON, JSON.stringify(  getDetectorObject(obj.id)  ), true);
               
                  // 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, true);
                              else {
                                  if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                                  setState(idAlarmAccoustical, true, true);
                                  setState(idAlarmOptical, true, true);
                              }
                          } else {
                              if (loglevel >= 3) log ("Detector is not delayed");
                              setState(idAlarmAccoustical, true, true);
                              setState(idAlarmOptical, true, 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, true);
                              else {
                                  if (loglevel >= 3) log ("EntryDelay was already active, alarming now");
                                  setState(idAlarmAccoustical, true, true);
                                  setState(idAlarmOptical, true, true);
                              }
                          } else {
                              if (loglevel >= 3) log ("Detector is not delayed");
                              if (loglevel >= 2) log ("System is ALARMING now!");
                              setState(idAlarmAccoustical, true, true);
                              setState(idAlarmOptical, true, 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);
                  if (!existsState(id)){
                      createState(
                          id, 
                          val,
                          {
                              read: !writeaccess, 
                              write: writeaccess, 
                              name: descr,
                              type: typ,
                              def: val,
                              role: role ? role : "state"
                          },
                          function() {
                              setState(id, val, true);
                              if (loglevel >= 3) log ("ID " + id + " sucessfully created.");
                          }
                      );
                  } else {
                      if (loglevel >= 3) log ("ID " + id + " already existed.");
                  }
              }
               
              // 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);
                  if (!existsState(id)){
                      createState(id, val, {  read: true, 
                                          write: writeaccess, 
                                          name: descr,
                                          type: typ,
                                          def: val,
                                          min: minimum, 
                                          max: maximum, 
                                          states: list,
                                          role: role ? role : "state"
                      });
                  } else {
                      if (loglevel >= 3) log ("ID " + id + " already existed.");
                  }
              }
              
              // 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, true, "switch");
                      detectorsIgnoreOpen[i].push(idBase + detectorName);
                      i++;
                  }
              }
              
              // Funktion addIgnoreOpenFlags
              // ==============================
              // Parameter:       Keine
              // Funktion:        Fügt dem Array für die Ignore-Open Datenpunkte die Flags hinzu.
              // Rückgabewert:    Keiner.
              function addIgnoreOpenFlags(){
                  var detectorName;
                  var idBase = "javascript." + javascriptInstance + "." + pathToCreatedStates + ".Input.IgnoreOpen.";
                  var i=0;
                  while (i<detectorsOuterSkin.length) {
                      detectorName = getObject(detectorsOuterSkin[i]).common.name.replace(/\./g,"_");
                      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, true);
                  var ok = checkDetectors(detectorsOuterSkin.concat(detectorsIndoor));
                  if (ok) {
                      setState(idActiveExternal, true, true);
                      setState(idActive, true, true);
                      setState(idStatusText, textStatusActiveExternal, true);
                      setState(idAlarmText, textAlarmInactive, true);
                      setState(idAlarmingDetector,"", true);
                      setState(idError, false, true);
                      if (loglevel >= 2) log ("Switched to External Active");
                  } else {
                      if (loglevel >= 2) log ("NOT ready to switch to External Active!");
                      setState(idError, true, 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, true);
                      setState(idActive, true, true);
                      setState(idStatusText, textStatusActiveInternal, true);
                      setState(idAlarmText, textAlarmInactive, true);
                      setState(idAlarmingDetector,"", true);
                      setState(idError, false, true);
                      if (loglevel >= 2) log ("Switched to Internal Active");
                  } else {
                      if (loglevel >= 2) log ("NOT ready to switch to Internal Active!");
                      setState(idError, true, 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, true);
                  setState(idExitDelayActive, false, true);
                  setState(idActiveExternal, false, true);
                  setState(idActiveInternal, false, true);
                  setState(idActive, false, true);
                  setState(idError, false, true);
                  clearStateDelayed(idAlarmAccoustical);
                  clearStateDelayed(idAlarmOptical);
                  setState(idAlarmAccoustical, false, true);
                  setState(idAlarmOptical, false, true);
                  setState(idAlarm, false, true);
                  setState(idAlarmText, textAlarmInactive, true);
                  setState(idStatusText, textStatusInactive, true);
                  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, true);
                      else
                          setState(idActiveNumber, 0, true);
                  }
                  if (internal) setState(idActiveNumber, 1, true);
                  if (external){
                      if (entry)
                          setState(idActiveNumber, 3, true);
                      else
                          setState(idActiveNumber, 2, true);
                  }
              }
               
              // 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, true);
                  setState(idOpenDetectorsWithIgnoreOpenFlagSet, textListOfDetectorsIgnoreOpen, true);
                  setState(idOpenDetectorsJSON, JSON.stringify(objOpenDetectors), true);
                  setState(idOpenDetectorsOuterSkinJSON, JSON.stringify(objOpenDetectorsOuterSkin), true);
                  setState(idOpenDetectorsIndoorJSON, JSON.stringify(objOpenDetectorsIndoor), true);
               
                  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 (falls es welche gibt)
                  var obj    = getObject(id);
                  var objParent = null;
                  if ($('state[id=' + idParent + '$]').length > 0) {
              
                      objParent = getObject(idParent);
                  }
                  var objParentsParent = null;
                  if ($('state[id=' + idParentsParent + '$]').length > 0) {
                      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;
              }
              

              Änderungshistorie

              • 2020-05-01, Erstellung
              • 2020-05-02, Number-Datenpunkte für Ein- und Ausgabe des Schaltzustands (Idee von @Homer.J.)
              • 2020-05-03, Korrekturen, u.a. für Melderauswertung (chage: "ne") & Status-Text
              • 2020-05-04, 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, 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.
                Außerdem 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.ä.
              • 2022-03-20 Andreas Kos Verbesserung beim Laden der Parents- und Parentsparents-Objekte und Umbau auf aktuellen Javascript-Adapter mit Ack-Flags bei createState und setState
              • 2022-12-02 Andreas Kos Korrektur beim Prüfen der IgnoreOpen-Flags.
              • 2022-12-18 Andreas kos Korrektur beim Anlegen der States, sodass ein Neustart des Scripts eine weitere Funktion der Anlage garantiert, auch, wenn diese zuvor im Zustand "scharf" war.
              L Offline
              L Offline
              LaBamba
              schrieb am zuletzt editiert von
              #95

              @andreaskos

              Hallo, ich habe eine Frage zur Einbindung von Nuki!
              Sehe ich es richtig, dass nur Sensoren funktionieren die den Wert true/false ausgeben.
              Beim Nuki Türschloss ist es der Wert 2 oder 3. Ist es irgendwie möglich, dies in die Alarmanlage einzubinden?
              Viele Grüße

              1 Antwort Letzte Antwort
              0
              • W Offline
                W Offline
                wizard2010
                schrieb am zuletzt editiert von
                #96

                Hi @andreaskos, nice work with this very good initiative.
                I'm trying to get this work with my setup using KNX, but I've facing some issues, I'm doing this configuration:

                // Arrays für die Melder
                var detectorsOuterSkin = [
                    'knx.0.Corredor.Status.PORTA_ENTRADA_STATUS',
                    'knx.0.Cozinha.Status.COZ_DOOR_STATUS',
                    'knx.0.Arrumos.Status.LAV_DOOR_STATUS',
                    'knx.0.Escritório.Status.ESC_WINDOW_STATUS',
                    'knx.0.Sala_de_Estar.Status.SALA_DOOR_DIR_STATUS',
                    'knx.0.Sala_de_Estar.Status.SALA_DOOR_ESQ_STATUS',
                    'knx.0.Suite.Status.SUI_DOOR_STATUS',
                    'knx.0.Suite.Status.SUI_WC_WINDOW_STATUS'
                ];
                var detectorsIndoor = [];
                var detectorsDelayed = [];
                 
                

                But this seems that is not working.
                Can you tell me if I'm doing this in the right way?
                By the way, can you please also tell me where is the latest version of the script and VIS?

                Really good work.
                Thank you.

                1 Antwort Letzte Antwort
                0
                • andreaskosA Offline
                  andreaskosA Offline
                  andreaskos
                  schrieb am zuletzt editiert von andreaskos
                  #97

                  Hi folks,

                  Danke für euer Interesse an dem Skript. Ich möchte mich für die späte Reaktion entschuldigen und auf eure Anfragen eingehen:

                  @Freaknet
                  Die Funktion über die einzene Ausnahme von Meldern ist etwas, das man öfter brauchen könnte. Hast du immer noch Bedarf? Ich werde das einbauen, nur widme ich derzeit meine Zeit vorwiegend anderen Dingen. Ich werde hier posten, wenn es soweit ist, aber leider kann ich keine Deadline angeben momentan.

                  @LaBamba
                  Du muss rausfinden, was das Schloss von sich gibt, bei den unterschiedlichen Zuständen. Ich kenne es selbst leider nur aus der Werbung, aber etwa so:
                  1 = geschlossen
                  2 = offen
                  Und dann kannst du mit einem Skript den Zustand übersetzen. Möglicherweise geht das noch eleganter mit einem Alias, siehe hier, aber damit kenne ich mich leider nicht so gut aus.

                  @wizard2010
                  It all seems right. Please check the settings of your KNX adapter. You can define if it uses 1 and 0 or instead true and false for the KNX datapoints. This could be the reason. You should set it to true/false.
                  The latest version of the script can be found in the first post if this thread.

                  Best regards
                  Andreas

                  F 1 Antwort Letzte Antwort
                  0
                  • andreaskosA Offline
                    andreaskosA Offline
                    andreaskos
                    schrieb am zuletzt editiert von andreaskos
                    #98

                    @wizard2010
                    One more thing: did you check, if the states can trigger anything? Often the flags for the corresponding groups are not correctly set after importing the knxproj-file by the KNX adapter. Maybe you should have a look at the read/write/update flags on the objects tab. There you should set them read=true, write=false, update=true.

                    1 Antwort Letzte Antwort
                    0
                    • SchmakusS Offline
                      SchmakusS Offline
                      Schmakus
                      Developer
                      schrieb am zuletzt editiert von
                      #99

                      Hi,
                      schönes Script! Ich hätte jedoch noch einen Vorschlag bezüglich der Scharfstellung bei geöffneten Fenstern.
                      Grundsätzlich sollten ja alle Fenster geschlossen sein, wenn man das Haus verlässt und die Alarmanlage scharf schaltet.
                      Jedoch gibt es Fenster im Haus, welche gerne gekippt sind, jedoch für einen Einbrecher nahezu nicht erreichbar sind.
                      Das wären Kellerfenster, welche durch das gesicherte Gitter des Schachts unzugänglich sind, oder Fenster im OG, welche nur über eine Leiter erreichbar sind.

                      Der Anwender sollte die Möglichkeit haben, selbst zu entscheiden, welche Fenster "offen" sein dürfen, wenn die Anlage scharf geschaltet wird.
                      Ein Ändern des Zustands von Offen => Zu => Offen würde dann zum Auslösen der Anlage führen.

                      Die ließe sich entweder über eine weitere Aufzählung lösen z.B.: "Alarmanlage_Innenraum_IgnoreOpen" oder für jede Aufzählung wird ein separater Datenpunkt erzeugt, über welchen "IgnoreOpen" ein- und ausgeschaltet werden kann. Das mit dem Datenpunkt ist sogar die bessere Alternative, da man darüber mehr Kontrolle hat und ggf. diesen auch über andere Scripte steuern könnte.

                      Abschließend sollte dies natürlich auch zurückgemeldet werden. D.h. wenn die Alarmanlage scharf geschaltet wird, obwohl ein Fenster gewollt offen ist, sollte ein Datenpunkt dies anzeigen. So kann man es in der Visu anzeigen lassen, als unterschiedliche Farbe einer Lampe oder Alexa weißt einen darauf hin.
                      Beim Verlassen des Hause bleibt es dann jedem selbst überlassen, ob er mit diesem "Sicherheitsrisiko" leben kann, oder nicht.

                      Grüße
                      Markus

                      Dev of LightControl Adapter, Contributor of HUE and DoorBird Adapter

                      1 Antwort Letzte Antwort
                      0
                      • S Offline
                        S Offline
                        Straty
                        schrieb am zuletzt editiert von
                        #100

                        Guten Abend zusammen.
                        Sehr schönes Script und vielen dank an Andreas, das es soweit auch veröffentlicht wurde.
                        Ich habe leider noch ein kleines Problem mit der Alarmierung über die beiden Outputs AlarmAccoustical bzw. AlarmOptical.
                        Nach auslösen vom Alarm werden beide states auf TRUE gesetzt. Soweit so gut. nach Ablauf der Delaytime werden auch beide auf FALSE zurück gesetzt, jedoch bei erneutem Wechsel eines Sensors von FALSE auf TRUE gehen beide wieder in den TRUE zustand und durchlaufen wieder die Delaytime. Ist das ganze so gewollt oder eventuell nur bei mir ein Fehler, der nicht da sein sollte.
                        Das ganze läuft auf einem PI3B+ auf dem nur IoBroker läuft.
                        mfg Philip

                        andreaskosA 1 Antwort Letzte Antwort
                        0
                        • andreaskosA andreaskos

                          Hi folks,

                          Danke für euer Interesse an dem Skript. Ich möchte mich für die späte Reaktion entschuldigen und auf eure Anfragen eingehen:

                          @Freaknet
                          Die Funktion über die einzene Ausnahme von Meldern ist etwas, das man öfter brauchen könnte. Hast du immer noch Bedarf? Ich werde das einbauen, nur widme ich derzeit meine Zeit vorwiegend anderen Dingen. Ich werde hier posten, wenn es soweit ist, aber leider kann ich keine Deadline angeben momentan.

                          @LaBamba
                          Du muss rausfinden, was das Schloss von sich gibt, bei den unterschiedlichen Zuständen. Ich kenne es selbst leider nur aus der Werbung, aber etwa so:
                          1 = geschlossen
                          2 = offen
                          Und dann kannst du mit einem Skript den Zustand übersetzen. Möglicherweise geht das noch eleganter mit einem Alias, siehe hier, aber damit kenne ich mich leider nicht so gut aus.

                          @wizard2010
                          It all seems right. Please check the settings of your KNX adapter. You can define if it uses 1 and 0 or instead true and false for the KNX datapoints. This could be the reason. You should set it to true/false.
                          The latest version of the script can be found in the first post if this thread.

                          Best regards
                          Andreas

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

                          @andreaskos said in Umfassendes Alarmanlagen-Skript:

                          Hi folks,

                          Danke für euer Interesse an dem Skript. Ich möchte mich für die späte Reaktion entschuldigen und auf eure Anfragen eingehen:

                          @Freaknet
                          Die Funktion über die einzene Ausnahme von Meldern ist etwas, das man öfter brauchen könnte. Hast du immer noch Bedarf? Ich werde das einbauen, nur widme ich derzeit meine Zeit vorwiegend anderen Dingen. Ich werde hier posten, wenn es soweit ist, aber leider kann ich keine Deadline angeben momentan.

                          Hey @andreaskos,

                          erstmal Danke für Deine Rückmeldung :-)
                          Bedarf besteht natürlich noch immer, gerade jetzt dann wo die "warmen" Sommermonate anstehen. :stuck_out_tongue_winking_eye:
                          Meld dich einfach falls Du dazu kommst, bin gerne bereit auch als Tester zu fungieren.

                          Grüße
                          Freaknet

                          1 Antwort Letzte Antwort
                          0
                          • S Straty

                            Guten Abend zusammen.
                            Sehr schönes Script und vielen dank an Andreas, das es soweit auch veröffentlicht wurde.
                            Ich habe leider noch ein kleines Problem mit der Alarmierung über die beiden Outputs AlarmAccoustical bzw. AlarmOptical.
                            Nach auslösen vom Alarm werden beide states auf TRUE gesetzt. Soweit so gut. nach Ablauf der Delaytime werden auch beide auf FALSE zurück gesetzt, jedoch bei erneutem Wechsel eines Sensors von FALSE auf TRUE gehen beide wieder in den TRUE zustand und durchlaufen wieder die Delaytime. Ist das ganze so gewollt oder eventuell nur bei mir ein Fehler, der nicht da sein sollte.
                            Das ganze läuft auf einem PI3B+ auf dem nur IoBroker läuft.
                            mfg Philip

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

                            @straty
                            Hi! Ja, das Verhalten wäre so in Ordnung. Solange die Anlage scharf ist, geht der Alarm für die eingestellte Dauer los, wenn ein Melder anschlägt. Auch, wenn der Alarm zu diesem Zeitpunkt zuvor schon einmal durchlaufen wurde.
                            LG Andreas

                            1 Antwort Letzte Antwort
                            0
                            • 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 Offline
                                BBTownB Offline
                                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.0.7 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
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          754

                                          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