//Version 0.97.16 // Erläuterung Update: // Suche im Script nach 123456 und kopiere/ersetze ab diesem Punkt. So braucht ihr die Konfiguration nicht zu erneuern. // Das gilt solange die Version nicht im nächsten Abschnitt genannt wird, dann muß man auch die Konfiguration neumachen oder im Forum nach den Änderungen schauen. // Link: https://forum.iobroker.net/topic/30616/script-dwd-uwz-nina-warnungen-als-push-sprachnachrichten/ // // V.0.97 Vor dem Start des Scriptes den Datenzweig .alert löschen. // V.0.97.2 Konfigurationsoption "const uFilterDuplicate" entfernt, kann ab 123456 kopiert werden. // V.0.97.5 uMaxCharToSpeak hinzugefügt in Konfiguration // V.0.97.6 4 neue Konfigurationsoptionen hinzugefügt // V.0.97.7.1 2 neue Konfigurationsoptionen hinzugefügt // V.0.97.8 Neuen Datenpunkt für Ausgabe des Email Bodys eingefügt. // V.0.97.9 Iogo maximale Zeichenbegrenzung und splitten langer Nachrichten eingebaut. /* /* ************************************************************************* */ /* Script zum Übertragen der DWD/UWZ-Wetterwarnungen über */ /* Telegram, Pushover, Home24-Mediaplayer, SayIt, Alexa */ /* Datenpunkt, eMail oder ioGo */ /* Pushnachrichten können manuell ausgelöst werden */ /* höchstes Warnlevel pro Warnungstyp is als State vorhanden */ /* mit freundlicher Unterstützung von Paul53 (Tausend Dank nochmals) */ /* Stand: 13022017 PrinzEisenherz1 */ /* Stand: 08032020 ticaki */ /* */ /* */ /* ************************************************************************* */ /* Unterstützt: - Telegram, Pushover, Home24-Mediaplayer, SayIt, Alexa, Datenpunkt, eMail oder ioGo - DWD-Adapter & Unwetterzentrale-Script & NINA-Adapter V0.0.22 - Wetterwarnung - Wetterentwarnung Funktionen: - Filter die Warnungen nach doppelt, Gefahr(level) und Höhe - Umschalten über iobroker zwischen DWD/UWZ/NINA - Autorestart bei Datenpunkterstellung - Automatischer Versand und/oder manueller Nachrichtenversand - Zeitschaltuhr für Sprachausgabe - Datenpunkte mit der Startzeit, Endzeit, Type, Schlagzeile, Beschreibung, Farbe für Level(bgcolor) und höchstem Warnlevel dieses Typs - Unterstützung für 0_userdata - Datenpunkthauptpfade sind konfigurierbar incl. 0_userdata - Konfigurationsprüfung soweit möglich - Automodus und einzelne Pushdienste über iobroker schaltbar, sowohl für Automodus als auch Manuell - Optimierte Sprachausgabe - Fingerweg vom .alive state :) Kleinkram: - Sprachausgabe: Sturmdetails werden ausgefiltert oder korrekt ausgesprochen (konfigurierbar) - Sprachausgabe: Pause zwischen dem Absenden der einzelnen Warnungen an die Wiedergabeeinheit konfigurierbar. - Manuelle Sprachnachrichten können die Zeitschaltuhr missachten. (konfigurierbar) - Multi-User/Device bei fast allen Pushdiensten verfügbar (außer Datenpunkt & pushover) - Alexa und SayIt mit Lautstärkeeinstellung. Alexagruppen unterstützen keine Lautstärke trotzdem konfigurieren. - Zusätzliche Hervorhebung konfigurierbar über attentionWarningLevel (im Betreff/Ansage) - Filter für Nina-sender - Namesbezeichner für Nina verfügbar, diese werden benötigt, falls in der Warnung Ort genannt wird, das auszugeben und damit die Bedeutung der Warnung hervorzuheben. Farben-Bedeutung: 0 - Grün 1 - Dunkelgrün 2 - Gelb Wetterwarnungen (Stufe 2) 3 - Orange Warnungen vor markantem Wetter (Stufe 3) 4 - Rot Unwetterwarnungen (Stufe 4) // im Grunde höchste Stufe in diesem Skript. 5 - Violett Warnungen vor extremem Unwetter (nur DWD/ Weltuntergang nach aktueller Erfahrung) Dank an: - Mic für die createUserStates() Funktionen - CruziX der diese eingebaut hat. - crunchip, sigi234, Latzi fürs Testen und Ideen - die ursprünglichen Authoren s.o. /* ************************************************************************ /* ************************************************************************ */ /* ************************************************************************ */ /* Datenpfad konfigurieren */ /* ************************************************************************ */ /* */ /* 0_userdata. möglich */ /* */ /* ************************************************************************ */ var mainStatePath = 'javascript.0.wetterwarnung_test.'; /* ************************************************************************ */ /* Datenpfad konfigurieren ENDE */ /* ************************************************************************ */ /* ************************************************************************ */ /* NICHT EDITIEREN */ /* ************************************************************************ */ /* ************************************************************************ */ var konstanten = [ {'name':'telegram','value':1,count:0, delay:200, maxChar: 4000 }, {"name":'pushover',"value":2, count:0, delay:1000, maxChar: 1000}, {"name":'email',"value":4}, {"name":'sayit',"value":8, count:0, delay:0, maxChar: 940}, {"name":'home24',"value":16, count:0, delay:0}, {"name":'alexa',"value":32, count:0, delay:0, maxChar: 940}, {"name":'state',"value":64}, {"name":'iogo',"value":128, maxChar: 940, count: 0, delay: 300}, {"name":'state_html',"value":256} ]; const TELEGRAM = konstanten[0].value; const PUSHOVER = konstanten[1].value; const EMAIL = konstanten[2].value; const SAYIT = konstanten[3].value; const HOMETWO = konstanten[4].value; const ALEXA = konstanten[5].value; const STATE = konstanten[6].value; const IOGO = konstanten[7].value; const STATE_HTML = konstanten[8].value; var uPushdienst = 0; const DWD = 1; const UWZ = 2; const NINA = 4; const MODES = [{mode:DWD, text:'DWD'},{mode:UWZ, text:'UWZ'},{mode:NINA, text:'NINA'}]; if(mainStatePath[mainStatePath.length - 1] != '.') mainStatePath += '.'; const aliveState = mainStatePath+'alive'; if (extendedExists(aliveState)) { setState(aliveState, true, true); } /* ************************************************************************* */ /* ************************************************************************* */ /* ************************************************************************* */ /* Konfiguration ab hier */ /* ************************************************************************* */ /* ************************************************************************* */ /* ************************************************************************* */ /* Konfiguration der zu nutzenden Ausgabe um //uPushdienst+= PUSHOVER; zu aktivieren, bitte die // enfernen, also uPushdienst+= PUSHOVER; */ uPushdienst+= TELEGRAM; // Auskommentieren zum aktivieren //uPushdienst+= PUSHOVER; // Auskommentieren zum aktivieren //uPushdienst+= EMAIL; // Auskommentieren zum aktivieren. Einstellungen nicht vergessen //uPushdienst+= SAYIT; // Auskommentieren zum aktivieren. Einstellungen nicht vergessen //uPushdienst+= HOMETWO; // Auskommentieren zum aktivieren. Einstellungen nicht vergessen //uPushdienst+= ALEXA; // Auskommentieren zum aktivieren. Einstellungen nicht vergessen //uPushdienst+= STATE; // Auskommentieren zum aktivieren. State befindet sich unter mainStatePath.message //uPushdienst+= IOGO; // Auskommentieren zum aktivieren. Einstellungen nicht vergessen //uPushdienst+= STATE_HTML; // Auskommentieren zum aktivieren. State_html befindet sich unter mainStatePath.messageHtml als Tabelle /* ************************************************************************* */ /* Beispiele zur weiteren Konfiguration */ /* ************************************************************************* */ /* /* kein oder einen Eintrag möglich: /* var senderEmailID = ["max@mustermann.de"]; /* /* kein oder mehrfach nach gleichem Muster [1, 2, 3] bzw. ['1', '2', '3'] Einträge /* '' ist das selbe wie "", jedoch nicht mischen. /* /* var empfaengerEmailID = ["max@musterman.de","max2@musterman.de"]; /* var telegramUser = []; // leer /* var telegramUser = ['']; // leer /* var telegramUser = ['Hans']; // User mit Namen Hans /* var telegramUser = ['Hans', 'Gretel']; // User mit Namen Hans und User mit Namen Gretel /* var idSayIt = ["sayit.0.tts.text"]; /* var sayItVolumen = [60]; // Zahl ohne '' /* var idSayIt = ["sayit.0.tts.text","sayit.1.tts.text"]; /* var sayItVolumen = [60, 30]; // mehrfach Zahl ohne '' /* var ioGoUser = ['max@musterman.de']; /* var idAlexaSerial =['G090RV32984110Y', 'G090RZ3345643XR']; /* var alexaVolumen = [40, 30]; // Lautstärke die gleiche Anzahl an Einträgen wie bei idAlexaSerial /* /* ************************************************************************* */ /* weitere Konfiguration */ /* ************************************************************************* */ /* für UWZ Regionnamen eingeben "Warnung der Unwetterzentrale für XXXX" */ /* Textbeispiel anstatt Entenhausen: 'Stadt / Dorfname' 'Berlin' 'den Regionsbezeichnung' 'den Schwarzwald' ''*/ /* var regionName = ['UWZDE13245', 'Entenhausen'] */ var regionName = [['UWZDEXXXX','XXXX']]; // für Nina wird die Gemeinde und der Landkreis benötigt. Am besten von hier kopieren: https://warnung.bund.de/assets/json/suche_channel.json // ohne die kryptischen Zeichen. Das ersetzt nicht den NINA-Adapter var uGemeinde = 'XXXX'; // hier steht zum Beispiel, Hamburg, Unterdorf var uLandkreis = 'XXXX'; // hier Kreis Bitburg, Landkreis Fürth /* Einstellungen zur Emailbenachrichtigung*/ var senderEmailID = [""]; // mit Sender Emailadresse füllen. email Adapter muß installiert sein. 1 Eintrag erlaubt [] oder ["email1"] var empfaengerEmailID = [""]; // mit Empfänger Emailadresse füllen. Mehrere Empfänger möglich. [] oder ["email1"] oder ["email1","email2"] /* Konfiguration Sprachausgabe über Home24 - Mediaplayer */ //var idMediaplayer = ["192.168.178.x:Port"]; var idMediaplayer = [""]; // Eingabe IP-Adresse incl. Port für Home24-Mediaplayer mehrere Möglich - ungetestet /* Konfiguration Telegram */ var telegramUser = ['Michael']; // Einzelnutzer ['Hans']; Multinutzer ['Hans', 'Gretel']; Nutzer vom Adapter übernehmen []; var telegramChatId = ['XXXXXXXX']; var uTelegramReplyMarkup = {keyboard: [['Übersicht']], resize_keyboard: true}; // Falls ihr ein Telegrammmenü verwendet, könnt ihr hier einen Weg zurück definieren z.B.: {keyboard: [['Zurück']], resize_keyboard: true}; var uTelegramAllowNotification = true; // Erlaube Telegramnotification (Benachrichtigungston/Hinweise auf dem Empfangsgerät) /* Konfiguration Pushover */ var uPushoverDeviceName = ''; // ein bestimmtes Gerät z.B: ['droid4']; var uPushoverSound = ''; // Sounds siehe: https://pushover.net/api#sounds //Konfiguration von ioGo var ioGoUser = ['']; // // Einzelnutzer ['Hans']; Multinutzer ['Hans', 'Gretel']; Nutzer vom Adapter übernehmen []; /* Konfiguration Sprachausgabe über SayIt */ var idSayIt = ["sayit.0.tts.text"]; // mehrfach Einträge möglich var sayItVolumen = [30]; // gleiche Anzahl wie idSayIt /* Konfiguration Sprachausgabe über Alexa /* mehrere Einträge möglich, bei mir ging nur der Echo, 2 dots 2.Gen reagieren nicht auf announcement. */ var idAlexaSerial = ['']; // die reine Seriennummer des Echos z.B.: var idAlexaSerial =['G090RV32984110Y', 'G090RV32984110Y'] var alexaVolumen = [30]; // Lautstärke die gleiche Anzahl an Einträgen wie bei idAlexaSerial // Filtereinstellungen const minlevel = 1 // Warnungen unterhalb dieses Levels nicht senden; const attentionWarningLevel = 4 // Warnung gleich oder oberhalb dieses Levels mit zusätzlichen Hinweisen versehen const minhoehe = 0 // Warnung für eine Höhe unterhalb dieses Wertes nicht senden const maxhoehe = 5000 // Warnung für eine Höhe oberhalb dieses Wertes nicht senden //Formatierungsstring für Datum / Zeit Alternative "TT.MM.YYYY SS:mm" KEINE Anpassung nötig const formatierungString = "TT.MM.YY SS:mm"; // Sprachausgabe Zeiten // Für durchgehende Sprachausgabe die Einstellung der Zeiten auf '' setzen. z.B. var startTimeSpeak = ''; var startTimeSpeak = '6:45';// Zeiten mo - fr ab der Sprachausgaben ok sind. Nicht unter 6 Uhr gehen oder den Schedule ändern var startTimeSpeakWeekend = '9:00';// sa + so Bemerkung siehe oben var endTimeSpeak = '22:30'; // ab diesem Zeitpunkt gibt es keine Sprachausgabe // Ein manuellen Auslösen von Sprachnachrichten, löscht alle noch nicht ausgegebenen Sprachnachrichten aus der Liste. var uManuellClickClearSpeakMessageList = true; //Auslösen der Pushnachricht über States ignoriert Sprachausgabezeiten var forcedSpeak = true; // keine Ansage über m/s Knoten und Windstärke. Die Angabe mit Kilometer pro Stunde wird angesagt var windForceDetailsSpeak = false; /* ************************************************************************* */ /* Nur Anpassen wenn nötig */ /* ************************************************************************* */ // Die Geschwindigkeit gibt an wie lange das Skript wartet bevor es eine neue Nachricht an die Sprachausgabe sendet. konstanten[3].delay /*SayIt*/ = 86; // Vorlese Geschwindigkeit pro Zeichen in ms konstanten[4].delay /*Home24*/ = 90; // Vorlese Geschwindigkeit pro Zeichen in ms konstanten[5].delay /*Alexa*/ = 86; // Vorlese Geschwindigkeit pro Zeichen in ms // Mit diesen Optionen verringert man die Nachrichtenlänge in dem Beschreibung oder Handlungsanweisungen // nicht der Nachricht hinzugefügt werden. var uHtmlMitBeschreibung = true; // gilt für Email var uHtmlMitAnweisungen = true; // uHtmlMitBeschreibung muß evenfalls true sein um Anweisungen zu erhalten var uTextMitBeschreibung = true; // gilt nicht für Email, aber für alle anderen Textnachrichten var uTextMitAnweisungen = true; // uTextMitBeschreibung muß evenfalls true sein um Anweisungen zu erhalten var uSpracheMitBeschreibung = true; // gilt für alle Sprachnachrichten var uSpracheMitAnweisungen = true; // uSpracheMitBeschreibung muß evenfalls true sein um Anweisungen zu erhalten // Obergrenze an Zeichen die über Sprachausgabe ausgegeben werden, bei überschreitung wird nur die Schlagzeile ausgegebenen var uMaxCharToSpeak = 0; // 0 = aus - Zahl größer als 0 = maximal Zeichenanzahl (1000 sind rund 86 Sekunden bla bla) // Automodus Filter um Warnungen unterhalb attentionWarningLevel von DWD, UWZ oder NINA zu unterdrücken // Sprachausgabe bei auto und manuell unterdrückt. // Diese Warnungen sind vorhanden, sie werden nur in den benannten Fällen ausgeblendet. // Ist eine feste Vorgabe überschreibt alles andere var uFilterList = 0; // generelles Filter für den AutoModus ( = DWD + UWZ; oder = NINA; oder = 0;), außer Warnungslevel ist gleich/über attentionWarningLevel var uAutoNinaFilterList = ['CAP@hochwasserzentralen.de']; //Nina only. Filter diesen Sender raus s.o. - mehrere ['abc','cde']; var uwzPath= 'javascript.0.UWZ'; var dwdPath= 'dwd.0'; var ninaPath= 'nina.0' var telegramInstanz= 'telegram.0'; var pushoverInstanz= 'pushover.0'; var ioGoInstanz= 'iogo.0'; var alexaInstanz= 'alexa2.0'; var emailInstanz= 'email.0'; var uLogAusgabe= true; // auf false gibt es überhaupt keine Ausgabe beim normalen Betrieb. /* ************************************************************************* */ /* ************************************************************************* */ /* ************************************************************************* */ /* Konfiguration Ende */ /* ************************************************************************* */ /* Keine Anpassungen ab hier, außer du weißt was du tuest */ /* ************************************************************************* */ /* ************************************************************************* */ /* ************************************************************************* */ //Logausgabe var DEBUG = false; var DEBUGSENDEMAIL = false; //ab hier bei Update // 123456 var uTelegramMessageShort = 'Wetterwarnungen kurz'; var uTelegramMessageLong = 'Wetterwarnungen lang'; // Aus diesen Elementen wird die html warnung zusammengesetzt. // Prefix wird als ersten eingefügt, dann mehrfach html_headline und html_message, wenn verfügbar. Zum Schluß kommt html_end // html_headline_color wird verwendet wenn eine Farbe angegeben ist und bildet hier die Hintergrundfarbe. // Jede einzelne Warnung wird mit Headline, Message und Farbe(optional) aufgerufen, wenn headline oder message leer ist, wird // die Zeichenkette nicht hinzugefügt. ###color###, ###message###, ###headline### sind Platzhalter für die jeweilgen Zeichenketten. Farbe ist // ein hexdezimaler Wert als Zeichenkette. var html_prefix = ''; var html_headline_color = ''; var html_headline = ''; var html_message = ''; var html_end = '
' + '###headline###' + '
' + '###headline###' + '
' + '###message###' + '
'; // MODE einstellen über Datenpunkte, das hier hat keine auswirkungen // nur für ersten Lauf nötig, ab dann überschreiben States diesen Wert var MODE = 0; // DWD oder UWZ wird von gültigen Einstellungen im Datenpfad überschrieben // Wandel Usereingabe in sauberes True / False um forcedSpeak = !!forcedSpeak; windForceDetailsSpeak = !!windForceDetailsSpeak; // Variable nicht konfigurierbar const SPEAK = ALEXA + HOMETWO + SAYIT; const PUSH = TELEGRAM + PUSHOVER + IOGO + STATE; const ALLMSG = EMAIL | STATE_HTML; const ALLMODES = DWD | UWZ | NINA; const CANHTML = EMAIL + STATE_HTML; const CANPLAIN = PUSH + EMAIL; const placeHolder = 'XXXXPLACEHOLDERXXXX'; const configModeState = mainStatePath + 'config.mode'; const mirrorMessageState = mainStatePath + 'message'; const mirrorMessageStateHtml = mainStatePath + 'messageHtml'; const SPACE = ' '; const NEWLINE = '\n'; var idAlexa = alexaInstanz + '.Echo-Devices.' + placeHolder + '.Commands.announcement'; var idAlexaVolumen = alexaInstanz + '.Echo-Devices.' + placeHolder + '.Commands.speak-volume'; var autoSendWarnings = true; var forceSpeak = false; var timer = null; var onClickCheckRun = false; var warnDatabase = { new: [], old: [] }; var subDWDhandler = null; var subUWZhandler = null; var subNINAhandler = null; var timeoutFromCreateState = null; var dwdpushdienst = uPushdienst, ninapushdienst = uPushdienst, uwzpushdienst = uPushdienst; let dwdManpushdienst = uPushdienst, ninaManpushdienst = uPushdienst, uwzManpushdienst = uPushdienst; var firstRun = true;; var _speakToArray = [{ speakEndtime: new Date() }]; // muß immer 1 Element enthalten var _speakToInterval = null // Warning types var warningTypesString = []; warningTypesString[DWD] = [ ['Gewitter', '⚡'], ['Sturm', '🌪'], ['Regen', '🌧'], ['Schnee', '🌨'], ['Nebel', '🌁'], ['Frost', '🌡'], ['Glatteis', '❄'], ['Tauwetter', '⛄'], ['Hitzewarnungen', '🔥'], ['UV_Warnungen', '🔆'] /*, ['Kuestenwarnungen', ''], ['Binnenseewarnungen', '']*/ ]; warningTypesString[UWZ] = [ ['n_a', ''], ['unbekannt', ''], ['Sturm-Orkan', '🌪'], ['Schneefall', '🌨'], ['Starkregen', '🌧'], ['Extremfrost', '🌡'], ['Waldbrandgefahr', '🔥'], ['Gewitter', '⚡'], ['Glätte', '❄'], ['Hitze', '🔆'], ['Glatteisregen', '❄'], ['Bodenfrost', '🌡'] ]; // State über den man gesonderte Aktionen auslösen kann, gibt die höchste Warnstufe aus. const stateAlert = // Änderungen auch in setAlertState() anpassen [ { "name": 'level', "default": -1, "type": { read: true, write: false, type: "number", name: '' } }, { "name": 'type', "default": -1, "type": { read: true, write: false, type: "number", name: '' } }, { "name": 'begin', "default": 0, "type": { read: true, write: false, role: "value.time", type: "number", name: '' } }, { "name": 'end', "default": 0, "type": { read: true, write: false, role: "value.time", type: "number", name: '' } }, { "name": 'headline', "default": '', "type": { read: true, write: false, type: "string", name: '' } }, { "name": 'description', "default": '', "type": { read: true, write: false, type: "string", name: '' } }, { "name": 'color', "default": '', "type": { read: true, write: false, type: "string", name: '' } }, { "name": 'symbol', "default": '', "type": { read: true, write: false, type: "string", name: '' } }, { "name": 'hash', "default": 0, "type": { read: true, write: false, role: "value", type: "number", name: '' } } ] // hash erzeugen String.prototype.hashCode = function() { var hash = 0, i, chr; if (this.length === 0) return hash; for (i = 0; i < this.length; i++) { chr = this.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; }; var deviceList = {}; for (let a = 0; a < konstanten.length; a++) { deviceList[konstanten[a].value] = {}; if (konstanten[a].count !== undefined) deviceList[konstanten[a].value].count = konstanten[a].count; if (konstanten[a].delay !== undefined) deviceList[konstanten[a].value].delay = konstanten[a].delay; if (konstanten[a].maxChar !== undefined) deviceList[konstanten[a].value].maxChar = konstanten[a].maxChar; } /* ************************************************************************* * Überprüfe Nutzerkonfiguration /* ************************************************************************* */ { testValueTypeLog(uPushdienst & (SPEAK + PUSH + ALLMSG), 'uPushdienst', 'number', true); testValueTypeLog(uwzPath, 'uwzPath', 'string', true); testValueTypeLog(dwdPath, 'dwdPath', 'string', true); testValueTypeLog(ninaPath, 'ninaPath', 'string', true); testValueTypeLog(telegramInstanz, 'telegramInstanz', 'string', true); testValueTypeLog(pushoverInstanz, 'pushoverInstanz', 'string', true); testValueTypeLog(ioGoInstanz, 'ioGoInstanz', 'string', true); testValueTypeLog(alexaInstanz, 'alexaInstanz', 'string', true); testValueTypeLog(emailInstanz, 'emailInstanz', 'string', true); testValueTypeLog(uGemeinde, 'uGemeinde', 'string'); testValueTypeLog(uLandkreis, 'uLandkreis', 'string'); if (!Array.isArray(regionName[0])) { regionName = [regionName]; } let b = 0; for (var a = 0; a < regionName.length; a++) { b++; if (Array.isArray(regionName) && regionName[a].length != 0) { if (regionName[a].length != 2) { if (uLogAusgabe) log('Konfiguration enthält Fehler. var regionName - Eintrag: ' + (b) + ' hat keine 2 Werte [\'UWZxxxxxxx\',\'name\']', 'error'); stopScript(scriptName); } else { if (!regionName[a][0] && !regionName[a][1]) regionName.splice(a--, 1) else { testValueTypeLog(regionName[a][0], 'regionName Wert: ' + (b) + '.01', 'string', true); testValueTypeLog(regionName[a][1], 'regionName Wert: ' + (b) + '.02', 'string'); } } } else { regionName.splice(a--, 1) } } function checkConfigArray(arr, name, type) { for (let a = 0; a < arr.length; a++) { if (!arr[a]) arr.splice(a--, 1); else { testValueTypeLog(arr[a], 'name', type); } } } checkConfigArray(uAutoNinaFilterList, 'uAutoNinaFilterList', 'string'); checkConfigArray(senderEmailID, 'senderEmailID', 'string'); checkConfigArray(empfaengerEmailID, 'empfaengerEmailID', 'string'); checkConfigArray(idAlexaSerial, 'idAlexaSerial', 'string'); checkConfigArray(idMediaplayer, 'idMediaplayer', 'string'); checkConfigArray(telegramUser, 'telegramUser', 'string'); checkConfigArray(idSayIt, 'idSayIt', 'string'); checkConfigArray(ioGoUser, 'ioGoUser', 'string'); checkConfigArray(telegramChatId, 'telegramChatId', 'string'); for (let a = 0; a < sayItVolumen.length; a++) { if (sayItVolumen[a] === undefined) sayItVolumen[a] = 0; else testValueTypeLog(sayItVolumen[a], 'sayItVolumen', 'number'); } for (let a = 0; a < alexaVolumen.length; a++) { if (alexaVolumen[a] === undefined) alexaVolumen[a] = 0; else testValueTypeLog(alexaVolumen[a], 'alexaVolumen', 'number'); } if ((uPushdienst & ALEXA) != 0) { testValueTypeLog(idAlexaSerial, 'idAlexaSerial', 'array'); if (idAlexaSerial.length == 0) { log('Keine Alexa / Echoseriennummer eingetragen. Überpüfen!', 'error'); stopScript(scriptName); } for (let a = 0; a < idAlexaSerial.length; a++) { if (!extendedExists(replacePlaceholder(idAlexa, idAlexaSerial[a]))) { log('Alexa - Serial ' + idAlexaSerial[a] + ' ist fehlerhaft. Überpüfen! Object ID:' + replacePlaceholder(idAlexa, idAlexaSerial[a]), 'error'); stopScript(scriptName); } } } if ((uPushdienst & SAYIT) != 0) { testValueTypeLog(idSayIt, 'idSayIt', 'array'); for (let a = 0; a < idSayIt.length; a++) { if ( !extendedExists(idSayIt[a]) ) { if (uLogAusgabe) log('SayIt - Konfiguration ist fehlerhaft. Überpüfen!', 'error'); stopScript(scriptName); } } } if ((uPushdienst & EMAIL) != 0) { if (senderEmailID.length > 1) { log('eMail - Konfiguration ist fehlerhaft. Nur 1 Eintrag in senderEmailID erlaubt!', 'error'); stopScript(scriptName); } } } /*************************************************************************************** * function testValueTypeLog(test, teststring, typ, need = false) * @param {any} test Variable deren Typ / Inhalt getestet werden soll * @param {string} teststring Variable als String, wie er im Script steht * @param {string} typ Soll - Type der Variable alles + 'array' * @param {boolean} need Variable darf nicht null / leer sein /***************************************************************************************/ function testValueTypeLog(test, teststring, typ, need = false) { if (test === undefined) { let errorLog = 'Konfiguration enthält Fehler. Der / Ein Wert von var ' + teststring + ' ist undefiniert oder fehlt!'; log(errorLog, 'error'); stopScript(scriptName); } if (typ == 'array') { if (!test || !Array.isArray(test)) { let errorLog = 'Konfiguration enthält Fehler. Der / Ein Wert von var ' + teststring + ' ist kein Array. Es fehlen wohl die umschließenden []!'; log(errorLog, 'error'); stopScript(scriptName); } } else if (typeof test !== typ) { let errorLog = 'Konfiguration enthält Fehler. Ändere ' + teststring + ' = ['; if (typ == 'string') { errorLog += test + '];//(' + typeof test + ') in ' + teststring + ' = [\'' + test + '\'];//(' + typ + ')'; } else { errorLog += '\'' + test + '\'];//(' + typeof test + ') in ' + teststring + ' = [' + test + '];//(' + typ + ')'; } log(errorLog, 'error'); stopScript(scriptName); } if (need && !test) { log('Konfiguration enthält Fehler. Der Wert von var ' + teststring + ' wird benötigt, ist jedoch nicht konfiguriert!', 'error'); stopScript(scriptName); } } /* ************************************************************************* * Überprüfe Nutzerkonfiguration ENDE /* ************************************************************************* * Erstellung von Datenpunkten * Trigger aktivieren und Datenpflege für eigene Datenpunkte /* ************************************************************************* */ function changeMode(modeFromState) { if (MODE != modeFromState || firstRun) { let oldMode = MODE; MODE = modeFromState; myLog('MODE wurde geändert. MODE: ' + MODE + ' firstRun:' + firstRun); if ( MODE == 0 ) log('Alle Benachrichtigungen ausgeschaltet, bitte unter ioBroker - Objektansicht .config einstellen.', 'warn'); InitDatabase(firstRun); dataSubscribe(); if (!firstRun) { // überspringe das beim Starten des Scripts for (var a = 0; a < konstanten.length; a++) { for (let x = 0; x < MODES.length; x++) { let oid = mainStatePath + 'config.auto.' + MODES[x].text.toLowerCase() + '.' + konstanten[a].name; let update = !!((switchFlags(MODE, oldMode, false) & MODES[x].mode)); if (extendedExists(oid)) { setState(oid, update || !!(getAutoPushFlags(MODE & MODES[x].mode) & konstanten[a].value)); } oid = mainStatePath + 'config.manuell.' + MODES[x].text.toLowerCase() + '.' + konstanten[a].name; if (extendedExists(oid)) { setState(oid, update || !!(getManuellPushFlags(MODE & MODES[x].mode) & konstanten[a].value)); } } } } if (autoSendWarnings && !firstRun) checkWarningsMain(); firstRun = false; } setConfigModeStates(modeFromState); } { // State der Pushnachrichten über pushover / telegram spiegelt if (!extendedExists(mirrorMessageState)) { createCustomState(mirrorMessageState, '', { read: true, write: false, desc: "State der für jede Warnung neu geschrieben wird", type: "string", }); } if (!extendedExists(mirrorMessageStateHtml)) { createCustomState(mirrorMessageStateHtml, '', { read: true, write: false, desc: "State mit dem selben Inhalt wie die Email", type: "string", }); } // MODE änderung über Datenpunkte string if (!extendedExists(aliveState)) { createCustomState(aliveState, false, { read: true, write: false, desc: "Script läuft", type: "boolean", def: false }); } if (!extendedExists(configModeState)) { createCustomState(configModeState, 'DWD', { read: true, write: true, desc: "Modusauswahl DWD oder UWZ", type: "string", def: '' }); } else { on({ id: configModeState, change: 'ne', ack: false }, function(obj) { if (obj.state.val && typeof obj.state.val === 'string' && (obj.state.val.toUpperCase().includes('DWD') || obj.state.val.toUpperCase().includes('UWZ') || obj.state.val.toUpperCase().includes('NINA'))) { //setState(configModeState, MODE, true) let mode = 0; mode |= obj.state.val.toUpperCase().includes('DWD') ? DWD : 0; mode |= obj.state.val.toUpperCase().includes('UWZ') ? UWZ : 0; mode |= obj.state.val.toUpperCase().includes('NINA') ? NINA : 0; if (MODE != mode) { myLog('Modus wird geändert von: ' + mode + ' String:' + obj.state.val); changeMode(mode); } else { changeMode(MODE); } } else { changeMode(MODE); } }); } // MODE änderung über Datenpunkte Boolean for (let a = 0; a < MODES.length; a++) { let tok = MODES[a].text.toLowerCase(); let id = mainStatePath + 'config.' + tok; if (!extendedExists(id)) { let mi = !!(MODE & MODES[a].mode); createCustomState(id, mi, { read: true, write: true, desc: "Aktivere " + tok.toUpperCase() + '.', type: "boolean", def: mi }); } else { on({ id: id, change: 'ne', ack: false }, function(obj) { let arr = obj.id.split('.'); let tok = arr[arr.length - 1].toUpperCase(); let mode = MODES[MODES.findIndex(function(j) { return j.text == tok })].mode; let oldMode = MODE; oldMode = switchFlags(oldMode, mode, obj.state.val); myLog('Modus wird geändert von: ' + MODE); changeMode(oldMode); }); MODE = switchFlags(MODE, MODES[a].mode, getState(id).val); } } //Initialisierung falls oben nicht geschehen if (firstRun) changeMode(MODE); // Automodus ein und ausschalten let id = mainStatePath + 'config.auto.on'; if (!extendedExists(id)) { createCustomState(id, true, { read: true, write: true, desc: "Aktivere automatischen Push bei eintreffen der Warnungen.", type: "boolean", def: true }); } else { autoSendWarnings = getState(id).val; setState(id, autoSendWarnings, true); } } // setzte alle MODE Datenpunkte function setConfigModeStates(mode) { if (extendedExists(configModeState)) setState(configModeState, (mode & DWD ? 'DWD' : '') + (mode & UWZ ? 'UWZ' : '') + (mode & NINA ? 'NINA' : ''), true); for (let a = 0; a < MODES.length; a++) { let t = MODES[a].text.toLowerCase(); let id = mainStatePath + 'config.' + t; if (extendedExists(id)) setState(id, !!(mode & MODES[a].mode), true); } } { let allStateExist = true; let mode = [MODES[0], MODES[1]]; for (let c = 0; c < mode.length; c++) { let stateAlertId = mainStatePath + 'alert.' + mode[c].text.toLowerCase() + '.'; for (let b = 0; b < warningTypesString[mode[c].mode].length; b++) { for (let a = 0; a < stateAlert.length; a++) { let stateAlertIdFull = stateAlertId + warningTypesString[mode[c].mode][b][0] + '.' + stateAlert[a].name; stateAlert[a].type.name = stateAlert[a].name; if (!extendedExists(stateAlertIdFull)) { createCustomState(stateAlertIdFull, stateAlert[a].default, stateAlert[a].type); allStateExist = false; } } } } } // Nachrichtenversand per Click States/ config. und auto . erzeugen und subscript for (var a = 0; a < konstanten.length; a++) { if ((uPushdienst & konstanten[a].value) != 0) { if (!extendedExists(mainStatePath + 'commands.' + konstanten[a].name)) { createCustomState(mainStatePath + 'commands.' + konstanten[a].name, false, { read: true, write: true, desc: "Gebe Warnungen auf dieser Schiene aus", type: "boolean", role: "button", def: false }); } if (!extendedExists(mainStatePath + 'commands.' + konstanten[a].name + '_short')) { createCustomState(mainStatePath + 'commands.' + konstanten[a].name + '_short', false, { read: true, write: true, desc: "Gebe Kurzwarnungen auf dieser Schiene aus", type: "boolean", role: "button", def: false }); } if (!extendedExists(mainStatePath + 'commands.' + konstanten[a].name + '_long')) { createCustomState(mainStatePath + 'commands.' + konstanten[a].name + '_long', false, { read: true, write: true, desc: "Gebe Kurzwarnungen auf dieser Schiene aus", type: "boolean", role: "button", def: false }); } for (let x = 0; x < MODES.length; x++) { let oid = mainStatePath + 'config.auto.' + MODES[x].text.toLowerCase() + '.' + konstanten[a].name; if (!extendedExists(oid)) { createCustomState(oid, ((uPushdienst & konstanten[a].value) != 0), { read: true, write: true, desc: "Schalte Autopushmöglichkeiten ein / aus", type: "boolean", def: ((uPushdienst & konstanten[a].value) != 0) }); } else { setConfigKonstanten(oid, getState(oid).val, true); } oid = mainStatePath + 'config.manuell.' + MODES[x].text.toLowerCase() + '.' + konstanten[a].name; if (!extendedExists(oid)) { createCustomState(oid, ((uPushdienst & konstanten[a].value) != 0), { read: true, write: true, desc: "Schalte Manuellepushmöglichkeiten ein / aus", type: "boolean", def: ((uPushdienst & konstanten[a].value) != 0) }); } else { setConfigKonstanten(oid, getState(oid).val, false); } } } } // on() für alles unter config.auto subscribe({ id: new RegExp(getRegEx(mainStatePath + 'config.auto', '^') + '.*'), change: 'ne', ack: false }, function(obj) { if (obj.id == mainStatePath + 'config.auto.on') { myLog('Auto trigger: ' + obj.id + ' Value:' + obj.state.val); autoSendWarnings = !!obj.state.val; setState(obj.id, autoSendWarnings, true); for (var a = 0; a < konstanten.length; a++) { for (let x = 0; x < MODES.length; x++) { let oid = mainStatePath + 'config.auto.' + MODES[x].text.toLowerCase() + '.' + konstanten[a].name; if (extendedExists(oid)) { setState(oid, obj.state.val); } } } } else { myLog('else auto trigger: ' + obj.id + ' Value:' + obj.state.val); setConfigKonstanten(obj.id, obj.state.val, true); } }); // on() für alles unter config.manuell subscribe({ id: new RegExp(getRegEx(mainStatePath + 'config.manuell', '^') + '.*'), change: 'ne', ack: false }, function(obj) { myLog('Manuell trigger: ' + obj.id + ' Value:' + obj.state.val); setConfigKonstanten(obj.id, obj.state.val, false); }); subscribe({ id: new RegExp(getRegEx(mainStatePath + 'commands', '^') + '.*') }, function(obj) { if (!obj.state.val) return; setState(obj.id, false, true); let b = obj.id.split('.'); let msgLength = 0; let d = konstanten.findIndex(function(c) { return (c.name === b[b.length - 1]); }) if (d == -1) { d = konstanten.findIndex(function(c) { return (c.name + '_short' === b[b.length - 1]); }); msgLength = 1; if (d == -1) { d = konstanten.findIndex(function(c) { return (c.name + '_long' === b[b.length - 1]); }); msgLength = 2; if (d == -1) { return } } } let oldA = uTextMitAnweisungen, oldB = uTextMitBeschreibung, oldC = uSpracheMitAnweisungen, oldD = uSpracheMitBeschreibung, oldE = uHtmlMitAnweisungen, oldF = uHtmlMitBeschreibung;; if (msgLength != 0 ) { uTextMitAnweisungen = msgLength == 2; uTextMitBeschreibung = msgLength == 2; uSpracheMitAnweisungen = msgLength == 2; uSpracheMitBeschreibung = msgLength == 2; uHtmlMitAnweisungen = msgLength == 2; uHtmlMitBeschreibung = msgLength == 2; } warnDatabase.old = []; let oPd = uPushdienst; uPushdienst &= konstanten[d].value; forceSpeak = forcedSpeak; onClickCheckRun = true; if ((uPushdienst & SPEAK) != 0 && uManuellClickClearSpeakMessageList) _speakToArray = [{ speakEndtime: new Date() }]; checkWarningsMain(); uTextMitAnweisungen = oldA; uTextMitBeschreibung = oldB; uSpracheMitAnweisungen = oldC; uSpracheMitBeschreibung = oldD; uHtmlMitAnweisungen = oldE; uHtmlMitBeschreibung = oldF; onClickCheckRun = false; forceSpeak = false; uPushdienst = oPd; }); // Hilfsfunktion zu on() function setConfigKonstanten(id, val, auto) { let b = id.split('.'); let m = b[b.length - 2]; let d = konstanten.findIndex(function(c) { return (c.name === b[b.length - 1]); }); if (d == -1) return; let value = konstanten[d].value let tp = 0; switch (m) { case 'dwd': { val = val && !!(MODE & DWD); if (auto) dwdpushdienst = switchFlags(dwdpushdienst, value, val); else dwdManpushdienst = switchFlags(dwdManpushdienst, value, val); break; } case 'uwz': { val = val && !!(MODE & UWZ); if (auto) uwzpushdienst = switchFlags(uwzpushdienst, value, val); else uwzManpushdienst = switchFlags(uwzManpushdienst, value, val); break; } case 'nina': { val = val && !!(MODE & NINA); if (auto) ninapushdienst = switchFlags(ninapushdienst, value, val); else ninaManpushdienst = switchFlags(ninaManpushdienst, value, val); break; } default: { log('unbekannter Mode:' + m + 'in setConfigKonstanten', 'error'); } } setState(id, val, true); } // setzte die Alert States auf die höchste aktuelle Warnstufe function setAlertState() { let mode = [MODES[0], MODES[1]]; for (let a = 0; a < 2; a++) { if (!(MODE & mode[a].mode)) continue; let stateAlertid = mainStatePath + 'alert.' + mode[a].text.toLowerCase() + '.'; for (let b = 0; b < warningTypesString[mode[a].mode].length; b++) { let stateAlertIdFull = stateAlertid + warningTypesString[mode[a].mode][b][0] + '.'; let AlertLevel = -1; let AlertIndex = -1; for (let c = 0; c < warnDatabase.new.length; c++) { if (warnDatabase.new[c].type == b && warnDatabase.new[c].level > AlertLevel) { AlertLevel = warnDatabase.new[c].level; AlertIndex = c; } } if (extendedExists(stateAlertIdFull + stateAlert[0].name)) { if (getState(stateAlertIdFull + stateAlert[0].name).val != AlertLevel || (AlertIndex > -1 && getState(stateAlertIdFull + stateAlert[8].name).val != warnDatabase.new[AlertIndex].hash)) { setState(stateAlertIdFull + stateAlert[0].name, AlertLevel); setState(stateAlertIdFull + stateAlert[1].name, b); setState(stateAlertIdFull + stateAlert[2].name, (AlertIndex > -1 ? new Date(warnDatabase.new[AlertIndex].start).getTime() : 0)); setState(stateAlertIdFull + stateAlert[3].name, (AlertIndex > -1 ? new Date(warnDatabase.new[AlertIndex].end).getTime() : 0)); setState(stateAlertIdFull + stateAlert[4].name, (AlertIndex > -1 ? warnDatabase.new[AlertIndex].headline : '')); setState(stateAlertIdFull + stateAlert[5].name, (AlertIndex > -1 ? warnDatabase.new[AlertIndex].description : '')); setState(stateAlertIdFull + stateAlert[6].name, (AlertIndex > -1 ? warnDatabase.new[AlertIndex].color : '')); setState(stateAlertIdFull + stateAlert[7].name, (AlertIndex > -1 ? warnDatabase.new[AlertIndex].picture : '')); setState(stateAlertIdFull + stateAlert[8].name, (AlertIndex > -1 ? warnDatabase.new[AlertIndex].hash : 0)); } } } } } /* ************************************************************************* * Erstellung von Datenpunkten ENDE * Trigger aktivieren und Datenpflege für eigene Datenpunkte ENDE /* ************************************************************************* */ /* ************************************************************************* * Hilfsfunktion für Flags Bearbeitung Pushdienste & MODE /* ************************************************************************* */ function getPushModeFlag(mode, noflags) { if (noflags === undefined || !noflags) { if (onClickCheckRun) return getManuellPushFlags(mode); else return getAutoPushFlags(mode); } else { if (onClickCheckRun) return getManuellPushMode(mode); else return getAutoPushMode(mode); } } function getAutoPushMode(mode) { if (onClickCheckRun) return getManuellPushMode(mode); if (mode !== undefined) { if (mode & DWD) mode = switchFlags(mode, DWD, !!(uPushdienst & dwdpushdienst)); if (mode & UWZ) mode = switchFlags(mode, UWZ, !!(uPushdienst & uwzpushdienst)); if (mode & NINA) mode = switchFlags(mode, NINA, !!(uPushdienst & ninapushdienst)); return mode; } myLog('getAutoPushFlags() mode unbekannt!', 'info'); return 0; } function getManuellPushMode(mode) { if (!onClickCheckRun) return getAutoPushMode(mode); if (mode !== undefined) { if (mode & DWD) mode = switchFlags(mode, DWD, !!(uPushdienst & dwdManpushdienst)); if (mode & UWZ) mode = switchFlags(mode, UWZ, !!(uPushdienst & uwzManpushdienst)); if (mode & NINA) mode = switchFlags(mode, NINA, !!(uPushdienst & ninaManpushdienst)); return mode; } myLog('getAutoPushFlags() mode unbekannt!', 'error'); return 0; } function getAutoPushFlags(mode) { if (mode !== undefined) { let m = 0; if (mode & DWD) m |= (uPushdienst & dwdpushdienst); if (mode & UWZ) m |= (uPushdienst & uwzpushdienst); if (mode & NINA) m |= (uPushdienst & ninapushdienst); return m; } myLog('getAutoPushFlags() mode unbekannt!', 'error'); return 0; } function getManuellPushFlags(mode) { if (mode !== undefined) { let m = 0; if (mode & DWD) m |= (uPushdienst & dwdManpushdienst); if (mode & UWZ) m |= (uPushdienst & uwzManpushdienst); if (mode & NINA) m |= (uPushdienst & ninaManpushdienst); return m; } myLog('getManuellPushFlags() mode unbekannt!', 'error'); return 0; } function switchFlags(g, f, b) { if (b) g |= f; else g &= ~f; return g; } function getModeState() { if (extendedExists(configModeState)) { let value = getState(configModeState).val; let mode = 0; mode |= value.toUpperCase().includes('DWD') ? DWD : 0; mode |= value.toUpperCase().includes('UWZ') ? UWZ : 0; mode |= value.toUpperCase().includes('NINA') ? NINA : 0; return mode; } return null; } /* ************************************************************************* * Hilfsfunktion für Flags bearbeitung Pushdienste ENDE /* ************************************************************************* * Zeitschaltuhr /* ************************************************************************* */ // Zeitsteuerung für SayIt & Alexa var START = new Date(); var ENDE = new Date(); setWeekend(); function setWeekend() { if (forceSpeak) return; let date = new Date(); let n = date.getDay(); let weekend = 0; weekend = (n === 0 || n == 6) ? 1 : 0; if (weekend == 1) { // wenn Wochenende, dann setze Start auf 9h, sonst 6:45h START = convertStringToDate(startTimeSpeakWeekend); } else { START = convertStringToDate(startTimeSpeak); } ENDE = convertStringToDate(endTimeSpeak); } // Hilsfunktion function convertStringToDate(s) { if (typeof s !== 'string' ) return null; var e = s.split(':'); if (!Array.isArray(e) || e.length != 2) return null; var d = new Date(); d.setHours(Number(e[0]), Number(e[1]), 0); return d; } /* ************************************************************************* * Zeitschaltuhr ENDE /* ************************************************************************* */ /* ************************************************************************* * Hauptfunktion zur Auswahl der Warnungen zum Versenden und Aufbereiten der * Nachrichten /* ************************************************************************* */ // Hauptfunktion entscheiden was wohin gesendet wird function checkWarningsMain() { if (!forcedSpeak) forceSpeak = (!startTimeSpeakWeekend || !startTimeSpeak || !endTimeSpeak); setWeekend(); let DebugMail = ''; if (DEBUGSENDEMAIL) { for (a = 0; a < warnDatabase.new.length; a++) DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.new' + a, JSON.stringify(warnDatabase.new[a])); for (a = 0; a < warnDatabase.old.length; a++) DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.old' + a, JSON.stringify(warnDatabase.old[a])); DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.new.length', warnDatabase.new.length.toString(), null); DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.old.length', warnDatabase.old.length.toString(), null); } let ignoreWarningCount = 0, ignoreModes = 0; for (let a = 0; a < warnDatabase.new.length; a++) { let w = warnDatabase.new[a]; for (let b = 0; b < warnDatabase.old.length; b++) { let w2 = warnDatabase.old[b]; if ( w.mode !== w2.mode || w.type !== w2.type || w.level > attentionWarningLevel || w2.level > attentionWarningLevel || w.hash == w2.hash ) continue; // w endet vor / gleich w2 && w2 startet bevor / gleich w endet && w hat kleiner gleiches level wie w2 -> lösche w2 if (w2.end <= w.end && w2.end >= w.start && w2.level <= w.level) { let i = getIndexOfHash(warnDatabase.new, w2.hash); if (i != -1) { warnDatabase.new.splice(i, 1); if (i < a) --a; } myLog('Nr 5 Remove Msg with headline:'+w2.headline); warnDatabase.old.splice(b--, 1); } } } for (let a = 0; a < warnDatabase.new.length; a++) { let w = warnDatabase.new[a]; if ( isWarnIgnored(w)) { ignoreWarningCount++ ignoreModes |= w.mode; } } warnDatabase.new.sort(function(a, b) { return a.level == b.level ? b.begin - a.begin : b.level - a.level; }) var collectMode = 0; let emailHtmlWarn = ''; let emailHtmlClear = ''; let speakMsgTemp = []; collectMode = 0; let debugdata = ''; /* Bereich für 'Wetterwarnung gültig bis wurde aufgehoben' */ for (let i = 0; i < warnDatabase.old.length; i++) { let entry = warnDatabase.old[i]; let description = entry.description; let headline = entry.headline; let hash = entry.hash; let area = entry.areaID; let mode = entry.mode; let count = 0; let picture = entry.picture ? entry.picture + SPACE : ''; if (isWarnIgnored(entry)) continue; if (DEBUGSENDEMAIL) debugdata += i + SPACE + mode + SPACE + hash + SPACE + getIndexOfHash(warnDatabase.new, hash) + SPACE + (getPushModeFlag(mode) & PUSH).toString(2) + ' ignoreWarningCount)) { let prefix = '' let end = entry.end ? getFormatDate(entry.end) : null; collectMode |= mode; // Text Entwarnungen if (mode === NINA) { prefix = 'Die Warnung'; } else { prefix = 'Die Wetterwarnung'; } let pushMsg = picture + prefix + getArtikelMode(mode) + "'" + headline + area + (end ? " gültig bis " + end + "Uhr'" : '') + " wurde aufgehoben."; // EMAIL emailHtmlClear += pushMsg + '
'; // PUSH // Insgesamt x... anhängen pushMsg += getStringWarnCount(null, warnDatabase.new.length); sendMessage(getPushModeFlag(mode) & PUSH, picture + (mode == NINA ? 'Entwarnung' : 'Wetterentwarnung') + SPACE + (i + 1), pushMsg); myLog('text old:' + pushMsg); // SPEAK pushMsg = headline + getArtikelMode(mode, true) + area + (end ? ' gültig bis ' + getFormatDateSpeak(end) + ' Uhr' : '') + ' wurde aufgehoben' + ' . '; if (forceSpeak || compareTime(START, ENDE, 'between')) { sendMessage(getPushModeFlag(mode) & SPEAK, '', pushMsg, entry); } myLog('Sprache old:' + pushMsg); } } if (DEBUGSENDEMAIL) DebugMail = buildHtmlEmail(DebugMail, 'Index Mode Hash Index-New Flags', debugdata, null); let gefahr = false; let count = 0; /* Bereich für 'Neue Amtliche Wetterwarnung' */ for (let i = warnDatabase.new.length-1; i >= 0; i--) { let entry = warnDatabase.new[i]; let headline = entry.headline; let description = entry.description; let level = entry.level; let instruction = entry.instruction; let hash = entry.hash; let area = entry.areaID; let color = entry.color; let mode = entry.mode; let picture = entry.picture ? entry.picture + SPACE : ''; if (DEBUGSENDEMAIL) debugdata += i + SPACE + mode + SPACE + hash + SPACE + getIndexOfHash(warnDatabase.old, hash) + SPACE + (getPushModeFlag(mode)).toString(2) + SPACE + isWarnIgnored(entry) + ' attentionWarningLevel; let begin = entry.start ? getFormatDate(entry.start) : '', end = entry.end ? getFormatDate(entry.end) : ''; let sTime = SPACE, bt = (begin || end); if (begin || end) sTime = "gültig "; if (begin) sTime += "vom " + begin + " Uhr"; if ((begin && end)) sTime += SPACE; if (end) sTime += "bis " + end + " Uhr"; // html if ((getPushModeFlag(mode) & CANHTML) != 0) { let he = '', de = ''; let prefix = isNewMessage && !onClickCheckRun ? 'Neu: ' : ''; if (entry.html !== undefined) { let html = entry.html; if (html.headline) he = prefix + html.headline; else he = prefix + headline; if ( uHtmlMitBeschreibung ) { if (html.description) de = html.description; else de = description; if ( uHtmlMitAnweisungen ) { if (html.instruction && html.instruction.length > 2) de += '

Handlungsanweisungen:
' + html.instruction; else if (instruction && instruction.length > 2) de += '

Handlungsanweisungen:
' + instruction; } if (entry.html.web) de += '

' + entry.html.web; } } else { he = prefix + headline; if (uHtmlMitBeschreibung) { de = description; if ( uHtmlMitAnweisungen && instruction && instruction.length > 2) de += '

Handlungsanweisungen:
' + instruction; } } let html = (bt ? sTime + '
' : '') + de; html = html[0].toUpperCase() + html.substring(1); emailHtmlWarn = buildHtmlEmail(emailHtmlWarn, picture + he + getArtikelMode(mode) + area + ':', html, color, false); html = he + getArtikelMode(mode) + area + ':' + html; if (warnDatabase.new.length > 1) html += getStringWarnCount(count, warnDatabase.new.length); let b = getPushModeFlag(mode) & CANHTML & ~EMAIL & ~STATE_HTML; sendMessage(b, picture + getTopic(mode), html, entry); todoBitmask &= ~b & ~EMAIL & ~STATE_HTML; } if (!isNewMessage) continue; // Plain text if ((getPushModeFlag(mode) & CANPLAIN & todoBitmask) != 0) { let pushMsg = headline + getArtikelMode(mode) + area + (bt ? NEWLINE + sTime : '') if (uTextMitBeschreibung) { pushMsg+= NEWLINE + description; if (uTextMitAnweisungen && !!instruction && typeof instruction === 'string' && instruction.length > 2) { pushMsg += NEWLINE + 'Handlungsanweisungen:' + NEWLINE + instruction; } } // Anzahl Meldungen erst am Ende zu email hinzufügen if (todoBitmask & (EMAIL | STATE_HTML)) emailHtmlWarn = buildHtmlEmail(emailHtmlWarn, headline + getArtikelMode(mode) + area + ':', pushMsg, color, false); /* ab Level 4 zusätzlicher Hinweis */ if (warnDatabase.new.length > 1) pushMsg += getStringWarnCount(count, warnDatabase.new.length); let b = getPushModeFlag(mode) & CANPLAIN & todoBitmask & PUSH; sendMessage(b, picture + getTopic(mode) + SPACE + count, picture + pushMsg, entry); myLog('text new:' + pushMsg); todoBitmask &= ~b; } // Sprache if ((getPushModeFlag(mode) & SPEAK) != 0) { sTime = SPACE; if (begin || end) sTime += "gültig "; if (begin) sTime += "vom " + getFormatDateSpeak(begin) + " Uhr"; if ((begin && end)) sTime += " "; if (end) sTime += "bis " + getFormatDateSpeak(end) + " Uhr"; let i if (uSpracheMitAnweisungen && !!instruction && typeof instruction === 'string' && instruction.length > 2) { description += SPACE + SPACE + 'Handlungsanweisungen:' + NEWLINE + instruction; } let speakMsg = getTopic(mode, true) + headline + getArtikelMode(mode, true) + area + sTime + '.' + SPACE; description = replaceTokenForSpeak(description); if (uMaxCharToSpeak === 0 || (speakMsg + description).length <= uMaxCharToSpeak) { if (uSpracheMitBeschreibung) speakMsg += description; } else speakMsg += ' Weiterführende Informationen sind vorhanden.'; if (!isWarnIgnored(entry) && (forceSpeak || compareTime(START, ENDE, 'between')) && (getPushModeFlag(mode) & SPEAK) != 0) { sendMessage(getPushModeFlag(mode) & SPEAK, '', speakMsg, entry); } myLog('Sprache new:' + speakMsg + ' isWarnIgnored():' + isWarnIgnored(entry)); } function getTopic(mode, s) { if (s == undefined) s = false; let result = ''; if (mode !== NINA) { result = (level > attentionWarningLevel) ? 'Wichtige Wetterwarnung: ' : s ? '' : 'Wetterwarnung'; } else { result = (level > attentionWarningLevel) ? 'Gefahr Warnung: ' : s ? '' : 'Warnung'; } return result; } } } if (DEBUGSENDEMAIL) DebugMail = buildHtmlEmail(DebugMail, 'Index Mode Hash Index-old Flags ignored', debugdata, null); if ((getPushModeFlag(collectMode) & ALLMSG) != 0 && (emailHtmlWarn + emailHtmlClear)) { emailHtmlWarn = buildHtmlEmail(emailHtmlWarn, (emailHtmlClear ? 'Aufgehobene Warnungen' : null), emailHtmlClear, 'silver', false); emailHtmlWarn = buildHtmlEmail(emailHtmlWarn, null, getStringWarnCount(null, warnDatabase.new.length), null, true); sendMessage(getPushModeFlag(collectMode) & ALLMSG, (gefahr ? "Wichtige Warnungen" : "Warnungen") + getArtikelMode(collectMode) + "(iobroker)", emailHtmlWarn); } /* Bereich für 'Alle Wetterwarnungen wurden aufgehoben' */ if (!emailHtmlWarn && warnDatabase.new.length == ignoreWarningCount && (warnDatabase.old.length > ignoreWarningCount || onClickCheckRun)) { for (let a = 0; a < warnDatabase.old.length; a++) collectMode |= warnDatabase.old[a].mode; let pushMsg = 'Alle Warnmeldungen' + getArtikelMode(collectMode) + 'wurden aufgehoben.' + getStringIgnoreCount(ignoreWarningCount); // Einen Mode ermitteln der aktiv ist und der das Versenden erlauben würde. if (!getPushModeFlag(collectMode)) collectMode = getPushModeFlag(switchFlags(ALLMODES, collectMode, false) & MODE, true); if (!getPushModeFlag(collectMode)) log('Keine erlaubten Versandmöglichkeiten im ' + (onClickCheckRun ? 'manuellen Modus' : 'Automatikmodus') + ' gefunden!'); /* Bereich für Sprachausgabe über SayIt & Alexa & Home24*/ if (forceSpeak || compareTime(START, ENDE, 'between')) { // Ansage über Sayit nur im definierten Zeitbereich sendMessage(getPushModeFlag(collectMode) & SPEAK, '', pushMsg); } myLog('all all:' + pushMsg + ' PUSH' + (getPushModeFlag(collectMode) & PUSH).toString(2) + ' ALLMSG:' + (getPushModeFlag(collectMode) & ALLMSG).toString(2)); let topic = ((collectMode & NINA || !collectMode) ? 'Entwarnungen' : 'Wetterentwarnung'); sendMessage(getPushModeFlag(collectMode) & PUSH, topic, pushMsg, ); sendMessage(getPushModeFlag(collectMode) & ALLMSG, topic + getArtikelMode(collectMode) + '(iobroker)', buildHtmlEmail('', pushMsg, null, 'silver', true)); } if (DEBUGSENDEMAIL) { let a; DebugMail = buildHtmlEmail(DebugMail, 'uPushdienst', 'Binär:' + uPushdienst.toString(2) + ' Decimal:' + uPushdienst.toString(), null); for (a = 0; a < warnDatabase.new.length; a++) DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.new' + a, JSON.stringify(warnDatabase.new[a])); for (a = 0; a < warnDatabase.old.length; a++) DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.old' + a, JSON.stringify(warnDatabase.old[a])); DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.new.length', warnDatabase.new.length.toString(), null); DebugMail = buildHtmlEmail(DebugMail, 'warnDatabase.old.length', warnDatabase.old.length.toString(), null, true); if (DEBUGSENDEMAIL) sendMessage(uPushdienst & EMAIL, 'Debug checkWarningsMain() ' + scriptName, DebugMail); //log(DebugMail); } /* Neue Werte sichern */ warnDatabase.old = cloneObj(warnDatabase.new); } /* ************************************************************************* * Hauptfunktion zur Auswahl der Warnungen zum Versenden und Aufbereiten der * Nachrichten ENDE /* ************************************************************************* */ /* ************************************************************************* * Senden der Nachricht über die verschiedenen Möglichkeiten /* ************************************************************************* */ //Versende die Warnungen über die Schienen function sendMessage(pushdienst, topic, msg, entry) { if (entry === undefined) entry = null; if ((pushdienst & TELEGRAM) != 0) { let nMsg = {}; if (entry && entry.web && entry.webname) nMsg.reply_markup = { inline_keyboard: [[{ text: entry.webname, url: entry.web }]] }; if (uTelegramReplyMarkup) nMsg.reply_markup = uTelegramReplyMarkup; if (!uTelegramAllowNotification) nMsg.disable_notification = true; if (telegramUser.length > 0) { nMsg.user = telegramUser; _sendSplitMessage(TELEGRAM, msg.slice(), nMsg, function(msg, opt) { opt.text = msg; _sendTo(TELEGRAM, telegramInstanz, opt); }); } if (telegramChatId.length > 0) { nMsg.ChatId = telegramChatId; _sendSplitMessage(TELEGRAM, msg.slice(), nMsg, function(msg, opt) { opt.text = msg; _sendTo(TELEGRAM, telegramInstanz, opt); }); } if (!(telegramUser.length > 0 || telegramChatId.length > 0)) { _sendSplitMessage(TELEGRAM, msg.slice(), nMsg, function(msg, opt) { opt.text = msg; _sendTo(TELEGRAM, telegramInstanz, opt); }); } } if ((pushdienst & PUSHOVER) != 0) { let newMsg = { html: 1 }; let usesound = ((deviceList[PUSHOVER].count == undefined || deviceList[PUSHOVER].count == 0) || !(!entry || entry.level < attentionWarningLevel)); newMsg.message = msg; newMsg.title = topic; if (entry) { if (entry.web && entry.web.length < 512) { newMsg.url = entry.web ; newMsg.url_title = entry.webname; } newMsg.message = msg.replace(entry.headline, '' + entry.headline + ''); if (entry.level >= attentionWarningLevel) newMsg.priority = 1; } if (!usesound) newMsg.sound = 'none'; else if (uPushoverSound) newMsg.sound = uPushoverSound; if (uPushoverDeviceName) newMsg.device = uPushoverDeviceName; _sendSplitMessage(PUSHOVER, newMsg.message.slice(), newMsg, function(msg, opt, c) { opt.message = msg; if (c > 1) { opt.title += ' Teil ' + c; opt.sound = 'none'; } _sendTo(PUSHOVER, pushoverInstanz, opt); }); } if ((pushdienst & IOGO) != 0) { let j = {}; j.text = msg; j.title = topic; if (ioGoUser.length > 0) { j.user = ioGoUser[0]; for (let a = 1; a < ioGoUser.length; a++) { j.user += ',' + ioGoUser[a]; } } _sendSplitMessage(IOGO, j.text.slice(), j, function(msg, opt, c) { opt.text = msg; _sendTo(IOGO, ioGoInstanz, opt); }); } if ((pushdienst & STATE) != 0) { setState(mirrorMessageState, msg, true); } if ((pushdienst & STATE_HTML) != 0) { setState(mirrorMessageStateHtml, msg, true); } if ((pushdienst & SPEAK) != 0) { _speakTo(pushdienst & SPEAK, msg); } if ((pushdienst & EMAIL) != 0) { let j = {}; j.html = msg; j.subject = topic; if (senderEmailID[0]) j.from = senderEmailID[0]; if (empfaengerEmailID.length > 0) { for (let a = 0; a < empfaengerEmailID.length; a++) { j.to = empfaengerEmailID[a]; _sendTo(EMAIL, emailInstanz, j); } } else { _sendTo(EMAIL, emailInstanz, j); } } function _sendTo(dienst, a, b) { if (deviceList[dienst].count == undefined) { sendTo(a, b); } else { setTimeout(function(dienst, a, b) { sendTo(a, b); deviceList[dienst].count--; }, (deviceList[dienst].count++ * deviceList[dienst].delay + 20), dienst, a, b); } } // nur einmal pro Mitteilung aufrufen // Element 0 im Array muß immer vorhanden sein. function _speakTo(dienst, msg) { if (_speakToInterval) clearInterval(_speakToInterval); _speakToArray = _addItem(_speakToArray, msg, dienst); _speakToArray = _speakToArray.sort(function(a, b) { return a.startTimeSpeak - b.startTimeSpeak; }); _speakToInterval = setInterval(function() { if (_speakToArray.length > 1) { let entry = _speakToArray[1]; if (entry.startTimeSpeak <= new Date()) { if ( entry.part > 1 ) entry.msg = 'Teil ' + entry.part+': ' + entry.msg; let nTime = new Date(new Date().getTime() + (deviceList[entry.dienst].delay * (entry.msg + _getMsgCountString(_speakToArray, entry.dienst)).length)); let value = nTime.getTime() - new Date(entry.endTimeSpeak).getTime(); for (let a = 1; a < _speakToArray.length; a++) { if (entry.dienst == _speakToArray[a].dienst) { _speakToArray[a].endTimeSpeak = new Date(_speakToArray[a].endTimeSpeak.getTime() + value); if (a != 1 || value < 0) _speakToArray[a].startTimeSpeak = new Date(_speakToArray[a].startTimeSpeak.getTime() + value); } } if (entry.dienst == HOMETWO) { for (let a = 0; a < idMediaplayer.length; a++) { var Url2 = "http://" + idMediaplayer[a] + "/track = 4fachgong.mp3|tts=" + entry.msg + _getMsgCountString(_speakToArray, entry.dienst); myLog('Url2 :' + Url2); request(Url2); } } else if (entry.dienst == SAYIT) { for (let a = 0; a < idSayIt.length; a++) { setState(idSayIt[a], sayItVolumen[a] + ";" + entry.msg + _getMsgCountString(_speakToArray, entry.dienst)); } } else if (entry.dienst == ALEXA) { for (let a = 0; a < idAlexaSerial.length; a++) { // Wenn auf Gruppe, keine Lautstärkenregelung möglich if (extendedExists(replacePlaceholder(idAlexaVolumen, idAlexaSerial[a]))) setState(replacePlaceholder(idAlexaVolumen, idAlexaSerial[a]), alexaVolumen[a]); setState(replacePlaceholder(idAlexa, idAlexaSerial[a]), entry.msg + _getMsgCountString(_speakToArray, entry.dienst)); } } myLog('Länge der auszugebenen Sprachnachricht: ' + (entry.endTimeSpeak.getTime() - entry.startTimeSpeak)); _speakToArray.shift(); _speakToArray = _speakToArray.sort(function(a, b) { return a.startTimeSpeak - b.startTimeSpeak; }); } } else clearInterval(_speakToInterval); }, 1000); return; // Hilfunktionen // gibt den letzten Satz zur Sprachausgabe zurück. function _getMsgCountString(arr, dienst) { let msgAppend = ''; let len = arr.slice(1).filter(function(a, b) { return (!!(a.dienst & dienst)) && a.part === 1; }).length - 1; if (len > 0) { if (len == 1) { msgAppend = ' Eine weitere neue Warnung.'; } else { msgAppend = ' Es gibt ' + (len) + ' weitere neue Warnungen.'; } } else { if (warnDatabase.new.length == 0) { if (!onClickCheckRun) msgAppend = ' keine weitere Warnung.'; } else { if (warnDatabase.new.length == 1) msgAppend = ' Insgesamt eine aktive Warnung.'; else msgAppend = ' Insgesamt ' + warnDatabase.new.length + ' aktive Warnungen.'; } } return msgAppend; } // fügt eine Sprachausgabe dem Array hinzu function _addItem(arr, a, dienst) { if ((dienst & HOMETWO) != 0) { let m = deviceList[HOMETWO].delay * a.length + 2000; arr = __addItem(arr, a, HOMETWO, m, 1) } if ((dienst & SAYIT) != 0) { arr = _sendSplitMessage(SAYIT, a.slice(), arr, _splitedSpeakMessage); } if ((dienst & ALEXA) != 0) { arr = _sendSplitMessage(ALEXA, a.slice(), arr, _splitedSpeakMessage); } return arr; // Hilfsunktion function __addItem(arr, a, dienst, m, count) { let t = null; for (let a = arr.length - 1; a >= 0; a--) { if (dienst == arr[a].dienst) { t = arr[a].endTimeSpeak; break; } } t = t || new Date(); let nt = new Date(t); nt.setMilliseconds(t.getMilliseconds() + m); arr.push({ msg: a, dienst: dienst, endTimeSpeak: nt, startTimeSpeak: t, part: count}); return arr; } function _splitedSpeakMessage(dienst, str, c, opt) { let m = deviceList[dienst].delay * str.length + 2000; return __addItem(opt, str, dienst, m, c); } } } function _sendSplitMessage(dienst, str, opt, callback) { let c = 1; let text = '\n* Warnung wurde aufgeteilt *'; let index = deviceList[dienst].maxChar !== undefined ? deviceList[dienst].maxChar-text.length : 0; let e = 0; do { let msg = str; e = 0; if (index != 0 && index < msg.length) { e = _getLastIndexToSplit(msg, index); msg = str.substring(0, e) + text; } log (msg); if ( dienst & SPEAK ) { opt = callback(dienst, msg, c++, opt); }else { callback(msg, cloneObj(opt), c++); } if (e != 0) str = str.substring(e).trimLeft(); } while (e != 0 ) return opt; } function _getLastIndexToSplit(str, index) { let f = str.substring(0,index).match(/..\n|..
|[a-zA-Z][a-z][\.\!\?\:](?= [A-Z])|[a-zA-Z][a-z]\.(?=[A-Z][a-zA-Z]{3})/gi); let e = index; if (f && f.length > 0) e = str.lastIndexOf(f[f.length-1],index) + f[f.length-1].length; return e; } } /* ************************************************************************* * Senden der Nachricht über die verschiedenen Möglichkeiten * ENDE /* ************************************************************************* */ /* ************************************************************************* * Datenquelle Trigger /* ************************************************************************* */ // setzt on() für DWD oder UWZ function dataSubscribe() { if (subDWDhandler) unsubscribe(subDWDhandler); if (MODE & DWD) { let r = getRegEx(dwdPath, '^'); r += '.*\.object$'; myLog('subscribe path:' + r); subDWDhandler = subscribe({ id: new RegExp(r), change: 'ne' }, onChangeDWD); } if (subUWZhandler) unsubscribe(subUWZhandler); if (MODE & UWZ) { let r = getRegEx(uwzPath, '^'); r += '.*\.object$'; myLog('subscribe path:' + r); subUWZhandler = subscribe({ id: new RegExp(r), change: 'ne' }, onChangeUWZ); } if (subNINAhandler) unsubscribe(subNINAhandler); if (MODE & NINA) { let r = getRegEx(ninaPath, '^'); r += '.*.rawJson$'; myLog('subscribe path:' + r); subNINAhandler = subscribe({ id: new RegExp(r), change: 'ne' }, onChangeNina); } } function onChangeDWD(dp) { myLog('onchange DWD id:' + dp.id); onChange(dp, DWD); } function onChangeUWZ(dp) { myLog('onchange UWZ id:' + dp.id); onChange(dp, UWZ); } function onChangeNina(dp) { myLog('onchange NINA ' + dp.id); onChange(dp, NINA); } // funktion die von on() aufgerufen wird function onChange(dp, mode) { if (addDatabaseData(dp.id, dp.state.val, mode, false)) { myLog('Datenbank wurde geändert - checkWarningsMain():' + autoSendWarnings + ' id:' + dp.id + ' Mode:' + mode); if (timer) clearTimeout(timer); if (autoSendWarnings) timer = setTimeout(checkWarningsMain, 20000); } } /* ************************************************************************* * Datenquelle Trigger ENDE /* ************************************************************************* */ /* ************************************************************************* * Datenbank /* ************************************************************************* */ // Erstes befüllen der Database function InitDatabase(first) { if (first) warnDatabase = { new: [], old: [] }; if (MODE & DWD) { _helper($("state[state.id=" + dwdPath + ".*.object$]"), DWD, first); } if (MODE & UWZ) { _helper($("state[state.id=" + uwzPath + ".*.object$]"), UWZ, first); } if (MODE & NINA) { _helper($("state[state.id=" + ninaPath + ".*.rawJson$]"), NINA, first); } warnDatabase.new = warnDatabase.new.filter(function(j) { return (j.mode & MODE); }); if (!first) { warnDatabase.new = _filter(warnDatabase.new); warnDatabase.old = _filter(warnDatabase.old); } return; function _helper(arr, mode, first) { for (let a = 0; a < arr.length; a++) { let id = arr[a]; addDatabaseData(id, getState(id).val, mode, first); } } function _filter(database) { if (database && database.length > 0) { database = database.filter(function(j, i){ let b = (-1 == database.findIndex(function(j2, i2){ return i > i2 && j.mode == j2.mode && j.hash == j2.hash; })); if (!b) myLog('filtere:'+JSON.stringify(j)); return b;} ) } return database; } } // für Objekt zur Database hinzu function addDatabaseData(id, value, mode, old) { var warn = null; let change = false; let jvalue = null; myLog("addDatabaseData() ID + JSON:" + id + SPACE + JSON.stringify(value)); if (value && value != {} && value !== undefined && value != "{}") jvalue = JSON.parse(value); if (mode == UWZ) { change = removeDatabaseDataID(id); if (jvalue) { warn = getDatabaseData(jvalue, mode); if (warn) { warn.areaID = getRegionNameUWZ(id); warn.hash = JSON.stringify(warn).hashCode(); warn.id = id; warnDatabase.new.push(warn); if (old) warnDatabase.old.push(warn); change = true; if (uLogAusgabe) log("Add UWZ warning to database. headline: " + warn.headline); } } } else if (mode == DWD) { change = removeDatabaseDataID(id); if (jvalue) { warn = getDatabaseData(jvalue, mode); if (warn) { warn.areaID = " für " + warn.areaID; warn.hash = JSON.stringify(warn).hashCode(); warn.id = id; warnDatabase.new.push(warn); if (old) warnDatabase.old.push(warn); change = true; if (uLogAusgabe) log("Add DWD warning to database. headline: " + warn.headline); } } } else if (mode == NINA) { if (jvalue.info === undefined || !Array.isArray(jvalue.info)) return false; let tempArr = []; let grouphash = 0; // sammele die neuen Daten for (let a = 0; a < jvalue.info.length; a++) { warn = getDatabaseData(jvalue.info[a], mode); // Warnungen nur aufnehmen wenn sie nicht beendet sind. Null berücksichtigt. if (warn && (!warn.end || new Date(warn.end) > new Date())) { warn.identifier = jvalue.identifier === undefined ? "" : jvalue.identifier; warn.sender = jvalue.sender === undefined ? "" : jvalue.sender; warn.hash = JSON.stringify(warn).hashCode(); // setzte start auf das Sendungsdatum, aber nicht im Hash berücksichtigen, ist keine neue Nachricht nur weil sich das datum ändert. warn.start = warn.start || jvalue.sent === undefined ? warn.start : getDateObject(jvalue.sent).getTime(); warn.id = id; // davon ausgehend das die Nachrichten immer gleich sortiert sind und der NINA-Adapter das nicht umsortiert sollte der Hash der ersten Nachrichten // immer der selbe sein. Benutze diesen um die Gruppe an Nachrichten zu identifizieren. if (!grouphash) grouphash = warn.hash; warn.grouphash = grouphash; tempArr.push(warn); myLog("Added to tempdatabase"); } } // Vergleiche vorhandene und neue Daten wenn hash = hash aktualisiere ID, wenn nicht und ID = ID setzte ID auf null if (tempArr.length > 0) { for (let a = 0; a < tempArr.length; a++) { for (let b = 0; b < warnDatabase.new.length; b++) { if (tempArr[a].hash == warnDatabase.new[b].hash) { if (uLogAusgabe && warnDatabase.new[b].id != tempArr[a].id) { log( "Update database Nina warning old id<>new id. headline: " +warn.headline ); } warnDatabase.new[b].id = tempArr[a].id; tempArr.splice(a--, 1); break; } else if ( tempArr[a].id == warnDatabase.new[b].id && tempArr[a].grouphash != warnDatabase.new[b].grouphash ) { myLog( "warnDatabase.new set id to null - duplicate id and wrong grouphash: " + warnDatabase.new[b].headline ); warnDatabase.new[b].id = null; } } } } if (tempArr.length > 0) { for (let a = 0; a < tempArr.length; a++) { warn = tempArr[a]; warnDatabase.new.push(warn); if (old) warnDatabase.old.push(warn); if (uLogAusgabe) log( "Add Nina warning to database. headline: " + warn.headline ); } change = true; } } if (change) setAlertState(); return change; // vergleich regionName und die Obj.id und gib den benutzerfreundlichen Namen zurück. function getRegionNameUWZ(id) { if (!Array.isArray(regionName) || regionName.length == 0) return ""; for (let a = 0; a < regionName.length; a++) { if (id.includes(regionName[a][0])) { return "für " + regionName[a][1]; } } return ""; } } function isWarnIgnored(warn) { if (warn.level <= attentionWarningLevel) { if ((uFilterList & warn.mode) != 0) return true; if ((warn.mode & NINA) != 0) { if (uAutoNinaFilterList.indexOf(warn.sender) != -1) { myLog('Filter: \'' + warn.sender + '\' ist in uAutoNinaFilterList - level: ' + warn.level); return true; } } } return false; } function getIndexOfHash(db, hash, mode, id) { if (id === undefined && mode === undefined) return db.findIndex(function(j) { return j.hash === hash; }); else if (id === undefined) return db.findIndex(function(j) { return j.hash === hash && j.mode == mode; }); else if (mode === undefined) return db.findIndex(function(j) { return j.hash === hash && j.id == id; }); else return db.findIndex(function(j) { return j.hash === hash && j.mode == mode && j.id == id; }); } // Wandelt den Datensatz in ein internes Format um function getDatabaseData(warn, mode){ if (!warn || warn === undefined || typeof warn !== 'object' || warn === {} || warn =='{}') return null; let result={}; if (mode === DWD) { if ( warn.altitudeStart > maxhoehe || (warn.altitudeEnd && warn.altitudeEnd < minhoehe) || warn.level < minlevel ) {myLog('Übergebenens Json DWD verworfen');return null;} result['mode'] = DWD; result['description'] = warn.description === undefined ? '' : warn.description; result['headline'] = warn.headline === undefined ? '' : warn.headline; result['start'] = warn.start === undefined ? null : warn.start || null; result['end'] = warn.end === undefined ? null : warn.end || null; result['instruction'] = warn.instruction === undefined ? '' : warn.instruction; result['type'] = warn.type === undefined ? -1 : warn.type; result['level'] = warn.level === undefined ? -1 : warn.level; result['areaID'] = warn.regionName === undefined ? '' : warn.regionName; result['web'] = ''; result['webname'] = ''; result['picture'] = result.type === -1 ? '' : warningTypesString[DWD][result.type][1]; } else if (mode === UWZ) { if ( warn.payload === undefined || warn.payload.altMin > maxhoehe || (warn.payload.altMax && warn.payload.altMax < minhoehe) ) {myLog('Übergebenens Json UWZ verworfen');return null;} result['mode'] = UWZ; result['description'] = warn.payload.translationsLongText.DE === undefined ? '' : warn.payload.translationsLongText.DE; result['start'] = warn.dtgStart === undefined ? null : warn.dtgStart * 1000 || null; result['end'] = warn.dtgEnd === undefined ? null : warn.dtgEnd * 1000 || null; result['instruction'] = warn.instruction === undefined ? '' : warn.instruction; result['type'] = warn.type === undefined ? -1 : warn.type; result['level'] = warn.payload.levelName === undefined ? -1 : getUWZLevel(warn.payload.levelName); result['headline'] = warn.type === undefined ? '' : 'Warnung vor '+warningTypesString[UWZ][result.type][0]; result['areaID'] = warn.areaID === undefined ? '' : warn.areaID; result['web'] = ''; result['webname'] = ''; result['picture'] = result.type === -1 ? '' : warningTypesString[UWZ][result.type][1]; if ( result.level < minlevel ) {myLog('Übergebenens Json UWZ verworfen');return null;} } else if (mode === NINA) { // level 2, 3, 4 let web=''; web = warn.web === undefined || !warn.web || !isValidUrl(warn.web)? '' : '
'+warn.web+'
'; result['mode'] = NINA; //result['identifier'] = warn.identifier === undefined ? '' : warn.identifier; //result['sender'] = warn.sender === undefined ? '' : warn.sender; result['web'] = warn.web === undefined || !warn.web || !isValidUrl(warn.web) ? '' : warn.web.replace(/(\.+\<\/a\>)/ig,''); result['webname'] = warn.web === undefined || !warn.web || !isValidUrl(warn.web) ? '' : warn.web.replace(/(\)|(\<\/a\>)/ig,''); result['description'] = warn.description === undefined ? '' : removeHtml(warn.description); result['start'] = warn.onset === undefined ? null : getDateObject(warn.onset).getTime() || null; result['end'] = warn.expires === undefined ? null : getDateObject(warn.expires).getTime() || null; result['instruction'] = warn.instruction === undefined ? '' : removeHtml(warn.instruction); result['typename'] = warn.event === undefined ? '' : removeHtml(warn.event); result['type'] = result.typename.hashCode(); //result['urgency'] = warn.urgency === undefined ? '' : warn.urgency; result['severity'] = warn.severity === undefined ? '' : warn.severity; //result['certainty'] = warn.certainty === undefined ? '' : warn.certainty; result['headline'] = warn.headline === undefined ? '' : removeHtml(warn.headline); result['areaID'] = warn.area === undefined ? '' : getNinaArea(warn.area); result['level'] = warn.severity === undefined ? -1 : getNinaLevel(warn.severity, result.typename); result['html'] = {}; result['html']['web'] = warn.web === undefined || !warn.web || !isValidUrl(warn.web) ? '' : warn.web; result['html']['instruction'] = warn.instruction === undefined ? '' : warn.instruction; result['html']['headline'] = warn.headline === undefined ? '' : warn.headline; result['html']['description'] = warn.description === undefined ? '' : warn.description; result['picture'] = ''; if ( result.level < minlevel ) return null; } result['color'] = getLevelColor(result.level); result['id']=''; result['pending'] = 0; result['hash'] = 0; myLog('result: ' + JSON.stringify(result)); return result; function getNinaArea(value) { let result = 'für ihre Region' if (!value && !Array.isArray(value)) return result; // gibt nur 1 nix zum Suchen. if (value.length == 0) return 'für ' + value[0].areaDesc; let region = ''; let lvl = 5; let len = 1000; for (let a = 0; a < value.length; a++) { if (value[a].areaDesc !== undefined) { let area = value[a].areaDesc; if (area.includes(uGemeinde) && area.length - uGemeinde.length < len) { region = area; len = area.length - uGemeinde.length; lvl = 1; } else if (lvl > 2 && area.includes(uLandkreis)) { lvl = 2; region = area; } } if (value[a].geocode !== undefined) { let newval = value[a].geocode; for (let b = 0; b < newval.length; b++) { if (newval[b].valueName === undefined) continue; let area = newval[b].valueName; if (area.includes(uGemeinde) && area.length - uGemeinde.length < len) { region = area; len = area.length - uGemeinde.length; lvl = 1; } else if (lvl > 2 && area.includes(uLandkreis)) { lvl = 2; region = area; } } } } if (region) region = 'für ' + region; return region || result; } // gibt Nina level zurück function getNinaLevel(str, type) { let ninaLevel = [ 'Minor', 'Moderate', 'Severe', 'Extreme' ] let offset = 2; // Hochwassser ist immer Severe das ist im Vergleich denke ich zu hoch. if (type == 'Hochwasserinformation') offset = 0; return ninaLevel.indexOf(str) + offset; } // Gibt Farben für die level zurück function getLevelColor(level) { var color = [ '#00ff00', // 0 - Grün '#009b00', // 1 - Dunkelgrün '#d7d700', // 2 - Gelb Wetterwarnungen (Stufe 2) //vorher:#ffff00 '#ffb400', // 3 - Orange Warnungen vor markantem Wetter (Stufe 3) '#ff0000', // 4 - Rot Unwetterwarnungen (Stufe 4) // im grunde höchste Stufe in diesem Skript. '#ff00ff', // 5 - Violett Warnungen vor extremem Unwetter (nur DWD/ Weltuntergang nach aktueller Erfahrung) ]; if (level >= 0 && level <= 5) return color[level]; else return color[0]; } function getUWZLevel(warnName) { var result = -1; // -1 is an error! var alert = warnName.split("_"); var colors = { color: ["green", "darkgreen", "yellow", "orange", "red", "violet"], level: [0, 0, 1, 2, 3, 4] // um 1 level reduziert, sond nicht mit DWD vergleichbar nach Erfahrungen }; if (alert[0] == "notice") { result = 1; } else if (alert[1] == "forewarn") { result = 1; } else { result = colors.level[colors.color.indexOf(alert[2])]; } return result; } } function removeHtml(a) { let b = a.replace(//ig, NEWLINE); b = b.replace(/( |<([^>]+)>)/ig, ''); return b; } // Überprüfe wegen Nina - Adapter häufig die DB ob obj.ids gelöscht wurden. // Dachte ich zuerst, die Server sind aber sehr unzuverlässig und Meldungen werden laufend nicht ausgeliefert. // Folglich werden Entwarnung raus geschickt. Jetzt warten wir 10 * 9 = 90 Minuten entwarnen erst dann. // Abgelaufene Meldungen werden aufgeräumt. schedule('18 */10 * * * *', function() { let c = false; for (let a = 0; a < warnDatabase.new.length; a++) { let w = warnDatabase.new[a]; if (!extendedExists(w.id)) { if (warnDatabase.new[a].pending++ >= 8) { // 9 Durchläufe if (uLogAusgabe) log('Remove old warning with id: ' + warnDatabase.new[a].id + ' and headline: ' + warnDatabase.new[a].headline); warnDatabase.new.splice(a--, 1); c = true; } } else { w.pending = 0; } if (w.end && new Date(w.end) < new Date()) { if (uLogAusgabe) log('Remove expired warning with id: ' + warnDatabase.new[a].id + ', headline: ' + warnDatabase.new[a].headline + ' expire:' + new Date(w.end)); warnDatabase.new.splice(a--, 1); c = true; } } if (c && autoSendWarnings) { if (timer) clearTimeout(timer); checkWarningsMain(); } }); // entferne Eintrag aus der Database function removeDatabaseDataID(id, multitimes) { if (!id || (typeof id !== 'string')) return false; if (multitimes === undefined) multitimes = false; let change = false; if (warnDatabase.new && warnDatabase.new.length > 0) { let i=-2; while (i!=-1) { i = warnDatabase.new.findIndex(function(j){return j.id == id}); if (i!=-1) { warnDatabase.new.splice(i, 1); change = true; } if (!multitimes) break; } } return change; } /* ************************************************************************* * Datenbank ENDE /* ************************************************************************* */ /* ************************************************************************* * Aufbereitung von Texten für die verschiedenen Pushmöglichkeiten /* ************************************************************************* */ function getArtikelMode(mode, speak = false) { let r = SPACE; if (mode & DWD) r += (DEBUG ? 'des DWD('+scriptName+') ' : 'des DWD '); if (mode & UWZ) { if (r.length > 1) r += 'und '; if (speak) r += (DEBUG ? 'der Unwetterzentrale('+scriptName+') ' : 'der Unwetterzentrale '); else r += (DEBUG ? 'der UWZ('+scriptName+') ' : 'der UWZ '); } if (mode & NINA) { if (r.length > 1) r += 'und '; r += (DEBUG ? 'von Nina('+scriptName+') ' : 'von Nina '); } return r; } // Gibt einen fertigen Zähler string zurück. 1 / 3 wenn es Sinn macht und manuelle Auslösung function getStringWarnCount(i, c) { return SPACE + 'Insgesamt ' + ((i && onClickCheckRun && c > 1) ? (i.toString() + '/') : '') + ((c == 1) ? 'eine gültige Warnung.' : (c.toString() + ' gültige Warnungen.')); } // gibt einen fertigen String für ignorierte Warnungen zurück function getStringIgnoreCount(c) { if (c == 0) return ''; let r = SPACE; if (c == 1) r += 'Es wird eine Warnung ignoriert.'; else r += 'Es werden ' + c.toString() + ' Warnungen ignoriert.'; return r; } // ersetzt Placeholder function replacePlaceholder(str, insertText) { return str.replace(placeHolder, insertText); } // baut eine html table für Email function buildHtmlEmail(mailMsg, headline, msg, color, last = false) { if (!mailMsg) mailMsg = html_prefix; if (headline) { if (color) mailMsg += html_headline_color.replace('###color###', color).replace('###headline###', headline); else mailMsg += html_headline.replace('###headline###', headline); } if (msg) mailMsg += html_message.replace('###message###', msg); if (last) mailMsg += html_end; return mailMsg; } /* Entfernt "°C" und anders aus Sprachmeldung und ersetzt es durch "Grad" */ /* noch nicht für UWZ angepasst */ function replaceTokenForSpeak(beschreibung) { var rueckgabe = beschreibung; try { rueckgabe = rueckgabe.replace(/\°C/g, "Grad"); rueckgabe = rueckgabe.replace(/km\/h/g, "Kilometer pro Stunde"); rueckgabe = rueckgabe.replace(/l\/m\²/g, "Liter pro Quadratmeter"); rueckgabe = rueckgabe.replace(/\d{1,2}\.\d{1,2}\.\d{4}../gi, function(x) { return getFormatDateSpeak(x); }) rueckgabe = rueckgabe.replace(/\d{1,2}\.\d{1,2}\.../gi, function(x) { return getFormatDateSpeak(x); }) if (!windForceDetailsSpeak) { rueckgabe = rueckgabe.replace(/\([0-9]+.m\/s..[0-9]+kn..Bft.[0-9]+../g, ""); } else { rueckgabe = rueckgabe.replace(/kn/g, " Knoten"); rueckgabe = rueckgabe.replace(/Bft/g, " Windstärke"); rueckgabe = rueckgabe.replace(/m\/s/g, " Meter pro Sekunde"); } } catch (e) { log(e, 'warn'); } return rueckgabe; } // Formatiere Date zu string function getFormatDate(a) { if (!a || (!(typeof a === 'number')) && !(typeof a === 'object')) return ''; return formatDate(new Date(a).getTime(), formatierungString); } // hilffunktion für Zeitausgabe über Sprache // @PARAM Rückgabe von getFormatDate function getFormatDateSpeak(a) { if (!a || typeof a !== 'string') return ''; let b = a.split('.'); let m = ''; switch (b[1]) { case '01': m='Januar'; break; case '02': m='Februar'; break; case '03': m='März'; break; case '04': m='April'; break; case '05': m='Mai'; break; case '06': m='Juni'; break; case '07': m='Juli'; break; case '08': m='August'; break; case '09': m='September'; break; case '10': m='Oktober'; break; case '11': m='November'; break; case '12': m='Dezember'; break; default: m=''; } // if (Number(b[0]) < 10) b[0]=b[0].slice(1, 1); // Das geht echt einfacher *g* b[0] = Number(b[0]).toString(); b[1] = m; // setze Monatsname // entferne Jahr let c = b[2].split(SPACE); c[0] = ''; b[2] = c.join(SPACE); return b.join(SPACE); } /* ************************************************************************* * Aufbereitung von Texten für die verschiedenen Pushmöglichkeiten ENDE /* ************************************************************************* */ /* ************************************************************************* * Anfrage über Telegramm mit Ww? und WetterWarnungen? /* ************************************************************************* */ if ((uPushdienst & TELEGRAM) != 0) { on({ id: telegramInstanz + '.communicate.request', change: "any", ack: false }, function(obj) { var msg = obj.state.val; var user = msg.substring(1, msg.indexOf(']')); msg = msg.substring(msg.indexOf(']') + 1, msg.length); if (DEBUG && msg.includes('Wwdmail')) { let olddebug = DEBUGSENDEMAIL; DEBUGSENDEMAIL = true; setState(mainStatePath + 'commands.' + konstanten[2].name, true, function() { setTimeout(function() { DEBUGSENDEMAIL = olddebug; }, 200); }); } else if (msg.includes('Wwdon') || msg == 'DWDUZWNINA#!§$debugan') { DEBUG = true; } else if (msg.includes('Wwdoff') || msg == 'DWDUZWNINA#!§$debugaus') { DEBUG = false; } else if (msg === uTelegramMessageLong || msg === 'DWDUZWNINA#!§$LONG' || msg === uTelegramMessageShort || msg.includes('Wetterwarnungen?') || msg == 'DWDUZWNINA#!§$TT') { warnDatabase.old = []; let oPd = uPushdienst; uPushdienst &= TELEGRAM; forceSpeak = forcedSpeak; onClickCheckRun = true; let oldA = uTextMitAnweisungen, oldB = uTextMitBeschreibung; let long = true; if ( msg === uTelegramMessageShort || msg.includes('Wetterwarnungen?') || msg == 'DWDUZWNINA#!§$TT') long = false; uTextMitAnweisungen = long; uTextMitBeschreibung = long; checkWarningsMain(); uTextMitAnweisungen = oldA; uTextMitBeschreibung = oldB; onClickCheckRun = false; forceSpeak = false; uPushdienst = oPd; } }); } /* ************************************************************************* * Anfrage über Telegramm mit Ww? und WetterWarnungen? * ENDE /* ************************************************************************* */ /* ************************************************************************* * Restartfunktion /* ************************************************************************* */ // wenn alive schon false, starte das Skript neu onStop(function(callback) { if (extendedExists(aliveState)) { if (!getState(aliveState).val) { log('wird neugestartet!'); setState(aliveState, false, true, function() { setTimeout(function() { startScript(scriptName); log('Neustart wurde ausgeführt'); }, 1000) }); } else { log('wurde beendet!'); setState(aliveState, false, true); } } callback(); }, 200) // stop das Skript und setzt den Alivestatus function restartScript() { setTimeout(function() { setState(aliveState, false, false, function() { myLog('Wird über restartScript() beendet.!'); stopScript(scriptName); }); }, 200); } /* ************************************************************************* * Restartfunktion * ENDE /* ************************************************************************* */ /* ************************************************************************* * Erstellung von States incl. 0_userdata & Zugehöriges /* ************************************************************************* */ // gibt die ersten beiden Teile von ID zurück function getCustomRoot(id) { let sRoot = id.split('.'); if (!Array.isArray(sRoot)) { log('Fehler: ' + id + ' ist fehlerhaft. Es fehlt ein . ', 'error'); stopScript(scriptName); } if (sRoot[0] === '0_userdata') sRoot = '0_userdata.0'; else sRoot = 'javascript.' + id.split('.')[1]; return sRoot; } // gibt das zurück was nicht zu getCustomRoot() gehört function getEndOfState(id) { return id.replace(getCustomRoot(id) + '.', ''); } // erweiterte existsState() funktion function extendedExists(id) { return (id) && ($(id).length > 0) && (existsState(id)); } // verhält sich wie createState() function createCustomState(id, def, type, callback = undefined) { if (!extendedExists(id)) { myLog('getCustomRoot: ' + getCustomRoot(id)); myLog('getEndOfState: ' + getEndOfState(id)); if (def == null && type.type == 'string') type.def = ''; else type.def = def; createUserStates(getCustomRoot(id), false, [ [getEndOfState(id), type], ], callback); // Restart Skript nach dem States erzeugt wurden // Nutze Timeout um erst am Ende aller CreateStates das Skript neuzustarten if (timeoutFromCreateState) clearTimeout(timeoutFromCreateState); timeoutFromCreateState = setTimeout(function() { restartScript(); }, 400); } } /** * Create states under 0_userdata.0 or javascript.x * Current Version: https://github.com/Mic-M/iobroker.createUserStates * Support: https://forum.iobroker.net/topic/26839/ * Autor: Mic (ioBroker) | Mic-M (github) * Version: 1.1 (26 January 2020) * Example: see https://github.com/Mic-M/iobroker.createUserStates#beispiel * ----------------------------------------------- * PLEASE NOTE: Per https://github.com/ioBroker/ioBroker.javascript/issues/474, the used function setObject() * executes the callback PRIOR to completing the state creation. Therefore, we use a setTimeout and counter. * ----------------------------------------------- * @param {string} where Where to create the state: '0_userdata.0' or 'javascript.x'. * @param {boolean} force Force state creation (overwrite), if state is existing. * @param {array} statesToCreate State(s) to create. single array or array of arrays * @param {object} [callback] Optional: a callback function -- This provided function will be executed after all states are created. */ function createUserStates(where, force, statesToCreate, callback = undefined) { const WARN = false; // Only for 0_userdata.0: Throws warning in log, if state is already existing and force=false. Default is false, so no warning in log, if state exists. const LOG_DEBUG = false; // To debug this function, set to true // Per issue #474 (https://github.com/ioBroker/ioBroker.javascript/issues/474), the used function setObject() executes the callback // before the state is actual created. Therefore, we use a setTimeout and counter as a workaround. const DELAY = 50; // Delay in milliseconds (ms). Increase this to 100, if it is not working. // Validate "where" if (where.endsWith('.')) where = where.slice(0, -1); // Remove trailing dot if ( (where.match(/^((javascript\.([1-9][0-9]|[0-9]))$|0_userdata\.0$)/) == null) ) { log('This script does not support to create states under [' + where + ']', 'error'); return; } // Prepare "statesToCreate" since we also allow a single state to create if(!Array.isArray(statesToCreate[0])) statesToCreate = [statesToCreate]; // wrap into array, if just one array and not inside an array // Add "where" to STATES_TO_CREATE for (let i = 0; i < statesToCreate.length; i++) { let lpPath = statesToCreate[i][0].replace(/\.*\./g, '.'); // replace all multiple dots like '..', '...' with a single '.' lpPath = lpPath.replace(/^((javascript\.([1-9][0-9]|[0-9])\.)|0_userdata\.0\.)/,'') // remove any javascript.x. / 0_userdata.0. from beginning lpPath = where + '.' + lpPath; // add where to beginning of string statesToCreate[i][0] = lpPath; } if (where != '0_userdata.0') { // Create States under javascript.x let numStates = statesToCreate.length; statesToCreate.forEach(function(loopParam) { if (LOG_DEBUG) log('[Debug] Now we are creating new state [' + loopParam[0] + ']'); let loopInit = (loopParam[1]['def'] == undefined) ? null : loopParam[1]['def']; // mimic same behavior as createState if no init value is provided createState(loopParam[0], loopInit, force, loopParam[1], function() { numStates--; if (numStates === 0) { if (LOG_DEBUG) log('[Debug] All states processed.'); if (typeof callback === 'function') { // execute if a function was provided to parameter callback if (LOG_DEBUG) log('[Debug] Function to callback parameter was provided'); return callback(); } else { return; } } }); }); } else { // Create States under 0_userdata.0 let numStates = statesToCreate.length; let counter = -1; statesToCreate.forEach(function(loopParam) { counter += 1; if (LOG_DEBUG) log ('[Debug] Currently processing following state: [' + loopParam[0] + ']'); if( ($(loopParam[0]).length > 0) && (extendedExists(loopParam[0])) ) { // Workaround due to https://github.com/ioBroker/ioBroker.javascript/issues/478 // State is existing. if (WARN && !force) log('State [' + loopParam[0] + '] is already existing and will no longer be created.', 'warn'); if (!WARN && LOG_DEBUG) log('[Debug] State [' + loopParam[0] + '] is already existing. Option force (=overwrite) is set to [' + force + '].'); if(!force) { // State exists and shall not be overwritten since force=false // So, we do not proceed. numStates--; if (numStates === 0) { if (LOG_DEBUG) log('[Debug] All states successfully processed!'); if (typeof callback === 'function') { // execute if a function was provided to parameter callback if (LOG_DEBUG) log('[Debug] An optional callback function was provided, which we are going to execute now.'); return callback(); } } else { // We need to go out and continue with next element in loop. return; // https://stackoverflow.com/questions/18452920/continue-in-cursor-foreach } } // if(!force) } // State is not existing or force = true, so we are continuing to create the state through setObject(). let obj = {}; obj.type = 'state'; obj.native = {}; obj.common = loopParam[1]; setObject(loopParam[0], obj, function (err) { if (err) { log('Cannot write object for state [' + loopParam[0] + ']: ' + err); } else { if (LOG_DEBUG) log('[Debug] Now we are creating new state [' + loopParam[0] + ']') let init = null; if(loopParam[1].def === undefined) { if(loopParam[1].type === 'number') init = 0; if(loopParam[1].type === 'boolean') init = false; if(loopParam[1].type === 'string') init = ''; } else { init = loopParam[1].def; } setTimeout(function() { setState(loopParam[0], init, true, function() { if (LOG_DEBUG) log('[Debug] setState durchgeführt: ' + loopParam[0]); numStates--; if (numStates === 0) { if (LOG_DEBUG) log('[Debug] All states processed.'); if (typeof callback === 'function') { // execute if a function was provided to parameter callback if (LOG_DEBUG) log('[Debug] Function to callback parameter was provided'); return callback(); } } }); }, DELAY + (20 * counter) ); } }); }); } } /* ************************************************************************* * Erstellung von States incl. 0_userdata & Zugehöriges * ENDE /* ************************************************************************* */ /* ************************************************************************* * Hilffunktion sonstiges /* ************************************************************************* */ // Klone das Objekt function cloneObj(j) { if (Array.isArray(j)) { var arr = [j.length]; for (let a=0;a.+\<\/a\>)/ig,'')); } /* ************************************************************************* * Hilffunktion sonstiges * ENDE /* ************************************************************************* */