Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. [Script] MessageHandler: Nachrichten protokollieren +VIS

    NEWS

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    • Minor js-controller 7.0.7 Update in latest repo

    [Script] MessageHandler: Nachrichten protokollieren +VIS

    This topic has been deleted. Only users with topic management privileges can see it.
    • T
      Tirador last edited by Tirador

      Ich habe nun die neue Version veröffentlicht.
      Enthält nun pushover als Nachrichtenereignis.
      Außerdem wurde die Vis Ausgabe überarbeitet.
      Falls ihr gefallen an dem Skript habt wäre ein Daumen hoch im ersten Post toll!

      1 Reply Last reply Reply Quote 1
      • S
        Saschag @Tirador last edited by

        @Tirador

        Super, Danke 😊

        1 Reply Last reply Reply Quote 0
        • K
          kilasat last edited by

          Hallo @Tirador bevor ich etwas falsches mache. Bei der Installation steht :

          Das Javascript "MessageGlobal" als globales Script installieren und starten.

          *Das Javascript "MessageHandler" serverseitiges Script installieren und starten-5 Sek warten-stoppen-starten. Beim 1.Start werden die notwendigen States unter STATE_PATH = '0_userdata.0.messageHandler.' erzeugt. Erst beim 2.Start instanziiert das Script die Event-Handler und läuft dann.

          Das Javascript "MessageStateCreator" installieren und starten (optional)*

          Was ist den ein "globales Script" und ein "serverseitiges Script" ?

          Uhula 1 Reply Last reply Reply Quote 0
          • Uhula
            Uhula @kilasat last edited by

            @kilasat sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

            Was ist den ein "globales Script" und ein "serverseitiges Script" ?

            Serverseitig sind alle, die auf dem Server laufen, also in einer Javascript-Instanz dort:
            0344cb72-bc44-4642-8a7b-4b2ea9ef4020-image.png

            Dort wiederum ist ein globales Script ein solches, welches im Script-Ordner global abgelegt wird:
            31e94801-5b80-42cc-8835-18639cc6b606-image.png

            K 1 Reply Last reply Reply Quote 0
            • K
              kilasat @Uhula last edited by

              @Uhula sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

              @kilasat sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

              Was ist den ein "globales Script" und ein "serverseitiges Script" ?

              Serverseitig sind alle, die auf dem Server laufen, also in einer Javascript-Instanz dort:
              0344cb72-bc44-4642-8a7b-4b2ea9ef4020-image.png

              Dort wiederum ist ein globales Script ein solches, welches im Script-Ordner global abgelegt wird:
              31e94801-5b80-42cc-8835-18639cc6b606-image.png

              Danke. War bei mir ausgeblendet!

              1 Reply Last reply Reply Quote 0
              • K
                kilasat last edited by

                Muss ich nicht verwendete Message_IDs auskommentieren?

                D T 2 Replies Last reply Reply Quote 0
                • D
                  der-eine @kilasat last edited by

                  @kilasat ja, weil sonst das Skript nicht läuft.

                  1 Reply Last reply Reply Quote 1
                  • T
                    Tirador @kilasat last edited by

                    @kilasat said in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                    Muss ich nicht verwendete Message_IDs auskommentieren?

                    Nur im MessageStateCreator. Im MessageHandler kannst du die IDS stehen lassen.

                    1 Reply Last reply Reply Quote 0
                    • D
                      der-eine last edited by

                      @Tirador ist das nur bei mir so das die Icons abgeschnitten werden? 🤷‍♂️ 😟

                      IMG_7303.PNG

                      S T 2 Replies Last reply Reply Quote 0
                      • S
                        Saschag @der-eine last edited by

                        @der-eine

                        bei mir nicht in ioBroker iPhone App

                        D 1 Reply Last reply Reply Quote 0
                        • D
                          der-eine @Saschag last edited by

                          @Saschag danke für die Info. 👍

                          S 1 Reply Last reply Reply Quote 0
                          • OstfrieseUnterwegs
                            OstfrieseUnterwegs last edited by

                            Gibt es eine Möglichkeit den Text einer Auswahlliste anzuzeigen?
                            Mein Landroid hat in .status eine Zahl eingetragen. Im .common.states steht dann aber ja der Klartext. In meinen Scripten behelfe ich mir so:

                            // Landroid Egon 
                            // iStatus = worx.0.1234567890.mower.status
                            // myObject = getObject('worx.0.1234567890.mower.status'/*Landroid status*/);
                            // tStatus = myObject.common.states[iStatus];
                            

                            Und gebe dann tStatus aus. Wäre nett, wenn man sowas auch per dp
                            ausgeben könnt. Dann müsste ich nicht extra Datenpunkte erzeugen. Sowas kommt ja auch noch an anderen Geräten vor. Mein zwave Bewegungsmelder z.B. haben auch solche dp.

                            Hier der State in raw

                            {
                              "type": "state",
                              "common": {
                                "name": "Landroid status",
                                "type": "number",
                                "role": "indicator.status",
                                "read": true,
                                "write": false,
                                "desc": "Current status of lawn mower",
                                "states": {
                                  "0": "IDLE",
                                  "1": "Home",
                                  "2": "Start sequence",
                                  "3": "Leaving home",
                                  "4": "Follow wire",
                                  "5": "Searching home",
                                  "6": "Searching wire",
                                  "7": "Mowing",
                                  "8": "Lifted",
                                  "9": "Trapped",
                                  "10": "Blade blocked",
                                  "11": "Debug",
                                  "12": "Remote control",
                                  "30": "Going home",
                                  "32": "Border Cut",
                                  "33": "Searching zone",
                                  "34": "Pause"
                                }
                              },
                              "native": {},
                              "from": "system.adapter.worx.0",
                              "user": "system.user.admin",
                              "ts": 1559388071920,
                              "_id": "worx.0.123456789.mower.status",
                              "acl": {
                                "object": 1636,
                                "state": 1636,
                                "owner": "system.user.admin",
                                "ownerGroup": "system.group.administrator"
                              }
                            }
                            
                            T 1 Reply Last reply Reply Quote 0
                            • S
                              Saschag @der-eine last edited by

                              @der-eine
                              so habe heute auf die Version 0.7 umgestellt und nun sieht es beim iPhone leider wie bei Dir aus ;-(

                              D 1 Reply Last reply Reply Quote 0
                              • T
                                Tirador @der-eine last edited by

                                @der-eine wir hatten ja schonmal so einen Effekt auf den Apple Geräten. Damals lag es doch an einem nbsp-Tag. Kannst du irgendwie herausfinden, woran es im HTML-Code liegen mag?

                                D 1 Reply Last reply Reply Quote 0
                                • T
                                  Tirador @OstfrieseUnterwegs last edited by

                                  @OstfrieseUnterwegs said in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                                  Gibt es eine Möglichkeit den Text einer Auswahlliste anzuzeigen?

                                  Ich werde das mal auf die Todo-Liste nehmen, so ein Mapping abzubilden für die Ausgabe im Nachrichtentext. Fraglich ist, ob man die Übersetzung direkt aus dem State auslesen kann (also mit welcher Javascript-Funktion), oder ob man dies nochmal separat definieren muss. Sachdienliche Hinweise nehme ich gerne auf. 🙂

                                  Uhula 1 Reply Last reply Reply Quote 0
                                  • D
                                    der-eine @Tirador last edited by der-eine

                                    @Tirador ja, ich schau mal drüber ob ich was finde. Die Markierung für den Wechsel in die View ist an die HR gebunden? Wie kann ich diese weiter nach links verschieben?

                                    1 Reply Last reply Reply Quote 0
                                    • Uhula
                                      Uhula @Tirador last edited by

                                      @Tirador sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                                      Sachdienliche Hinweise nehme ich gerne auf

                                      Da du die State-ID hast, kannst du es aus dem Objekt auslesen.

                                      let instance = getObject(id);
                                      if (instance && instance.common && instance.common.states) {
                                          mystateText = instance.common.states[n] ;
                                      }
                                      
                                      T 1 Reply Last reply Reply Quote 0
                                      • T
                                        Tirador @Uhula last edited by

                                        Ich habe die State-Übersetzung testweise eingebaut. Die Übersetzung des States funktioniert nun automatisch, wenn im Datenpunkt eine States-Liste hinterlegt ist.

                                        Ich bekomme im Code Editor nun aber Fehler angezeigt, Skript läuft aber dennoch:

                                        2020-05-17 10_43_32-javascript - ioBroker.png

                                        @Uhula Besten Dank für deine Unterstützung.
                                        @OstfrieseUnterwegs Kannst Du dies mal testen mit deinem Mähroboter und eine Rückmeldung geben. Danke!

                                        Anbei die Beta-Fassung des MessageStateCreators:

                                        /*******************************************************************************
                                        * MessageStateCreator
                                        * ----------------------------------------------------
                                        * Ermöglicht die Überwachung von Datenpunkten und das Auslösen von Nachrichten
                                        * mit dem MessageHandler-Nachrichtensystem.
                                        * ----------------------------------------------------
                                        * Autor: Github-Name: St0Ma ioBroker-Forum-Name: Tirador 
                                        * Source:  https://github.com/St0Ma/ioBroker-MessageHandler
                                        * Support: https://forum.iobroker.net/topic/32207/script-messagehandler-nachrichten-protokollieren-vis
                                        * ----------------------------------------------------
                                        * Change Log:
                                        *  0.6  - Minor fix DWD
                                        *  0.5  - Erweiterung um Attribute Wartezeit delayTime und Wiederholungszeit repatTime
                                        *         Möglichkeit der Zahlenformatierung über Attribute decimals und format
                                        *  0.4  - Subscriptions nur noch für jeden Datenpunkt einmal, Fehlerausgabe bei fehlerhaften Trigger-DP
                                        *  0.3  - few code improvements
                                        *  0.2  - Initial Release
                                        * ---------------------------------------------------- 
                                        * (c) 2020 by Tirador, MIT License, no warranty, use on your own risc
                                        ******************************************************************************
                                        
                                        
                                        *******************************************************************************
                                        * Installation
                                        *******************************************************************************
                                        
                                        1. Das Javascript "MessageGlobal" als globales Script installieren und starten.
                                        
                                        2. Den Javascript "MessageHandler" serverseitiges Script installieren und starten-5 Sek warten-stoppen-starten. 
                                        Beim 1.Start werden die notwendigen States unter STATE_PATH = '0_userdata.0.messageHandler.' 
                                        erzeugt. Erst beim 2.Start instanziiert das Script die Event-Handler und läuft dann.
                                        
                                        3. Das Javascript "MessageStateCreator" installieren und starten.
                                        
                                        *******************************************************************************
                                        * Basis-Konfiguration
                                        *******************************************************************************
                                        
                                        Optional kann in der Funktion MessageHandler|doInit() eine Anpassung der KONFIGURATION vorgenommen werdne.
                                        
                                        Zur Konfiguration sind zwei Schritte erforderlich:
                                        
                                        1. Die Grundkonfiguration erfolgt über die Festlegung von MESSAGE-IDs (Nachrichten-Ids)
                                         im Javascript "MessageHandler".
                                        
                                        2. Über das Javascript "MessageStateCreator" können Datenpunkte überwacht werden 
                                          und Nachrichten automatisiert ausgelöst werden. Die Konfiguration erfolgt hierfür im Javascript "MessageStateCreator".
                                        
                                        /*******************************************************************************/
                                        
                                        // ------------------------------------------------------------------------------------- 
                                        // Konfiguration der zu überwachenden Datenpunkte mit Konfiguration der Nachrichten (MSG-IDs)
                                        // ------------------------------------------------------------------------------------- 
                                        
                                        /////////////////////
                                        // Hier die einzelnen Nachrichten anlegen und einstellen.
                                        // Die Konfiguration ist vor dem Skriptstart an die eigenenen Datenpunkte anzupassen!
                                        // nicht benötigte/vorhandene Konfigurationen sind auszukommentieren / zu löschen
                                        // Im ersten Beispiel ist alles im Detail beschrieben.
                                        /////////////////////
                                        
                                        const MESSAGE_EVENTS = [
                                        
                                           
                                           // Anzahl geöffneter Fenster mit Räumen
                                           // Datenpunkte basieren auf Pitinis Fensterskript
                                           // GITHUB: https://github.com/Pittini/iobroker-Batterienauswertung
                                           // Forum IOBroker: https://forum.iobroker.net/topic/31676/vorlage-generische-batteriestands%C3%BCberwachung-vis-ausgabe
                                           {
                                           	
                                           	// msgID: Eindeutige msgID, die im Javascript "MessageHandler" definiert ist.
                                           	//        Über die msgID erfolgt die Steuerung der 
                                           	//        Priorität, Loglevel (INFO, WARNING, ALARM, ERROR),
                                           	//        die Vorgabe des Icons, der Iconfarbe, ob eine Nachricht nur einmal geloggt wird uvm.
                                           	
                                               msgID: 'WINDOW_ISOPEN_INFO', 
                                           	
                                           	// Datenpunkte, die als Trigger überwacht werden (auf die bei Veränderung von Werten reagiert wird).
                                           	// Es kann ein Datenpunkt in der Notation '' angegeben werden, oder mehrere wie folgt im Beispiel in der Notation ['', '',...] 
                                           	
                                               triggerDP: ['javascript.0.FensterUeberwachung.RoomsWithOpenWindows'],
                                           	
                                        
                                           	// postMsg: Nachricht nur erzeugen, wenn ein vorgegebener Datenpunkt einer bestimmten Bedingung entspricht.
                                           	//          Im Beispiel müssen die Anzahl der geöffneten Fenster größer als 0 sein,
                                           	//          damit die Nachricht "Fenster geöffnet" ausgelöst wird.
                                           	//          
                                           	//       dp: Datenpunkt dessen Wert der Bedingung entsprichen muss
                                           	//       comp: Vergleichsoperator. Es sind folgende Operatoren erlaubt:
                                           	//             == gleich
                                           	//             != ungleich
                                           	//             >= größer gleich
                                           	//             <= kleiner gleich
                                           	//             >  größer
                                           	//             <  kleiner
                                           	//       val: Wert
                                           	//       
                                           	//       Die Nachricht wird erzeugt, wenn die Bedingung "dp comp val" eintritt.
                                           	//
                                           	//       delayTime: Verzögerungszeit in Sekunden für die Auslösung der Nachricht. 
                                           	//                  In der Logik wird initial geprüft, ob die Bedingung gilt und erneut nach der Delay-Zeit.
                                           	//                  Erst wenn nach der Delay-Zeit auch die Bedingung der Nachricht gilt, wird die Nachricht erzeugt.
                                           	//
                                           	//                  Am Beispiel des Fenstersensors: die Nachricht soll erst ausgelöst werden, 
                                           	//                  wenn das Fenster länger als 60*20 Sekunden (d.h. 20 Minuten) offen ist. 
                                           	// 					In der Praxis macht das Setzen des Delays nur für einzelne Sensoren Sinn 
                                           	//                  (und keine States, die gemeinsame Zustände (z.B. Gruppen von Fenstern abbilden)!)
                                           	//
                                           	//       repeatTime: Wiederholungszeit in Sekunden. Prüft im Intervall in Sekunden, ob die Bedingung der Nachricht gilt.
                                               //                   Die Nachricht wird frühestens nach der ersten konkreten Auslösung wiederholt.
                                               //                   Wenn eine Delay-Zeit vorgegeben ist, beginnt die Wiederholungszeit nach der Delay-Zeit 
                                               //                   (sofern die Bedingung der Nachricht weiterhin gilt).
                                               //                   Sofern Zwischenzeitlich der Datenpunkt erneut getriggert wird, wird ein bereits ausgelöster Timer
                                               //                   zur Wiederholung erneut gestartet.
                                           	
                                               postMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '>', val:0, delayTime:0, repeatTime:0}, 
                                           	
                                           	
                                           	// removeMsgDP: Nachricht entfernen, wenn ein vorgegebener Datenpunkt einer bestimmten Bedingung entspricht.
                                           	//          Im Beispiel wird die Nachricht "Fenster geöffnet" entfernt, 
                                           	//          wenn die Anzahl der geöffneten Fenster gleich 0 ist.
                                           	//
                                           	//       dp: Datenpunkt dessen Wert der Bedingung entsprichen muss
                                           	//       comp: Vergleichsoperator. Es sind folgende Operatoren erlaubt:
                                           	//             == gleich
                                           	//             != ungleich
                                           	//             >= größer gleich
                                           	//             <= kleiner gleich
                                           	//             >  größer
                                           	//             <  kleiner
                                           	//       val: Wert
                                           	//       Die Nachricht wird entfernt, wenn die Bedingung "dp comp val" eintritt.
                                           			
                                               removeMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '==', val:0}, // Nachricht enfernen, wenn die Bedingung eintritt
                                           	
                                           	// msgText_<Nr> : Diese Attribute bestimmen die Ausgabe des Nachrichtentextes.
                                           	// 
                                           	//                Es kann ein statischer Text ausgegeben werden durch das Attribut text:
                                           	//                Beispiel: 
                                           	//                msgText_1: {text: 'Fenster ist geöffnet'},
                                           	//        
                                           	//                Der Wert eines Datenpunkts kann in die Fehlernachricht mit ausgegeben werden.
                                           	//                Beispiel: 
                                           	//                msgText_2: {dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'},
                                               //
                                               //                In Datenpunkten mit Zahlen kann eine Aufbereitung der Zahl vorgenommen werden 
                                               //                über die Attribute format und decimals:
                                               //                Beispiel:
                                               //                msgText_2: {dp: 'deconz.0.Sensors.18.temperature', format:'"##,#"', decimals:1},
                                               //                
                                               //                Die Attribute im einzelnen:
                                               //                format: '#.###,##' // Ausgabe mit 1000er Trennzeichen Punkt und Komma
                                               //                decimals: Ausabe mit vorgegebenen Nachkommastellen
                                           	// 
                                           	//                Es können beliebig viele msgText_ Attribute (mit fortlaufender Nummer) 
                                           	//                eingefügt werden (msgText_1, msgText_2, msgText_3, usw.).
                                           	//                Der Nachrichtentext ergibt sich aus der Konkatenation aller einzelner Bausteine.
                                           	
                                               msgText_1: {text: ''},
                                               msgText_2: {dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'},
                                           	
                                           	
                                           	// countEventsDP: Information wieviele Ereignisse für die Meldung eingetreten sind.
                                           	//                Dieses Element ist optional.
                                           	//                Die Anzahl wird über den vorgegebenen Datenpunkt ermittelt.
                                           	// 
                                               //                Beispiele: Für das Beispiel werden die Anzahl der offenen Fenster ausgegeben.
                                           	
                                               countEventsDP: 'javascript.0.FensterUeberwachung.WindowsOpen'
                                           },
                                           
                                           // Eigene Nachricht, wenn alle Fenster geschlossen sind (Nur INFO)
                                           // Datenpunkte basieren auf Pitinis Fensterskript
                                           // GITHUB: https://github.com/Pittini/iobroker-Batterienauswertung
                                           // Forum IOBroker: https://forum.iobroker.net/topic/31676/vorlage-generische-batteriestands%C3%BCberwachung-vis-ausgabe
                                           {
                                               msgID: 'WINDOW_ISCLOSED_INFO', 
                                               triggerDP: ['javascript.0.FensterUeberwachung.RoomsWithOpenWindows'], // , 'javascript.0.FensterUeberwachung.WindowsOpen'
                                               postMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '==', val:0},
                                               removeMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '>', val:0}, // Nachricht enfernen, wenn die Bedingung eintritt
                                               msgText_1: {text: ''},
                                               msgText_2: {dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'},
                                               countEventsDP: 'javascript.0.FensterUeberwachung.WindowsOpen'
                                           },
                                        
                                           // Nachrichten für länger geöffnete Fenster
                                           {
                                               msgID: 'WINDOW_ISLONGEROPEN_GARAGE', 
                                               triggerDP: ['javascript.0.FensterUeberwachung.Garage.IsOpen'],
                                               postMsgDP: {dp:'javascript.0.FensterUeberwachung.Garage.IsOpen', comp: '==', val: true, delayTime: 9000, repeatTime:0},  
                                               removeMsgDP: {dp:'javascript.0.FensterUeberwachung.Garage.IsOpen', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                                               msgText_1: {text: 'Fenster Garage länger als 15 Minuten geöffnet'},
                                               countEventsDP: 'javascript.0.FensterUeberwachung.Garage.RoomOpenWindowCount'
                                           },
                                        
                                           // Nachrichten für länger geöffnete Fenster
                                           {
                                               msgID: 'WINDOW_ISLONGEROPEN_HAUS', 
                                               triggerDP: ['javascript.0.FensterUeberwachung.Haus.IsOpen'],
                                               postMsgDP: {dp:'javascript.0.FensterUeberwachung.Haus.IsOpen', comp: '==', val: true, delayTime: 9000, repeatTime:0},  
                                               removeMsgDP: {dp:'javascript.0.FensterUeberwachung.Haus.IsOpen', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                                               msgText_1: {text: 'Fenster Haus länger als 15 Minuten geöffnet'},
                                               countEventsDP: 'javascript.0.FensterUeberwachung.Haus.RoomOpenWindowCount'
                                           },
                                        
                                           // Letzter Briefkasteneinwurf
                                           // Eine Nachricht wird nur ausgelöst, wenn der Sensor aktiviert wird
                                           {
                                               msgID: 'LAST_POSTENTRACE_INFO',
                                               triggerDP: 'deconz.0.Sensors.8.open',
                                               postMsgDP: {dp:'deconz.0.Sensors.8.open', comp: '==', val:true},
                                               msgText_1: {text: ''},
                                               countEventsDP: ''
                                           },    
                                        
                                           // Anzahl anwesender Personen mit Personenangabe
                                           // An- und Abwesenheitserkennung über TR-064-Community-Adapter (von Mic) 
                                           // (Quelle: https://github.com/Mic-M/iobroker.presence-script-for-tr-064-community-adapter)
                                           {
                                               msgID: 'PERSONS_AVAILABLE_INFO', 
                                               triggerDP: '0_userdata.0.Anwesenheit.Status.presentPersonsString',
                                               postMsgDP: {dp:'0_userdata.0.Anwesenheit.Status.allPresentPersonsCount'},
                                               msgText_1: {dp: '0_userdata.0.Anwesenheit.Status.presentPersonsString'},
                                               countEventsDP: '0_userdata.0.Anwesenheit.Status.allPresentPersonsCount'
                                           },
                                        
                                           // Verpasste Anrufe (des Tages)
                                           // Über TR-064-Community-Adapter
                                           {
                                               msgID: 'MISSED_CALLS', 
                                               triggerDP: 'tr-064.0.calllists.missed.count',
                                               postMsgDP: {dp:'tr-064.0.calllists.missed.count'},
                                               msgText_1: {text: 'Anzahl verpasster Anrufe: '},
                                               msgText_2: {dp: 'tr-064.0.calllists.missed.count'},
                                               countEventsDP: 'tr-064.0.calllists.missed.count'
                                           } ,
                                        
                                           // letzter Anruf (des Tages)
                                           // Über TR-064-Community-Adapter
                                           {
                                               msgID: 'LAST_CALL', 
                                               triggerDP: 'tr-064.0.callmonitor.lastCall.callerName',
                                               postMsgDP: {dp:'tr-064.0.callmonitor.lastCall.callerName'},
                                               msgText_1: {text: 'Anrufer: '},
                                               msgText_2: {dp: 'tr-064.0.callmonitor.lastCall.callerName'},
                                               msgText_3: {text: '</br>Angerufen: '},
                                               msgText_4: {dp: 'tr-064.0.callmonitor.lastCall.calleeName'},
                                               countEventsDP: ''
                                           } ,
                                        
                                        
                                           // Status Alarmanlage
                                           // über Skript von andreaskos
                                           // https://forum.iobroker.net/topic/32885/umfassendes-alarmanlagen-skript/3
                                           {
                                               msgID: 'ALARMANLAGE_STATUS', 
                                               triggerDP: ['javascript.0.Alarmanlage.Output.StatusText', 'sonos.0.root.192_168_178_59.state'],
                                               msgText_1: {text: 'Aktiv: '},
                                               msgText_2: {dp: 'javascript.0.Alarmanlage.Output.StatusText'},
                                               msgText_3: {text: '<br>'},
                                               msgText_4: {text: 'Status: '},        
                                               msgText_5: {dp: 'javascript.0.Alarmanlage.Output.AlarmText'}
                                           },
                                        
                                           // SONOS_INFO
                                           // über SONOS-Adapter
                                           {
                                               msgID: 'SONOS_INFO', 
                                               triggerDP: ['sonos.0.root.192_168_178_59.current_artist', 'sonos.0.root.192_168_178_59.state'],
                                               msgText_1: {text: '<img src=\''},
                                               msgText_2: {dp: 'sonos.0.root.192_168_178_59.current_cover'},
                                               msgText_3: {text: '\' height=\'50%\' width=\'50%\'></img>'},
                                               msgText_5: {text: '</br>Künstler: '},
                                               msgText_6: {dp: 'sonos.0.root.192_168_178_59.current_artist'},
                                               msgText_7: {text: '</br>Album: '},
                                               msgText_8: {dp: 'sonos.0.root.192_168_178_59.current_album'}
                                           },
                                        
                                           // Corona-Statistics
                                           // über Corona-Adapter
                                           {
                                               msgID: 'CORONA_STATS_CASES', 
                                               triggerDP: ['coronavirus-statistics.0.Germany.cases', 'coronavirus-statistics.0.Germany.deaths'],
                                               postMsgDP: {dp:'coronavirus-statistics.0.Germany.cases', format:'"#.###"', decimals:0},
                                               msgText_1: {text: '☣ Bestätigt: '},
                                               msgText_2: {dp: 'coronavirus-statistics.0.Germany.cases', format:'"#.###"', decimals:0},
                                               msgText_3: {text: '</br>♱ Tote: '},
                                               msgText_4: {dp: 'coronavirus-statistics.0.Germany.deaths', format:'"#.###"', decimals:0},
                                               countEvents: 'coronavirus-statistics.0.Germany.deaths'
                                           },
                                        
                                           // Temperatur-Information
                                           // Außen und Innentemperatur über eigene Sensoren
                                           {
                                               msgID: 'TEMPERATURE_INFO', 
                                               triggerDP: ['deconz.0.Sensors.18.temperature', 'deconz.0.Sensors.3.temperature'],
                                               postMsgDP: {dp:'deconz.0.Sensors.18.temperature'},
                                               msgText_1: {text: '🌐 '},
                                               msgText_2: {dp: 'deconz.0.Sensors.18.temperature', format:'"##,#"', decimals:1},
                                               msgText_3: {text: ' °C'},
                                               msgText_5: {text: ' 🏠 '},
                                               msgText_6: {dp: 'deconz.0.Sensors.3.temperature', format:'"##,#"', decimals:1},
                                               msgText_7: {text: ' °C'},
                                               countEvents: ''
                                           },
                                        
                                           // Müllabholung - Nächster Mülltermin
                                           // über Adapter trashschedule
                                           {
                                               msgID: 'NEXT_GARBAGE_INFO', 
                                               triggerDP: ['trashschedule.0.next.daysleft', 'trashschedule.0.next.types'],
                                               postMsgDP: {dp:'trashschedule.0.next.daysleft'},
                                               msgText_1: {text: ''},
                                               msgText_2: {dp: 'trashschedule.0.next.types'},
                                               msgText_3: {text: ' in '},
                                               msgText_4: {dp: 'trashschedule.0.next.daysleft'},
                                               msgText_5: {text: ' Tage(n)'},
                                               countEvents: 'trashschedule.0.next.daysleft'
                                           },
                                        
                                           // Batterieüberwachung - Evtl. nächste Batterie zu wechseln 
                                           // GITHUB: https://github.com/Pittini/iobroker-Batterienauswertung
                                           // Forum ioBroker: https://forum.iobroker.net/topic/31676/vorlage-generische-batteriestandsüberwachung-vis-ausgabe
                                           {
                                               msgID: 'BATTERIE_INFO', 
                                               triggerDP: 'javascript.0.BatterieUeberwachung.NextExpectedLowBatt',
                                               postMsgDP: {dp:'javascript.0.BatterieUeberwachung.NextExpectedLowBatt', comp: '!=', val:''},
                                               removeMsgDP: {dp:'javascript.0.BatterieUeberwachung.NextExpectedLowBatt', comp: '==', val:''},
                                               msgText_1: {text: ''},
                                               msgText_2: {dp: 'javascript.0.BatterieUeberwachung.NextExpectedLowBatt'},
                                               countEventsDP: ''
                                           },
                                        
                                           // Gefrierschrank geöffnet
                                           // über eigenen Sensor
                                           {
                                               msgID: 'FREEZER_DOOR_ISOPEN_INFO', 
                                               triggerDP: 'deconz.0.Sensors.56.open',
                                               postMsgDP: {dp:'deconz.0.Sensors.56.open', comp: '==', val:true, delayTime: 60, repeatTime: 180},
                                               removeMsgDP: {dp:'deconz.0.Sensors.56.open', comp: '==', val:false}, 
                                               msgText_1: {text: ''},
                                           },
                                        
                                           // Kühlschrank geöffnet
                                           // über eigenen Sensor
                                           {
                                               msgID: 'FRIDGE_DOOR_ISOPEN_INFO', 
                                               triggerDP: 'deconz.0.Sensors.57.open',
                                               postMsgDP: {dp:'deconz.0.Sensors.57.open', comp: '==', val:true, delayTime: 30, repeatTime: 180},
                                               removeMsgDP: {dp:'deconz.0.Sensors.57.open', comp: '==', val:false}, 
                                               msgText_1: {text: ''},
                                           },
                                           
                                        
                                           // DWD Wetterwarnung 
                                           // Über DWD-Adapter, erfordert die Konfiguration von 3 Meldungen im Adapter
                                           {
                                               msgID: 'DWD_WARN', 
                                               triggerDP: 'dwd.0.warning.severity',
                                               postMsgDP: {dp:'dwd.0.warning.severity', comp: '!=', val:0, delayTime: 10},
                                               removeMsgDP: {dp:'dwd.0.warning.severity', comp: '==', val:0},
                                               msgText_1: {dp: 'dwd.0.warning.text'},
                                               msgText_2: {text: ' <br> '},
                                               msgText_3: {dp: 'dwd.0.warning.description'},
                                               msgText_4: {text: ' <br> '},
                                               msgText_5: {dp: 'dwd.0.warning1.text'},
                                               msgText_6: {text: ' <br> '},
                                               msgText_7: {dp: 'dwd.0.warning1.description'},
                                               msgText_8: {dp: 'dwd.0.warning.severity'},
                                               countEventsDP: ''
                                           },
                                        
                                           
                                           // Wassersensor Werkzeugraum
                                           // über eigenen Sensor
                                           {
                                               msgID: 'WATER_ALARM', 
                                               triggerDP: 'deconz.0.Sensors.21.water',
                                               postMsgDP: {dp:'deconz.0.Sensors.21.water', comp: '==', val:true},
                                               //removeMsgDP: {dp:'deconz.0.Sensors.21.water', comp: '==', val:false}, // Nachricht wird zur Sicherheit nicht entfernt, falls der Sensor toggelt!
                                               msgText_1: {text: 'Wasseralarm im Werkzeugraum!'},
                                               countEventsDP: ''
                                           },
                                        
                                           // Wassersensor Waschraum
                                           // über eigenen Sensor
                                           {
                                               msgID: 'WATER_ALARM', 
                                               triggerDP: 'deconz.0.Sensors.34.water',
                                               postMsgDP: {dp:'deconz.0.Sensors.34.water', comp: '==', val:true},
                                               //removeMsgDP: {dp:'deconz.0.Sensors.34.water', comp: '==', val:false}, // Nachricht wird zur Sicherheit nicht entfernt, falls der Sensor toggelt!
                                               msgText_1: {text: 'Wasseralarm im Waschraum!'},
                                               countEventsDP: ''
                                           },
                                        
                                           // Wassersensor Küche
                                           // über eigenen Sensor
                                           {
                                               msgID: 'WATER_ALARM', 
                                               triggerDP: 'deconz.0.Sensors.6.water',
                                               postMsgDP: {dp:'deconz.0.Sensors.6.water', comp: '==', val:true},
                                               //removeMsgDP: {dp:'deconz.0.Sensors.6.water', comp: '==', val:false}, // Nachricht wird zur Sicherheit nicht entfernt, falls der Sensor toggelt!
                                               msgText_1: {text: 'Wasseralarm in der Küche!'},
                                               countEventsDP: ''
                                           },
                                        
                                           // Wassersensor großer Kellerraum
                                           // über eigenen Sensor
                                           {
                                               msgID: 'WATER_ALARM', 
                                               triggerDP: 'deconz.0.Sensors.7.water',
                                               postMsgDP: {dp:'deconz.0.Sensors.7.water', comp: '==', val:true},
                                               //removeMsgDP: {dp:'deconz.0.Sensors.7.water', comp: '==', val:false}, // Nachricht wird zur Sicherheit nicht entfernt, falls der Sensor toggelt!
                                               msgText_1: {text: 'Wasseralarm im großen Kellerraum!'},
                                               countEventsDP: ''
                                           },
                                        
                                        
                                           // Logitech Harmony
                                           // Über Harmony-Adapter
                                           {
                                               msgID: 'HARMONY_INFO', 
                                               triggerDP: 'harmony.0.Harmonyhub.activities.currentActivity',
                                               postMsgDP: {dp:'harmony.0.Harmonyhub.activities.currentActivity', comp: '!=', val:'PowerOff'},
                                               removeMsgDP: {dp:'harmony.0.Harmonyhub.activities.currentActivity', comp: '==', val:'PowerOff'}, // Nachricht wird zur Sicherheit nicht entfernt, falls der Sensor toggelt!
                                               msgText_1: {text: 'Aktivität: '},
                                               msgText_2: {dp: 'harmony.0.Harmonyhub.activities.currentActivity'},
                                               countEventsDP: ''
                                           },
                                           
                                        
                                           // Spritpreis-Info 
                                           // über tankerkoenig-Adapter
                                           {
                                               msgID: 'TANK_INFO', 
                                               triggerDP:  ['tankerkoenig.0.stations.cheapest.e5.feed','tankerkoenig.0.stations.cheapest.diesel.feed'],
                                               postMsgDP: {dp:'tankerkoenig.0.stations.cheapest.e5.feed', comp: '>', val:0},
                                               removeMsgDP: {dp:'tankerkoenig.0.stations.cheapest.e5.feed', comp: '==', val:0},
                                               msgText_1: {text: 'DIESEL: '},
                                               msgText_2: {dp: 'tankerkoenig.0.stations.cheapest.diesel.name'},
                                               msgText_3: {text: ': '},
                                               msgText_4: {dp: 'tankerkoenig.0.stations.cheapest.diesel.feed', format:'"#.##"', decimals:2},
                                               msgText_5: {text: ' €'},
                                               msgText_6: {text: '</br>SUPER:'},
                                               msgText_7: {dp: 'tankerkoenig.0.stations.cheapest.e5.name'},
                                               msgText_8: {text: ': '},
                                               msgText_9: {dp: 'tankerkoenig.0.stations.cheapest.e5.feed', format:'"#.##"', decimals:2},
                                               msgText_10: {text: ' €'},
                                               countEventsDP: ''
                                           },    
                                        
                                        
                                           // Update ioBroker
                                           // über Admin-Adapter
                                           {
                                               msgID: 'UPDATE_INFO', 
                                               triggerDP: 'admin.0.info.updatesList',
                                               postMsgDP: {dp:'admin.0.info.updatesNumber', comp: '>', val:0},
                                               removeMsgDP: {dp:'admin.0.info.updatesNumber', comp: '==', val:0},
                                               msgText_1: {text: 'Adapter: '},
                                               msgText_2: {dp: 'admin.0.info.updatesList'},
                                               msgText_3: {text: '. Bitte aktualisieren.'},
                                               countEventsDP: 'admin.0.info.updatesNumber'
                                           },
                                        
                                           // Deconz Warnung, wenn Verbindung ausgefallen im Adapter
                                           // über Deconz-Adapter
                                           {
                                               msgID: 'DECONZ_Warning', 
                                               triggerDP: 'deconz.0.info.connection',
                                               postMsgDP: {dp:'deconz.0.info.connection', comp: '==', val:false},
                                               removeMsgDP: {dp:'deconz.0.info.connection', comp: '==', val:true},
                                               msgText_1: {text: 'Zigbee offline! Deconz-Adapter nicht verbunden!'}
                                           },
                                           
                                           /*
                                           // Gäste WLAN
                                           // über tr.064-Adapter
                                           {
                                               msgID: 'GUEST_WIFI', 
                                               triggerDP: 'tr-064.0.states.wlanGuest',
                                               postMsgDP: {dp:'tr-064.0.states.wlanGuest', comp: '==', val:true},
                                               removeMsgDP: {dp:'tr-064.0.states.wlanGuest', comp: '==', val:false},
                                               msgText_1: {text: 'Gäste WLAN eingeschalten'},
                                               msgText_2: {dp: 'javascript.0.QR-Code.Gast'},
                                               countEventsDP: ''
                                           },
                                        
                                        
                                           // Internetverbindung Down Fritz!Box
                                           // Prüfung über UPNP-Adapter 
                                           // Github: https://github.com/Jey-Cee/ioBroker.upnp
                                           // ioBroker-Forum: https://forum.iobroker.net/topic/14802/tutorial-vis-fritzbox-status-up-downloadanzeige
                                        
                                           {
                                              msgID: 'INTERNET_DOWN', 
                                              triggerDP: 'upnp.0.WANDevice_-_FRITZ!Box_6490_Cable_(kdg).WANDevice.WANCommonInterfaceConfig.GetCommonLinkProperties.NewPhysicalLinkStatus',
                                              postMsgDP: {dp:'upnp.0.WANDevice_-_FRITZ!Box_6490_Cable_(kdg).WANDevice.WANCommonInterfaceConfig.GetCommonLinkProperties.NewPhysicalLinkStatus', comp: '==', val:'Down'},
                                              //removeMsgDP: {dp:'upnp.0.WANDevice_-_FRITZ!Box_6490_Cable_(kdg).WANDevice.WANCommonInterfaceConfig.GetCommonLinkProperties.NewPhysicalLinkStatus', comp: '==', val:'Up'}, 
                                              msgText_1: {text: 'Keine Internetverbindung'},
                                              countEventsDP: ''
                                           },
                                           */
                                        ];
                                        
                                        // ------------------------------------------------------------------------------------- 
                                        // Ab hier keine Konfiguration mehr durchführen!!!
                                        // ------------------------------------------------------------------------------------- 
                                        
                                        // ------------------------------------------------------------------------------------- 
                                        // MessageStateCreator
                                        // ------------------------------------------------------------------------------------- 
                                        
                                        class MessageStateCreator {
                                           
                                        
                                        
                                           constructor() {
                                             this.init();
                                           }
                                           
                                           //
                                           init() {
                                               // const
                                               this.DEBUG      = false;
                                               this.VERSION    = '0.2/2020-04-04';
                                               this.NAME       = 'MessageStateCreator';
                                               this.so         = this;
                                        
                                               /****************************************************************************
                                                * Global variables and constants
                                                ****************************************************************************/
                                        
                                               this.G_DelayTimers = []; // Delay Timers
                                               this.G_RepeatTimers = []; // Repeat Timers
                                        
                                        
                                               // var
                                               this.installed = false;
                                               this.subscribers = [];
                                               this.schedulers = [];
                                        
                                           }
                                           
                                           // start the script/class
                                           start() {
                                        
                                               if(!this.validate()) {
                                                   return;
                                               }
                                        
                                               if (this.doStart())
                                                   this.log('script started');
                                           }
                                           
                                           // stop the script/class
                                           stop() {
                                               if (this.doStop()) {
                                                   this.log('script stopped');
                                                   for (let i=0; i<this.subscribers.length; i++) if (this.subscribers[i] !== undefined) unsubscribe( this.subscribers[i] );
                                                   this.subscribers = [];
                                                   for (let i=0; i<this.schedulers.length; i++) if (this.schedulers[i] !== undefined) clearSchedule( this.schedulers[i] );
                                                   this.schedulers = [];
                                               }
                                           }
                                           
                                        
                                           // start the script/class
                                           doStart() {
                                        		
                                               let triggerDPArray = [];
                                               let createMsgDPArray = [];
                                           	
                                           	let id = 0;
                                           	
                                               for(const MsgConf of MESSAGE_EVENTS) {
                                           		
                                           		// Vergabe eindeutiger Id zur Laufzeit für Timer
                                           		// 
                                           		MsgConf.id = id++;
                                           		
                                           		// initialize Timer
                                           	
                                           		this.G_DelayTimers[MsgConf.id] = new myTimer();
                                                   this.G_RepeatTimers[MsgConf.id] = new myTimer();
                                                   
                                           		
                                                   let first = true;
                                                   // We are allowing multiple trigger for one msgID.
                                                   // triggerDP: [{dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'}, {dp:'javascript.0.FensterUeberwachung.WindowsOpen'}],
                                                   // Ein Datenpunkt kann mehrfach als Trigger in verschiedenen MSGs auftreten, 
                                                   // daher wird der Trigger nur einmal angelegt, pro Datenpunkt
                                                  
                                                   if (typeof MsgConf.triggerDP == 'string') {
                                                       // If we just have one sensor as string
                                                       if(!triggerDPArray.includes(MsgConf.triggerDP)) {
                                                           triggerDPArray.push(MsgConf.triggerDP);
                                                           createMsgDPArray.push(MsgConf.triggerDP);
                                                       }
                                                   } else {
                                                       for (let key in MsgConf.triggerDP) {
                                                           if(!triggerDPArray.includes(MsgConf.triggerDP[key])) {
                                                               triggerDPArray.push(MsgConf.triggerDP[key]);
                                                               if(first) {
                                                                   createMsgDPArray.push(MsgConf.triggerDP[key]);
                                                                   first = false;
                                                               }
                                                           }
                                                       }
                                                       
                                                   }  
                                               }
                                               
                                               // Mit Skriptstart die Nachrichten auslösen
                                               for (const msgDP of createMsgDPArray) {
                                                   this.createMessage(msgDP);
                                               }
                                        
                                               // subscriber erzeugen                    
                                               for (const triggerDP of triggerDPArray) {
                                                   this.subscribers.push( on( triggerDP, obj => { this.onChangeDP(obj) } ));
                                               }
                                        
                                               return true;
                                           }
                                           
                                           doStop() { return true; }
                                        
                                           // newMessage
                                           onChangeDP(obj) {
                                        
                                               if(this.DEBUG) {
                                                   this.log("New Value from state:" + obj.id);
                                               }
                                        
                                               this.createMessage(obj.id);
                                           }  
                                        
                                           /*
                                           / Prüfung auf plausible Konfiguration
                                           */
                                           validate() {
                                           	
                                           	/*
                                           	msgID: 'WINDOW_ISOPEN_INFO', 
                                               triggerDP: ['javascript.0.FensterUeberwachung.RoomsWithOpenWindows', 'javascript.0.FensterUeberwachung.WindowsOpen'],
                                               postMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '>', val:0}, // Nachricht erzeugen, wenn der DP geändert wird und der Bedingung entspricht
                                               removeMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '==', val:0}, // Nachricht enfernen, wenn die Bedingung eintritt
                                               msgText_1: {text: ''},
                                               msgText_2: {dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'},
                                               countEventsDP: 'javascript.0.FensterUeberwachung.WindowsOpen'
                                           	*/
                                           	
                                               let errorCount = 0;
                                        
                                               if (this.DEBUG) log('[DEBUG] ' + 'VALIDIERUNG *** START: Prüfung der Script-Konfiguration ***');
                                        
                                               for(const MsgConf of MESSAGE_EVENTS) {
                                        
                                           		//-----------------------------------------------------
                                           		// 1. Prüfe, ob msgID vorhanden ist
                                           		// Beispiel: msgID: 'WINDOW_ISOPEN_INFO'
                                           		//-----------------------------------------------------
                                           		
                                           		if (this.isLikeEmpty(MsgConf.msgID)) {
                                                       this.logError('Attribut "msgID" wurde nicht gesetzt in Script-Konfiguration. Bitte Script-Konfiguration überprüfen.'); 
                                           			errorCount++;
                                                   }
                                                   
                                           		//-----------------------------------------------------			
                                           		// 2. Prüfe, ob triggerDP vorhanden ist		
                                           		// Beispiel: triggerDP: ['javascript.0.FensterUeberwachung.RoomsWithOpenWindows', 'javascript.0.FensterUeberwachung.WindowsOpen'],
                                           		//-----------------------------------------------------
                                           		
                                                   if (this.isLikeEmpty(MsgConf.triggerDP)) {
                                                       this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [triggerDP] wurde nicht gesetzt in Script-Konfiguration! Bitte Script-Konfiguration überprüfen.');
                                                       errorCount++;
                                                   }
                                        
                                                   // We are allowing multiple trigger for one msgID.
                                                   // triggerDP: ['javascript.0.FensterUeberwachung.RoomsWithOpenWindows', 'javascript.0.FensterUeberwachung.WindowsOpen'],
                                                   let triggerDPArray = [];
                                                   if (typeof MsgConf.triggerDP == 'string') {
                                                       // If we just have one sensor as string
                                                       triggerDPArray.push(MsgConf.triggerDP);
                                                   } else {
                                                       triggerDPArray = MsgConf.triggerDP;
                                                   }
                                        
                                           		// Erweiterte Prüfung, ob die trigger-Datenpunkte vorhanden sind
                                                   for (const triggerDP of triggerDPArray) {
                                           			if( !this.isLikeEmpty(triggerDP)) { 
                                           				if(!this.existState(triggerDP)) {
                                                               this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [triggerDP] Datenpunkt: [' + triggerDP + '] existiert nicht! Bitte Script-Konfiguration überprüfen.');
                                           					errorCount++;
                                           				}
                                           			}
                                           		}
                                           		
                                           		//-----------------------------------------------------
                                           		// 3. Prüfe, ob postMsgDP vorhanden ist			
                                           		// Beispiel: postMsgDP: {dp:'javascript.0.FensterUeberwachung.WindowsOpen', comp: '>', val:0}, // Nachricht erzeugen, wenn der DP geändert wird und der Bedingung entspricht
                                           		//-----------------------------------------------------
                                           		
                                           		errorCount += this.checkField(MsgConf, 'postMsgDP');
                                        
                                                     
                                             		//-----------------------------------------------------
                                           		// 4. Prüfe, ob msgText vorhanden ist			
                                           		// Beispiel:
                                           		// msgText_1: {text: ''},
                                           		// msgText_2: {dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'},
                                        
                                           		//-----------------------------------------------------
                                        
                                                   let msgText = '';
                                                           
                                        
                                                   let MSGTEXT_KEYS = (Object.keys(MsgConf).filter(str => str.includes('msgText_'))); // gibt alle Keys mit 'msgText_' als Array zurück, also z.B. ['msgText_1','msgText_2']
                                        
                                                   if (this.isLikeEmpty(MSGTEXT_KEYS)) {
                                           			this.logWarn('msgID: [' + MsgConf.msgID + '] Es wurde kein Nachrichtentext definiert (msgText_1, etc.). Bitte Script-Konfiguration überprüfen.');
                                           			errorCount++;
                                                   } else {
                                        
                                                       for (const MSGTEXT_KEY of MSGTEXT_KEYS) {
                                           				let dp = MsgConf[MSGTEXT_KEY].dp;                    
                                           				
                                           				if( ! this.isLikeEmpty(dp)) { 
                                           					if(! this.existState(dp)) {
                                                                   this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [' + MSGTEXT_KEY + '] Datenpunkt: [' + dp + '] existiert nicht! Bitte Script-Konfiguration überprüfen.');
                                           					}
                                           				} 
                                                                   
                                           				let text = MsgConf[MSGTEXT_KEY].text;                    
                                           				if( this.isLikeEmpty(text)  ) {
                                           					//if (this.DEBUG) log('[DEBUG] VALIDIERUNG ' +  MsgConf.msgID + ': In [' + MSGTEXT_KEY + '] wurde kein gültiger Text definiert .');
                                                           }
                                                       }
                                           		}
                                           		
                                           		//-----------------------------------------------------
                                           		// 5. Prüfe, ob countEventsDP vorhanden ist
                                           		// Beispiel:
                                                   // countEventsDP: 'javascript.0.FensterUeberwachung.WindowsOpen'
                                           		//-----------------------------------------------------
                                                   
                                           		let countEventsDP = 0;
                                           		if(MsgConf.countEventsDP != undefined && ! this.isLikeEmpty(MsgConf.countEventsDP) ) {
                                           			if(! this.existState(MsgConf.countEventsDP)) {
                                                           this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [countEventsDP] Datenpunkt: [' + MsgConf.countEventsDP  + '] existiert nicht! Bitte Script-Konfiguration überprüfen.');
                                           			}
                                           		}
                                        
                                                                   
                                           		errorCount += this.checkField(MsgConf, 'removeMsgDP');
                                        
                                               }	
                                        
                                               if (errorCount == 0) {
                                                   if (this.DEBUG) this.log('[DEBUG] ' + 'VALIDIERUNG *** ENDE: Prüfung der Script-Konfiguration, Ergebnis: keine Fehler ***');
                                                   return true;
                                               } else {
                                                   this.logError('Insgesamt ' + errorCount + ' Fehler in der Script-Konfiguration gefunden. Daher wird abgebrochen und das Script nicht weiter ausgeführt.');
                                                   return false;
                                               }
                                               
                                           } 
                                        
                                           // Hilfsfunktion zum Prüfen von Feldern
                                           checkField(MsgConf, field) {
                                           	
                                           	let errorCount = 0;
                                           	
                                           	if (this.isLikeEmpty(MsgConf[field])) {
                                           		if(field == 'postMsgDP') {
                                                       this.log('HINWEIS: msgID: [' + MsgConf.msgID + '] Attribut: [' + field + ']  wurde nicht gesetzt in Script-Konfiguration');
                                                   }
                                           		//errorCount++;
                                                   return errorCount;
                                           	}
                                        
                                           	// 3.a) Prüfung [postMsgDp].dp
                                           	let postMsgDP = MsgConf[field].dp;  // VOrher MsgConf['postMsgDP'].dp;
                                        
                                           	if( this.isLikeEmpty(postMsgDP)) { 
                                           		if(!this.existState(postMsgDP)) {
                                                       this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [' + field + '] Datenpunkt: [' + postMsgDP + '] existiert nicht!');
                                           			errorCount++;
                                           		}
                                           	} 
                                           	
                                           	// 3.b) Prüfung [postMsgDp].comp
                                        
                                           	let condDP = MsgConf[field].comp;   
                                           	if( condDP == undefined) {
                                           		condDP = '==';
                                           	}
                                           	if( this.isLikeEmpty(condDP)) { 
                                           		this.logError('msgID[' + MsgConf.msgID + '] Attribut: [' + field + '] Operator ' + condDP + ' existiert nicht!');
                                           		errorCount++;
                                           	}
                                           	
                                           	if( ! ( condDP == '!=' || condDP == '==' || condDP == '>' || condDP == '<' || condDP == '<=' || condDP == '>=' ) )
                                           	{
                                           		this.logError('msgID: [' + MsgConf.msgID + '] Attribut: [' + field + '] Operator ' + condDP + ' existiert nicht!');
                                           		errorCount++;
                                           	}
                                           	
                                           	return errorCount;
                                           }
                                        
                                           // createMessage
                                           createMessage(objID, hasDelay=true) {
                                        
                                               for(const MsgConf of MESSAGE_EVENTS) {
                                                      
                                                   // We are allowing multiple trigger for one msgID.
                                                   // triggerDP: [{dp: 'javascript.0.FensterUeberwachung.RoomsWithOpenWindows'}, {dp:'javascript.0.FensterUeberwachung.WindowsOpen'}],
                                                   let triggerDPArray = [];
                                                   if (typeof MsgConf.triggerDP == 'string') {
                                                       // If we just have one sensor as string
                                                       triggerDPArray.push(MsgConf.triggerDP);
                                                   } else {
                                                       triggerDPArray = MsgConf.triggerDP;
                                                   }
                                        
                                                   for (const triggerDP of triggerDPArray) {
                                        
                                           			if(triggerDP == objID) {
                                        
                                           				if(this.DEBUG) this.log("Trigger ausgelöst:" + triggerDP);               
                                        
                                           				let createMsg = this.checkCondition(objID, MsgConf, 'postMsgDP', hasDelay);
                                           				
                                           				let removeMsg = this.checkCondition(objID, MsgConf, 'removeMsgDP', hasDelay);
                                        
                                           				if(createMsg || removeMsg) {
                                        
                                           					// erzeugen Nachrichtentext aus Vorgabe und Datenpunkten
                                           					let msgText = '';
                                        
                                           					let MSGTEXT_KEYS = (Object.keys(MsgConf).filter(str => str.includes('msgText_'))); // gibt alle Keys mit 'msgText_' als Array zurück, also z.B. ['msgText_1','msgText_2']
                                        
                                           					if (this.isLikeEmpty(MSGTEXT_KEYS)) {
                                           						this.logWarn('Konfiguration der Textausgabe ' + MsgConf.msgID + 'Es wurde kein Nachrichtentext definiert (msgText_1, etc.). Bitte Script-Konfiguration überprüfen.');
                                           					} else {
                                           						for (const MSGTEXT_KEY of MSGTEXT_KEYS) {
                                           							let dp = MsgConf[MSGTEXT_KEY].dp;  
                                        
                                           							if( ! this.isLikeEmpty(dp)) { 
                                           								if(this.existState(dp)) {
                                        
                                                                               let val = getState(dp).val;
                                                                               // Aufbereitung States Mapping 
                                                                               let txtStates = this.getStatesObj(dp);
                                                                               if (txtStates != null) {
                                                                                   
                                                                                   msgText += this.getStatetxt(dp, val) ;
                                        
                                                                               } else {
                                                                                
                                                                                   let decimals = MsgConf[MSGTEXT_KEY].decimals;                   
                                                                                   let format = MsgConf[MSGTEXT_KEY].format;  
                                        
                                                                                   if( ! this.isLikeEmpty(decimals) && !this.isLikeEmpty(format)) { 
                                                                                       val = formatValue(val, decimals, format);
                                                                                   } else if (!this.isLikeEmpty(format)) {
                                                                                       val = formatValue(val, 0, format);
                                                                                   }
                                                                                   
                                                                                   msgText += val;  
                                                                               }                                      
                                                                               
                                           								} else {
                                           								    this.log('Datenpunkt ' + dp + ' existiert nicht! [' + MsgConf.msgID + '].');
                                           								}
                                           							} 
                                           							
                                           							let text = MsgConf[MSGTEXT_KEY].text;                    
                                           							if( this.isLikeEmpty(text)  ) { 
                                           								//if (DEBUG) log('[DEBUG] VALIDIERUNG ' + LPCONF.name + ': In [' + LP_PERIOD_KEY + '] wurden keine Sekunden zum Ausschalten definiert oder auf 0 gesetzt, daher wird nicht automatisch abgeschaltet.');
                                           							} else {
                                           								msgText += text;
                                           							} 
                                        
                                           						}
                                           					}
                                           				
                                           					// erzeugen Anzahl
                                           					let countEventsDP = 0;
                                           					if(MsgConf.countEventsDP != undefined && MsgConf.countEventsDP != '') {
                                           						countEventsDP = getState(MsgConf.countEventsDP).val;
                                           					}
                                        
                                           					if(createMsg) {
                                           						this.log("postMessage('" + MsgConf.msgID + "', '" + msgText + "', " + countEventsDP + ")");
                                           						// Erzeugen der Nachricht über MessageHandler
                                           						postMessage(MsgConf.msgID, msgText, countEventsDP); 
                                           					}
                                        
                                           					if(removeMsg) {
                                           						this.log("removeMessage('" + MsgConf.msgID + "', '" + msgText + "')");
                                           						// Entfernen der Nachricht über MessageHandler
                                           						removeMessage(MsgConf.msgID, msgText); 
                                        
                                           					}
                                                               
                                                               if(createMsg && removeMsg) {
                                                                   this.logError('msgID: [' + MsgConf.msgID + '] Die Nachricht mit Nachrichtentext "' + msgText + '" wird gleichzeitig erzeugt und entfernt. Bitte Skript-Konfiguration prüfen!' )
                                                               }
                                           				}
                                           			} // if
                                           		} // for
                                               } // for
                                           } 
                                        
                                           getStatesObj(id) {
                                        
                                               if(!getObject(id)) {
                                                   //log(id + ': kein Objekt', 'warn');
                                                   return null;
                                               }
                                        
                                               var obj = getObject(id);
                                               if (!obj.common.states) {
                                                   //log(id + ': keine Zustandtexte', 'warn');
                                                   return null;
                                               }
                                               var states = obj.common.states;
                                        
                                               if (typeof states == 'string') {
                                                   var arr = states.split(';');
                                                   states = {};
                                                   for(var i = 0; i < arr.length; i++) {
                                                       var ele = arr[i].split(':');
                                                       states[ele[0]] = ele[1];
                                                   }
                                               }
                                               return states;
                                        
                                           }
                                        
                                           getStatetxt(id, val) {
                                               var states = this.getStatesObj(id);
                                               if(states) return states[val];
                                               else return null;
                                           }
                                           
                                           checkCondition(objID, MsgConf, field, hasDelay) {
                                        
                                          		if (this.isLikeEmpty(MsgConf[field])) {
                                           		// if(this.DEBUG) this.logWarn(field + ' wurde nicht gesetzt in Script-Konfiguration.');
                                           		// Wenn postMsgDP nicht definiert, Nachricht erzeugen
                                           		// Wenn removeMsgDP nicht definiert ist, wird die Nachricht NICHT gelöscht
                                           		if(field == 'postMsgDP') {
                                                       return true;
                                                   } else if(field == 'removeMsgDP') {
                                                       return false;
                                                   }
                                                   
                                           	}
                                           	
                                           	let dp = MsgConf[field].dp;
                                        
                                           	let createMsg = false;
                                        
                                           	let comp = MsgConf[field].comp;   
                                        
                                           	if( this.isLikeEmpty(comp)) {
                                           		comp = '==';
                                           	}
                                        
                                           	let val = MsgConf[field].val;   
                                        
                                        
                                           	if( val == undefined) {
                                           		createMsg = true;
                                           	} else if(comp == '==') {   
                                           		if( getState(dp).val == val) {
                                           			createMsg = true;
                                           		}
                                           	} else if(comp == '!=') {
                                        
                                           		if( getState(dp).val != val) {
                                           			createMsg = true;
                                           		}
                                           	} else if(comp == '>') {
                                           		if( getState(dp).val > val) {
                                           			createMsg = true;
                                           		}
                                           	} else if(comp == '<') {
                                           		if( getState(dp).val < val) {
                                           			createMsg = true;
                                           		}
                                           	} else if(comp == '>=') {
                                           		if( getState(dp).val >= val) {
                                           			createMsg = true;
                                           		}
                                           	} else if(comp == '<=') {
                                           		if( getState(dp).val <= val) {
                                           			createMsg = true;
                                           		}
                                           	}
                                        
                                               if(this.DEBUG) this.log('msgID: [' + MsgConf.msgID + '] Datenpunkt: [' + field + '] dp: [' + dp + '] State dp.val: [' + getState(dp).val + '] comp: [' + comp + '] val: [' + val + '] createMsg:' + createMsg);
                                           	
                                               //-----------------------------------------------------------		
                                               // Falls Delay-Zeit vorgegeben: Timer prüfen / setzen 
                                               //-----------------------------------------------------------
                                               		
                                               let delayTime = MsgConf[field].delayTime;   
                                        
                                               if( field == 'postMsgDP' && !this.isLikeEmpty(delayTime) && (delayTime > 0) ) {
                                        
                                                   if(hasDelay) {
                                                       if (this.G_DelayTimers[MsgConf.id].isRunning()) {
                                        
                                                           if(createMsg == false) {
                                                               // Der Trigger ist nicht mehr aktiv, aber der Timer läuft, also Stop den Timer
                                                               this.G_DelayTimers[MsgConf.id].stop();
                                                           } else {
                                                               // Wenn innerhalb des Delays erneut getriggert wird verlängert sich nicht die Zeit!
                                                               this.log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + '): Check #1: Delay-Timer ist noch aktiv für ' + Math.round(this.G_DelayTimers[MsgConf.id].getTimeLeft()/1000) + ' Sekunden, also schalten wir nicht und brechen hier ab.');
                                                           }
                                                           
                                                       } else {
                                                           // Timer wird nur bei positiver Auslösung gestartet
                                                           if(createMsg == true) {
                                                               log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + '): Start "Delay"-Timer. Die Nachricht wird nach ' + delayTime + ' Sekunden geprüft und eventuell ausgelöst. ');
                                                               // Timer-Start
                                                               this.G_DelayTimers[MsgConf.id].start(function() {
                                        
                                                                   log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + ') "Delay"-Timer ist nach ' + delayTime + ' Sekunden abgelaufen. Die Nachricht ' + objID + ' ausgelöst.');
                                                                   this.G_DelayTimers[MsgConf.id].stop(); // just in case
                                                                   this.createMessage(objID, false); // erzeugen Aktion neue Nachricht ohne Delay
                                                                   
                                        
                                                               }.bind(this), delayTime * 1000);
                                                           }
                                                       }
                                                       createMsg=false;
                                                   } else {
                                                       this.log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + '): Nachricht hat kein Delay mehr! ');
                                        
                                                   }
                                               }
                                        
                                           
                                           	//-----------------------------------------------------------		
                                           	// Falls Repeat-Zeit vorgegeben: Timer prüfen / setzen 
                                           	// Wenn innerhalb des laufenden Timers eine neue Nachricht ausgelöst wird,
                                           	// wird der Timer zurückgesetzt.
                                           	//-----------------------------------------------------------
                                           	 
                                           	let repeatTime = MsgConf[field].repeatTime;   
                                        
                                           	if( field == 'postMsgDP' && !this.isLikeEmpty(repeatTime) && (repeatTime > 0) ) {
                                        
                                           		if (this.G_RepeatTimers[MsgConf.id].isRunning()) {
                                           			// Der Timer ist noch aktiv und wird gestoppt
                                           			this.G_RepeatTimers[MsgConf.id].stop();
                                           			log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + '): Der "Repeat"-Timer wurde zurückgesetzt, weil die Nachricht zwischenzeitlich ausgelöst wurde. ');
                                           		}
                                           		
                                           		// Timer wird nur bei positiver Auslösung gestartet
                                           		if(createMsg == true) {
                                           			log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + '): Start "Repeat"-Timer. Die Nachricht wird nach ' + delayTime + ' Sekunden erneut geprüft und eventuell ausgelöst. ');
                                           				// Timer-Start
                                           				this.G_RepeatTimers[MsgConf.id].start(function() {
                                        
                                           					log('[DEBUG] ' + MsgConf.msgID + '(' + MsgConf.id + ') "Repeat"-Timer ist nach ' + delayTime + ' Sekunden abgelaufen. Die Nachricht ' + objID + ' ausgelöst.');
                                           					this.G_RepeatTimers[MsgConf.id].stop(); // just in case
                                           					this.createMessage(objID, false); // erzeugen Aktion neue Nachricht ohne Delay
                                        
                                           				}.bind(this), delayTime * 1000);
                                           		}
                                           	}
                                        
                                           	return createMsg;
                                           }
                                               
                                           //------------------------------------------------------------------------------
                                           // --------------------- helper functions 
                                           //------------------------------------------------------------------------------
                                        
                                           logDebug(msg) { if (this.DEBUG) console.log('['+this.NAME+'] '+msg); }
                                           log(msg) { console.log('['+this.NAME+'] '+msg); }
                                           logWarn(msg) { console.warn('['+this.NAME+'] '+msg); }
                                           logError(msg) { console.error('['+this.NAME+'] '+msg); }
                                           
                                           // über den $-Operator nachsehen, ob der state bereits vorhanden ist
                                           // getState().notExists geht auch, erzeugt aber Warnmeldungen!
                                           existState(id) {
                                               return ( $(id).length==0?false:true);
                                           }
                                        
                                        
                                           /**
                                            * Checks if Array or String is not undefined, null or empty.
                                            * 08-Sep-2019: added check for [ and ] to also catch arrays with empty strings.
                                            * @param inputVar - Input Array or String, Number, etc.
                                            * @return true if it is undefined/null/empty, false if it contains value(s)
                                            * Array or String containing just whitespaces or >'< or >"< or >[< or >]< is considered empty
                                            */
                                           isLikeEmpty(inputVar) {
                                               if (typeof inputVar !== 'undefined' && inputVar !== null) {
                                                   let strTemp = JSON.stringify(inputVar);
                                                   strTemp = strTemp.replace(/\s+/g, ''); // remove all whitespaces
                                                   strTemp = strTemp.replace(/\"+/g, "");  // remove all >"<
                                                   strTemp = strTemp.replace(/\'+/g, "");  // remove all >'<
                                                   strTemp = strTemp.replace(/[+/g, "");  // remove all >[<
                                                   strTemp = strTemp.replace(/]+/g, "");  // remove all >]<
                                                   if (strTemp !== '') {
                                                       return false;
                                                   } else {
                                                       return true;
                                                   }
                                               } else {
                                                   return true;
                                               }
                                           }
                                           
                                        
                                        }   
                                        
                                        
                                           /**
                                            * Better timer function
                                            * Features: Find out time remaining, stop timer easily, check status (running yes/no).
                                            * Autor:               Mic (ioBroker) | Mic-M (github)
                                            * Version:             0.1 (14 March 2020)
                                            * Source:              https://stackoverflow.com/questions/3144711/
                                            * -----------------------------------------------
                                            * Make a timer:
                                           	  let a = new myTimer();
                                           	  a.start(function() {
                                           	   // Do what ever
                                           	  }, 5000);
                                            * Time remaining:      a.getTimeLeft()
                                            * Stop (clear) timer:  a.stop()
                                            * Is timer running:    a.isRunning()
                                            * -----------------------------------------------
                                            */
                                           function myTimer() {
                                           	let fcallback;
                                           	let id;
                                           	let started;
                                           	let remaining = 0;
                                           	let running = false;
                                        
                                           	this.start = function(callback, delay) {
                                           		fcallback = callback;
                                           		remaining = delay;
                                           		clearTimeout(id);
                                           		id = null;
                                           		running = true;
                                           		started = Date.now();
                                           		id = setTimeout(fcallback, remaining);
                                           	}
                                        
                                           	this.pause = function() {
                                           		running = false;
                                           		clearTimeout(id);
                                           		remaining -= Date.now() - started;
                                           	}
                                        
                                           	this.stop = function() {
                                           		running = false;
                                           		clearTimeout(id); id = null;
                                           		remaining = 0;
                                           	}
                                        
                                           	this.getTimeLeft = function() {
                                           		if (running) {
                                           			this.pause();
                                           			this.start(fcallback, remaining);
                                           			return remaining;
                                           		} else {
                                           			return 0;
                                           		}
                                           	}
                                        
                                           	this.isRunning = function() {
                                           		return running;
                                           	}
                                        
                                           }
                                           
                                        // create instance and start
                                        var messageStateCreator = new MessageStateCreator();
                                        messageStateCreator.start();
                                        
                                        
                                        
                                        // on script stop, stop instance too
                                        onStop(function () { 
                                           messageStateCreator.stop(); 
                                        }, 1000 );
                                           
                                           
                                        

                                        OstfrieseUnterwegs 1 Reply Last reply Reply Quote 0
                                        • OstfrieseUnterwegs
                                          OstfrieseUnterwegs @Tirador last edited by

                                          @Tirador sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                                          @OstfrieseUnterwegs Kannst Du dies mal testen mit deinem Mähroboter und eine Rückmeldung geben. Danke!

                                          Funktioniert bestens, danke!
                                          Allerdings musste ich in

                                             isLikeEmpty(inputVar) {
                                                 if (typeof inputVar !== 'undefined' && inputVar !== null) {
                                                     let strTemp = JSON.stringify(inputVar);
                                                     strTemp = strTemp.replace(/\s+/g, ''); // remove all whitespaces
                                                     strTemp = strTemp.replace(/\"+/g, "");  // remove all >"<
                                                     strTemp = strTemp.replace(/\'+/g, "");  // remove all >'<
                                                     strTemp = strTemp.replace(/[+/g, "");  // remove all >[<
                                                     strTemp = strTemp.replace(/]+/g, "");  // remove all >]<
                                                     if (strTemp !== '') {
                                                         return false;
                                                     } else {
                                                         return true;
                                                     }
                                                 } else {
                                                     return true;
                                                 }
                                             }
                                          

                                          in Z7 noch ein \ vor die [ setzen

                                          S 1 Reply Last reply Reply Quote 0
                                          • S
                                            Saschag @OstfrieseUnterwegs last edited by

                                            @OstfrieseUnterwegs sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                                            @Tirador sagte in [Script] MessageHandler: Nachrichten protokollieren +VIS:

                                            @OstfrieseUnterwegs Kannst Du dies mal testen mit deinem Mähroboter und eine Rückmeldung geben. Danke!

                                            Funktioniert bestens, danke!
                                            Allerdings musste ich in

                                               isLikeEmpty(inputVar) {
                                                   if (typeof inputVar !== 'undefined' && inputVar !== null) {
                                                       let strTemp = JSON.stringify(inputVar);
                                                       strTemp = strTemp.replace(/\s+/g, ''); // remove all whitespaces
                                                       strTemp = strTemp.replace(/\"+/g, "");  // remove all >"<
                                                       strTemp = strTemp.replace(/\'+/g, "");  // remove all >'<
                                                       strTemp = strTemp.replace(/[+/g, "");  // remove all >[<
                                                       strTemp = strTemp.replace(/]+/g, "");  // remove all >]<
                                                       if (strTemp !== '') {
                                                           return false;
                                                       } else {
                                                           return true;
                                                       }
                                                   } else {
                                                       return true;
                                                   }
                                               }
                                            

                                            in Z7 noch ein \ vor die [ setzen

                                            Und wie sieht es dann im MessageCreator mit dem dB aus, würde dies nämlich auch übernehmen wollen 😊

                                            OstfrieseUnterwegs 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate

                                            828
                                            Online

                                            31.6k
                                            Users

                                            79.5k
                                            Topics

                                            1.3m
                                            Posts

                                            25
                                            336
                                            41002
                                            Loading More Posts
                                            • Oldest to Newest
                                            • Newest to Oldest
                                            • Most Votes
                                            Reply
                                            • Reply as topic
                                            Log in to reply
                                            Community
                                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                            The ioBroker Community 2014-2023
                                            logo