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

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

Community Forum

  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. [Script] MessageHandler: Nachrichten protokollieren +VIS

NEWS

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

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

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

[Script] MessageHandler: Nachrichten protokollieren +VIS

Geplant Angeheftet Gesperrt Verschoben JavaScript
336 Beiträge 25 Kommentatoren 64.0k Aufrufe 40 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • UhulaU Uhula

    @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 Offline
    T Offline
    Tirador
    schrieb am zuletzt editiert von
    #240

    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 );
       
       
    

    OstfrieseUnterwegsO 1 Antwort Letzte Antwort
    0
    • T Tirador

      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 );
         
         
      

      OstfrieseUnterwegsO Offline
      OstfrieseUnterwegsO Offline
      OstfrieseUnterwegs
      schrieb am zuletzt editiert von
      #241

      @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 Antwort Letzte Antwort
      0
      • OstfrieseUnterwegsO OstfrieseUnterwegs

        @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 Offline
        S Offline
        Saschag
        schrieb am zuletzt editiert von
        #242

        @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 😊

        OstfrieseUnterwegsO 1 Antwort Letzte Antwort
        0
        • S Saschag

          @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 😊

          OstfrieseUnterwegsO Offline
          OstfrieseUnterwegsO Offline
          OstfrieseUnterwegs
          schrieb am zuletzt editiert von
          #243

          @Saschag

          Im Moment so:
          Man muss nun auf den Text vergleichen comp: '==', val:'Home'.

              // Landroid Egon 
          
              {
                  msgID: 'LANDROID_INFO', 
                  triggerDP: 'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status'/*Landroid status*/,
                  postMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status', comp: '!=', val:'Home', delayTime: 10},
                  removeMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status', comp: '==', val:'Home'},
                  msgText_1: {text: 'Egon arbeitet: '},
                  msgText_2: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status'/*Landroid status*/},
                  countEventsDP: ''
              },
          
              {
                  msgID: 'LANDROID_WARN', 
                  triggerDP: 'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error'/*Landroid Error*/,
                  postMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error', comp: '!=', val:'No error', delayTime: 10},
                  removeMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error', comp: '==', val:'No error'},
                  msgText_1: {text: 'Egons Gesundheitszustand: '},
                  msgText_2: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error'/*Landroid error*/},
                  countEventsDP: ''
              },
           
          
          S 1 Antwort Letzte Antwort
          0
          • OstfrieseUnterwegsO OstfrieseUnterwegs

            @Saschag

            Im Moment so:
            Man muss nun auf den Text vergleichen comp: '==', val:'Home'.

                // Landroid Egon 
            
                {
                    msgID: 'LANDROID_INFO', 
                    triggerDP: 'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status'/*Landroid status*/,
                    postMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status', comp: '!=', val:'Home', delayTime: 10},
                    removeMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status', comp: '==', val:'Home'},
                    msgText_1: {text: 'Egon arbeitet: '},
                    msgText_2: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.status'/*Landroid status*/},
                    countEventsDP: ''
                },
            
                {
                    msgID: 'LANDROID_WARN', 
                    triggerDP: 'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error'/*Landroid Error*/,
                    postMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error', comp: '!=', val:'No error', delayTime: 10},
                    removeMsgDP: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error', comp: '==', val:'No error'},
                    msgText_1: {text: 'Egons Gesundheitszustand: '},
                    msgText_2: {dp:'worx.0.2019xxxxxxxxxxxxxxxxxx.mower.error'/*Landroid error*/},
                    countEventsDP: ''
                },
             
            
            S Offline
            S Offline
            Saschag
            schrieb am zuletzt editiert von
            #244

            @OstfrieseUnterwegs

            Danke werde ich für unseren „Oskar“ übernehmen 😊

            1 Antwort Letzte Antwort
            0
            • T Offline
              T Offline
              Tirador
              schrieb am zuletzt editiert von
              #245

              Mal was neues von mir:

              Ich habe das Raumklima-Skript integriert (basierend auf der absoluten Feuchte und Temperaturen innen / außen wird eine Lüftungsempfehlung gegeben).

              Skript siehe: https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen

              2020-05-20 20_44_23-vis.png

              MessageStateCreator:

                  // Raumklima - Lüftungserinnerung
                  // Unterstützung durch Raumklima-Skript / Absolute Feuchte berechnen
                  // https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen
                  {
                      msgID: 'RAUMKLIMA_INFO', 
                      triggerDP: ['javascript.0.Raumklima.Lüften'],
                      postMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '==', val: true},  
                      removeMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                      msgText_1: {text: 'Bitte lüften in den folgenden Räumen:'},
                      msgText_2: {dp: 'javascript.0.Raumklima.Lüften_Liste'},
                      countEventsDP: 'javascript.0.Raumklima.Lüften_Anzahl'
                  },
              

              MessageHandler:

                      // Erinnerung Fenster lüften!
                      RAUMKLIMA_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "Lüftungserinnerung", msgText: "Bitte Fenster öffnen", quit: false, mdIcon: 'opacity', mdIconColor: '', fontColor: '', backgroundColor: ''},
               
              
              D B 2 Antworten Letzte Antwort
              1
              • BostilB Offline
                BostilB Offline
                Bostil
                schrieb am zuletzt editiert von
                #246

                Ist es Unsinn zu hoffen, dass dieses Script mal als ein Adapter (mit entsprechend einfacherer Handhabung) integriert werden könnte ?

                :-)

                T 1 Antwort Letzte Antwort
                0
                • BostilB Bostil

                  Ist es Unsinn zu hoffen, dass dieses Script mal als ein Adapter (mit entsprechend einfacherer Handhabung) integriert werden könnte ?

                  :-)

                  T Offline
                  T Offline
                  Tirador
                  schrieb am zuletzt editiert von Tirador
                  #247

                  @Bostil eventuell. Momentan habe ich dafür keinen Bedarf. Durch die getrennte Architektur reden wir hier auch über zwei Adaptern. Die Komplexität ist am Ende die gleiche, wenn man die einzelne Konfiguration in Adapter Feldern machen müsste. Ich sehe jetzt keinen mega Mehrwert.

                  1 Antwort Letzte Antwort
                  1
                  • T Tirador

                    Mal was neues von mir:

                    Ich habe das Raumklima-Skript integriert (basierend auf der absoluten Feuchte und Temperaturen innen / außen wird eine Lüftungsempfehlung gegeben).

                    Skript siehe: https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen

                    2020-05-20 20_44_23-vis.png

                    MessageStateCreator:

                        // Raumklima - Lüftungserinnerung
                        // Unterstützung durch Raumklima-Skript / Absolute Feuchte berechnen
                        // https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen
                        {
                            msgID: 'RAUMKLIMA_INFO', 
                            triggerDP: ['javascript.0.Raumklima.Lüften'],
                            postMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '==', val: true},  
                            removeMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                            msgText_1: {text: 'Bitte lüften in den folgenden Räumen:'},
                            msgText_2: {dp: 'javascript.0.Raumklima.Lüften_Liste'},
                            countEventsDP: 'javascript.0.Raumklima.Lüften_Anzahl'
                        },
                    

                    MessageHandler:

                            // Erinnerung Fenster lüften!
                            RAUMKLIMA_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "Lüftungserinnerung", msgText: "Bitte Fenster öffnen", quit: false, mdIcon: 'opacity', mdIconColor: '', fontColor: '', backgroundColor: ''},
                     
                    
                    D Offline
                    D Offline
                    der-eine
                    schrieb am zuletzt editiert von
                    #248

                    @Tirador danke, genau so brauch ichs fürs Wiki! :+1:

                    @all zeigt uns doch mal eure Messages damit wir sie ins Wiki aufnehmen können. :grin:

                    B 2 Antworten Letzte Antwort
                    0
                    • D der-eine

                      @Tirador danke, genau so brauch ichs fürs Wiki! :+1:

                      @all zeigt uns doch mal eure Messages damit wir sie ins Wiki aufnehmen können. :grin:

                      B Offline
                      B Offline
                      BoehserWolf
                      schrieb am zuletzt editiert von BoehserWolf
                      #249

                      @der-eine

                      Hab noch einen für die Türklingel. Bei wird das mit einen HmIP-DSD-PCB erkannt.

                      MessageStateCreator:

                          // Türklingel
                          {
                              msgID: 'DOORBELL_RING', 
                              triggerDP: ['hm-rpc.0.0026DA49A82A43.1.STATE'],
                              postMsgDP: {dp:'hm-rpc.0.0026DA49A82A43.1.STATE', comp: '==', val: true}, 
                              msgText_1: {text: 'Jemand nervt an der Haustür...'}, 
                          },
                      

                      MessageHandler:

                              // Türklingel
                              DOORBELL_RING: {msgEvent: ['TELEGRAM'], logType: 'LAST',  severity: 'INFO',  msgHeader: "Klingel", msgText: "Es klingelt.", mdIcon: 'notifications_active', quit: true, visView: '', mdIconColor: '', fontColor: '', backgroundColor: ''},
                      

                      052dc767-a03d-4c5d-9f72-1612e288a23c-grafik.png

                      283e9cb0-b103-496f-98df-03ee8cce9c3a-grafik.png

                      D 1 Antwort Letzte Antwort
                      0
                      • B BoehserWolf

                        @der-eine

                        Hab noch einen für die Türklingel. Bei wird das mit einen HmIP-DSD-PCB erkannt.

                        MessageStateCreator:

                            // Türklingel
                            {
                                msgID: 'DOORBELL_RING', 
                                triggerDP: ['hm-rpc.0.0026DA49A82A43.1.STATE'],
                                postMsgDP: {dp:'hm-rpc.0.0026DA49A82A43.1.STATE', comp: '==', val: true}, 
                                msgText_1: {text: 'Jemand nervt an der Haustür...'}, 
                            },
                        

                        MessageHandler:

                                // Türklingel
                                DOORBELL_RING: {msgEvent: ['TELEGRAM'], logType: 'LAST',  severity: 'INFO',  msgHeader: "Klingel", msgText: "Es klingelt.", mdIcon: 'notifications_active', quit: true, visView: '', mdIconColor: '', fontColor: '', backgroundColor: ''},
                        

                        052dc767-a03d-4c5d-9f72-1612e288a23c-grafik.png

                        283e9cb0-b103-496f-98df-03ee8cce9c3a-grafik.png

                        D Offline
                        D Offline
                        der-eine
                        schrieb am zuletzt editiert von
                        #250

                        @BoehserWolf super. Kannst Du bitte mal ein Foto nur von der Nachricht alleine machen? Danke.

                        B 1 Antwort Letzte Antwort
                        0
                        • D der-eine

                          @BoehserWolf super. Kannst Du bitte mal ein Foto nur von der Nachricht alleine machen? Danke.

                          B Offline
                          B Offline
                          BoehserWolf
                          schrieb am zuletzt editiert von
                          #251

                          @der-eine Done.

                          D 1 Antwort Letzte Antwort
                          0
                          • B BoehserWolf

                            @der-eine Done.

                            D Offline
                            D Offline
                            der-eine
                            schrieb am zuletzt editiert von der-eine
                            #252

                            @BoehserWolf danke. :+1:

                            1 Antwort Letzte Antwort
                            0
                            • T Tirador

                              Mal was neues von mir:

                              Ich habe das Raumklima-Skript integriert (basierend auf der absoluten Feuchte und Temperaturen innen / außen wird eine Lüftungsempfehlung gegeben).

                              Skript siehe: https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen

                              2020-05-20 20_44_23-vis.png

                              MessageStateCreator:

                                  // Raumklima - Lüftungserinnerung
                                  // Unterstützung durch Raumklima-Skript / Absolute Feuchte berechnen
                                  // https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen
                                  {
                                      msgID: 'RAUMKLIMA_INFO', 
                                      triggerDP: ['javascript.0.Raumklima.Lüften'],
                                      postMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '==', val: true},  
                                      removeMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                                      msgText_1: {text: 'Bitte lüften in den folgenden Räumen:'},
                                      msgText_2: {dp: 'javascript.0.Raumklima.Lüften_Liste'},
                                      countEventsDP: 'javascript.0.Raumklima.Lüften_Anzahl'
                                  },
                              

                              MessageHandler:

                                      // Erinnerung Fenster lüften!
                                      RAUMKLIMA_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "Lüftungserinnerung", msgText: "Bitte Fenster öffnen", quit: false, mdIcon: 'opacity', mdIconColor: '', fontColor: '', backgroundColor: ''},
                               
                              
                              B Offline
                              B Offline
                              BoehserWolf
                              schrieb am zuletzt editiert von BoehserWolf
                              #253

                              @Tirador bzw. alle: Sag mal hast du bei einigen Events auch teilweise leere Inhalte?

                              Ein gutes Beispiel ist die Lüftungserinnerung aus dem Script skript-absolute-feuchte-berechnen. Bei mir kam es schon öfter vor, dass eine Erinnerung vorliegt (DP javascript.0.Raumklima.Lüften = true), aber der Text entnommen aus dem DP javascript.0.Raumklima.Lüften_Liste, war leer im Event auf der VIS.
                              Wenn ich dann im DP javascript.0.Raumklima.Lüften_Liste nachsehe, ist er mit den erwarteten Werten/Räumen gefüllt.

                              Ich denke, dass der zeitliche Ablauf im Script eine entscheidende Rolle spielt. In obigen Bsp. wird im Script zuerst der DP javascript.0.Raumklima.Aktualsierung gesetzt, danach alle anderen wie auch der Listen DP.

                              Ich habe im Script jetzt das Setzen des DP javascript.0.Raumklima.Aktualsierung als letztes gesetzt, so dass alle DP vorher gefüllt sind und beobachte die Situation im Moment noch.

                              @all Kann das jemand bestätigen?
                              @Tirador Falls ja, hast du eine Idee wie man den zeitlichen Ablauf beim Triggern irgendwie in den Griff bekommen kann? Damit meine ich ohne immer zwangsläufig auf den letzten DP im Script triggern oder das Script entsprechend anpassen zu müssen?

                              Ganz nebenbei: Super geniale Idee mit der Umsetzung :+1:

                              T 1 Antwort Letzte Antwort
                              0
                              • B BoehserWolf

                                @Tirador bzw. alle: Sag mal hast du bei einigen Events auch teilweise leere Inhalte?

                                Ein gutes Beispiel ist die Lüftungserinnerung aus dem Script skript-absolute-feuchte-berechnen. Bei mir kam es schon öfter vor, dass eine Erinnerung vorliegt (DP javascript.0.Raumklima.Lüften = true), aber der Text entnommen aus dem DP javascript.0.Raumklima.Lüften_Liste, war leer im Event auf der VIS.
                                Wenn ich dann im DP javascript.0.Raumklima.Lüften_Liste nachsehe, ist er mit den erwarteten Werten/Räumen gefüllt.

                                Ich denke, dass der zeitliche Ablauf im Script eine entscheidende Rolle spielt. In obigen Bsp. wird im Script zuerst der DP javascript.0.Raumklima.Aktualsierung gesetzt, danach alle anderen wie auch der Listen DP.

                                Ich habe im Script jetzt das Setzen des DP javascript.0.Raumklima.Aktualsierung als letztes gesetzt, so dass alle DP vorher gefüllt sind und beobachte die Situation im Moment noch.

                                @all Kann das jemand bestätigen?
                                @Tirador Falls ja, hast du eine Idee wie man den zeitlichen Ablauf beim Triggern irgendwie in den Griff bekommen kann? Damit meine ich ohne immer zwangsläufig auf den letzten DP im Script triggern oder das Script entsprechend anpassen zu müssen?

                                Ganz nebenbei: Super geniale Idee mit der Umsetzung :+1:

                                T Offline
                                T Offline
                                Tirador
                                schrieb am zuletzt editiert von
                                #254

                                @BoehserWolf das Verhalten ist sehr einfach erklärbar. Die Datenpunkte, die als Trigger gesetzt sind werden nur dann ausgelöst, wenn der Inhalt des Datenpunkts sich verändert.

                                Daher sollte man einen Datenpunkt bzw. mehrere Datenpunkte als Trigger definieren, der/die bei Änderung möglichst alle "Systemzustände" abdeckt/abdecken. Wenn Du beim Raumklimaskript nur den Datenpunkt nimmst, dass gelüftet werden soll (ja/nein) kann dies nicht hinreichend sein. Angenommen du hast drei Räume. Das Raumklimaskript sagt nun Lüften = Ja für den ersten Raum. Damit wird die Nachricht getriggert und ausgelöst. Sofern nun ein zweiter Raum hinzukommt, in dem auch gelüftet werden soll wird keine erneute Nachricht ausgelöst.

                                Für das Raumklimaskript hatte ich initial auch den DP lueften überwacht, nun aber das ganze auf den Datenpunkt mit der Raumliste umgestellt.

                                    // Raumklima - Lüftungserinnerung
                                    // Unterstützung durch Raumklima-Skript / Absolute Feuchte berechnen
                                    // https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen
                                    {
                                        msgID: 'RAUMKLIMA_INFO', 
                                        triggerDP: ['javascript.0.Raumklima.Lüften_Liste'],
                                        postMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '==', val: true},  
                                        removeMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                                        msgText_1: {text: 'Bitte lüften in den folgenden Räumen:'},
                                        msgText_2: {dp: 'javascript.0.Raumklima.Lüften_Liste'},
                                        countEventsDP: 'javascript.0.Raumklima.Lüften_Anzahl'
                                    },
                                
                                OstfrieseUnterwegsO 1 Antwort Letzte Antwort
                                0
                                • T Tirador

                                  @BoehserWolf das Verhalten ist sehr einfach erklärbar. Die Datenpunkte, die als Trigger gesetzt sind werden nur dann ausgelöst, wenn der Inhalt des Datenpunkts sich verändert.

                                  Daher sollte man einen Datenpunkt bzw. mehrere Datenpunkte als Trigger definieren, der/die bei Änderung möglichst alle "Systemzustände" abdeckt/abdecken. Wenn Du beim Raumklimaskript nur den Datenpunkt nimmst, dass gelüftet werden soll (ja/nein) kann dies nicht hinreichend sein. Angenommen du hast drei Räume. Das Raumklimaskript sagt nun Lüften = Ja für den ersten Raum. Damit wird die Nachricht getriggert und ausgelöst. Sofern nun ein zweiter Raum hinzukommt, in dem auch gelüftet werden soll wird keine erneute Nachricht ausgelöst.

                                  Für das Raumklimaskript hatte ich initial auch den DP lueften überwacht, nun aber das ganze auf den Datenpunkt mit der Raumliste umgestellt.

                                      // Raumklima - Lüftungserinnerung
                                      // Unterstützung durch Raumklima-Skript / Absolute Feuchte berechnen
                                      // https://forum.iobroker.net/topic/2313/skript-absolute-feuchte-berechnen
                                      {
                                          msgID: 'RAUMKLIMA_INFO', 
                                          triggerDP: ['javascript.0.Raumklima.Lüften_Liste'],
                                          postMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '==', val: true},  
                                          removeMsgDP: {dp:'javascript.0.Raumklima.Lüften', comp: '!=', val: true}, // Nachricht enfernen, wenn die Bedingung eintritt
                                          msgText_1: {text: 'Bitte lüften in den folgenden Räumen:'},
                                          msgText_2: {dp: 'javascript.0.Raumklima.Lüften_Liste'},
                                          countEventsDP: 'javascript.0.Raumklima.Lüften_Anzahl'
                                      },
                                  
                                  OstfrieseUnterwegsO Offline
                                  OstfrieseUnterwegsO Offline
                                  OstfrieseUnterwegs
                                  schrieb am zuletzt editiert von
                                  #255

                                  @Tirador
                                  Ich glaube ich habe einen Bug gefunden.
                                  In Messagehandler Script steht

                                                     let telegramChatId = this.clearStr(MESSAGE_EVENTS[defMsgEvent]['telegramChatId']);
                                  
                                                      if (telegramChatId.length > 0) {
                                                          sendTo(telegramInstance, {ChatId: telegramChatId, text: telegramMsg, parse_mode: 'Markdown'}   );
                                                      }
                                  
                                  

                                  Es sollte aber statt ChatId chatId sein, mit kleinem c

                                  Ich mache noch ein GitHub Issue auf

                                  T 1 Antwort Letzte Antwort
                                  0
                                  • D Offline
                                    D Offline
                                    der-eine
                                    schrieb am zuletzt editiert von
                                    #256

                                    Hallo zusammen,

                                    könnt ihr mir bitte für das Wiki Messages für folgende Events schicken:

                                    • Kühlschranktür offen

                                    • Alarmanlage ausgelöst

                                    • Fenster länger geöffnet

                                    • Logitech Harmony

                                    • Landroid

                                    Die Fotos sollten nur die Message an sich zeigen. Danke :v:

                                    Bildschirmfoto 2020-06-05 um 02.22.35.png

                                    @Tirador gibt es eine Möglichkeit, die Telegram Nachrichten zu entprellen? Damit ich nicht 5 Nachrichten innerhalb 1 min bekomme wenn der Postbote jeden Brief einzeln einwirft?

                                    S 2 Antworten Letzte Antwort
                                    0
                                    • D Offline
                                      D Offline
                                      der-eine
                                      schrieb am zuletzt editiert von der-eine
                                      #257

                                      Für alle die ihre eingeschaltenen Lichter zählen und im MessageHandler anzeigen wollen hier der aktualisierte Wiki-Eintrag mit Skript (4.6).

                                      Bildschirmfoto 2020-06-05 um 18.30.08.png

                                      S 1 Antwort Letzte Antwort
                                      0
                                      • D der-eine

                                        Hallo zusammen,

                                        könnt ihr mir bitte für das Wiki Messages für folgende Events schicken:

                                        • Kühlschranktür offen

                                        • Alarmanlage ausgelöst

                                        • Fenster länger geöffnet

                                        • Logitech Harmony

                                        • Landroid

                                        Die Fotos sollten nur die Message an sich zeigen. Danke :v:

                                        Bildschirmfoto 2020-06-05 um 02.22.35.png

                                        @Tirador gibt es eine Möglichkeit, die Telegram Nachrichten zu entprellen? Damit ich nicht 5 Nachrichten innerhalb 1 min bekomme wenn der Postbote jeden Brief einzeln einwirft?

                                        S Offline
                                        S Offline
                                        Saschag
                                        schrieb am zuletzt editiert von Saschag
                                        #258

                                        @der-eine

                                        AF9ADB17-D574-49D3-9516-B80C0BEFE27E.jpeg

                                        Rest folgt gleich :-)

                                        so:

                                        // Logitech Harmony
                                            // Über Harmony-Adapter
                                            {
                                                msgID: 'HARMONY_INFO', 
                                                triggerDP: 'harmony.0.Wohnzimmer_Harmony-Hub.activities.currentActivity',
                                                postMsgDP: {dp:'harmony.0.Wohnzimmer_Harmony-Hub.activities.currentActivity', comp: '!=', val:'PowerOff'},
                                                removeMsgDP: {dp:'harmony.0.Wohnzimmer_Harmony-Hub.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.Wohnzimmer_Harmony-Hub.activities.currentActivity'},
                                                countEventsDP: ''
                                            },
                                        
                                        
                                        
                                        // Logitech Harmony Info
                                                HARMONY_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "Wohnzimmer Multimedia", msgText: "", mdIcon: 'settings_remote', quit: true, visView: 'pageStart', mdIconColor: '', fontColor: '', backgroundColor: ''},
                                        
                                        
                                        1 Antwort Letzte Antwort
                                        0
                                        • D der-eine

                                          Hallo zusammen,

                                          könnt ihr mir bitte für das Wiki Messages für folgende Events schicken:

                                          • Kühlschranktür offen

                                          • Alarmanlage ausgelöst

                                          • Fenster länger geöffnet

                                          • Logitech Harmony

                                          • Landroid

                                          Die Fotos sollten nur die Message an sich zeigen. Danke :v:

                                          Bildschirmfoto 2020-06-05 um 02.22.35.png

                                          @Tirador gibt es eine Möglichkeit, die Telegram Nachrichten zu entprellen? Damit ich nicht 5 Nachrichten innerhalb 1 min bekomme wenn der Postbote jeden Brief einzeln einwirft?

                                          S Offline
                                          S Offline
                                          Saschag
                                          schrieb am zuletzt editiert von Saschag
                                          #259

                                          @der-eine

                                          7E583885-4E31-44A2-B067-9C1256818262.jpeg BDD6885B-6DF5-48D7-A37E-2359B5B877F1.jpeg

                                                  // Mover
                                                  MOVER_LOAD_POS_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "", msgText: "", quit: true, visView: 'page11', mdIcon: 'ev_station', mdIconColor: '', fontColor: '', backgroundColor: ''},
                                          
                                                  // Mover status
                                                  LANDROID_INFO: {msgEvent: [''], logType: 'LAST',  severity: 'INFO',  msgHeader: "", msgText: "", quit: true, visView: 'page11', mdIcon: 'ev_station', mdIconColor: '', fontColor: '', backgroundColor: ''},
                                                  
                                          
                                               // Mover Landrois Parkplatz Oskar
                                              // 
                                              {
                                                  msgID: 'MOVER_LOAD_POS_INFO', 
                                                  triggerDP: 'worx.0.201930198403016966D4.mower.status',
                                                  postMsgDP: {dp:'worx.0.201930198403016966D4.mower.status', comp: '==', val:1},
                                                  removeMsgDP: {dp:'worx.0.201930198403016966D4.mower.status', comp: '!=', val:1},
                                                  msgText_1: {text: 'Oskar in Parkposition'},
                                                  countEventsDP: ''
                                              },
                                          
                                              // Landroid Oskar 
                                           
                                              {
                                                  msgID: 'LANDROID_INFO', 
                                                  triggerDP: 'worx.0.201930198403016966D4.mower.status',
                                                  postMsgDP: {dp:'worx.0.201930198403016966D4.mower.status', comp: '!=', val:1, delayTime: 5},
                                                  removeMsgDP: {dp:'worx.0.201930198403016966D4.mower.status', comp: '==', val:1},
                                                  msgText_1: {text: 'Oskar arbeitet: '},
                                                  msgText_2: {dp:'worx.0.201930198403016966D4.mower.status'},
                                                  countEventsDP: ''
                                              },
                                          

                                          Das ICON vom Mover "Oskar" ist noch nicht so das wahre ;-)

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


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          663

                                          Online

                                          32.4k

                                          Benutzer

                                          81.4k

                                          Themen

                                          1.3m

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

                                          • Du hast noch kein Konto? Registrieren

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