[{"id":"ba787640.458788","type":"tcp in","server":"client","host":"172.16.130.254","port":"1012","datamode":"stream","datatype":"buffer","newline":" \\n","topic":"FritzBox Telnet Calls","name":"tcp: ### IP ADRESSE FritzBox ANPASSEN ###","base64":false,"x":242.5,"y":257.5,"z":"64b98f40.9b467","wires":[["3951e22b.c6ae1e","9726285.f68d9d8"]]},{"id":"3928a50.fc6d75c","type":"comment","name":"FRITZ!box Anrufernummer, RING, Anruferliste (doppelklick für mehr Infos)","info":"\nSchnelleinstieg:\n----------------\n\n1.) Port 1012 (Callmonitor) auf der Fritzbox aktivieren.\n Per Telefonanruf zur #96*5* von einem Telefon an der Fritzbox.\n \n2.) IP-Adresse der eigenen Fritzbox im tcp Node eintragen\n\n\nAusführliche Infos unter:\n-------------------------\n\nhttp://[eigene IP Node red]:1880/fritzbox\n\nWenn die Portnummer von Node-red vom Standard 1880 abweichend eingestellt ist,\nmuss diese in deer URL oben auch angepasst werden.\n\n\nAnrufe aus den Anruferlisten:\n-----------------------------\n\nIn der Config kann festgelegt werden, ob die Anruferlisten mit wählbaren Links aufgebaut werden sollen.\nDazu muss html:true und wählbar:true gewählt werden.\n\nAm PC/Mac wird dann die App für ein Telefonat verwendet, welche mit den Links Verknüpft ist,\ndie mit tel:+49.... beginnen. Beim Mac ist die App innerhalb der Facetime Einstellungen auswählbar.\n\n\n\n\n\n-----------------------------------------------------------------------------------------\n\nFür jede Call ID werden diese Informationen erzeugt:\n\n// [0] callid\t\t\t\t // eindeutige ID des aktuellen Rufes\n// [1] date\t\t\t\t\t // Datum Uhrzeit der Meldung in der Form: yy-mm-tt hh:mm:ss\n// [2] calltype\t\t\t\t // CALL, RING, CONNECT, DISCONNECT \n// [3] callingNumber\t\t // die anrufende Nummer\n// [4] calledNumber\t\t\t // die angerufene Nummer\n// [5] connectedNumber\t\t // Nummer mit der die Verbindung zustande gekommen ist\n// [6] intNumber\t\t\t // interne Nebenstelle\n// [7] line\t\t\t\t\t // Leitung: POTS, SIP0, ...\n// [8] connect\t\t\t\t // verbunden: true/false\n// [9] direction\t\t\t // Richtung: \"gehend\", \"kommend\"\n// [10] duration\t\t\t // Dauer der Verbindung in Sekunden\n// [11] dateStart\t\t\t // Datum Start Verbindungsaufbau\n// [12] dateConnect\t\t\t // Datum Verbindung\n// [13] dateEnd\t\t\t\t // Datum aufgelegt\n// [14] rufdauer\t\t\t // Zeit zwischen RING/CALL und einem CONNECT in Sekunden\n// [15] deltaZeitMeldungSystemSek // Delta zwischen der Zeit aus der Fritzboxmeldung und des ioBroker Systems in Sek.\n// [16] dateEpoche // Meldungsdatum [1] in Epoche (Sek. seit dem 1.1.1970)\n// [17] epocheNow // Systemzeit in 1.000stel Sekunden seit dem 1.1.1970\n// [18] externeNummerF // Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n// [19] eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n// [20] verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n// [22] duration2F // Verbindungsdauer 2 als formatierter Text\n// [23] epocheStart\n// [24] externeNummer // Externe Rufnummer, unformatiert\n\n\nMit einem DISCONNECT ist ein Ruf/Gespräch vorbei.\nDie DISCONECT Variablen enthalten alle notwendigen Informationen für das Gespräch,\nda diese mit den vorherigen Zuständen ergänzt wurden.\n\n\n","x":332.6588134765625,"y":155.8294439315796,"z":"64b98f40.9b467","wires":[]},{"id":"a809fd84.57f6","type":"function","name":"Telnet: parse alle Meldungen","func":"//Name: Parse FritzBox Telnet\n//\n//Requirements:\n//- must be able to reach tcp port 1012 on your FB\n//- activate call monitor on FB by dialing #96*5*\n\ncontext.buff = context.buff || \"\"; // wenn es context.buff nicht gibt, anlegen mit \"\"\ncontext.buff = context.buff + msg.payload; // \n\nmsg.payload = context.buff;\ncontext.buff = \"\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":1688.6669540405273,"y":1346.3333616256714,"z":"64b98f40.9b467","wires":[["79fd50aa.8602b","7c58eaf6.83a714"]]},{"id":"aad98929.552678","type":"inject","name":"10.05.15 20:06:58;CALL;1;11;021147110815;08925006881;POTS;","topic":"","payload":"10.05.15 20:06:58;CALL;1;11;08947110815;021125006881;POTS;","payloadType":"string","repeat":"","crontab":"","once":false,"x":324.5001220703125,"y":2240.667034626007,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"ed78e0d3.12872","type":"inject","name":"10.05.15 20:07:00;CONNECT;1;11;08925006881;","topic":"","payload":"10.05.15 20:07:00;CONNECT;1;11;08925006881;","payloadType":"string","repeat":"","crontab":"","once":false,"x":294.5001220703125,"y":2278.6669960021973,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"89033ea.f76fcc","type":"inject","name":"10.05.15 20:07:07;DISCONNECT;1;2;","topic":"","payload":"10.05.15 20:07:07;DISCONNECT;1;2;","payloadType":"string","repeat":"","crontab":"","once":false,"x":238.5001220703125,"y":2316.6669960021973,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"4f3569cd.b0ca98","type":"comment","name":"gehendes Gespräch Küche mit Verbindung","info":"","x":224.5001220703125,"y":2198.667034626007,"z":"64b98f40.9b467","wires":[]},{"id":"8921d25e.76de3","type":"inject","name":"10.05.15 19:06:58;RING;0;08913211545;022143238456;SIP0;","topic":"","payload":"10.05.15 19:06:58;RING;0;08913211545;022143238456;SIP0;","payloadType":"string","repeat":"","crontab":"","once":false,"x":315.5001220703125,"y":2434.6669960021973,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"7f8643c.f8079bc","type":"comment","name":"kommendes Gespr. 089 zur Sipgate 0201, Nebenstelle 10 geht dran","info":"","x":307.50011444091797,"y":2396.667034626007,"z":"64b98f40.9b467","wires":[]},{"id":"624a5347.9db5ac","type":"comment","name":"### todo ###","info":"Fehler: \n\nPrio 1:\n- Berechnungen mit Zeit auf einheitliche Zeit zur Meldung (Systemzeit), d.h. epocheConnect, usw. basierend auf der Systemzeit\n (Hintergrund: keine Abweichung bei der Berechnugn von lfd. Rufdauer, usw.)\n- (!!!) persistente Konfig beim Deploy (Anzahl verpasste Anrufe, Einstellungen Pushover, Email), Werte aus ioBroker übernehmen\n- Konfig: soll der Zähler verpasste Anrufe Nachts gelöscht werden?\n- Rufe (ring und aktive Calls nach voreingestellter Zeit ) nach einstellbarer Zeit aufräumen (Zeit der letzten Fritzbox- Meldung)\n- Anzahl verpasst \"Komfortzähler\" (spätere Gespräche abziehen, d.h. Liste der verpassten Anrufe führen -> JSON)\n- Trigger, um eine Anruferliste zu löschen, Variablen und aktueller String\n- html, txt, json parallelausgeben\n- Umbau: Anruferlisten immer in beiden Formaten ausgeben (Text und html)\n\n\nPrio 2:\n- Bluefox Tabellen Widget einbauen, bzw. bedienen\n- verpasste Anrufer mit Zähler, Anrufe gleicher Tag (Anrufer als ARRAY, Löschen per CRON)\n- Komfortliste: erreichte Rufnr in der verpassten Liste nachträglich kennzeichnen\n- Anruferliste als zusätzliches Objekt anlegen & eigene JSON Webausgabe\n- Pushover Priorotät für VIP Rufnummern\n- Info Email: Liste verpasster Anrufer, Liste Anrufer\n- Widgetbeschreibung (Namen) vervollständigen\n- Widget: rote Fehlermeldung in der Mitte, wenn Config Fehler aufweisst\n- Format Array: Datensatz je Anruf (DISC): jede Spalte als Wert mit und ohne Formatierung: Jahr:2015, Monat:06, extNummer:\n (zur weiteren Verarbeitung durch den User)\n\n\nPrio 3:\n- Anruferlisten: alle (erl.), geh, kom, verpasst (erl.)\n- CDR Kommasepariert, alle Werte\n- CDR Anruferliste ASCII\n- Zähler Connect, getrennt nach gehenden und kommenden Verbindungen\n- Neue HTML Formatierung für die Listen... rechts- / linksbündig, Zeilenfarbe, Linie zwischen den Zeilen, Schriftart, ggf. Templates zur Auswahl\n- Telefonbuch aus Fritzbox (export)\n- Ortsvorwahlen, Länderkennzahlen\n- Telefonbuch Webanbindung\n- Anruferlisten einzeln löschbar machen\n- Dashboard: Kreisdiagramm, angenommene zu verlorene Anrufe\n (Servicelevel des Tages: angenommenw Anrzfe im Verhlätnis zu allen kommensen Anrufen)\n- alle ioBroker Variablen neu in einer weiteren Baumstruktur ordnen\n- Einzel Callsimulation: Zeitstempel zum Zeitpunkt des Auslösens\n- Widget Infofeld: gegen ein \"basic - ValueList 8 html Style\" austauschen (weniger Widgets).\n- \n\nTesten\n======\n\n- \n\nFehler beseitigt:\n=================\n- cdr wird nicht mehr geschrieben, obwohl msg im Debug rauskommt\n (msg statt msg.payload wurde ausgegeben)\n- Beschriftung der Butto start/stop cg gehen im Demo auf Ursprung\n\n\nerledigt:\n==========================================\n- Eintrag Anruferliste bei Disconnect\n- CDRs als JSON\n- Aktiver RING j/n\n- Zähler: Anzahl aktiver RINGS\n- Anzeige der aktiven Gespräche (CONNECT)\n- Zähler: Anzahl aktiver Calls\n- Anruferliste verpasst als Liste\n- Anruferliste gesamt als Liste\n- Anruferlisten Länge konfigurierbar machen\n- Anruferliste html mit Überschriftspalte\n- !!! von msg.config auf global.context umbauen\n- Zähler: aktive Rufaufbau\n- String externe Rufnummern auf die eingestellte Länge kürzen\n- Berechnung der Rufdauer\n- Vergleich aktuelle Zeit System Timestamp, Zeit aus Fritzbox und (NTP Internet -> ntp nicht realisiert) - Liste verpasste Anrufe\n- Anruferliste verpasst löscht nicht, wenn mann context.global löscht\n (war kein Fehler: Liste wird gelöscht (JSON), letzter String ist im Widget noch sichtbar)\n- Zähler verpasste Anrufe\n- call generator Variablen umbauen auf: context.global.fbVars.callgenerator.\n- Wert +/- Zeitunterschied konfigurierbar -> Flag\n- letzte aktiver RING\n (über VIS gelöst, letzter RING als Variable bleibt auch nach dem Auflegen bestehen. \n Über ringAktiv true/false kann bestimmt werden, ob man die Variable noch anzeigen will\n Alternativ kann man bei ringAktiv = false die letzte Rufnummer aus der Variable löschen)\n- Anruferliste kommend: Eintrag kommende Rufnumer: undifined (aus dem Call Generator)\n- Anruferliste gehend: Eintrag ext. Rufnummer: \"\"\n (beides ggf. durch Abbruch des Call Generators durch Deploy???)\n- call generator: 3-5 bekannte Anrufernummern, um die geplante Komfortanruferliste zu testen\n- Demoschalter: start Demo Rufe mit parallelen Calls, Begrenzung auf x Anrufen, Möglichkeit zum stoppe\n- Ausgabe Anzahl Testcalls wird nun zu beginn des Anrufs aktualisiert und nicht mehr zum Ende\n- Call Generator: Durchlauf endet nun bei 0 und nicht bei 1\n- Call Generator: callids für Testcall ab 10 (keine Überschneidung mit \"echten\" Calls)\n (Call Generator: Vergabe der ID !!! Prüfen, ob die ID von einem echten Call belegt ist !!! wenn ja, nächste freie ID)\n- Dokumentation angepasst\n- eigene Webseite erstellt:\n- Eigene Webseite über Node-Red für den Flow\n- Alert bei zu großer Abweichung der Meldungszeit von der Systemzeit -> Log, Nachricht, Variable\n- Liste aktive Ring (über ein Array mit RING ID) \n- Liste aktive Gespräche (über ein Array mit CONECTION ID)\n- Email, verpasster Anruf\n- Pushover verpasster Anruf\n- Fehler: Call Generator: endet mit 1\n- Rufnummernformatierung: alle   und Leerzeichen gegen utf-8 Non-Breaking-Space (auf dem Mac: alt+Leerzeichen) ersetzt\n- aktuelle Gespräche mit den bisher bekannten Infos darstellen.\n- nicht mehr nachvollziehbar: - Test Calls Sekunden tlw. Mehrstellig (>2)\n- Gesprächsdauer, wenn 0, dann \" \" statt 0:00\n- Gesprächsdauer in Sekunden aller aktiven Calls (erledigt. Format Ausgabe noch anpassen h:mm:ss)\n- Gesprächszeit zu kurz? mm:ss was wenn mehr als 60/99 Minuten?\n- call Generator: Duration nicht mehr zufällig, sondern als Zeit zwischen start und disconnect\n (Zeit zwischen CONN und DISC => Zeit bis der int. Tln aufgelegt hat, Duration = echte Gesprächszeit)\n- prüfen: beim Deploy immer alle Vars löschen und dann Init durchführen? (nur mit persistenter Konfig)\n Hinweis: teilweise löschen: call IDs (erl.), Zustände, ...\n Nicht löschen: Anruferlisten.\n- Sortierung Anruferliste Gesamt: ist nach Endzzeit, Angezeigt wird die Startzeit -> geändert in Anzeige Endzeit (DISCONNECT)\n- diverse Webservices (Abfragen, Rückmeldungen, z.B. Anruferliste, aktiver Call ,...)\n- tel.49211.... Links (erl: Link in Call ID hinzugefügt) todo: Formatierung für Anruferlisten, Abschneiden, nicht in der verlinkten Rufnummer, Formatierung für Rufnummer only (ohne Leerzeichen)\n- \"verpasst seit\" Datum einfügen\n- Tastendesign: Tasten, die gerade keinen Sinn machen -> leicht ausgrauen\n (tlw. erledigt: verpasste Anruferliste löschen ausgrauen, wenn 0 -> anders gelöst: auch bei 0 kann man löschen, um, z.B. das Datum zurückstellen)\n- Info: verpasst \"seit dem xx.xx.xx\" einfügen\n- kanonisches Format -> Pushover, Email\n- gekürzte Rufnummern in der Anruferliste mit ...x anzeigen\n- \n\n\n","x":377.83333587646484,"y":190.83331775665283,"z":"64b98f40.9b467","wires":[]},{"id":"79fd50aa.8602b","type":"function","name":"Meldungen in Objekten umbauen & Topic=Call ID","func":"// es wird für jeden der vier calltype das Objekt mit allen 14 Werten zusammengebaut,\n// damit die Nachricht im Objekt zu jeder Zeit synchron ist\n// Werte, die aus vorherigen Nachrichten übernommen werden, werden aus\n// global.context.fbVars[] impoertiert (fbVars = fritzboxVariablen)\n\nmess \t= msg.payload; \t\t// die geparste Meldung aus dem tcp Stream als Ganzes\nslices \t= mess.split(\";\"); \t// speichert die Felder der Meldung in ein Array mit dem Namen \"slices\"\n\n// die Call ID wird als erstes ausgelesen, da diese für die eindeutige Zuordnung\n// der Werte zum richtigen Call benötigt wird (es kann mehrere Calls parallel geben)\nmsg.callid\t\t= slices[2]; // an dritter Stelle steht die CallID (Zurordnung zum aktuellen Ruf)\n\nvar callid\t = msg.callid; // für das Array global.context.fbVars.callid[callid]\n\n\ncontext.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\n// Umbau der Variablen in ein Array\ncontext.global.fbVars.callid = context.global.fbVars.callid || [];\ncontext.global.fbVars.callid[msg.callid] = context.global.fbVars.callid[msg.callid] || {};\n\n\n\n\nfunction fritzboxZeitEpoche(datum) {\ndatum = datum || \"\";\nvar jahr = \"20\" + datum.substring(6,8);\nvar monat = datum.substring(3,5);\nvar monatJS = parseInt(datum.substring(3,5))-1;\nvar tag = datum.substring(0,2);\nvar stunde = datum.substring(9,11);\nvar minute = datum.substring(12,14);\nvar sekunde = datum.substring(15,17);\n\nvar zeit = new Date(jahr,monatJS,tag,stunde,minute,sekunde);\nvar epoche = Date.parse(zeit) / 1000; // Zeit aus der Meldung in Epoche\n \nreturn epoche;\n} \n\n\nfunction fill(n) {\n\tvar leerzeichen = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tleerzeichen += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn leerzeichen;\n\t}\n\nfunction fill0(n) {\n\tvar nullen = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tnullen += \"0\";\n\treturn nullen;\n\t}\n\nfunction rnrformat(rufnummer) {\n var x = 0;\n if (rufnummer.length > context.global.fbVars.config.länge_ext_rnr) {\n rufnummer = rufnummer.substring(0,context.global.fbVars.config.länge_ext_rnr - 1 ) + \"x\";\n }\n var rnr = rufnummer.substring(0,context.global.fbVars.config.länge_ext_rnr); // sollte die externen Rufnummern insgesamt länger sein, werden diese auf die max. gewünschte Länge gekürzt\n rnr = rnr + fill(context.global.fbVars.config.länge_ext_rnr - rnr.length);\n return rnr;\n}\n\n\n\n\nvar now = new Date(); \nnow = Date.parse(now) / 1000 ; // aktuelle Zeit in Epoche\n\n\n\n\n\n// für alle Gesprächszustände identisch:\n// -------------------------------------\n\n// [0]callid\n context.global.fbVars.callid[callid].callid = msg.callid;\n// [1]date\n msg.date \t\t= slices[0]; // an erster Stelle steht immer das Datum in der Form: 10.05.15 20:06:58\n context.global.fbVars.callid[callid].date = msg.date;\n// [2]calltype\n msg.calltype \t= slices[1]; // an zweiter Stelle steht der Ruftyp (CALL, RING, CONNECT, DISCONECT)\n context.global.fbVars.callid[callid].calltype = msg.calltype;\n\nvar tst = fritzboxZeitEpoche(msg.date);\n\n// [15] deltaZeitMeldungSystemSek\n msg.deltaZeitMeldungSystemSek = tst - now;\n\tcontext.global.fbVars.callid[callid].deltaZeitMeldungSystemSek = msg.deltaZeitMeldungSystemSek;\n// [16] dateEpoche\n msg.dateEpoche = tst;\n\tcontext.global.fbVars.callid[callid].dateEpoche = msg.dateEpoche;\n// [17] epocheNow - Systemzeit\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n\n\n\n// die restlichen Stellen der Message sind je nach calltype mit unterschiedlichlichen Variablen belegt. \n\n\n\n// ######## RING ######## (kommendes Gespräch = Ruf)\n\nif (msg.calltype == \"RING\") {\n\n// [3] callingNumber\n\tif (slices[3] === \"\") { // keine Rufnummer -> \"Nummer unterdrückt\"\n\t\tmsg.callingNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.callingNumber = slices[3];\n\t\t}\n\tcontext.global.fbVars.callid[callid].callingNumber = msg.callingNumber;\n// [4] calledNumber\n\tmsg.calledNumber = slices[4];\n\tcontext.global.fbVars.callid[callid].calledNumber = msg.calledNumber;\n// [5] connectedNumber\n\tmsg.connectedNumber = \"\"; // im Zustand Call gibt es keine Connected, diese wird hier gelöscht\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6] intNumber\n\tmsg.intNumber = \"\";\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7] line\n\tmsg.line = slices[5];\n\tcontext.global.fbVars.callid[callid].line = msg.line;\n// [8] connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = false;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9] direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = \"kommend\";\n\tcontext.global.fbVars.callid[callid].direction = msg.direction;\n// [10] duration\n\tmsg.duration = 0;\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11] dateStart\n\tmsg.dateStart = msg.date;\n\tcontext.global.fbVars.callid[callid].dateStart = msg.dateStart;\n// [12] dateConnect\n\tmsg.dateConnect = \"\";\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13] dateEnd\n\tmsg.dateEnd = \"\";\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14] rufdauer\n\tmsg.rufdauer = \"\";\n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [18] externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n\tmsg.externeNummerF = rnrformat(msg.callingNumber);\n context.global.fbVars.callid[callid].externeNummerF = msg.externeNummerF;\n// [19] eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n\tmsg.eigenesAmtF = rnrformat(msg.calledNumber);\n context.global.fbVars.callid[callid].eigenesAmtF = msg.eigenesAmtF;\n// [20] verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = \" -> \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = 0;\n\tcontext.global.fbVars.callid[callid].duration2 = msg.duration2;\n// [22] duration2F // Verbindungsdauer 2 als formatierter Text\n\tmsg.duration2F = \"\";\n\tcontext.global.fbVars.callid[callid].duration2F = msg.duration2F;\n// [23] epocheStart\n msg.epocheStart = fritzboxZeitEpoche(msg.date);\n\tcontext.global.fbVars.callid[callid].epocheStart = msg.epocheStart;\n// [24] externeNummer // Externe Rufnummer, unformatiert\n\tmsg.externeNummer = msg.callingNumber;\n context.global.fbVars.callid[callid].externeNummer = msg.externeNummer;\n\n \n \n} // ++++ Ende RING ++++\n\n\n\n\n// ######## CALL ######## (gehendes Gespräch)\n\nif (msg.calltype == \"CALL\") {\n\n// [3]callingNumber\n\tif (slices[4] === \"\") { // keine Rufnummer -> \"Nummer unterdrückt\"\n\t\tmsg.callingNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.callingNumber = slices[4];\n\t\t}\n\tcontext.global.fbVars.callid[callid].callingNumber = msg.callingNumber;\n// [4]calledNumber\n\tmsg.calledNumber = slices[5];\n\tcontext.global.fbVars.callid[callid].calledNumber = msg.calledNumber;\n// [5]connectedNumber\n\tmsg.connectedNumber = \"\";\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = slices[3];\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7]line\n\tmsg.line = slices[6];\n\tcontext.global.fbVars.callid[callid].line = msg.line;\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = false;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = \"gehend\";\t\n\tcontext.global.fbVars.callid[callid].direction = msg.direction;\n// [10]duration\n\tmsg.duration = 0;\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11]dateStart\n\tmsg.dateStart = msg.date;\n\tcontext.global.fbVars.callid[callid].dateStart = msg.dateStart;\n// [12]dateConnect\n\tmsg.dateConnect = \"\";\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13]dateEnd\n\tmsg.dateEnd = \"\";\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14]rufdauer\n\tmsg.rufdauer = \"\";\n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n\tmsg.externeNummerF = rnrformat(msg.calledNumber);\n context.global.fbVars.callid[callid].externeNummerF = msg.externeNummerF;\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n\tmsg.eigenesAmtF = rnrformat(msg.callingNumber);\n context.global.fbVars.callid[callid].eigenesAmtF = msg.eigenesAmtF;\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = \" <- \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = 0;\n\tcontext.global.fbVars.callid[callid].duration2 = msg.duration2;\n// [22] duration2F // Verbindungsdauer 2 als formatierter Text\n\tmsg.duration2F = \"\";\n\tcontext.global.fbVars.callid[callid].duration2F = msg.duration2F;\n// [23] epocheStart\n msg.epocheStart = fritzboxZeitEpoche(msg.date);\n\tcontext.global.fbVars.callid[callid].epocheStart = msg.epocheStart;\n// [24] externeNummer // Externe Rufnummer, unformatiert\n\tmsg.externeNummer = msg.calledNumber;\n context.global.fbVars.callid[callid].externeNummer = msg.externeNummer;\n\n\n} // ++++ Ende CALL ++++\n\n\n\n\n// ######## CONNECT ######## (verbundenes Gespräch)\n\nif (msg.calltype == \"CONNECT\") {\n\n// [3]callingNumber\n context.global.fbVars.callid[callid].callingNumber = context.global.fbVars.callid[callid].callingNumber || \"????????????\";\n msg.callingNumber = context.global.fbVars.callid[callid].callingNumber;\n// [4]calledNumber\n context.global.fbVars.callid[callid].calledNumber = context.global.fbVars.callid[callid].calledNumber || \"????????????\";\n\tmsg.calledNumber = context.global.fbVars.callid[callid].calledNumber;\n// [5]connectedNumber\n\tif (slices[4] === \"\") {\n\t\tmsg.connectedNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.connectedNumber = slices[4];\n\t\t}\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = slices[3];\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7]line\n\tmsg.line = context.global.fbVars.callid[callid].line;\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = true;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = context.global.fbVars.callid[callid].direction;\n// [10]duration\n\tmsg.duration = context.global.fbVars.callid[callid].duration;\n// [11]dateStart\n\tmsg.dateStart = context.global.fbVars.callid[callid].dateStart;\n// [12]dateConnect\n\tmsg.dateConnect = msg.date;\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13]dateEnd\n\tmsg.dateEnd = context.global.fbVars.callid[callid].dateEnd;\n// [14]rufdauer\n var zeitConnectEpoche = fritzboxZeitEpoche(msg.date);\n\tmsg.rufdauer = zeitConnectEpoche - context.global.fbVars.callid[callid].epocheStart; \n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n\tmsg.externeNummerF = rnrformat(msg.connectedNumber);\n context.global.fbVars.callid[callid].externeNummerF = msg.externeNummerF;\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.eigenesAmtF = context.global.fbVars.callid[callid].eigenesAmtF;\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \nif (msg.direction == \"gehend\") {\n msg.verbindungssymbol = \"<<- \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n} else {\n msg.verbindungssymbol = \" ->>\";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n}\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = context.global.fbVars.callid[callid].duration2;\n// [22] duration2F // Verbindungsdauer 2 als formatierter Text\n\tmsg.duration2F = \"\";\n\tcontext.global.fbVars.callid[callid].duration2F = msg.duration2F;\n// [23] epocheStart\n msg.epocheStart = context.global.fbVars.callid[callid].epocheStart;\n// [24] externeNummer // Externe Rufnummer, unformatiert\n\tmsg.externeNummer = msg.connectedNumber;\n context.global.fbVars.callid[callid].externeNummer = msg.externeNummer;\n\n} // ++++ Ende CONNECT ++++\n\n\n\n// ######## DISCONNECT ######## (beendetes Gespräch / Gesprächsversuch)\n\n// wenn der Flow während eines aktiven Gesprächs gestartet wird,\n// sind diverse Zustände nicht bekannt. Diese werden hier abgefangen.\n\nif (msg.calltype == \"DISCONNECT\") {\n// [3]callingNumber\n context.global.fbVars.callid[callid].callingNumber = context.global.fbVars.callid[callid].callingNumber || \"????????????\";\n\tmsg.callingNumber = context.global.fbVars.callid[callid].callingNumber;\n// [4]calledNumber\n context.global.fbVars.callid[callid].calledNumber = context.global.fbVars.callid[callid].calledNumber || \"????????????\";\n\tmsg.calledNumber = context.global.fbVars.callid[callid].calledNumber;\n// [5]connectedNumber\n context.global.fbVars.callid[callid].connectedNumber = context.global.fbVars.callid[callid].connectedNumber || \"\";\n\tmsg.connectedNumber = context.global.fbVars.callid[callid].connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = context.global.fbVars.callid[callid].intNumber;\n\tif (msg.intNumber == null) { msg.intNumber = \"??\"; }\n// [7]line\n\tmsg.line = context.global.fbVars.callid[callid].line;\n\tif (msg.line == null) { msg.line = \"????\"; }\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = context.global.fbVars.callid[callid].connect;\n\tif (msg.connect == null) { msg.connect = true }\t\t\t\t\t// undefinierter Zustand, wenn der Flow im aktiven Gespräch gestartet wird (Annahme: Gespräch, da wahrscheinlicher (dauert in der Regel länger als ein Rufzustand))\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = context.global.fbVars.callid[callid].direction;\n\tif (msg.direction == null) { msg.direction = \"??????\" }\t\t\t// undefinierter Zustand (gehend oder kommend nicht bekannt, wenn der Flow im aktiven Gespräch gestartet wird)\n// [10]duration\n\tmsg.duration = slices[3];\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11]dateStart\n\tmsg.dateStart = context.global.fbVars.callid[callid].dateStart;\n\tif (msg.dateStart == null) { msg.dateStart = msg.date; }\n// [12]dateConnect\n\tmsg.dateConnect = context.global.fbVars.callid[callid].dateConnect;\n\tif (msg.dateConnect == null) { msg.dateConnect = msg.date; }\n// [13]dateEnd\n\tmsg.dateEnd = msg.date;\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14]rufdauer\n\tmsg.rufdauer = context.global.fbVars.callid[callid].rufdauer;\n\tif (msg.rufdauer == null) { msg.rufdauer = 0; }\n// [17]epocheNow - Systemzeit in 1.000stel Sekunden\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.externeNummerF = context.global.fbVars.callid[callid].externeNummerF;\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.eigenesAmtF = context.global.fbVars.callid[callid].eigenesAmtF;\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = context.global.fbVars.callid[callid].verbindungssymbol;\nif (msg.connect == false) {\n if (msg.direction == \"gehend\") {\n msg.verbindungssymbol = \"X<- \";\n } else {\n if (msg.direction == \"kommend\") {\n msg.verbindungssymbol = \" ->X\";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n }\n \n }\n}\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = context.global.fbVars.callid[callid].duration2;\n// [22] duration2F // Verbindungsdauer 2 als formatierter Text\n\tmsg.duration2F = context.global.fbVars.callid[callid].duration2F;\n// [23] epocheStart\n msg.epocheStart = context.global.fbVars.callid[callid].epocheStart;\n// [24] externeNummer // Externe Rufnummer, unformatiert\n msg.externeNummer = context.global.fbVars.callid[callid].externeNummer;\n\n\n} // ++++ Ende DISCONNECT ++++\n\n\n\n\n// ungültige Zustände abfangen (wenn ein Deploy mitten im Gespräch erfolgt)\n// ------------------------------------------------------------------------\nif (msg.verbindungssymbol == null || msg.verbindungssymbol == \"undefined\") {\n \tmsg.verbindungssymbol = \"????\";\t \t // Flow startet in einem aktiven Call: Symbol \"????\"\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n }\n\nif (msg.externeNummerF == null || msg.externeNummerF == \"undefined\") {\n \tmsg.externeNummerF = rnrformat(\"????????????\");\t \t // Flow startet in einem aktiven Call: Symbol \"????\"\n context.global.fbVars.callid[callid].externeNummerF = msg.externeNummerF;\n msg.externeNummer = msg.externeNummerF;\t \t // Flow startet in einem aktiven Call: Symbol \"????\"\n context.global.fbVars.callid[callid].externeNummer = msg.externeNummer;\n\n }\n\nif (msg.eigenesAmtF == null || msg.eigenesAmtF == \"undefined\") {\n \tmsg.eigenesAmtF = rnrformat(\"????????????\");\t \t // Flow startet in einem aktiven Call: Symbol \"????\"\n context.global.fbVars.callid[callid].eigenesAmtF = msg.eigenesAmtF;\n }\n\n\n\n// ###########################\n\nmsg.config = {};\nmsg.config.callid_anlegen = context.global.fbVars.config.callid_anlegen;\nmsg.config.cdr_to_disk = context.global.fbVars.config.cdr_to_disk;\n\nif (msg.callid) return msg; // wenn Callid != null, dann weiter\nreturn null;","outputs":1,"valid":true,"x":1761.8336868286133,"y":1449.0003786087036,"z":"64b98f40.9b467","wires":[["cbfdf96f.340208","415f035.fbea0fc","abbedbad.544128"]]},{"id":"b3c0e4b4.4c3f18","type":"function","name":"### KONFIGURATION ###","func":"context.global.fbVars.config = {\n\n// ###### KONFIGURATION START ######\n\n \ttopic_prefix: \"node-red.0.fritzbox.\",\t// Pfad unter dem die Daten in ioBroker gespeichert werden sollen\n // Achtung: wenn der Pfad geändert wird, müssen auch alle ioBroker input Nodes angepasst werden, sowie das VIS Widget \n\n eigenerCC: \"49\", // eigener Country Code (Landesvorwahl, ohne Präfix (z.B. 00, +)\n eigenerAC: \"211\", // eigener aerea Code (Ortsnetz), ohne Präfix\n\n\n// rnr_unbekannt: \"rnr unbekannt\", \t\t// Text, wenn die Rufnummer unbekannt/unterdrückt ist (auf die Länge achten)\n rnr_unbekannt: \"### ? ###\",\t\t \t\t// Text, wenn die Rufnummer unbekannt/unterdrückt ist (auf die Länge achten)\n \n\tcdr_to_disk:true,\t\t\t\t\t\t// (false/true default:false) schreib CDRs (Call Detail Records auf Disk), gespeichert unter: /opt/iobroker/fritzbox-cdr.txt\n\n deltaZeit:5,\t \t\t\t\t // (default:10) Zeit Abweichung in Sekunden zwischen Systemzeit und der Zeit der Meldung aus der Fritzbox \n\n\n // Infoservice verpasste Anrufe -> Email / Pushover\n // --------------------------------------------------------------------------------------------------------------\n infoPushover:true,\t \t\t\t\t// (default:false) Verpasster Anruf per Pushover\n infoEmail:true, \t\t\t\t// (default:false) Verpasster Anruf per Email\n infoDemo:false, // (default:false) Anrufe vom Call Generator (Demo) nicht als Info an Email oder Pushover\n\n // Formatierung Anruferlisten\n // --------------------------------------------------------------------------------------------------------------\n \tlänge_ext_rnr: 14,\t\t\t\t\t\t// (default: 14) Anzeige: max. Länge externe Rufnummern (der Rest wird abgeschnitten)\n\n // Formatierung der Anruferliste per html (Festbreitenschrift und Farbe)\n html:true,\t\t\t\t\t\t\t\t// (true/false, default:true) Anruferlisten in html formatieren\n wählbar: true, // (true/false, default:true) externe Rufnummer als wählbaren Link in der Anruferliste (nur bei html:true)\n fontsize:\"14px\",\t\t\t\t\t\t// (default:\"14px\") Schriftgröße\n\n\t// welche Daten sollen in den Anruferlisten angezeigt werden\n\t// alle Anruferlisten:\n anz_datum:true,\t\t\t\t\t\t\t// true: Spalte Datum im Format\t\tmm.dd.\t(Format kann im Node einfach geändert werden)\n anz_uhrzeit:true,\t\t\t\t\t\t// true: Spalte Uhrzeit im Format\thh:dmm\t(Format kann im Node einfach geändert werden)\n\n\t// Ruflisten Anzeige Spalten (nur in der Gesamtliste:)\n\tanz_int_rnr:true,\t\t\t\t\t\t// true: Spalte für die interne Rufnummer beim verbundenen Gespräch\n\tanz_eigenes_amt:true,\t\t\t\t\t// true: Spalte für die eigenen verwendeten Amtsrufnummer\n\tanz_line:true,\t\t\t\t\t\t\t// true: Spalte für die Art des Amts (POTS, SIP0, usw.)\n\tanz_duration:true, // true: Spalte für die Dauer des Gespräches in mm:ss\n \n anz_anzahl_zeilen:10, // (default: 10) Anzahl Zeilen in den Anruferlisten\n\n anz_kopfzeile:true, // (default: true) Kopfzeile für die Anruferliste ausgeben\n\n // Call Generator\n // --------------------------------------------------------------------------------------------------------------\n cgZeitfehler:false // (default: false) true simuliert bewusst Zeitfehler in der Fritzbox Meldung\n \n};\n\n\n\n\n// Buttons für VIS\n// ---------------\n\ncontext.global.fbVars.config.button = {\n\n // Callgenerator: start Button\n // {node-red.0.fritzbox.button.startDemo}\n startDemoInaktiv: \"start
Demo\",\n startDemoAktiv: 'Demo
läuft
',\n startDemoGestoppt: 'Anrufe
beenden
',\n\n\n // Callgenerator: stop Button\n // {node-red.0.fritzbox.button.stopDemo}\n stopDemoInaktiv: 'keine Demo
aktiv
',\n stopDemoAktiv: \"Stop
Demo\",\n stopDemoGestoppt: 'Demo wird
gestoppt
'\n};\n\n\n// ###### KONFIGURATION ENDE ######\n\n\nmsg.payload = 2;\nmsg.topic = context.global.fbVars.config.topic_prefix + \"adapterInit\"; // Variablenname\n\n\n\nreturn msg;\n","outputs":1,"valid":true,"x":303.3332824707031,"y":296.66668701171875,"z":"64b98f40.9b467","wires":[["61a626d3.9e59d8","e7821d5e.187de"]]},{"id":"de0f3b54.21f0c8","type":"switch","name":"(1) RING (2) CALL (3) CONNECT (4) DISCONNECT","property":"calltype","rules":[{"t":"eq","v":"RING"},{"t":"eq","v":"CALL"},{"t":"eq","v":"CONNECT"},{"t":"eq","v":"DISCONNECT"}],"checkall":"true","outputs":4,"x":2415.6904296875,"y":1441.4764404296875,"z":"64b98f40.9b467","wires":[[],[],[],["b5e51677.4a1ae8","9185a48e.6e7a58"]]},{"id":"b5e51677.4a1ae8","type":"function","name":"DISCONNECT: Werte für Rufliste (1) alle, (2) verpasst","func":"\nvar anruferliste = \"\";\nvar anruferlisteKopf = \"\";\nvar verpasst =\"\";\nvar verpasstKopf =\"\";\n\nvar externeNummer = msg.externeNummerF;\nvar externeNummerKopf = \"ext. Rufnr.\";\nvar verbindungssymbol = msg.verbindungssymbol;\nvar eigenesAmt = msg.eigenesAmtF;\nvar eigenesAmtKopf = \"Eigenes Amt\";\nvar line = msg.line;\nvar lineKopf = \"Ltg.\";\nvar intNummer = msg.intNumber;\nvar intNummerKopf = \"Nbst\";\n\nvar duration = \"\";\nvar durationKopf = \"  Dauer\"\n\n\nif (context.global.fbVars.config.html == true) {\n if (context.global.fbVars.config.wählbar == true) {\n externeNummer = msg.externeNummerW;\n }\n}\n\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn empty_chars;\n\t}\n\nfunction fill0(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn empty_chars ;\n\t}\n\n\n\n\n// neue Berechnung inkl. h (04.06.2015):\n// Test:\n// msg.duration = 3661;\n\nvar durationMin = Math.floor(parseInt(msg.duration) / 60 );\nvar durationSek = parseInt(msg.duration) % 60;\nvar durationStd = Math.floor(durationMin / 60);\ndurationMin %= 60;\n\n\n\n// CSS Farbe Verbindungssymbol\n\tif (msg.connect == true ) cssvs = '';\n\tif (msg.connect == false) cssvs = '';\n\tif (msg.verbindungssymbol == \"????\") cssvs = '';\n\n// css\nif (context.global.fbVars.config.html === true) {\n\tvar cssstart = '';\n\tvar cssend = \"\";\n\tvar cssba = \"\";\n\tvar cssbe = \"\";\n\t} else {\n\tvar cssstart = \"\";\n\tvar cssend = \"\";\n\tvar cssba = \"\";\n\tvar cssbe = \"\";\n\tvar cssvs = \"\";\n\t}\n\t\n\n//\tvar zeitstempel = msg.dateStart; // Zeit des RING\n var zeitstempel = msg.dateEnd; // Zeit des DISCONNECT\n\n\tvar jahr = zeitstempel.substring(6,8);\n\tvar monat = zeitstempel.substring(3,5);\n\tvar tag = zeitstempel.substring(0,2);\n\tvar stunde = zeitstempel.substring(9,11);\n\tvar minute = zeitstempel.substring(12,14);\n\tvar sekunde = zeitstempel.substring(15,17);\n\n\t//var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n\tvar uhrzeit = stunde + \":\" + minute + \" \";\n var uhrzeitKopf = \"Zeit  \";\n\n\t//var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n\t//var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n\tvar datum = tag + \".\" + monat + \". \";\n var datumKopf = \"Tag    \";\n// duration = durationMin + \":\" + fill(2 - durationSek.length);\n\n\n// Ausgabeformat Duration\nif (durationStd < 1) {\n if (durationMin < 1) {\n duration = durationSek;\n } else {\n duration = durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n }\n} else {\n duration = durationStd + \":\" + fill0(2- durationMin.toString().length) + durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n} \nduration = duration.toString();\n\n\n\nif (duration == \"0\") {\n duration = \"-\";\n}\n\nif (duration.length > 7) {\n duration = \"> 10h\";\n}\n\n// duration = duration.substring(0,7); // Dauer auf 7 Stellen kürzen (wenn Dauer= > 10h) [rausgenommen, da bei gr. 10h nun der Text \"> 10h\" angezeigt wird]\nduration = fill(7 - duration.toString().length) + duration; // auf 7-Stellen auffüllen \n\n\n\n// Felder rausfiltern, die laut Konfig nicht angezeigt werden sollen\nif (context.global.fbVars.config.anz_datum === true) {\n\t} else {\n\tdatum = \"\";\n\tdatumKopf = \"\";\n\t}\n\nif (context.global.fbVars.config.anz_uhrzeit === true) {\n\t} else {\n\tuhrzeit = \"\";\n\tuhrzeitKopf = \"\";\n\t}\n\nif (context.global.fbVars.config.anz_duration === true) {\n\t} else {\n\tduration = \"\";\n\tdurationKopf = \"\";\n\t}\n\n\n// sollte die externen Rufnummern insgesamt länger sein, werden diese auf die max. gewünschte Länge gekürzt\nexterneNummerKopf = externeNummerKopf.substring(0,context.global.fbVars.config.länge_ext_rnr);\neigenesAmtKopf = eigenesAmtKopf.substring(0,context.global.fbVars.config.länge_ext_rnr);\n\n\n// Amtsrufnummern (externe und eigene) auf gewünschte Länge mit Leerzeichen auffüllen \nexterneNummerKopf = externeNummerKopf + fill(context.global.fbVars.config.länge_ext_rnr - externeNummerKopf.length);\nintNummer = fill(5 - intNummer.length) + intNummer;\nintNummerKopf = fill(5 - intNummerKopf.length) + intNummerKopf;\neigenesAmtKopf = eigenesAmtKopf + fill(context.global.fbVars.config.länge_ext_rnr - eigenesAmtKopf.length);\nline = line + fill(5 - intNummer.length)+ \" \";\nlineKopf = lineKopf + fill(5 - intNummer.length)+ \" \";\n\n\n\n// Felder rausfiltern, die laut Konfig nicht angezeigt werden sollen\n\t\nif (context.global.fbVars.config.anz_int_rnr === true) {\n\t} else {\n\tintNummer =\"\";\n\tintNummerKopf =\"\";\n\t}\n\nif (context.global.fbVars.config.anz_eigenes_amt === true) {\n\t} else {\n\teigenesAmt =\"\";\n\teigenesAmtKopf =\"\";\n\t}\n\nif (context.global.fbVars.config.anz_line === true) {\n\t} else {\n\tline =\"\";\n\tlineKopf = \"\";\n\t}\n\n\n\n// Ausgabe alle Arten von Anrufen\n// =================================\nanruferliste = datum + uhrzeit + externeNummer + cssba + cssvs + verbindungssymbol + cssend + cssbe \n\t\t\t + intNummer + \" \" + eigenesAmt + line + duration;\n\nanruferlisteKopf = cssba + datumKopf + uhrzeitKopf + externeNummerKopf + \"g<>k\" \n\t\t\t + intNummerKopf + \" \" + eigenesAmtKopf + lineKopf + durationKopf + cssbe;\n\n\n// Ausgabe der verpassten kommenden Anrufe\n// =================================\nif (msg.direction == \"kommend\") {\n if (msg.connect == false) {\n\t verpasstKopf = cssba + datumKopf + uhrzeitKopf + \" \" + externeNummerKopf + cssbe;\n\t verpasst = datum + uhrzeit + \" \" + externeNummer;\n } else {\n\t verpasst = \"nichts\";\n\t }\n\t} else {\n verpasst = \"nichts\";\n }\n\n\n\nvar msg1 = {};\nvar msg2 = {};\n\nmsg1.topic = msg.topic + \"ruflisten.alleLetzterEintrag\";\nmsg2.topic = msg.topic + \"ruflisten.verpasstLetzterEintrag\";\n\nmsg1.payload = anruferliste;\nmsg2.payload = verpasst;\n\nmsg1.anruferlisteKopf = anruferlisteKopf;\nmsg2.verpasstKopf = verpasstKopf;\n\nreturn [msg1,msg2];\n","outputs":"2","valid":true,"x":2937.262107849121,"y":1450.119387626648,"z":"64b98f40.9b467","wires":[["eebd01f9.1143","2dde40b0.d221c"],["ebe3b508.141c48","c9dbb867.362448"]]},{"id":"37d4847.fc82b7c","type":"inject","name":"10.05.15 19:07:00;CONNECT;0;10;08913211545;","topic":"","payload":"10.05.15 19:07:00;CONNECT;0;10;08913211545;","payloadType":"string","repeat":"","crontab":"","once":false,"x":298.8334274291992,"y":2473.000286579132,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"dfc1a1cb.203e6","type":"inject","name":"10.05.15 19:07:07;DISCONNECT;0;42;","topic":"","payload":"10.05.15 19:07:07;DISCONNECT;0;42;","payloadType":"string","repeat":"","crontab":"","once":false,"x":244.83340454101562,"y":2509.6669960021973,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"ebe3b508.141c48","type":"switch","name":"(1) verpasst (2) nichts verpasst","property":"payload","rules":[{"t":"neq","v":"nichts"},{"t":"else"}],"checkall":"false","outputs":2,"x":3017.6189346313477,"y":1498.4526958465576,"z":"64b98f40.9b467","wires":[["13d8ec19.ec2714","eebd01f9.1143"],[]]},{"id":"ab181b8c.54e7e8","type":"inject","name":"10.05.15 21:06:58;RING;2;;022143238456;SIP0;","topic":"","payload":"10.05.15 21:06:58;RING;2;;022143238456;SIP0;","payloadType":"string","repeat":"","crontab":"","once":false,"x":261.16673278808594,"y":2608.8337440490723,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"5535728b.aaca8c","type":"comment","name":"kommendes Gespr. Nummer unterdrückt zur Sipgate 0221","info":"","x":264.16674041748047,"y":2575.833782672882,"z":"64b98f40.9b467","wires":[]},{"id":"49d83a8d.b627c4","type":"comment","name":"Version 0.4.2 - Versionsinfos","info":"0.4.2\n- wählbare Rufnummernlinks (tel:+....) in den Anruferlisten\n- Bugfixes\n\n0.4.1\n- Anrufmonitor eingebaut\n- Buttons mit farblichen (und Text) Feedback\n\n0.4.0\n- Webseite und Links JSON Objekte hinzugefügt\n- Dokumentation erweitert\n- Pushover und Email aktiviert und angepasst\n- Gesprächsdauer aktive Gespräche ergänzt (zählt die Sekunden hoch)\n- Call Generator: keine Zufallszeit mehr als Gesprächsdauer bei Gesprächsende\n\n0.3.3\n- Programmstruktur im Kern aufgeräumt\n- JSON Arrays für anstehende Anrufe, Gespräche und gehende Rufe aufgebaut\n (Vorbereitung für diverse Listen)\n- alle CallID ioBroker Objekte entfernt (wurden für die FUnktion nicht benötigt)\n\n0.3.2\n- Demomodus: 100 Anrufe, bis zu drei parallel, werden zufällig abgearbeitet\n- Zähler für verpasste Anrufe hinzugefügt\n\n0.3.1\n- Call Generator für Demo und Test hinzugefügt\n\n0.3.0\n- Konfiguration von msg.config auf context.global.fbVars.config umgestellt\n- http://[eingeneIP]:1880/fritzbox/vars -> Ausgabe des JSON Objekts mit den aktuellen Einstellungen\n- \n\n0.2.0\n- Interne Variablen auf Array nach Call ID umgestellt\n- Solange RING aktiv: Variable RING = true (zur Anzeige in VIS)\n- Anruferlisten für gesamt und verpasst (Format Text oder html, konfigurierbar)\n \n\n0.1.0\n- Werte für Anruferliste gesamt und verpasst sind konfigurierbar und werden ausgegeben\n (Formatierung wahlweise in HTML oder Text // Spalten in der Konfiguration auswählbar)\n- die wichtigsten Parameter können unter KONFIGURATION eingestellt werden\n- Variablen in ioBroker können für alle Call IDs angelegt werden\n Default: es werden keine Variablen angelegt (siehe KONFIGURATION)\n- CDRs to disk (konfigurierbar)\n\n ","x":191.83331298828125,"y":192.8333330154419,"z":"64b98f40.9b467","wires":[]},{"id":"e2419472.1dbe68","type":"debug","name":"","active":true,"console":"false","complete":"false","x":2137.8336181640625,"y":1261.33353805542,"z":"64b98f40.9b467","wires":[]},{"id":"123e23c9.edc1dc","type":"function","name":"Meldung aufräumen -> CDR JSON","func":"var callid = msg.callid;\n\nmsg = {};\nmsg.topic = \"cdrJSON\";\n\nmsg.payload = context.global.fbVars.callid[callid]; // nur die aktuelle Call ID als JSON ausgeben\n\nreturn msg;","outputs":1,"valid":true,"x":3754.4997940063477,"y":1119.000126838684,"z":"64b98f40.9b467","wires":[["8e3112e.f71cef","9e3ef6f.f61c108","e88f000e.1771"]]},{"id":"8e3112e.f71cef","type":"debug","name":"msg -> CDR (call detail Record) JSON","active":false,"console":"false","complete":"true","x":3376.499839782715,"y":1154.0001130104065,"z":"64b98f40.9b467","wires":[]},{"id":"e88f000e.1771","type":"file","name":"","filename":"/opt/iobroker/fritzbox-cdr-json.txt","appendNewline":true,"overwriteFile":"false","x":3767.8332901000977,"y":1165.666874885559,"z":"64b98f40.9b467","wires":[]},{"id":"9e3ef6f.f61c108","type":"debug","name":"","active":false,"console":"false","complete":"true","x":3801.166615804036,"y":1059.0001169840493,"z":"64b98f40.9b467","wires":[]},{"id":"9185a48e.6e7a58","type":"switch","name":"Konfiguration: CDRs auf Disk schreiben (j/n)","property":"config.cdr_to_disk","rules":[{"t":"true"}],"checkall":"true","outputs":1,"x":3391.166549682617,"y":1117.3334369659424,"z":"64b98f40.9b467","wires":[["123e23c9.edc1dc","f21c8a4e.0de378"]]},{"id":"e7dee54e.182118","type":"file","name":"","filename":"/opt/iobroker/fritzbox-cdr-json.txt","appendNewline":true,"overwriteFile":"delete","x":2483.5000915527344,"y":66.66666793823242,"z":"64b98f40.9b467","wires":[]},{"id":"7d6c49d1.8293b8","type":"inject","name":"CDR Datei löschen","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":2233.1668395996094,"y":66.83335494995117,"z":"64b98f40.9b467","wires":[["e7dee54e.182118"]]},{"id":"ac325813.53cda8","type":"ioBroker out","name":"[Pfad aud der Konfig] + Variablenname","topic":"","ack":"true","autoCreate":"true","x":3647.500045776367,"y":1449.833270072937,"z":"64b98f40.9b467","wires":[]},{"id":"cbfdf96f.340208","type":"debug","name":"","active":false,"console":"false","complete":"payload","x":1831.8812103271484,"y":1486.4528679847717,"z":"64b98f40.9b467","wires":[]},{"id":"415f035.fbea0fc","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1665.214542388916,"y":1487.4527840614319,"z":"64b98f40.9b467","wires":[]},{"id":"b725e271.48da2","type":"function","name":"context.global.fbVars löschen","func":"context.global.fbVars = {};\n\nmsg.payload = context.global.fbVars;\n\nreturn msg;","outputs":1,"valid":true,"x":1524.1665649414062,"y":81.83331298828125,"z":"64b98f40.9b467","wires":[["d105f7d9.2efa08"]]},{"id":"d105f7d9.2efa08","type":"debug","name":"","active":true,"console":"false","complete":"payload","x":1728.1665649414062,"y":79.83331298828125,"z":"64b98f40.9b467","wires":[]},{"id":"608837bd.9f77c8","type":"inject","name":"Löscht die globalen Variablen","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":1282.1665649414062,"y":83.83331298828125,"z":"64b98f40.9b467","wires":[["b725e271.48da2"]]},{"id":"f21c8a4e.0de378","type":"debug","name":"","active":false,"console":"false","complete":"true","x":3802.16658782959,"y":1025.5001130104065,"z":"64b98f40.9b467","wires":[]},{"id":"eebd01f9.1143","type":"function","name":"terminiert alle Variablen","func":"\nreturn msg;","outputs":1,"valid":true,"x":3371.1667556762695,"y":1445.1666955947876,"z":"64b98f40.9b467","wires":[["ac325813.53cda8","cd031aac.32fce8"]]},{"id":"85d12d26.7a2ed","type":"function","name":"Testmeldungen","func":"\nreturn msg;","outputs":1,"valid":true,"x":980.5000152587891,"y":2691.8337755203247,"z":"64b98f40.9b467","wires":[["3951e22b.c6ae1e"]]},{"id":"e77ce5b3.188318","type":"inject","name":"10.05.15 21:07:00;CONNECT;2;10;;","topic":"","payload":"10.05.15 21:07:00;CONNECT;2;10;;","payloadType":"string","repeat":"","crontab":"","once":false,"x":252.99999237060547,"y":2644.833538532257,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"8418ffe2.7be7","type":"inject","name":"10.05.15 21:07:07;DISCONNECT;2;42;","topic":"","payload":"10.05.15 21:07:07;DISCONNECT;2;42;","payloadType":"string","repeat":"","crontab":"","once":false,"x":233,"y":2678.8334999084473,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"91ff9544.6e0068","type":"inject","name":"10.05.15 20:06:58;RING;3;01713211545;022143238456;SIP0;","topic":"","payload":"10.05.15 20:06:58;RING;3;01713211545;022143238456;SIP0;","payloadType":"string","repeat":"","crontab":"","once":false,"x":821,"y":2430.8334999084473,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"99e9093c.6616f8","type":"comment","name":"kommendes Gespr. 0173 zur Sipgate 0201, Nebenstelle 12 geht dran","info":"","x":810.9999923706055,"y":2398.833538532257,"z":"64b98f40.9b467","wires":[]},{"id":"48ddd0.ffb7223","type":"inject","name":"10.05.15 20:07:00;CONNECT;3;12;01713211545;","topic":"","payload":"10.05.15 20:07:00;CONNECT;3;12;01713211545;","payloadType":"string","repeat":"","crontab":"","once":false,"x":808.3333129882812,"y":2466.1667518615723,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"f948ff85.06b7","type":"inject","name":"10.05.15 20:07:07;DISCONNECT;3;42;","topic":"","payload":"10.05.15 20:07:07;DISCONNECT;3;42;","payloadType":"string","repeat":"","crontab":"","once":false,"x":758.3333129882812,"y":2503.8334999084473,"z":"64b98f40.9b467","wires":[["85d12d26.7a2ed"]]},{"id":"cd031aac.32fce8","type":"debug","name":"","active":false,"console":"false","complete":"false","x":3573.5475692749023,"y":1406.7380514144897,"z":"64b98f40.9b467","wires":[]},{"id":"2dde40b0.d221c","type":"function","name":"Anruferliste gesamt als Liste","func":"\n\n// var events = [];\ncontext.global.fbVars.anruferlisteGesamt = context.global.fbVars.anruferlisteGesamt || [];\n\nfunction getEventsList() {\n var text = '';\n\n if (context.global.fbVars.config.html === true) text = '';\n\n for (var i = 0; i < context.global.fbVars.anruferlisteGesamt.length; i++) {\n// text += (text ? '
\\n' : '') + context.global.fbVars.anruferlisteGesamt[i];\n text += context.global.fbVars.anruferlisteGesamt[i] + (text ? '
\\n' : '');\n }\n \n if (context.global.fbVars.config.html === true) text = text + '
';\n \n return text;\n} \n\nif (context.global.fbVars.config.anz_kopfzeile === true) {\n context.global.fbVars.anruferlisteGesamt.shift(); // erste Element im Array löschen (Kopfzeile)\n context.global.fbVars.anruferlisteGesamt.unshift(msg.anruferlisteKopf, msg.payload); // (Kopfzeile und aktueller Eintrag an Stelle 1 und 2 hinzufügen)\n } else {\n context.global.fbVars.anruferlisteGesamt.unshift(msg.payload);\n }\n\n// if (context.global.fbVars.anruferlisteGesamt.length > context.global.fbVars.config.anz_anzahl_zeilen) context.global.fbVars.anruferlisteGesamt.pop();\n if (context.global.fbVars.anruferlisteGesamt.length > context.global.fbVars.config.anz_anzahl_zeilen) {\n context.global.fbVars.anruferlisteGesamt.length = context.global.fbVars.config.anz_anzahl_zeilen;\n }\n msg.payload = getEventsList();\n\nmsg.topic = context.global.fbVars.config.topic_prefix + \"ruflisten.gesamtListe\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":3344.16650390625,"y":1524.6668224334717,"z":"64b98f40.9b467","wires":[["a1cb973c.5e3468","eebd01f9.1143"]]},{"id":"a1cb973c.5e3468","type":"debug","name":"Anruferliste gesamt","active":false,"console":"false","complete":"payload","x":3574.166435241699,"y":1519.6668214797974,"z":"64b98f40.9b467","wires":[]},{"id":"13d8ec19.ec2714","type":"function","name":"Anruferliste verpasst als Liste","func":"// var events = [];\ncontext.global.fbVars.anruferlisteVerpasst = context.global.fbVars.anruferlisteVerpasst || [];\n\n\nfunction getEventsList() {\n var text = '';\n if (context.global.fbVars.config.html === true) text = '';\n\n for (var i = 0; i < context.global.fbVars.anruferlisteVerpasst.length; i++) {\n text += context.global.fbVars.anruferlisteVerpasst[i] + (text ? '
\\n' : '');\n }\n\n if (context.global.fbVars.config.html === true) text = text + '
';\n \n return text;\n} \n\n\n\n\n// context.global.fbVars.anruferlisteVerpasst.unshift(msg.payload);\n// if (context.global.fbVars.anruferlisteVerpasst.length > context.global.fbVars.config.anz_anzahl_zeilen) context.global.fbVars.anruferlisteVerpasst.pop();\n// msg.payload = getEventsList();\n\nif (context.global.fbVars.config.anz_kopfzeile === true) {\n context.global.fbVars.anruferlisteVerpasst.shift(); // erste Element im Array löschen (Kopfzeile)\n context.global.fbVars.anruferlisteVerpasst.unshift(msg.verpasstKopf, msg.payload); // (Kopfzeile und aktueller Eintrag an Stelle 1 und 2 hinzufügen)\n } else {\n context.global.fbVars.anruferlisteVerpasst.unshift(msg.payload);\n }\n\n// if (context.global.fbVars.anruferlisteVerpasst.length > context.global.fbVars.config.anz_anzahl_zeilen) context.global.fbVars.anruferlisteVerpasst.pop();\n if (context.global.fbVars.anruferlisteVerpasst.length > context.global.fbVars.config.anz_anzahl_zeilen) {\n context.global.fbVars.anruferlisteVerpasst.length = context.global.fbVars.config.anz_anzahl_zeilen;\n }\n msg.payload = getEventsList();\n\n\n\nmsg.topic = context.global.fbVars.config.topic_prefix + \"ruflisten.verpasstListe\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":3339.9998321533203,"y":1576.3334770202637,"z":"64b98f40.9b467","wires":[["c3533b90.3cacc8","eebd01f9.1143"]]},{"id":"c3533b90.3cacc8","type":"debug","name":"Anruferliste verpasst","active":false,"console":"false","complete":"payload","x":3576.2498664855957,"y":1577.5834980010986,"z":"64b98f40.9b467","wires":[]},{"id":"a51ff33f.5ae01","type":"http in","name":"","url":"/fritzbox/vars","method":"get","x":3000.8333892822266,"y":238.5000171661377,"z":"64b98f40.9b467","wires":[["1171fd27.ee8e03"]]},{"id":"a30e5670.5cf1a8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars","x":3799.071159362793,"y":235.40477561950684,"z":"64b98f40.9b467","wires":[]},{"id":"1171fd27.ee8e03","type":"function","name":"Ausgabe JSON context.global.fbVars","func":"msg.payload = context.global.fbVars;\nreturn msg;","outputs":1,"valid":true,"x":3247.4999643961582,"y":236.83334922790527,"z":"64b98f40.9b467","wires":[["a30e5670.5cf1a8"]]},{"id":"916af5c1.6e9508","type":"http in","name":"","url":"/fritzbox","method":"get","x":2974.49991607666,"y":110.78569650650024,"z":"64b98f40.9b467","wires":[["5710f4a.fa8ef0c"]]},{"id":"7c58eaf6.83a714","type":"function","name":"*.meldungAusDerFritzBox","func":"\nmsg.topic = msg.topic + \"meldungAusDerFritzBox\"; // Variablenpfad (aus der Konfigurationsfunktion) + \"meldung\"\n\nreturn msg;","outputs":1,"valid":true,"x":2111.50008392334,"y":1226.5002222061157,"z":"64b98f40.9b467","wires":[["e2419472.1dbe68","3c83f91b.c37c06"]]},{"id":"a5d14987.5a2eb8","type":"function","name":"*.deltaZeitMeldungSystemSek","func":"var msg1 = {};\nvar msg2 = {};\n\nif ((msg.deltaZeitMeldungSystemSek > context.global.fbVars.config.deltaZeit) || (msg.deltaZeitMeldungSystemSek < -context.global.fbVars.config.deltaZeit)){\n msg2.payload = false\n if (msg.callid <10) node.error(\"!! prüfen !! Delta Systemzeit ioBroker <-> Fritzbox\"); // Kein Demoanruf, Abweichung zu groß -> Node red Fehlermeldung\n} else {\n msg2.payload = true\n}\n\n\n\nmsg1.payload = msg.deltaZeitMeldungSystemSek;\nmsg1.topic = msg.topic + \"deltaZeitMeldungSystemSek\";\n\nmsg2.topic = msg.topic + \"deltaZeitMeldungSystemOK\";\n\n\n\n\nreturn [msg1, msg2];\n","outputs":"2","valid":true,"x":2192.737693786621,"y":1842.7146615982056,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"],["d11b4023.2ee4c"]]},{"id":"88039cea.77fc6","type":"inject","name":"<<<--- START CALL GENERATOR, zufällige Calls starten (bis zu vier parallele Calls)","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":343.28570556640625,"y":623.0238647460938,"z":"64b98f40.9b467","wires":[["18214dba.e7deb2"]]},{"id":"70e82574.8f17dc","type":"function","name":"Random Callparameter","func":"var vorwahlen = [\"0201\",\"0211\",\"030\",\"089\",\"040\"];\nvar eigeneRufnummern = [\"021147110815\",\"02118115643\",\"02114325666\"];\nvar eigeneLines = [\"POTS\",\"SIP0\",\"SIP1\"];\nvar extRufnummernBekannt = [\"05119181111\",\"0711987654321\"];\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\n//Zufahllszahlen zwischen min und max\nfunction rand(min, max) {\n\treturn Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n//Rufnummer ohne Vorwahl genereieren, Länge zwischen 6 und 8 Ziffern\nfunction rufnummer () {\n var länge = rand (6,8);\n var rufnummer = \"\";\n rufnummer = rufnummer + rand(1,9);\n for (var i = 0; i <= länge; i++)\n rufnummer = rufnummer + rand(0,9);\n return rufnummer;\n}\n\n\nfunction datum() {\n var now = new Date((new Date().getTime()) + (context.global.fbVars.callgenerator.zeitfehler * 1000) );\n\n var tag = now.getDate();\n var monat = now.getMonth()+1;\n var jahr = now.getFullYear();\n var stunde = now.getHours(); \n var minute = now.getMinutes(); \n var sekunde = now.getSeconds(); \n\n stunde = stunde.toString(); \n tag = tag.toString();\n monat = monat.toString();\n jahr = jahr.toString();\n minute = minute.toString();\n sekunde = sekunde.toString();\n jahr = jahr.substr(2,3);\n tag = fill(2 - tag.length) + tag;\n monat = fill(2 - monat.length) + monat;\n stunde = fill(2 - stunde.length) + stunde;\n minute = fill(2 - minute.length) + minute;\n sekunde = fill(2 - sekunde.length) + sekunde;\n\n \n var datumFritz = tag + \".\" + monat + \".\" + jahr + \" \" + stunde + \":\" + minute +\":\" + sekunde;\n return datumFritz;\n }\n\n\nvar eigeneNummer = rand(0,2);\n\nmsg.intNumber = rand(11,13);\nmsg.date = datum();\nmsg.eigeneNummer = eigeneRufnummern[eigeneNummer];\nmsg.line = eigeneLines[eigeneNummer];\n\nif (rand(1,10) < 7) {\n msg.connect = true; \n } else {\n msg.connect = false;\n}\n\nif (rand(1,10) < 6) {\n msg.direction = \"kommend\"; \n } else {\n msg.direction = \"gehend\";\n}\n\n\n// externe Rufnummer zufällig\n var rufnummer = rufnummer(); // zufällige Rufnummer ohne Vorwahl\n var dieseVorwahl = rand(0,vorwahlen.length-1); // \n msg.externeNummer = vorwahlen[dieseVorwahl] + rufnummer;\n\n\n// 20% der kommenden Rufnummern mit Unbekannt überschreiben\nif (msg.direction == \"kommend\") {\n if (rand(1,10) < 3) {\n var rufnummer = \"\";\n msg.externeNummer = \"\";\n }\n}\n\n// 20% der Rufnummern in bekannte Rufnummern ändern\n if (rand(1,10) < 3) {\n var bekannt = rand(0,extRufnummernBekannt.length - 1);\n msg.externeNummer = extRufnummernBekannt[bekannt];\n }\n\n\n\n\n var callid = 99;\n\n\tfor(var i = 10; i < context.global.fbVars.callgenerator.callidfrei.length; ++i) {\n\tif (context.global.fbVars.callgenerator.callidfrei[i] === true) {\n\t context.global.fbVars.callgenerator.callidfrei[i] = false;\n\t callid = i;\n\t break;\n\t }\n }\n\nmsg.callid = callid;\n\nif (callid == 99) {\n msg.direction = \"error\";\n}\nmsg.connectedNumber = msg.externeNummer;\n\n\n--context.global.fbVars.callgenerator.testcount;\n\nif (context.global.fbVars.callgenerator.testcount < 0) {\n return null;\n }\n\ncontext.global.fbVars.callgenerator.testcalls++; // aktuell laufende Calls\n\n\nreturn msg;\n","outputs":1,"valid":true,"x":376.2857208251953,"y":3160.4766035079956,"z":"64b98f40.9b467","wires":[["191bf518.e6e40b","97f482fa.680b8","43f3c36f.bc0c3c"]]},{"id":"191bf518.e6e40b","type":"switch","name":"(1) gehend (2) kommend (3) error","property":"direction","rules":[{"t":"eq","v":"gehend"},{"t":"eq","v":"kommend"},{"t":"else"}],"checkall":"true","outputs":3,"x":640.0000152587891,"y":3161.3335371017456,"z":"64b98f40.9b467","wires":[["4aaa1bf8.b555e4"],["d4fb50eb.2b04b"],["f7d84312.0827c"]]},{"id":"4aaa1bf8.b555e4","type":"function","name":"CALL","func":"// msg.externeNummer\n// msg.connectedNumber\n// msg.intNumber\n// msg.date\n// msg.eigeneNummer\n// msg.line\n// msg.connect\n// msg.direction\n// msg.callid\n\n\n\nmsg.payload = msg.date + \";CALL;\" + msg.callid + \";\" + msg.intNumber + \";\"\n + msg.eigeneNummer + \";\" + msg.externeNummer + \";\" + msg.line + \";\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":890.0000152587891,"y":3137.3335371017456,"z":"64b98f40.9b467","wires":[["ff5bfb11.00a408","de93d6be.216c28","4498c695.bb6738"]]},{"id":"97f482fa.680b8","type":"debug","name":"","active":false,"console":"false","complete":"true","x":404.00001525878906,"y":3121.3335371017456,"z":"64b98f40.9b467","wires":[]},{"id":"17626851.e89d98","type":"debug","name":"","active":true,"console":"false","complete":"payload","x":908.9999847412109,"y":3256.666814804077,"z":"64b98f40.9b467","wires":[]},{"id":"1eaa31b.fe155ce","type":"debug","name":"","active":false,"console":"false","complete":"payload","x":1227.0000076293945,"y":2957.333532691002,"z":"64b98f40.9b467","wires":[]},{"id":"d4fb50eb.2b04b","type":"function","name":"RING","func":"// msg.externeNummer\n// msg.connectedNumber\n// msg.intNumber\n// msg.date\n// msg.eigeneNummer\n// msg.line\n// msg.connect\n// msg.direction\n// msg.callid\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\n\nmsg.payload = msg.date + \";RING;\" + msg.callid + \";\" + msg.externeNummer + \";\"\n + msg.eigeneNummer + \";\" + msg.line + \";\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":889.4286041259766,"y":3175.6191816329956,"z":"64b98f40.9b467","wires":[["ff5bfb11.00a408","de93d6be.216c28","4498c695.bb6738"]]},{"id":"2660bc65.d99f44","type":"switch","name":"(1) Connect (2) kein Connect (3) error","property":"connect","rules":[{"t":"true"},{"t":"false"},{"t":"else"}],"checkall":"true","outputs":3,"x":1284.000015258789,"y":3155.3335371017456,"z":"64b98f40.9b467","wires":[["995e0ca8.66a1f"],["d855031b.27ab"],["f7d84312.0827c"]]},{"id":"f7d84312.0827c","type":"function","name":"error","func":"node.error(\"Fehler im Call Generator\");\nmsg.payload = \"fritzbox: Fehler im Call Generator\"\n\nreturn msg;","outputs":1,"valid":true,"x":771.0000114440918,"y":3258.6668668985367,"z":"64b98f40.9b467","wires":[["17626851.e89d98"]]},{"id":"995e0ca8.66a1f","type":"function","name":"CONNECT","func":"// msg.externeNummer\n// msg.connectedNumber\n// msg.intNumber\n// msg.date\n// msg.eigeneNummer\n// msg.line\n// msg.connect\n// msg.direction\n// msg.callid\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\nfunction datum() {\n var now = new Date((new Date().getTime()) + (context.global.fbVars.callgenerator.zeitfehler * 1000) );\n\n var tag = now.getDate();\n var monat = now.getMonth()+1;\n var jahr = now.getFullYear();\n var stunde = now.getHours(); \n var minute = now.getMinutes(); \n var sekunde = now.getSeconds(); \n\n stunde = stunde.toString(); \n tag = tag.toString();\n monat = monat.toString();\n jahr = jahr.toString();\n minute = minute.toString();\n sekunde = sekunde.toString();\n jahr = jahr.substr(2,3);\n tag = fill(2 - tag.length) + tag;\n monat = fill(2 - monat.length) + monat;\n stunde = fill(2 - stunde.length) + stunde;\n minute = fill(2 - minute.length) + minute;\n sekunde = fill(2 - sekunde.length) + sekunde;\n\n \n var datumFritz = tag + \".\" + monat + \".\" + jahr + \" \" + stunde + \":\" + minute +\":\" + sekunde;\n return datumFritz;\n }\n\n\nmsg.date = datum();\n\n\nmsg.payload = msg.date + \";CONNECT;\" + msg.callid + \";\" + msg.intNumber + \";\" + msg.externeNummer + \";\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":1514.000015258789,"y":3133.3335371017456,"z":"64b98f40.9b467","wires":[["ff5bfb11.00a408","78c603b4.8739fc","2a8a4533.d575ba"]]},{"id":"de93d6be.216c28","type":"delay","name":"","pauseType":"random","timeout":"6","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"4","randomLast":"16","randomUnits":"seconds","drop":false,"x":1052.000015258789,"y":3153.3335371017456,"z":"64b98f40.9b467","wires":[["2660bc65.d99f44"]]},{"id":"ff5bfb11.00a408","type":"function","name":"emulierte Fritzbox Message","func":"var payload = msg.payload;\nmsg = {};\n\nmsg.payload = payload;\n\nreturn msg;","outputs":1,"valid":true,"x":1267.500015258789,"y":2998.3335341215134,"z":"64b98f40.9b467","wires":[["1eaa31b.fe155ce","85d12d26.7a2ed"]]},{"id":"d855031b.27ab","type":"function","name":"DISCONNECT","func":"// msg.externeNummer\n// msg.connectedNumber\n// msg.intNumber\n// msg.date\n// msg.eigeneNummer\n// msg.line\n// msg.connect\n// msg.direction\n// msg.callid\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\nfunction datum() {\n var now = new Date((new Date().getTime()) + (context.global.fbVars.callgenerator.zeitfehler * 1000) );\n\n var tag = now.getDate();\n var monat = now.getMonth()+1;\n var jahr = now.getFullYear();\n var stunde = now.getHours(); \n var minute = now.getMinutes(); \n var sekunde = now.getSeconds(); \n\n stunde = stunde.toString(); \n tag = tag.toString();\n monat = monat.toString();\n jahr = jahr.toString();\n minute = minute.toString();\n sekunde = sekunde.toString();\n jahr = jahr.substr(2,3);\n tag = fill(2 - tag.length) + tag;\n monat = fill(2 - monat.length) + monat;\n stunde = fill(2 - stunde.length) + stunde;\n minute = fill(2 - minute.length) + minute;\n sekunde = fill(2 - sekunde.length) + sekunde;\n\n \n var datumFritz = tag + \".\" + monat + \".\" + jahr + \" \" + stunde + \":\" + minute +\":\" + sekunde;\n return datumFritz;\n } \n \nmsg.date = datum();\n\n\n\n//Zufahllszahlen zwischen min und max\nfunction rand(min, max) {\n\treturn Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\nvar callid = msg.callid;\ncontext.global.fbVars.callgenerator.callidfrei[callid] = true;\n\n\nif (msg.connect === true) {\n//msg.duration = rand(10,40); // Dauer des Gespräches nicht ausgerechnet (faul). Zufall\nmsg.duration = context.global.fbVars.callid[callid].duration2;\n } else {\n msg.duration = \"0\";\n}\n\nmsg.payload = msg.date + \";DISCONNECT;\" + msg.callid + \";\" + msg.duration + \";\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":1852.000015258789,"y":3153.3335371017456,"z":"64b98f40.9b467","wires":[["ff5bfb11.00a408","162b81f0.e9d47e","c830b9f0.37cf48"]]},{"id":"78c603b4.8739fc","type":"delay","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"8","randomLast":"30","randomUnits":"seconds","drop":false,"x":1678.000015258789,"y":3133.3335371017456,"z":"64b98f40.9b467","wires":[["d855031b.27ab"]]},{"id":"4498c695.bb6738","type":"debug","name":"","active":false,"console":"false","complete":"true","x":887.0000076293945,"y":3091.833536028862,"z":"64b98f40.9b467","wires":[]},{"id":"2a8a4533.d575ba","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1517.0000190734863,"y":3093.333535552025,"z":"64b98f40.9b467","wires":[]},{"id":"162b81f0.e9d47e","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1860.6666679382324,"y":3082.666939020157,"z":"64b98f40.9b467","wires":[]},{"id":"542e7279.abd18c","type":"function","name":"init","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.callgenerator = context.global.fbVars.callgenerator || {};\n\n//context.global.fbVars.callgenerator.callidfrei = [true,true,true,true,true,true,true,true,true,true,true,true,true,true,true];\n//context.global.fbVars.callgenerator.callidfrei = [];\ncontext.global.fbVars.callgenerator.callidfrei = [,,,,,,,,,,true,true,true,true,true,true,true,true,true,true,true,true];\ncontext.global.fbVars.callgenerator.testcount = 100; // Schleifendurchgänge (Anzahl Test Calls)\ncontext.global.fbVars.callgenerator.testcalls = 0; // aktuell laufende Calls\n\n\n//Zufahllszahlen zwischen min und max\nfunction rand(min, max) {\n\treturn Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n\nif (rand(0,1) == 1) {\n context.global.fbVars.callgenerator.zeitfehler = rand(-100,-10);\n} else {\n context.global.fbVars.callgenerator.zeitfehler = rand(10,100);\n}\n\nif (context.global.fbVars.config.cgZeitfehler == false) {\n context.global.fbVars.callgenerator.zeitfehler = 0;\n}\n\nreturn msg;\n","outputs":1,"valid":true,"x":185.99999618530273,"y":3157.8335374593735,"z":"64b98f40.9b467","wires":[["70e82574.8f17dc"]]},{"id":"c5dd4ced.3a22b","type":"comment","name":"###### Call Generator - simuliert zufällige Telefongespräche ######","info":"","x":251.00003051757812,"y":2977.8335350751877,"z":"64b98f40.9b467","wires":[]},{"id":"8a1e1dc8.75e1e","type":"delay","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"2","randomLast":"15","randomUnits":"seconds","drop":false,"x":1408.5001220703125,"y":3248.333251953125,"z":"64b98f40.9b467","wires":[["70e82574.8f17dc"]]},{"id":"c353e26d.3cac2","type":"catch","name":"Catch Fehler","x":158.66683959960938,"y":1406.333251953125,"z":"64b98f40.9b467","wires":[["c5a93f81.3a56c"]]},{"id":"c5a93f81.3a56c","type":"debug","name":"","active":true,"console":"false","complete":"true","x":326.66686630249023,"y":1408.3332271575928,"z":"64b98f40.9b467","wires":[]},{"id":"5a5a1ba3.a5a5e4","type":"comment","name":"Aktuelle Werte über http als JSON ausgeben","info":"","x":3073.500078837076,"y":72.50000762939453,"z":"64b98f40.9b467","wires":[]},{"id":"a50d29ae.5af2d8","type":"comment","name":"Für DEBUG: löscht die angelegten Variablen: context.global. !!! NICHT WÄHREND DER LAUFZEIT VERWENDEN !!!","info":"","x":1513.5000610351562,"y":48.5,"z":"64b98f40.9b467","wires":[]},{"id":"927107f5.6d8ef8","type":"pushover","title":"Home verpasster Anruf","name":"### konfigurieren ### Pushover","priority":0,"x":660.5,"y":253.5,"z":"64b98f40.9b467","wires":[]},{"id":"fff62b00.0009d8","type":"e-mail","server":"smtp.gmail.com","port":"465","name":"ruhr70@gmail.com","dname":"### konfigurieren ### Email","x":656.5,"y":297.5,"z":"64b98f40.9b467","wires":[]},{"id":"67fda77d.980258","type":"template","name":"Pushover Nachricht","field":"payload","format":"handlebars","template":"{{callingNumber}} -> {{calledNumber}}\n{{date}}","x":1310.1666946411133,"y":255.16666555404663,"z":"64b98f40.9b467","wires":[["927107f5.6d8ef8","92230e92.6ddcf"]]},{"id":"23211a86.dcdee6","type":"template","name":"Email Nachricht","field":"payload","format":"handlebars","template":"ioBroker (Fritzbox), verpasster Anruf, {{date}}:\n\nAnruf von {{externeNummerE164}} -->X {{calledNumber}}\n\n---------------------------------------------------------------------\nVerpasste Anrufer: {{anzahlVerpasst}} seit dem {{verpasstSeit}}\n\n\n\n","x":1301.4999313354492,"y":293.5000367164612,"z":"64b98f40.9b467","wires":[["fff62b00.0009d8","978f5663.6870a8"]]},{"id":"3aca9f71.c5356","type":"function","name":"Verpasste Anrufe - Meldung terminieren - Ausgabe j/n & Email Betreff","func":"msg.infoPushover = false;\nmsg.infoEmail = false;\n\nif (context.global.fbVars.config.infoPushover == true || context.global.fbVars.config.infoPushover == \"true\" ) {\n msg.infoPushover = true;\n}\n\nif (context.global.fbVars.config.infoEmail == true || context.global.fbVars.config.infoEmail == \"true\") {\n msg.infoEmail = true;\n}\n\nif (msg.callid >9) { // handelt es sich um einen Demoanruf aus dem Call Generator?\n if (context.global.fbVars.config.infoDemo == false || context.global.fbVars.config.infoDemo == \"false\") {return null;} // und Demo Anrufe sollen nicht signalisiert werden (false) -> keine Info\n}\n\n// msg.topic wird in der Betreffzeile der Email angezeigt:\nmsg.topic = \"verpasster Anruf: \" + msg.externeNummerE164 + \" -> \" + msg.calledNumber + \" (\" + msg.date + \")\";\n\nreturn msg;\n","outputs":1,"valid":true,"x":1216.5000610351562,"y":347.833309173584,"z":"64b98f40.9b467","wires":[["79cae486.86351c","d4b76b41.2b4898","76724988.898db8","968ea821.697158"]]},{"id":"8876044f.7789f8","type":"delay","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"8","randomUnits":"seconds","drop":false,"x":186.00000381469727,"y":3198.6667870283127,"z":"64b98f40.9b467","wires":[["70e82574.8f17dc"]]},{"id":"f6e08e58.091f7","type":"delay","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"8","randomUnits":"seconds","drop":false,"x":182.66669464111328,"y":3238.6667870283127,"z":"64b98f40.9b467","wires":[["70e82574.8f17dc"]]},{"id":"79cae486.86351c","type":"switch","name":"Pushover = true","property":"infoPushover","rules":[{"t":"true"}],"checkall":"true","outputs":1,"x":1102.166648864746,"y":253.50001573562622,"z":"64b98f40.9b467","wires":[["67fda77d.980258"]]},{"id":"d4b76b41.2b4898","type":"switch","name":"Email = true","property":"infoEmail","rules":[{"t":"true"}],"checkall":"true","outputs":1,"x":1108.166603088379,"y":294.1666579246521,"z":"64b98f40.9b467","wires":[["23211a86.dcdee6"]]},{"id":"92230e92.6ddcf","type":"debug","name":"","active":false,"console":"false","complete":"false","x":1491.1666641235352,"y":253.16667222976685,"z":"64b98f40.9b467","wires":[]},{"id":"978f5663.6870a8","type":"debug","name":"","active":false,"console":"false","complete":"false","x":1479.1665802001953,"y":296.8334069252014,"z":"64b98f40.9b467","wires":[]},{"id":"61a626d3.9e59d8","type":"function","name":"fritzbox - Config überprüfen: ","func":"\n\n\n// Fritzbox Pfad überprüfen\n// ------------------------\n// \"node-red.0.fritzbox.\"\n\npfad = context.global.fbVars.config.topic_prefix;\n \nif (pfad.substring(0,9) != \"node-red.\") {\n node.error(\"fritzbox config: ungültiger Variablenpfad\" + (pfad.substring(0,9)) );\n return null;\n}\n\n\n// config.eigenerCC prüfen\n// _______________________\n// Contry Code in String umwandeln, falls als Zahl eingegeben -> .toString()\n// dann alle Zeichen bis auf die Ziffern rauslöschen -> .replace(/\\D+/g,\"\")\nvar cc = context.global.fbVars.config.eigenerCC.toString().replace(/\\D+/g,\"\");\ncc = cc.replace(/^0+/,\"\"); // führende Nullen kürzen\n\nif (cc.length < 1) {node.error(\"fritzbox config: Country Code (Landesvorwahl) fehlt oder ist ungültig\")}\n\n// prüft, ob in der Landesvorwahl noch andere Zeichen als \"0\" vorhanden sind\n// (darf nicht vorkommen, da alles außer 0-9 oben schon rausgenommen wurde, nur zum lernen)\nif (cc.search(/^[0-9]+$/) == -1){node.error(\"fritzbox config: Ungültiger Country Code (Landesvorwahl)\");}\n\nif (cc != context.global.fbVars.config.eigenerCC) {node.warn(\"fritzbox config: cc von \" + context.global.fbVars.config.eigenerCC + \" - in \" + cc + \" geändert\");}\n\ncontext.global.fbVars.config.eigenerCC = cc;\n\n// ## Ende - config.eigenerCC prüfen ##\n\n\n\n// config.eigenerAC prüfen\n// _______________________\nvar ac = context.global.fbVars.config.eigenerAC.toString().replace(/\\D+/g,\"\"); // alles außer Ziffern entfernen\nac = ac.replace(/^0+/,\"\"); // führende Nullen kürzen\n\nif (ac.length < 2) {node.error(\"fritzbox config: Area Code (Ortsvorwahl) fehlt oder ist ungültig\")}\n\nif (ac != context.global.fbVars.config.eigenerAC) {node.warn(\"fritzbox config: ac von \" + context.global.fbVars.config.eigenerLC + \" - in \" + ac + \" geändert\");}\n\ncontext.global.fbVars.config.eigenerAC = ac;\n\n// ## Ende - config.eigenerAC prüfen ##\n\n\n\n\nmsg.topic = context.global.fbVars.config.topic_prefix;\n\nreturn msg;\n","outputs":1,"valid":true,"x":545.0001220703125,"y":1077.1668090820312,"z":"64b98f40.9b467","wires":[["212cef42.ded31","7604e0e5.89fb2"]]},{"id":"8306cd46.7cf93","type":"ioBroker in","name":"node-red.0.fritzbox.anzahlVerpasst","topic":"node-red.0.fritzbox.anzahlVerpasst","payloadType":"value","x":1973.8806991577148,"y":331.9285821914673,"z":"64b98f40.9b467","wires":[["b71a79c.f48e588","83fef4b9.7c0108"]]},{"id":"b71a79c.f48e588","type":"function","name":"verpassteAnrufeZahl aus ioBroker übernehmen","func":"// wenn in ioBroker die verpassten Anrufe zurückgesetzt werden, wird der Wert in Node-red übernommen\ncontext.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.zustand = context.global.fbVars.zustand || {};\n\ncontext.global.fbVars.zustand.verpassteAnrufeZahl = msg.payload;\n\nreturn msg;","outputs":1,"valid":true,"x":2323.7379760742188,"y":332.78570556640625,"z":"64b98f40.9b467","wires":[["f49af2c7.0b651"]]},{"id":"f49af2c7.0b651","type":"debug","name":"","active":false,"console":"false","complete":"false","x":2591.8331604003906,"y":332.16666412353516,"z":"64b98f40.9b467","wires":[]},{"id":"3951e22b.c6ae1e","type":"function","name":"Start & Variablenpfad","func":"if (context.global.fbVars.config.topic_prefix == null) {return null}\n\nmsg.topic = context.global.fbVars.config.topic_prefix;\n\nreturn msg;","outputs":1,"valid":true,"x":1649.3334426879883,"y":1247.3335795402527,"z":"64b98f40.9b467","wires":[["a809fd84.57f6"]]},{"id":"a197c96.f5e6838","type":"inject","name":"init bei Deploy","topic":"","payload":"Fritzbox - Init","payloadType":"string","repeat":"","crontab":"","once":true,"x":124.33332824707031,"y":682.1666870117188,"z":"64b98f40.9b467","wires":[["a43d3a96.5bc2c8"]]},{"id":"3c83f91b.c37c06","type":"ioBroker out","name":"[Pfad aus der Konfig].*","topic":"","ack":"true","autoCreate":"true","x":2137.5000610351562,"y":1301.8334403038025,"z":"64b98f40.9b467","wires":[]},{"id":"d511a25a.2aee6","type":"comment","name":"Konfigurationsdaten, die auch in ioBroker als Obkjekt zur Verfügung stehen. Z.B. über VIS veränderbar.","info":"","x":696.5,"y":1041.8333740234375,"z":"64b98f40.9b467","wires":[]},{"id":"43f3c36f.bc0c3c","type":"function","name":".callgenerator.testcount","func":"msg.topic = context.global.fbVars.config.topic_prefix + \"callgenerator.testcount\";\nmsg.payload = context.global.fbVars.callgenerator.testcount;\n\nreturn msg;","outputs":1,"valid":true,"x":726.0000152587891,"y":3359.3335371017456,"z":"64b98f40.9b467","wires":[["df08f41c.20f708"]]},{"id":"df08f41c.20f708","type":"ioBroker out","name":"[Pfad aus der Konfig].*","topic":"","ack":"true","autoCreate":"true","x":1029,"y":3365.33349609375,"z":"64b98f40.9b467","wires":[]},{"id":"18214dba.e7deb2","type":"function","name":"Start Call Generator","func":"\nreturn msg;","outputs":1,"valid":true,"x":484.9999885559082,"y":3014.333485007286,"z":"64b98f40.9b467","wires":[["542e7279.abd18c","8876044f.7789f8","f6e08e58.091f7","9874bd40.678b4","fd1a661.f02e598"]]},{"id":"a18a0afe.5e75f8","type":"ioBroker in","name":"node-red.0.fritzbox.callgenerator.startDemo","topic":"node-red.0.fritzbox.callgenerator.startDemo","payloadType":"value","x":190.33330154418945,"y":3426.000184416771,"z":"64b98f40.9b467","wires":[["2bef8e07.d41072"]]},{"id":"2bef8e07.d41072","type":"function","name":"Trigger zurücksetzen","func":"if (msg.payload == \"true\" || msg.payload === true || msg.payload == 1 || msg.payload == \"1\") {\n msg.payload = false;\n msg.topic = context.global.fbVars.config.topic_prefix + \"callgenerator.startDemo\"; \n \n return msg;\n}\nreturn null;","outputs":1,"valid":true,"x":253.33330154418945,"y":3458.000184416771,"z":"64b98f40.9b467","wires":[["df08f41c.20f708","3cdb3f4e.c324c"]]},{"id":"67233712.98dcc8","type":"ioBroker in","name":"node-red.0.fritzbox.callgenerator.stopDemo","topic":"node-red.0.fritzbox.callgenerator.stopDemo","payloadType":"value","x":175.99997329711914,"y":3498.666736960411,"z":"64b98f40.9b467","wires":[["ef200680.10dff8"]]},{"id":"ef200680.10dff8","type":"function","name":"Stop Testcalls","func":"if (msg.payload == \"true\" || msg.payload === true|| msg.payload == 1 || msg.payload == \"1\") {\n msg.payload = false;\n msg.topic = context.global.fbVars.config.topic_prefix + \"callgenerator.stopDemo\"; \n context.global.fbVars.callgenerator.testcount = 0;\n return msg;\n}\nreturn null;\n","outputs":1,"valid":true,"x":242.3332977294922,"y":3532.3334563970566,"z":"64b98f40.9b467","wires":[["df08f41c.20f708","43f3c36f.bc0c3c","d0cd2e4.f2f32d"]]},{"id":"9c1fc991.63e038","type":"function","name":"aktueller Stand: Listen, Zähler","func":"\n\n\nfunction dynamicSort(property) {\n var sortOrder = 1;\n if(property[0] === \"-\") {\n sortOrder = -1;\n property = property.substr(1);\n }\n return function (a,b) {\n var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;\n return result * sortOrder;\n }\n}\n\n\nvar anzahlRing = 0;\nvar anzahlCall = 0;\nvar anzahlConnect = 0;\nvar anzahlAlle = 0;\n\n\n// Liste der aktiven RING, CALL löschen\ncontext.global.fbVars.listeRing = [];\ncontext.global.fbVars.listeCall = [];\ncontext.global.fbVars.listeConnect = [];\ncontext.global.fbVars.listeAlle = [];\n\n\n// Verwendete Variablen initialisieren\n// context.global.fbVars.zustand = context.global.fbVars.zustand || {};\n\n// context.global.fbVars.ringLetzter = context.global.fbVars.ringLetzter || \"\"; \n// context.global.fbVars.ringAktuell = context.global.fbVars.ringAktuell || \"\"; \n// context.global.fbVars.ring = context.global.fbVars.ring || false;\n\ncontext.global.fbVars.zustand.ringLetzter = context.global.fbVars.zustand.ringLetzter || \"\";\ncontext.global.fbVars.zustand.ringLetzterVerpasst = context.global.fbVars.zustand.ringLetzterVerpasst || \"\";\ncontext.global.fbVars.zustand.ringAktuell = context.global.fbVars.zustand.ringAktuell || \"\"; \ncontext.global.fbVars.zustand.ring = context.global.fbVars.zustand.ring || false;\n\n\n// Schleife, Anzahl der Call IDs im Array: Zählt die jeweiligen Zustände, ein Array je Zustand\nfor (var i = 0; i < context.global.fbVars.callid.length; i++){ \n\tif (context.global.fbVars.callid[i] != null) {\n // Call Status = RING\n \tif (context.global.fbVars.callid[i].calltype === \"RING\"){ \n context.global.fbVars.listeRing[anzahlRing] = context.global.fbVars.listeRing[anzahlRing] || {};\n context.global.fbVars.listeRing[anzahlRing] = context.global.fbVars.callid[i];\n\t anzahlRing++; \n\t }\n\n\t // Call Status = CALL\n \tif (context.global.fbVars.callid[i].calltype === \"CALL\"){ \n context.global.fbVars.listeCall[anzahlCall] = context.global.fbVars.listeCall[anzahlCall] || {};\n context.global.fbVars.listeCall[anzahlCall] = context.global.fbVars.callid[i];\n anzahlCall++;\n\t }\n\n\t // Call Status = CONNECT\n \tif (context.global.fbVars.callid[i].calltype === \"CONNECT\"){ \n context.global.fbVars.listeConnect[anzahlConnect] = context.global.fbVars.listeConnect[anzahlConnect] || {};\n context.global.fbVars.listeConnect[anzahlConnect] = context.global.fbVars.callid[i];\n anzahlConnect++;\n\t }\n\n // Alle Status (RING, CALL, CONNECT)\n \tif (context.global.fbVars.callid[i].calltype !== \"DISCONNECT\"){ \n context.global.fbVars.listeAlle[anzahlAlle] = context.global.fbVars.listeAlle[anzahlAlle] || {};\n context.global.fbVars.listeAlle[anzahlAlle].callid = context.global.fbVars.callid[i].callid;\n context.global.fbVars.listeAlle[anzahlAlle].epocheStart = context.global.fbVars.callid[i].epocheStart;\n anzahlAlle++;\n \t}\n\n\t}\n}\n\n\n// sortiert die ermittelten Listen nach der tatsächlichen Meldungszeit (Systemzeit)\ncontext.global.fbVars.listeRing.sort(dynamicSort(\"-epocheNow\")); // Liste sortieren: jüngster Eintrag oben\ncontext.global.fbVars.listeCall.sort(dynamicSort(\"-epocheNow\")); // Liste sortieren: jüngster Eintrag oben\ncontext.global.fbVars.listeConnect.sort(dynamicSort(\"-epocheNow\")); // Liste sortieren: jüngster Eintrag oben\ncontext.global.fbVars.listeAlle.sort(dynamicSort(\"-epocheStart\")); // Liste sortieren: jüngster Eintrag oben\n\n\n// aktuellste Anrufernummer wird als Letzter Anrufer (Ring) gespeichert\nif (context.global.fbVars.listeRing[0] != null) {\n \n context.global.fbVars.zustand.ringAktuell = context.global.fbVars.listeRing[0].callingNumber; \n context.global.fbVars.zustand.ring = true;\n}\n\n// kein aktiver Ring, ringAktuell löschen && ring = false (kein Ring aktiv)\nif (anzahlRing < 1) {\n context.global.fbVars.zustand.ringAktuell = \"\";\n// context.global.fbVars.ring = false;\n context.global.fbVars.zustand.ring = false;\n}\n\n\n// Summen Anrufarten\ncontext.global.fbVars.zustand.anzahlRing = anzahlRing;\ncontext.global.fbVars.zustand.anzahlCall = anzahlCall;\ncontext.global.fbVars.zustand.anzahlConnect = anzahlConnect;\ncontext.global.fbVars.zustand.anzahlAlle = anzahlAlle;\n\n\n// letzter verpasste Anruf\nif (msg.calltype == \"DISCONNECT\") {\n if (msg.direction == \"kommend\") {\n\n context.global.fbVars.zustand.ringLetzter = msg.externeNummer; \n if (context.global.fbVars.config.wählbar == true) {\n if (msg.externeNummer.toString().replace(/\\D+/g,\"\").length > 0) {\n context.global.fbVars.zustand.ringLetzter = '' + msg.externeNummer + '';\n }\n }\n\n if (msg.connect == false) {\n context.global.fbVars.zustand.ringLetzterVerpasst = msg.externeNummer;\n if (context.global.fbVars.config.wählbar == true) {\n if (msg.callingNumber.toString().replace(/\\D+/g,\"\").length > 0) {\n context.global.fbVars.zustand.ringLetzterVerpasst = '' + msg.externeNummer + '';\n }\n } \n }\n } \n}\n\n\n// letzte gewählte Rufnummer\nif (msg.calltype == \"DISCONNECT\") {\n if (msg.direction == \"gehend\") {\n\n context.global.fbVars.zustand.callLetzter = msg.externeNummer; \n if (context.global.fbVars.config.wählbar == true) {\n if (msg.externeNummer.toString().replace(/\\D+/g,\"\").length > 0) {\n context.global.fbVars.zustand.callLetzter = '' + msg.externeNummer + '';\n }\n }\n }\n} \n\n\n\n\nreturn msg;\n","outputs":1,"valid":true,"x":2198.833152770996,"y":1961.1665658950806,"z":"64b98f40.9b467","wires":[["5a093045.a5f6d","d81d8a55.27e278","7b5af123.84a51","e6accc13.19533","55630e5e.aa9cf","e9def90.f162108","6b5d51a5.94a2b","93fbd3d0.6c043","c36e8f9b.3c917","4b1d0296.b4e2fc","5fc5b72e.a03a48","a9dc66c1.562398","bda72cb2.4258d"]]},{"id":"d11b4023.2ee4c","type":"ioBroker out","name":"[Pfad aud der Konfig] + Variablenname","topic":"","ack":"true","autoCreate":"true","x":3901.83309173584,"y":1839.1667232513428,"z":"64b98f40.9b467","wires":[]},{"id":"668d700f.99729","type":"comment","name":"Bei jeder Meldung werden die aktuellen Zustände aktualisiert","info":"","x":2288.166404724121,"y":1917.8333139419556,"z":"64b98f40.9b467","wires":[]},{"id":"d81d8a55.27e278","type":"function","name":"ringLetzter (Letzte Runfnummer die anruft/angerufen hat)","func":"if (context.global.fbVars.zustand.ringLetzter === null) context.global.fbVars.zustand.ringLetzter = \"\";\n\nmsg.payload = context.global.fbVars.zustand.ringLetzter;\nmsg.topic = msg.topic + \"ringLetzter\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3311.16658782959,"y":1962.8334712982178,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"e6accc13.19533","type":"function","name":"ringAktuell (letzte Rufnummer, die gerade aktuell anruft)","func":"if (context.global.fbVars.zustand.ringAktuell === null) context.global.fbVars.zustand.ringAktuell = \"\";\n\nmsg.payload = context.global.fbVars.zustand.ringAktuell;\nmsg.topic = msg.topic + \"ringAktuell\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3304.8330612182617,"y":2032.1667928695679,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"615cb1d3.9ea35","type":"comment","name":"schreibe ioBroker Variablen für Vis","info":"","x":3231.16658782959,"y":1918.8334712982178,"z":"64b98f40.9b467","wires":[]},{"id":"3cfe12a9.c301ee","type":"comment","name":"schreibe ioBroker Listen für Vis","info":"","x":3225.8330078125,"y":2294.166823387146,"z":"64b98f40.9b467","wires":[]},{"id":"c3ed1ba1.3c12e8","type":"function","name":"listeConnect, alle aktuellen Gespräche","func":"\nvar listeConnect = context.global.fbVars.listeConnect;\n\nif (listeConnect == null) return null;\n\n\nfunction datum(zeitstempel) {\n var jahr = zeitstempel.substring(6,8);\n var monat = zeitstempel.substring(3,5);\n var tag = zeitstempel.substring(0,2);\n var stunde = zeitstempel.substring(9,11);\n var minute = zeitstempel.substring(12,14);\n var sekunde = zeitstempel.substring(15,17);\n\n //var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n var uhrzeit = stunde + \":\" + minute;\n\n //var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n //var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n var datum = tag + \".\" + monat + \". \";\n \n var zeit = datum + uhrzeit;\n \n return zeit;\n}\n\n\n\n\n\n\nvar text = '';\nfor (var i = 0; i < listeConnect.length; i++) {\n //var gesprächsdauer = context.global.fbVars.callid[listeConnect[i].callid].duration2;\n var gesprächsdauerF = context.global.fbVars.callid[listeConnect[i].callid].duration2F;\n text += datum(listeConnect[i].dateStart) + \" \" + listeConnect[i].externeNummerF + gesprächsdauerF;\n if (i < (listeConnect.length - 1)) {\n text += (text ? '
\\n' : '');\n }\n}\n\n\nmsg.payload = text;\n\nmsg.topic = msg.topic + \"listeConnect\"; // Liste der aktiven Gespräche (Zustand: CONNECT)\n\nreturn msg;\n","outputs":"1","valid":true,"x":3251.166176845016,"y":2403.8336879726294,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c","577c4330.a883bc"]]},{"id":"e9def90.f162108","type":"function","name":"anzahlRing (Summe der aktuellen Anrufer)","func":"msg.payload = context.global.fbVars.zustand.anzahlRing;\nmsg.topic = msg.topic + \"anzahlRing\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3263.8330078125,"y":2140.166816711426,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"6b5d51a5.94a2b","type":"function","name":"anzahlCall (Summe der gehenden Rufe)","func":"msg.payload = context.global.fbVars.zustand.anzahlCall;\nmsg.topic = msg.topic + \"anzahlCall\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3257.8330993652344,"y":2175.5002422332764,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"93fbd3d0.6c043","type":"function","name":"anzahlConnect (Summe der aktuellen Gespräche)","func":"msg.payload = context.global.fbVars.zustand.anzahlConnect;\nmsg.topic = msg.topic + \"anzahlConnect\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3284.8330993652344,"y":2209.5002422332764,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"55630e5e.aa9cf","type":"function","name":"ring (true ein oder mehrer RING aktiv)","func":"msg.payload = context.global.fbVars.zustand.ring;\nmsg.topic = msg.topic + \"ring\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3247.8330001831055,"y":2063.166904449463,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"eb403c0a.14bfc","type":"comment","name":"Testanrufe, Einzelschritte vs. Call Generator unten","info":"","x":456.5,"y":2125.83349609375,"z":"64b98f40.9b467","wires":[]},{"id":"acfd4835.5302b8","type":"function","name":"listAlle, alle aktuellen Rufe (Anrufmonitor)","func":"\nvar listeAlle = context.global.fbVars.listeAlle;\n\n\n\nfunction datum(zeitstempel) {\n var jahr = zeitstempel.substring(6,8);\n var monat = zeitstempel.substring(3,5);\n var tag = zeitstempel.substring(0,2);\n var stunde = zeitstempel.substring(9,11);\n var minute = zeitstempel.substring(12,14);\n var sekunde = zeitstempel.substring(15,17);\n\n //var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n var uhrzeit = stunde + \":\" + minute+ \":\" + sekunde + \" \";\n\n //var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n //var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n var datum = tag + \".\" + monat + \". \";\n \n var zeit = uhrzeit;\n return zeit;\n}\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn(empty_chars);\n\t}\n\n\nvar cssga = \"\";\nvar cssge = \"\"; \n\nvar\tcssra = '';\nvar cssre = '';\n\n\n\n\nvar text = '';\nfor (var i = 0; i < listeAlle.length; i++) {\n var cssga = \"\";\n var cssge = \"\"; \n var callid = listeAlle[i].callid;\n var intNr = fill(4 - context.global.fbVars.callid[callid].intNumber.length) + context.global.fbVars.callid[callid].intNumber;\n\tif (context.global.fbVars.callid[callid].connect == true ) {\n\t cssga = '';\n cssge = '';\n\t}\n\tif (context.global.fbVars.callid[callid].verbindungssymbol == \" -> \" ) {\n\t intNr = cssra + \"RING\" + cssre;\n\t}\n text += datum(context.global.fbVars.callid[callid].dateStart) + \" \" + context.global.fbVars.callid[callid].externeNummerF;\n text += cssga + context.global.fbVars.callid[callid].verbindungssymbol + cssge + \" \"\n text += intNr;\n text += \" \" + cssga + context.global.fbVars.callid[callid].duration2F + cssge;\n if (i < (listeAlle.length - 1)) {\n text += (text ? '
\\n' : '');\n }\n}\n\n\nmsg.payload = text;\ncontext.global.fbVars.anrufmonitor = text;\n\nmsg.topic = msg.topic + \"listeAlle\"; // Liste der aktiven Anrufe\n\nreturn msg;\n","outputs":"1","valid":true,"x":3267.499755859375,"y":2478.833740234375,"z":"64b98f40.9b467","wires":[["19500353.e6affd","d11b4023.2ee4c"]]},{"id":"c36e8f9b.3c917","type":"function","name":"listeRing, alle aktuellen Anrufe (RING)","func":"\nvar listeRing = context.global.fbVars.listeRing;\n\n\nfunction datum(zeitstempel) {\n var jahr = zeitstempel.substring(6,8);\n var monat = zeitstempel.substring(3,5);\n var tag = zeitstempel.substring(0,2);\n var stunde = zeitstempel.substring(9,11);\n var minute = zeitstempel.substring(12,14);\n var sekunde = zeitstempel.substring(15,17);\n\n //var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n var uhrzeit = stunde + \":\" + minute;\n\n //var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n //var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n var datum = tag + \".\" + monat + \". \";\n \n var zeit = datum + uhrzeit;\n \n return zeit;\n}\n\n\n\n\n var text = '';\n for (var i = 0; i < listeRing.length; i++) {\n text += datum(listeRing[i].dateStart) + \" \" + listeRing[i].callingNumber;\n if (i < (listeRing.length - 1)) {\n text += (text ? '
\\n' : '');\n }\n }\n\n\nmsg.payload = text;\n\nmsg.topic = msg.topic + \"listeRing\"; // Liste der aktiv Anrufenden (Zustand: RING)\n\nreturn msg;\n","outputs":"1","valid":true,"x":3254.166343688965,"y":2330.500403404236,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"3cdb3f4e.c324c","type":"function","name":"Testcall neu starten, nur wenn kein aktueller Test läuft","func":"if (context.global.fbVars.callgenerator.testcount <= 0) {\n if (context.global.fbVars.callgenerator.testcalls <= 0) {\n return msg;\n }\n} \n\nreturn null;\n\n","outputs":1,"valid":true,"x":302.00001525878906,"y":3355.3335371017456,"z":"64b98f40.9b467","wires":[["18214dba.e7deb2"]]},{"id":"3dde2800.c221d8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox","x":3803.5952644348145,"y":109.53173494338989,"z":"64b98f40.9b467","wires":[]},{"id":"5a228bb6.a5dd74","type":"template","name":"Fritzbox Flow Webseite","field":"payload","format":"handlebars","template":"\n \n\n \n\n\tioBroker - Fritzbox! Node-red Flow\n\t\n\t\n \n\n \n\n\n\n\n\n \n\n

ioBroker - Fritzbox! Node-red Flow

\n\n

Voraussetzungen in der Fritzbox

\n

In der Fritzbox muss der Anrufmonitor per Telefon freigeschaltet werden (Tastencode eingeben und anrufen):\n

  • \n Anrufmonitor einschalten: #96*5*\n
  • \n
  • \n Anrufmonitor wieder ausschalten: #96*6*\n
  • \n
  • \n Die Freischaltung von Telnet ist nicht notwendig (#96*7*)\n
  • \n

    \n \n

    \n Tipp: Unter http://www.wehavemorefun.de/fritzbox/Tastencodes findet man eine Beschreibung aller verfügbaren Tastencodes, sowie zusätzliche Informationen zur Fritzbox.\n

    \n\n

    Inbetriebnahme

    \n\n

    Die Inbetriebnahme des Fritzbox Flows ist schnell erledigt:\n

  • \n Anrufmonitor in der Fritzbox einschalten: #96*5*, siehe unter Vorausetzungen.\n
  • \n
  • \n Im Flow oben links: im tcp node die IP-Adresse der eigenen Fritzbox eintragen\n
  • \n
  • \n Optional: Im Flow oben links: im function node \"### KONFIGURATION ###\" die Konfiguration überprüfen und ggf. anpassen.\n
  • \n
  • \n Wenn Pushover genutzt werden soll: Pushover Node in Node-Red installieren, siehe: http://forum.iobroker.org/viewtopic.php?f=32&t=763&start=20#p5726\n
  • \n
  • \n Email und Pushover: eigene Daten eintragen oder nodes löschen \n
  • \n
  • \n DEPLOY \n
  • \n
  • \n Optional: Das Demo VIS-Widget in VIS importieren. Das ist hilfreich, um die Funktion der neuen Variablen zu prüfen. \n
  • \n

    \n\n

    Test ohne Fritzbox

    \n

    Der Flow kann mit Hilfe des enthaltnen Call Generators auch ohne Fritzbox getestet werden. Dann sind nur folgende Schritte notwendig:\n

  • \n DEPLOY \n
  • \n
  • \n Das Demo VIS-Widget in VIS importieren. Demo Anrufe starten. \n
  • \n

    \n\n\n\n

    JSON

    \n

    Die JSON Objekte können in eigenen Flows und Scripte zur weiteren Verartbeitung verwendet werden.
    \n Die Links enthalten erst Werte, wenn der Flow einmal \"deployed\" wurde.\n

    \n\n

    \n\n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n
    JSON ObjektJSON LinkBeschreibung
    Alle Objekte/fritzbox/varsKomplettes JSON Objekt mit allen verwendeten Variablen.
    Call IDs/fritzbox/vars/callidBisher verwendete Call IDs, mit den gerade aktuellen Werten.
    0-9 = \"echte\" Anrufe.
    10-x = Anrufe des Call Generators.
    Config/fritzbox/vars/configIm Flow eingestellte individuelle Konfiguration. Beschreibung im Flow.
    Anruferliste gesamt/fritzbox/vars/anruferlisteGesamtAnruferliste aller Anrufe, neuster Eintrag oben. Anzahl der Einträge und Formatierung laut Konfiguration (config).
    Anruferliste verpasst/fritzbox/vars/anruferlisteVerpasstAnruferliste verpasster Anrufe, neuster Eintrag oben. Anzahl der Einträge und Formatierung laut Konfiguration (config).
    Zustand/fritzbox/vars/zustandAktuelle Zustände im laufendem System:

    \n verpassteAnrufeZahl (Anzahl der verpassten Anrufe seit dem letzten Zurücksetzen)
    \n ringLetzter (Rufnummer des letzten Anrufers)
    \n ringAktuell (Rufnummer, des aktuellen Anrufers, solange es klingelt)
    \n ring (true/false - steht aktuell ein Anruf an?)
    \n anzahlRing (Anzahl der aktuell anstehenden Anrufe)
    \n anzahlCall (Anzahl der gehenden Gesprächsversuche)
    \n anzahlConnect (Anzahl der aktuell geführten Gespräche, kommend und gehend)\n
    Liste RING/fritzbox/vars/listeRingListe aller anstehenden kommenden Rufe (RING) inklusiver aller zu dem Zeitpunkt vorliegenden Informationen. Der aktuellste Anruf steht oben.
    Liste CALL/fritzbox/vars/listeCallListe aller anstehenden gehenden Gesprächsaufbauten (CALL) inklusiver aller zu dem Zeitpunkt vorliegenden Informationen. Der aktuellste Gesprächsaufbau steht oben.
    Liste CONNECT/fritzbox/vars/listeConnectListe aller bestehenden Gespräche (CONNECT) inklusiver aller zu dem Zeitpunkt vorliegenden Informationen. Das aktuellste Gespräch steht oben.

    \n\n\n\n

    Konfiguration

    \n

    der erste Absatz…

    \n

    {{topic_prefix}}

    \n

    {{payload}}

    \n\n

    Call ID Informationen

    \n \n

    Die Informationen eines Rufes bauen sich von Phase zu Phase bis zum DISCONNECT weiter auf. Ein Ruf wird über die CALL ID eindeutig identifiziert. Mit dem DISCONNECT ist ein Ruf vollständig und alle Informationen stehen dann zur Verfügung. Mit dem DISCONNECT steht die CALL ID wieder für den nächste Ruf zur Verfügung.

    \n\n

    Mögliche Call Phasen

    \n

    gehende Gespräche

    \n

    CALL -> DISCONNECT (keine Verbindung)
    \n CALL -> CONNECT -> DISCONNECT (gehendes Gespräch)\n

    \n\n

    Kommende Gespräche

    \n

    RING -> DISCONNECT (keine Verbindung)
    \n RING -> CONNECT -> DISCONNECT (kommendes Gespräch)\n

    \n\n\n \n

    Call ID Variablen

    \n

    \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n\n \n \n \n \n \n \n \n\n\n\n \n \n \n \n \n \n \n\n\n\n
    VariableBeschreibungCALLRINGCONNDISCHerkunft
    [0] callideindeutige ID des aktuellen RufesXXXXFritzbox
    [1] dateDatum Uhrzeit der Meldung in der Form: yy-mm-tt hh:mm:ssXXXXFritzbox
    [2] calltypeCALL, RING, CONNECT, DISCONNECTXXXXFritzbox
    [3] callingNumberdie anrufende NummerXXFritzbox
    [4] calledNumberdie angerufene NummerXXFritzbox
    [5] connectedNumberNummer mit der die Verbindung zustande gekommen istXFritzbox
    [6] intNumberinterne NebenstelleXFritzbox
    [7] lineLeitung: POTS, SIP0, ...XXFritzbox
    [8] connectVerbunden (true/false)XFlow
    [9] directionRichtung gehend oder kommendXXFlow
    [10] durationDauer des Gespräches (Gesprächszeit)XFritzbox
    [11] dateStartDatum des 1. Vorgangs (CALL oder RING). [1] wird gespeichert.XXFlow
    [12] dateConnectDatum, zu dem ein Gespräch zu Stande kam. [1] wird gespeichert.XFlow
    [13] dateEndDatum, bei dem die Call ID mit DISCCONNECT beendet wurde.XFlow
    [14] rufdauerZeit zwischen RING/CALL und einem CONNECT in Sekunden.XFlow
    [15]deltaZeitMeldungSystemSekDelta zwischen der Zeit aus der Fritzboxmeldung und des ioBroker Systems in Sek.XXXXFlow
    [16]dateEpocheMeldungsdatum [1] in Epoche (Sek. seit dem 1.1.1970)XXXXFlow
    [17]epocheNowSystemzeit in 1.000stel Sekunden seit dem 1.1.1970XXXXFlow
    \n

    \n\n

    [3] Calling Number und [4] Called Number sind je nach Gesprächsrichtung die eigene Amtsrufnummer oder die externe Rufnummer.

    \n\n\n\n\n\n\n\n","x":3553.5952186584473,"y":111.10316896438599,"z":"64b98f40.9b467","wires":[["3dde2800.c221d8"]]},{"id":"17a1c436.e85e3c","type":"http in","name":"","url":"/fritzbox/vars/callid","method":"get","x":2999.785659790039,"y":282.4524173736572,"z":"64b98f40.9b467","wires":[["73ec0b2c.8c13f4"]]},{"id":"45fa28f5.ba05d8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/callid","x":3775.166458129883,"y":279.35717391967773,"z":"64b98f40.9b467","wires":[]},{"id":"73ec0b2c.8c13f4","type":"function","name":"Ausgabe JSON context.global.fbVars.callid","func":"msg.payload = context.global.fbVars.callid;\nreturn msg;","outputs":1,"valid":true,"x":3310.73779296875,"y":282.214319229126,"z":"64b98f40.9b467","wires":[["45fa28f5.ba05d8"]]},{"id":"6aa86c27.955794","type":"http in","name":"","url":"/fritzbox/vars/config","method":"get","x":3001.214370727539,"y":321.02385902404785,"z":"64b98f40.9b467","wires":[["95efbe2e.6a104"]]},{"id":"e414524c.1bebb","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/config","x":3776.595169067383,"y":317.92861557006836,"z":"64b98f40.9b467","wires":[]},{"id":"95efbe2e.6a104","type":"function","name":"Ausgabe JSON context.global.fbVars.config","func":"msg.payload = context.global.fbVars.config;\nreturn msg;","outputs":1,"valid":true,"x":3312.16650390625,"y":320.7857608795166,"z":"64b98f40.9b467","wires":[["e414524c.1bebb"]]},{"id":"5710f4a.fa8ef0c","type":"function","name":"Ausgabe JSON context.global.fbVars.config.topic_prefix","func":"msg.topic_prefix = JSON.stringify(context.global.fbVars.config.topic_prefix);\n\n\nfunction objToString (obj) {\n var str = '';\n for (var p in obj) {\n if (obj.hasOwnProperty(p)) {\n str += p + ' :: ' + obj[p] + '\\r\\n';\n }\n }\n return str;\n}\n\nmsg.payload = objToString(context.global.fbVars.config);\n\nreturn msg;","outputs":1,"valid":true,"x":3133.595417022705,"y":146.97622346878052,"z":"64b98f40.9b467","wires":[["5a228bb6.a5dd74"]]},{"id":"65ce50a2.9a31b","type":"http in","name":"","url":"/fritzbox/vars/anruferlisteGesamt","method":"get","x":3000.1297302246094,"y":364.648136138916,"z":"64b98f40.9b467","wires":[["874c87de.78b378"]]},{"id":"14033b12.ebfcc5","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/anruferlisteGesamt","x":3775.510528564453,"y":361.5528926849365,"z":"64b98f40.9b467","wires":[]},{"id":"874c87de.78b378","type":"function","name":"Ausgabe JSON context.global.fbVars. anruferlisteGesamt","func":"msg.payload = context.global.fbVars.anruferlisteGesamt;\nreturn msg;","outputs":1,"valid":true,"x":3356.0818481445312,"y":364.41002655029297,"z":"64b98f40.9b467","wires":[["14033b12.ebfcc5"]]},{"id":"f029bb60.0fd648","type":"http in","name":"","url":"/fritzbox/vars/anruferlisteVerpasst","method":"get","x":3002.5369567871094,"y":409.648136138916,"z":"64b98f40.9b467","wires":[["4a06aa57.b5f954"]]},{"id":"8cd62704.7329d8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/anruferlisteVerpasst","x":3777.917755126953,"y":406.5528926849365,"z":"64b98f40.9b467","wires":[]},{"id":"4a06aa57.b5f954","type":"function","name":"Ausgabe JSON context.global.fbVars. anruferlisteVerpasst","func":"msg.payload = context.global.fbVars.anruferlisteVerpasst;\nreturn msg;","outputs":1,"valid":true,"x":3358.4890747070312,"y":409.41002655029297,"z":"64b98f40.9b467","wires":[["8cd62704.7329d8"]]},{"id":"9953e3b1.66ac2","type":"http in","name":"","url":"/fritzbox/vars/zustand","method":"get","x":3004.7593688964844,"y":452.98144912719727,"z":"64b98f40.9b467","wires":[["47304338.b8cfbc"]]},{"id":"a80753af.57f8b","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/zustand","x":3780.140167236328,"y":449.8862056732178,"z":"64b98f40.9b467","wires":[]},{"id":"47304338.b8cfbc","type":"function","name":"Ausgabe JSON context.global.fbVars. zustand","func":"msg.payload = context.global.fbVars.zustand;\nreturn msg;","outputs":1,"valid":true,"x":3360.7114868164062,"y":452.7433395385742,"z":"64b98f40.9b467","wires":[["a80753af.57f8b"]]},{"id":"e4da412d.1b25c","type":"http in","name":"","url":"/fritzbox/vars/listeRing","method":"get","x":2997.9073181152344,"y":502.98144912719727,"z":"64b98f40.9b467","wires":[["46e46524.b91b9c"]]},{"id":"5413160.fabece8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/listeRing","x":3773.288116455078,"y":499.8862056732178,"z":"64b98f40.9b467","wires":[]},{"id":"46e46524.b91b9c","type":"function","name":"Ausgabe JSON context.global.fbVars. listeRing","func":"msg.payload = context.global.fbVars.listeRing;\nreturn msg;","outputs":1,"valid":true,"x":3353.8594360351562,"y":502.7433395385742,"z":"64b98f40.9b467","wires":[["5413160.fabece8"]]},{"id":"cf6ad79e.309528","type":"http in","name":"","url":"/fritzbox/vars/listeCall","method":"get","x":2997.9073181152344,"y":542.9814491271973,"z":"64b98f40.9b467","wires":[["b838cb74.47c738"]]},{"id":"2f0c88db.d0f378","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/listeCall","x":3773.288116455078,"y":539.8862056732178,"z":"64b98f40.9b467","wires":[]},{"id":"b838cb74.47c738","type":"function","name":"Ausgabe JSON context.global.fbVars. listeRing","func":"msg.payload = context.global.fbVars.listeCall;\nreturn msg;","outputs":1,"valid":true,"x":3353.8594360351562,"y":542.7433395385742,"z":"64b98f40.9b467","wires":[["2f0c88db.d0f378"]]},{"id":"8501ffc7.7afe","type":"http in","name":"","url":"/fritzbox/vars/listeConnect","method":"get","x":2997.9073181152344,"y":581.3148231506348,"z":"64b98f40.9b467","wires":[["2a9f2be4.d560d4"]]},{"id":"9f1c4b63.60e3b8","type":"http response","name":"http://[EIGENE-IP]:1880/fritzbox/vars/listeConnect","x":3773.288116455078,"y":578.2195796966553,"z":"64b98f40.9b467","wires":[]},{"id":"2a9f2be4.d560d4","type":"function","name":"Ausgabe JSON context.global.fbVars. listeConnect","func":"msg.payload = context.global.fbVars.listeConnect;\nreturn msg;","outputs":1,"valid":true,"x":3353.8594360351562,"y":581.0767135620117,"z":"64b98f40.9b467","wires":[["9f1c4b63.60e3b8"]]},{"id":"5a093045.a5f6d","type":"debug","name":"","active":false,"console":"false","complete":"true","x":2152.351704589624,"y":2010.944530265322,"z":"64b98f40.9b467","wires":[]},{"id":"6992d8af.966d28","type":"function","name":"Verpasste Anrufe durchlassen und zählen (max. 999)","func":"if (msg.calltype != \"DISCONNECT\") return null;\nif (msg.connect !== false) return null;\nif (msg.direction != \"kommend\") return null;\n\n\n\n\ncontext.global.fbVars.zustand.verpassteAnrufeZahl = context.global.fbVars.zustand.verpassteAnrufeZahl || 0;\n\n\n++context.global.fbVars.zustand.verpassteAnrufeZahl;\nif (context.global.fbVars.zustand.verpassteAnrufeZahl > 999) context.global.fbVars.zustand.verpassteAnrufeZahl = 999;\n\nmsg.anzahlVerpasst = context.global.fbVars.zustand.verpassteAnrufeZahl;\nmsg.verpasstSeit = context.global.fbVars.zustand.verpasstSeit;\n\n\nreturn msg;","outputs":1,"valid":true,"x":1240.83349609375,"y":462.05560302734375,"z":"64b98f40.9b467","wires":[["61816b01.9e7e94","3aca9f71.c5356","4879eda4.b78614"]]},{"id":"61816b01.9e7e94","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1522.8332977294922,"y":463.72222232818604,"z":"64b98f40.9b467","wires":[]},{"id":"4879eda4.b78614","type":"function","name":".anzahlVerpasst (verpasste Anrufe, max. 999)","func":"\nmsg.payload = msg.anzahlVerpasst;\nmsg.topic = context.global.fbVars.config.topic_prefix + \"anzahlVerpasst\";\n\nreturn msg;","outputs":1,"valid":true,"x":1258.7591552734375,"y":507.6110887527466,"z":"64b98f40.9b467","wires":[["54d1f4a0.ab2e0c"]]},{"id":"54d1f4a0.ab2e0c","type":"ioBroker out","name":"[Pfad aud der Konfig] + Variablenname","topic":"","ack":"true","autoCreate":"true","x":1297.8332214355469,"y":549.6481447219849,"z":"64b98f40.9b467","wires":[]},{"id":"abbedbad.544128","type":"function","name":"Wählbare Links","func":"callid = msg.callid;\n\nvar e164 = \"\";\n// verwendet wird die ungekürzte externe Rufnummer, NICHT die eventuell gekürzte externeNummerF\nvar extrnr = context.global.fbVars.callid[callid].externeNummer.toString().replace(/\\D+/g,\"\");\nvar ac = context.global.fbVars.config.eigenerAC;\nvar cc = context.global.fbVars.config.eigenerCC;\n\nif (extrnr.length > 0) {\n var i;\n var extrnr0 = 0;\n for (i=0; i < extrnr.length; i++) {\n if (extrnr.substr(i,i+1) != \"0\") {\n break;\n }\n extrnr0++;\n }\n extrnr = extrnr.slice(extrnr0,extrnr.length);\n \n if (extrnr0 == 0) { extrnr = \"+\" + cc + ac + extrnr;} \n if (extrnr0 == 1) { extrnr = \"+\" + cc + extrnr;} \n if (extrnr0 == 2) { extrnr = \"+\" + extrnr;} \n\n if (extrnr0 < 0 && extrnr0 > 2) {node.error(\"fritzbox - ungültige externe Rufnummer, Anzahl führender Nullen prüfen\");}\n \n e164 = extrnr;\n extrnr = '' + context.global.fbVars.callid[callid].externeNummerF + '';\n context.global.fbVars.callid[callid].externeNummerW = extrnr;\n} else {\n context.global.fbVars.callid[callid].externeNummerW = context.global.fbVars.callid[callid].externeNummerF;\n}\n\nmsg.externeNummerW = context.global.fbVars.callid[callid].externeNummerW;\ncontext.global.fbVars.callid[callid].externeNummerE164 = e164;\nmsg.externeNummerE164 = e164;\n\t\nreturn msg;\n","outputs":1,"valid":true,"x":1930.092529296875,"y":1412.685302734375,"z":"64b98f40.9b467","wires":[["de0f3b54.21f0c8","a5d14987.5a2eb8","9c1fc991.63e038","6992d8af.966d28"]]},{"id":"d6f9f3f3.29061","type":"comment","name":"Aktualisierte ioBroker Variablen in Node-red übernehmen - !!! Pfad anpassen, wenn ein anderer Pfad in der Config steht !!!","info":"","x":2249.907470703125,"y":279.9073791503906,"z":"64b98f40.9b467","wires":[]},{"id":"a43d3a96.5bc2c8","type":"function","name":"globale Objecte","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.config = {};\ncontext.global.fbVars.zustand = context.global.fbVars.zustand || {};\n\n//context.global.fbVars.callgenerator = context.global.fbVars.callgenerator || {};\ncontext.global.fbVars.callgenerator = {};\n\n// aktive Call ID s löschen\ncontext.global.fbVars.callid = [];\n\n// Liste aktive Verbindungszustände löschen\ncontext.global.fbVars.listeRing = [];\ncontext.global.fbVars.listeCall = [];\ncontext.global.fbVars.listeConnect = [];\ncontext.global.fbVars.listeAlle = [];\n\n\nreturn msg;","outputs":1,"valid":true,"x":130.31481170654297,"y":724.9815063476562,"z":"64b98f40.9b467","wires":[["b3c0e4b4.4c3f18"]]},{"id":"7b5af123.84a51","type":"function","name":"ringLetzterVerpasst (Letzte verpasste Rufnummer die angerufen hat)","func":"if (context.global.fbVars.zustand.ringLetzterVerpasst === null) context.global.fbVars.zustand.ringLetzterVerpasst = \"\";\n\nmsg.payload = context.global.fbVars.zustand.ringLetzterVerpasst;\nmsg.topic = msg.topic + \"ringLetzterVerpasst\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3344.203773498535,"y":1996.8703861236572,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"c9dbb867.362448","type":"debug","name":"","active":false,"console":"false","complete":"true","x":2939.203414916992,"y":1535.0185041427612,"z":"64b98f40.9b467","wires":[]},{"id":"c0091a45.3ff6e8","type":"ioBroker in","name":"node-red.0.fritzbox.config.infoEmail","topic":"node-red.0.fritzbox.config.infoEmail","payloadType":"value","x":1973.685203552246,"y":472.64812564849854,"z":"64b98f40.9b467","wires":[["3166fe53.ce9902"]]},{"id":"3166fe53.ce9902","type":"function","name":"infoEmail (true/false) aus ioBroker übernehmen","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.config = context.global.fbVars.config || {};\n\ncontext.global.fbVars.config.infoEmail = msg.payload;\n\nreturn msg;","outputs":1,"valid":true,"x":2323.54248046875,"y":473.5052490234375,"z":"64b98f40.9b467","wires":[["52a90edc.ad56f"]]},{"id":"52a90edc.ad56f","type":"debug","name":"","active":false,"console":"false","complete":"false","x":2591.637664794922,"y":472.8862075805664,"z":"64b98f40.9b467","wires":[]},{"id":"c83567b3.37ca98","type":"ioBroker in","name":"node-red.0.fritzbox.config.infoPushover","topic":"node-red.0.fritzbox.config.infoPushover","payloadType":"value","x":1973.685203552246,"y":520.9814386367798,"z":"64b98f40.9b467","wires":[["9b8340cd.647cc"]]},{"id":"9b8340cd.647cc","type":"function","name":"infoPushover (true/false) aus ioBroker übernehmen","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.config = context.global.fbVars.config || {};\n\ncontext.global.fbVars.config.infoPushover = msg.payload;\n\nreturn msg;","outputs":1,"valid":true,"x":2323.54248046875,"y":521.8385620117188,"z":"64b98f40.9b467","wires":[["db5e1e94.24a1e"]]},{"id":"db5e1e94.24a1e","type":"debug","name":"","active":false,"console":"false","complete":"false","x":2591.637664794922,"y":521.2195205688477,"z":"64b98f40.9b467","wires":[]},{"id":"212cef42.ded31","type":"debug","name":"","active":false,"console":"false","complete":"true","x":785.6481323242188,"y":1078.9814453125,"z":"64b98f40.9b467","wires":[]},{"id":"85425351.7abdb","type":"inject","name":"Jede Sekunde","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":true,"x":2209.610595703125,"y":2361.83349609375,"z":"64b98f40.9b467","wires":[["a3f1bdb0.5c0e4"]]},{"id":"577c4330.a883bc","type":"debug","name":"","active":false,"console":"false","complete":"false","x":3636.7960815429688,"y":2397.7966289520264,"z":"64b98f40.9b467","wires":[]},{"id":"a3f1bdb0.5c0e4","type":"function","name":"Aktive Gespräche?","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.zustand = context.global.fbVars.zustand || {};\ncontext.global.fbVars.zustand.anzahlConnect = context.global.fbVars.zustand.anzahlConnect || 0;\n\nif (context.global.fbVars.zustand.anzahlConnect > 0) {\n return msg;\n}\n\nreturn null;\n\n","outputs":1,"valid":true,"x":2427.351479579391,"y":2359.463280868137,"z":"64b98f40.9b467","wires":[["5fc5b72e.a03a48"]]},{"id":"6f9ff316.90600c","type":"function","name":"DISCONNECT: Werte für Rufliste (1) alle, (2) verpasst","func":"\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn(empty_chars);\n\t}\n\n\nfunction fill0(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\n\nvar anruferliste = \"\";\nvar anruferlisteKopf = \"\";\nvar verpasst =\"\";\nvar verpasstKopf =\"\";\n\nvar externeNummer = msg.externeNummerF;\nvar externeNummerKopf = \"ext. Rufnr.\";\nvar verbindungssymbol = msg.verbindungssymbol;\nvar eigenesAmt = msg.eigenesAmtF;\nvar eigenesAmtKopf = \"Eigenes Amt\";\nvar line = msg.line;\nvar lineKopf = \"Ltg.\";\nvar intNummer = msg.intNumber;\nvar intNummerKopf = \"Nbst\";\n\nvar duration = \"\";\nvar durationKopf = \"  Dauer\"\n\n\n// neue Berechnung inkl. h (04.06.2015):\n// Test:\n// msg.duration = 3661;\n\nvar durationMin = Math.floor(parseInt(msg.duration) / 60 );\nvar durationSek = parseInt(msg.duration) % 60;\nvar durationStd = Math.floor(durationMin / 60);\ndurationMin %= 60;\n\n\n\n// css\nif (context.global.fbVars.config.html === true) {\n\tvar cssstart = '';\n\tvar cssend = \"\";\n\tvar cssba = \"\";\n\tvar cssbe = \"\";\n\tvar cssvs = ''; // Farbe Verbindungssymbol\n\t} else {\n\tvar cssstart = \"\";\n\tvar cssend = \"\";\n\tvar cssba = \"\";\n\tvar cssbe = \"\";\n\tvar cssvs = \"\";\n\t}\n\t\n\n\tvar zeitstempel = msg.dateStart; // Zeit des RING\n\n\tvar jahr = zeitstempel.substring(6,8);\n\tvar monat = zeitstempel.substring(3,5);\n\tvar tag = zeitstempel.substring(0,2);\n\tvar stunde = zeitstempel.substring(9,11);\n\tvar minute = zeitstempel.substring(12,14);\n\tvar sekunde = zeitstempel.substring(15,17);\n\n\t//var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n\tvar uhrzeit = stunde + \":\" + minute + \" \";\n var uhrzeitKopf = \"Zeit  \";\n\n\t//var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n\t//var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n\tvar datum = tag + \".\" + monat + \". \";\n var datumKopf = \"Tag    \";\n// duration = durationMin + \":\" + fill(2 - durationSek.length);\n\n\n// Ausgabeformat Duration\nif (durationStd < 1) {\n if (durationMin < 1) {\n duration = durationSek;\n } else {\n duration = durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n }\n} else {\n duration = durationStd + \":\" + fill0(2- durationMin.toString().length) + durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n} \n\nduration = duration.toString();\n\nif (duration == \"0\") {\n duration = \"-\";\n}\n\n\nduration = fill(7 - duration.toString().length) + duration; \n\n\n\n// Felder rausfiltern, die laut Konfig nicht angezeigt werden sollen\nif (context.global.fbVars.config.anz_datum === true) {\n\t} else {\n\tdatum = \"\";\n\tdatumKopf = \"\";\n\t}\n\nif (context.global.fbVars.config.anz_uhrzeit === true) {\n\t} else {\n\tuhrzeit = \"\";\n\tuhrzeitKopf = \"\";\n\t}\n\nif (context.global.fbVars.config.anz_duration === true) {\n\t} else {\n\tduration = \"\";\n\tdurationKopf = \"\";\n\t}\n\n\n\n\n// CSS Farbe Verbindungssymbol\n\tif (msg.connect === true) cssvs = '';\n\tif (msg.connect === false) cssvs = '';\n\n\t\n\n// sollte die externen Rufnummern insgesamt länger sein, werden diese auf die max. gewünschte Länge gekürzt\nexterneNummerKopf = externeNummerKopf.substring(0,context.global.fbVars.config.länge_ext_rnr);\neigenesAmtKopf = eigenesAmtKopf.substring(0,context.global.fbVars.config.länge_ext_rnr);\n\n\n// Amtsrufnummern (externe und eigene) auf gewünschte Länge mit Leerzeichen auffüllen \nexterneNummerKopf = externeNummerKopf + fill(context.global.fbVars.config.länge_ext_rnr - externeNummerKopf.length);\nintNummer = fill(5 - intNummer.length) + intNummer;\nintNummerKopf = fill(5 - intNummerKopf.length) + intNummerKopf;\neigenesAmtKopf = eigenesAmtKopf + fill(context.global.fbVars.config.länge_ext_rnr - eigenesAmtKopf.length);\nline = line + fill(5 - intNummer.length)+ \" \";\nlineKopf = lineKopf + fill(5 - intNummer.length)+ \" \";\n\n\n\n// Felder rausfiltern, die laut Konfig nicht angezeigt werden sollen\n\t\nif (context.global.fbVars.config.anz_int_rnr === true) {\n\t} else {\n\tintNummer =\"\";\n\tintNummerKopf =\"\";\n\t}\n\nif (context.global.fbVars.config.anz_eigenes_amt === true) {\n\t} else {\n\teigenesAmt =\"\";\n\teigenesAmtKopf =\"\";\n\t}\n\nif (context.global.fbVars.config.anz_line === true) {\n\t} else {\n\tline =\"\";\n\tlineKopf = \"\";\n\t}\n\n\n\n// Ausgabe alle Arten von Anrufen\n// =================================\nanruferliste = datum + uhrzeit + externeNummer + cssba + cssvs + verbindungssymbol + cssend + cssbe \n\t\t\t + intNummer + \" \" + eigenesAmt + line + duration;\n\nanruferlisteKopf = cssba + datumKopf + uhrzeitKopf + externeNummerKopf + \"g<>k\" \n\t\t\t + intNummerKopf + \" \" + eigenesAmtKopf + lineKopf + durationKopf + cssbe;\n\n\n// Ausgabe der verpassten kommenden Anrufe\n// =================================\nif (msg.direction == \"kommend\") {\n if (msg.connect == false) {\n\t verpasstKopf = cssba + datumKopf + uhrzeitKopf + \" \" + externeNummerKopf + cssbe;\n\t verpasst = datum + uhrzeit + \" \" + externeNummer;\n } else {\n\t verpasst = \"nichts\";\n\t }\n\t} else {\n verpasst = \"nichts\";\n }\n\n\n\nvar msg1 = {};\nvar msg2 = {};\n\nmsg1.topic = msg.topic + \"ruflisten.alleLetzterEintrag\";\nmsg2.topic = msg.topic + \"ruflisten.verpasstLetzterEintrag\";\n\nmsg1.payload = anruferliste;\nmsg2.payload = verpasst;\n\nmsg1.anruferlisteKopf = anruferlisteKopf;\nmsg2.verpasstKopf = verpasstKopf;\n\nreturn [msg1,msg2];\n","outputs":"2","valid":true,"x":2888.8332138061523,"y":1284.8333292007446,"z":"64b98f40.9b467","wires":[[],[]]},{"id":"9d6c7f06.62938","type":"function","name":"Meldungen in Objekten umbauen & Topic=Call ID","func":"// es wird für jeden der vier calltype das Objekt mit allen 14 Werten zusammengebaut,\n// damit die Nachricht im Objekt zu jeder Zeit synchron ist\n// Werte, die aus vorherigen Nachrichten übernommen werden, werden aus\n// global.context.fbVars[] impoertiert (fbVars = fritzboxVariablen)\n\nmess \t= msg.payload; \t\t// die geparste Meldung aus dem tcp Stream als Ganzes\nslices \t= mess.split(\";\"); \t// speichert die Felder der Meldung in ein Array mit dem Namen \"slices\"\n\n// die Call ID wird als erstes ausgelesen, da diese für die eindeutige Zuordnung\n// der Werte zum richtigen Call benötigt wird (es kann mehrere Calls parallel geben)\nmsg.callid\t\t= slices[2]; // an dritter Stelle steht die CallID (Zurordnung zum aktuellen Ruf)\n\nvar callid\t = msg.callid; // für das Array global.context.fbVars.callid[callid]\n\n\ncontext.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\n// Umbau der Variablen in ein Array\ncontext.global.fbVars.callid = context.global.fbVars.callid || [];\ncontext.global.fbVars.callid[msg.callid] = context.global.fbVars.callid[msg.callid] || {};\n\n\nfunction fritzboxZeitEpoche(datum) {\ndatum = datum || \"\";\nvar jahr = \"20\" + datum.substring(6,8);\nvar monat = datum.substring(3,5);\nvar monatJS = parseInt(datum.substring(3,5))-1;\nvar tag = datum.substring(0,2);\nvar stunde = datum.substring(9,11);\nvar minute = datum.substring(12,14);\nvar sekunde = datum.substring(15,17);\n\nvar zeit = new Date(jahr,monatJS,tag,stunde,minute,sekunde);\nvar epoche = Date.parse(zeit) / 1000; // Zeit aus der Meldung in Epoche\n \nreturn epoche;\n} \n\n\n// für alle Gesprächszustände identisch:\n\n// [0]callid\ncontext.global.fbVars.callid[callid].callid = msg.callid;\n// [1]date\nmsg.date \t\t= slices[0]; // an erster Stelle steht immer das Datum in der Form: 10.05.15 20:06:58\ncontext.global.fbVars.callid[callid].date = msg.date;\n// [2]calltype\nmsg.calltype \t= slices[1]; // an zweiter Stelle steht der Ruftyp (CALL, RING, CONNECT, DISCONECT)\ncontext.global.fbVars.callid[callid].calltype = msg.calltype;\n\n\n// die restlichen Stellen der Message sind je nach calltype mit unterschiedlichlichen Variablen belegt. \n\n\n\n// ######## RING ######## (kommendes Gespräch = Ruf)\n\nif (msg.calltype == \"RING\") {\n\n// [3] callingNumber\n\tif (slices[3] === \"\") { // keine Rufnummer -> \"Nummer unterdrückt\"\n\t\tmsg.callingNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.callingNumber = slices[3];\n\t\t}\n\tcontext.global.fbVars.callid[callid].callingNumber = msg.callingNumber;\n// [4] calledNumber\n\tmsg.calledNumber = slices[4];\n\tcontext.global.fbVars.callid[callid].calledNumber = msg.calledNumber;\n// [5] connectedNumber\n\tmsg.connectedNumber = \"\"; // im Zustand Call gibt es keine Connected, diese wird hier gelöscht\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6] intNumber\n\tmsg.intNumber = \"\";\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7] line\n\tmsg.line = slices[5];\n\tcontext.global.fbVars.callid[callid].line = msg.line;\n// [8] connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = false;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9] direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = \"kommend\";\n\tcontext.global.fbVars.callid[callid].direction = msg.direction;\n// [10] duration\n\tmsg.duration = 0;\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11] dateStart\n\tmsg.dateStart = msg.date;\n\tcontext.global.fbVars.callid[callid].dateStart = msg.dateStart;\n// [12] dateConnect\n\tmsg.dateConnect = \"\";\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13] dateEnd\n\tmsg.dateEnd = \"\";\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14] rufdauer\n\tmsg.rufdauer = \"\";\n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [15] deltaZeitMeldungSystemSek\n var tst = fritzboxZeitEpoche(msg.date);\n var now = new Date(); \n now = Date.parse(now) / 1000;// aktuelle Zeit in Epoche\n msg.deltaZeitMeldungSystemSek = tst - now;\n\tcontext.global.fbVars.callid[callid].deltaZeitMeldungSystemSek = msg.deltaZeitMeldungSystemSek;\n// [16] dateEpoche\n msg.dateEpoche = tst;\n\tcontext.global.fbVars.callid[callid].dateEpoche = msg.dateEpoche;\n// [17] epocheNow - Systemzeit in 1.000stel Sekunden\n var now = new Date(); \n now = Date.parse(now) // aktuelle Zeit in Epoche\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n// [18] externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.externeNummerF = \"\";\n context.global.fbVars.callid[callid].externeNummerF = \"\";\n// [19] eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.eigenesAmtF = \"\";\n context.global.fbVars.callid[callid].eigenesAmtF = \"\";\n// [20] verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = \" -> \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = 0;\n\tcontext.global.fbVars.callid[callid].duration2 = msg.duration2;\n \n\t}\n\n\n\n\n// ######## CALL ######## (gehendes Gespräch)\n\nif (msg.calltype == \"CALL\") {\n\n// [3]callingNumber\n\tif (slices[4] === \"\") { // keine Rufnummer -> \"Nummer unterdrückt\"\n\t\tmsg.callingNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.callingNumber = slices[4];\n\t\t}\n\tcontext.global.fbVars.callid[callid].callingNumber = msg.callingNumber;\n// [4]calledNumber\n\tmsg.calledNumber = slices[5];\n\tcontext.global.fbVars.callid[callid].calledNumber = msg.calledNumber;\n// [5]connectedNumber\n\tmsg.connectedNumber = \"\";\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = slices[3];\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7]line\n\tmsg.line = slices[6];\n\tcontext.global.fbVars.callid[callid].line = msg.line;\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = false;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = \"gehend\";\t\n\tcontext.global.fbVars.callid[callid].direction = msg.direction;\n// [10]duration\n\tmsg.duration = 0;\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11]dateStart\n\tmsg.dateStart = msg.date;\n\tcontext.global.fbVars.callid[callid].dateStart = msg.dateStart;\n// [12]dateConnect\n\tmsg.dateConnect = \"\";\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13]dateEnd\n\tmsg.dateEnd = \"\";\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14]rufdauer\n\tmsg.rufdauer = \"\";\n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [15]deltaZeitMeldungSystemSek\n var tst = fritzboxZeitEpoche(msg.date);\n var now = new Date(); \n now = Date.parse(now) / 1000;// aktuelle Zeit in Epoche\n msg.deltaZeitMeldungSystemSek = tst - now;\n\tcontext.global.fbVars.callid[callid].deltaZeitMeldungSystemSek = msg.deltaZeitMeldungSystemSek;\n// [16]dateEpoche\n msg.dateEpoche = tst;\n\tcontext.global.fbVars.callid[callid].dateEpoche = msg.dateEpoche;\n// [17]epocheNow - Systemzeit in 1.000stel Sekunden\n var now = new Date(); \n now = Date.parse(now) // aktuelle Zeit in Epoche\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.externeNummerF = \"\";\n context.global.fbVars.callid[callid].externeNummerF = msg.externeNummerF;\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n msg.eigenesAmtF = \"\";\n context.global.fbVars.callid[callid].eigenesAmtF = msg.eigenesAmtF;\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = \" <- \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n\tmsg.duration2 = 0;\n\tcontext.global.fbVars.callid[callid].duration2 = msg.duration2;\n\n\t}\n\n\n// ######## CONNECT ######## (verbundenes Gespräch)\n\nif (msg.calltype == \"CONNECT\") {\n\n// [3]callingNumber\n context.global.fbVars.callid[callid].callingNumber = context.global.fbVars.callid[callid].callingNumber || \"????????????\";\n msg.callingNumber = context.global.fbVars.callid[callid].callingNumber;\n// [4]calledNumber\n context.global.fbVars.callid[callid].calledNumber = context.global.fbVars.callid[callid].calledNumber || \"????????????\";\n\tmsg.calledNumber = context.global.fbVars.callid[callid].calledNumber;\n// [5]connectedNumber\n\tif (slices[4] === \"\") {\n\t\tmsg.connectedNumber = context.global.fbVars.config.rnr_unbekannt;\n\t\t} else {\n\t\tmsg.connectedNumber = slices[4];\n\t\t}\n\tcontext.global.fbVars.callid[callid].connectedNumber = msg.connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = slices[3];\n\tcontext.global.fbVars.callid[callid].intNumber = msg.intNumber;\n// [7]line\n\tmsg.line = context.global.fbVars.callid[callid].line;\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = true;\n\tcontext.global.fbVars.callid[callid].connect = msg.connect;\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = context.global.fbVars.callid[callid].direction;\n// [10]duration\n\tmsg.duration = context.global.fbVars.callid[callid].duration;\n// [11]dateStart\n\tmsg.dateStart = context.global.fbVars.callid[callid].dateStart;\n// [12]dateConnect\n\tmsg.dateConnect = msg.date;\n\tcontext.global.fbVars.callid[callid].dateConnect = msg.dateConnect;\n// [13]dateEnd\n\tmsg.dateEnd = context.global.fbVars.callid[callid].dateEnd;\n// [14]rufdauer\n var zeitConnectEpoche = fritzboxZeitEpoche(msg.date);\n var zeitStartEpoche = fritzboxZeitEpoche(msg.dateStart);\n\tmsg.rufdauer = zeitConnectEpoche - zeitStartEpoche; \n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n// [15]deltaZeitMeldungSystemSek\n var tst = fritzboxZeitEpoche(msg.date);\n var now = new Date(); \n now = Date.parse(now) / 1000;// aktuelle Zeit in Epoche\n msg.deltaZeitMeldungSystemSek = tst - now;\n\tcontext.global.fbVars.callid[callid].deltaZeitMeldungSystemSek = msg.deltaZeitMeldungSystemSek;\n// [16]dateEpoche\n msg.dateEpoche = tst;\n\tcontext.global.fbVars.callid[callid].dateEpoche = msg.dateEpoche;\n// [17]epocheNow - Systemzeit in 1.000stel Sekunden\n var now = new Date(); \n now = Date.parse(now) // aktuelle Zeit in Epoche\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n// keine Änderung über die Meldung\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n// keine Änderung über die Meldung\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \nif (msg.direction == \"gehend\") {\n msg.verbindungssymbol = \"<<- \";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n} else {\n msg.verbindungssymbol = \" ->>\";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n}\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n// keine Änderung über die Meldung\n\n}\n\n\n\n// ######## DISCONNECT ######## (beendetes Gespräch / Gesprächsversuch)\n\n// wenn der Flow während eines aktiven Gesprächs gestartet wird,\n// sind diverse Zustände nicht bekannt. Diese werden hier abgefangen.\n\nif (msg.calltype == \"DISCONNECT\") {\n// [3]callingNumber\n context.global.fbVars.callid[callid].callingNumber = context.global.fbVars.callid[callid].callingNumber || \"????????????\";\n\tmsg.callingNumber = context.global.fbVars.callid[callid].callingNumber;\n// [4]calledNumber\n context.global.fbVars.callid[callid].calledNumber = context.global.fbVars.callid[callid].calledNumber || \"????????????\";\n\tmsg.calledNumber = context.global.fbVars.callid[callid].calledNumber;\n// [5]connectedNumber\n context.global.fbVars.callid[callid].connectedNumber = context.global.fbVars.callid[callid].connectedNumber || \"\";\n\tmsg.connectedNumber = context.global.fbVars.callid[callid].connectedNumber;\n// [6]intNumber\n\tmsg.intNumber = context.global.fbVars.callid[callid].intNumber;\n\tif (msg.intNumber == null) { msg.intNumber = \"??\"; }\n// [7]line\n\tmsg.line = context.global.fbVars.callid[callid].line;\n\tif (msg.line == null) { msg.line = \"????\"; }\n// [8]connect (Info anhand der Ruftyps selbst erstellt)\n\tmsg.connect = context.global.fbVars.callid[callid].connect;\n\tif (msg.connect == null) { msg.connect = true }\t\t\t\t\t// undefinierter Zustand, wenn der Flow im aktiven Gespräch gestartet wird (Annahme: Gespräch, da wahrscheinlicher (dauert in der Regel länger als ein Rufzustand))\n// [9]direction (Info anhand der Ruftyps selbst erstellt)\n\tmsg.direction = context.global.fbVars.callid[callid].direction;\n\tif (msg.direction == null) { msg.direction = \"??????\" }\t\t\t// undefinierter Zustand (gehend oder kommend nicht bekannt, wenn der Flow im aktiven Gespräch gestartet wird)\n// [10]duration\n\tmsg.duration = slices[3];\n\tcontext.global.fbVars.callid[callid].duration = msg.duration;\n// [11]dateStart\n\tmsg.dateStart = context.global.fbVars.callid[callid].dateStart;\n\tif (msg.dateStart == null) { msg.dateStart = msg.date; }\n// [12]dateConnect\n\tmsg.dateConnect = context.global.fbVars.callid[callid].dateConnect;\n\tif (msg.dateConnect == null) { msg.dateConnect = msg.date; }\n// [13]dateEnd\n\tmsg.dateEnd = msg.date;\n\tcontext.global.fbVars.callid[callid].dateEnd = msg.dateEnd;\n// [14]rufdauer\n\tmsg.rufdauer = context.global.fbVars.callid[callid].rufdauer;\n\tif (msg.rufdauer == null) { msg.rufdauer = 0; }\n// [15]deltaZeitMeldungSystemSek\n var tst = fritzboxZeitEpoche(msg.date);\n var now = new Date(); \n now = Date.parse(now) / 1000;// aktuelle Zeit in Epoche\n msg.deltaZeitMeldungSystemSek = tst - now;\n// [16]dateEpoche\n msg.dateEpoche = tst;\n\tcontext.global.fbVars.callid[callid].dateEpoche = msg.dateEpoche;\n// [17]epocheNow - Systemzeit in 1.000stel Sekunden\n var now = new Date(); \n now = Date.parse(now) // aktuelle Zeit in Epoche\n msg.epocheNow = now;\n\tcontext.global.fbVars.callid[callid].epocheNow = msg.epocheNow;\n// [18]externeNummerF - Externe Rufnummer über die Format-Funktion auf Länge (config) formatiert\n// keine Änderung über die Meldung\n// [19]eigenesAmtF // eigene Amtsrufnummer über die Format-Funktion auf Länge (config) formatiert\n// keine Änderung über die Meldung\n// [20]verbindungssymbol // Verbindungssymbol: Gesprächsrichtung & Erfolg oder nicht \n msg.verbindungssymbol = context.global.fbVars.callid[callid].verbindungssymbol;\nif (msg.connect == false) {\n if (msg.direction == \"gehend\") {\n msg.verbindungssymbol = \"X<- \";\n } else {\n if (msg.direction == \"kommend\") {\n msg.verbindungssymbol = \" ->X\";\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n }\n \n }\n}\n// [21] duration2 // Verbindungsdauer 2 in Sek. (wird während des CONNECTs hochgezählt)\n// keine Änderung über die Meldung\n\n}\n\n\n// ungültige Zustände abfangen (wnn ein Deploy mitten im Gespräch erfolgt)\n\nif (msg.verbindungssymbol == null || msg.verbindungssymbol == \"undefined\") {\n \tmsg.verbindungssymbol = \"????\";\t \t // Flow startet in einem aktiven Call: Symbol \"????\"\n }\n context.global.fbVars.callid[callid].verbindungssymbol = msg.verbindungssymbol;\n\n\n// ###########################\n\nmsg.config = {};\nmsg.config.callid_anlegen = context.global.fbVars.config.callid_anlegen;\nmsg.config.cdr_to_disk = context.global.fbVars.config.cdr_to_disk;\n\nif (msg.callid) return msg; // wenn Callid != null, dann weiter","outputs":1,"valid":true,"x":2478.8332138061523,"y":1284.8333292007446,"z":"64b98f40.9b467","wires":[[]]},{"id":"4b1d0296.b4e2fc","type":"function","name":"listeCALL, alle gehenden Gesprächsaufbauten (CALL)","func":"\nvar listeCall = context.global.fbVars.listeCall;\n\n\nfunction datum(zeitstempel) {\n var jahr = zeitstempel.substring(6,8);\n var monat = zeitstempel.substring(3,5);\n var tag = zeitstempel.substring(0,2);\n var stunde = zeitstempel.substring(9,11);\n var minute = zeitstempel.substring(12,14);\n var sekunde = zeitstempel.substring(15,17);\n\n //var uhrzeit = stunde + \":\" + minute + \":\"+ sekunde + \" \";\n var uhrzeit = stunde + \":\" + minute;\n\n //var datum = tag + \".\" + monat + \".20\" + jahr + \" \";\n //var datum = tag + \".\" + monat + \".\" + jahr + \" \";\n var datum = tag + \".\" + monat + \". \";\n \n var zeit = datum + uhrzeit;\n \n return zeit;\n}\n\n\n\n\n var text = '';\n for (var i = 0; i < listeCall.length; i++) {\n text += datum(listeCall[i].dateStart) + \" \" + listeCall[i].calledNumber;\n if (i < (listeCall.length - 1)) {\n text += (text ? '
    \\n' : '');\n }\n }\n\n\nmsg.payload = text;\n\nmsg.topic = msg.topic + \"listeCall\"; // Liste der aktiv Anrufenden (Zustand: CALL)\n\nreturn msg;\n","outputs":"1","valid":true,"x":3302.16658782959,"y":2364.8333349227905,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"5fc5b72e.a03a48","type":"function","name":"lfd. Gespräch, Gesprächsdauer","func":"msg.topic = context.global.fbVars.config.topic_prefix;\nvar listeConnect = context.global.fbVars.listeConnect;\n\n\nvar now = new Date(); \n now = Date.parse(now) / 1000;\n\n\nfunction fill(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn(empty_chars);\n\t}\n\nfunction fill0(n) {\n\tvar empty_chars = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tempty_chars += \"0\";\n\treturn(empty_chars);\n\t}\n\n\nfunction dauer(duration) {\n var durationMin = Math.floor(parseInt(duration) / 60 );\n var durationSek = parseInt(duration) % 60;\n var durationStd = Math.floor(durationMin / 60);\n durationMin %= 60;\n\n // Ausgabeformat Duration\n if (durationStd < 1) {\n if (durationMin < 1) {\n duration = durationSek;\n } else {\n duration = durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n }\n } else {\n duration = durationStd + \":\" + fill0(2- durationMin.toString().length) + durationMin + \":\" + fill0(2- durationSek.toString().length) + durationSek;\n } \n\n duration = duration.toString();\n\n if (duration == \"0\") {\n duration = \"-\";\n }\n if (duration.length > 7) {\n duration = \"> 10h\";\n }\n duration = fill(7 - duration.toString().length) + duration; \n return duration;\n}\n\n\n\n\nfor (var i = 0; i < listeConnect.length; i++) {\n var gesprächsdauer = now - (listeConnect[i].epocheNow);\n context.global.fbVars.callid[listeConnect[i].callid].duration2 = gesprächsdauer;\n context.global.fbVars.callid[listeConnect[i].callid].duration2F = dauer(gesprächsdauer);\n}\n\n\nreturn msg;\n","outputs":"1","valid":true,"x":2858.8334732055664,"y":2361.4999985694885,"z":"64b98f40.9b467","wires":[["c3ed1ba1.3c12e8","acfd4835.5302b8"]]},{"id":"19500353.e6affd","type":"debug","name":"","active":false,"console":"false","complete":"false","x":3640.5000190734863,"y":2471.5002431869507,"z":"64b98f40.9b467","wires":[]},{"id":"dab97460.254688","type":"function","name":"aktuelle Rufdauer berechnen","func":"\nfunction fritzboxZeitEpoche(datum) {\n datum = datum || \"\";\n var jahr = \"20\" + datum.substring(6,8);\n var monat = datum.substring(3,5);\n var monatJS = parseInt(datum.substring(3,5))-1;\n var tag = datum.substring(0,2);\n var stunde = datum.substring(9,11);\n var minute = datum.substring(12,14);\n var sekunde = datum.substring(15,17);\n var zeit = new Date(jahr,monatJS,tag,stunde,minute,sekunde);\n var epoche = Date.parse(zeit) / 1000; // Zeit aus der Meldung in Epoche\n return epoche;\n} \n\n\nfunction fill(n) {\n\tvar leerzeichen = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tleerzeichen += \" \"; //   als utf-8 Code (Mac: alt+Leerzeichen)\n\treturn leerzeichen;\n\t}\n\nfunction fill0(n) {\n\tvar nullen = \"\";\n\tfor(var i = 0; i < n; ++i)\n\tnullen += \"0\";\n\treturn nullen;\n\t}\n\nvar now = new Date(); \nnow = Date.parse(now) / 1000 ; // aktuelle Zeit in Epoche\n\n\n\n// [14]rufdauer\n var zeitConnectEpoche = fritzboxZeitEpoche(msg.date);\n\tmsg.rufdauer = now - context.global.fbVars.callid[callid].epocheStart; \n\tcontext.global.fbVars.callid[callid].rufdauer = msg.rufdauer;\n\nreturn msg;","outputs":1,"valid":true,"x":2822.1666285196934,"y":2273.1667439142857,"z":"64b98f40.9b467","wires":[[]]},{"id":"9874bd40.678b4","type":"delay","name":"","pauseType":"random","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"8","randomUnits":"seconds","drop":false,"x":181.33328247070312,"y":3275.6667890548706,"z":"64b98f40.9b467","wires":[["70e82574.8f17dc"]]},{"id":"7604e0e5.89fb2","type":"function","name":"Init - Variablen zurücksetzen","func":"/* Ausgabe\n\n01. config.infoEmail\n02. config.infoPushover\n03. anzahlVerpasst\n04. callgenerator.startDemo\n05. callgenerator.stopDemo\n06. callgenerator.testcount\n07. ringAktuell\n08. ring\n09. anzahlRing\n10. anzahlCall\n11. anzahlConnect\n12. listeRing\n13. listeCall\n14. listeConnect\n15. listeAlle\n16. button.startDemo \n17. button.stopDemo\n\n*/\n\n\n// einige Zustände löschen, die nach einem Neustart undefiniert sind:\n\ncontext.global.fbVars.zustand.ringAktuell = \"\";\ncontext.global.fbVars.zustand.ring = false;\ncontext.global.fbVars.zustand.anzahlRing = 0;\ncontext.global.fbVars.zustand.anzahlCall = 0;\ncontext.global.fbVars.zustand.anzahlConnect = 0;\ncontext.global.fbVars.zustand.anzahlAlle = 0;\ncontext.global.fbVars.zustand.verpassteAnrufeZahl = context.global.fbVars.zustand.verpassteAnrufeZahl || 0;\n\ncontext.global.fbVars.callgenerator.testcalls = 0;\ncontext.global.fbVars.callgenerator.testcount = 0;\n\ncontext.global.fbVars.listeRing = \"\";\ncontext.global.fbVars.listeCall = \"\";\ncontext.global.fbVars.listeConnect = \"\";\ncontext.global.fbVars.listeAlle = \"\";\n\n\nvar datum = new Date();\n\nvar year = datum.getFullYear();\nvar month = datum.getMonth()+1; \nvar day = datum.getDate();\nvar hour = datum.getHours();\nvar minute = datum.getMinutes();\nvar second = datum.getSeconds(); \nif(month.toString().length == 1) {\nvar month = '0'+month;\n}\nif(day.toString().length == 1) {\nvar day = '0'+day;\n} \nif(hour.toString().length == 1) {\nvar hour = '0'+hour;\n}\nif(minute.toString().length == 1) {\nvar minute = '0'+minute;\n}\nif(second.toString().length == 1) {\nvar second = '0'+second;\n} \n \ncontext.global.fbVars.zustand.verpasstSeit = context.global.fbVars.zustand.verpasstSeit || (day + \".\" + month + \". \" + hour + \":\" + minute);\n\n\n\nvar msgiobroker = [\n { // 01.\n topic: msg.topic + \"config.infoEmail\",\n payload: context.global.fbVars.config.infoEmail\n },\n {\n topic: msg.topic + \"config.infoPushover\",\n payload: context.global.fbVars.config.infoPushover\n },\n {\n topic: msg.topic + \"anzahlVerpasst\",\n payload: context.global.fbVars.zustand.verpassteAnrufeZahl\n },\n {\n topic: msg.topic + \"verpasstSeit\",\n payload: context.global.fbVars.zustand.verpasstSeit\n },\n {\n topic: msg.topic + \"callgenerator.startDemo\",\n payload: false\n },\n {\n topic: msg.topic + \"callgenerator.stopDemo\",\n payload: false\n },\n {\n topic: msg.topic + \"callgenerator.testcount\",\n payload: context.global.fbVars.callgenerator.testcount\n },\n {\n topic: msg.topic + \"ringAktuell\",\n payload: context.global.fbVars.zustand.ringAktuell\n },\n {\n topic: msg.topic + \"ring\",\n payload: context.global.fbVars.zustand.ring\n },\n {\n topic: msg.topic + \"anzahlRing\",\n payload: context.global.fbVars.zustand.anzahlRing\n },\n {\n topic: msg.topic + \"anzahlCall\",\n payload: context.global.fbVars.zustand.anzahlCall\n },\n {\n topic: msg.topic + \"anzahlConnect\",\n payload: context.global.fbVars.zustand.anzahlConnect\n },\n {\n topic: msg.topic + \"anzahlAlle\",\n payload: context.global.fbVars.zustand.anzahlAlle\n },\n\n {\n topic: msg.topic + \"listeRing\",\n payload: context.global.fbVars.listeRing\n },\n {\n topic: msg.topic + \"listeCall\",\n payload: context.global.fbVars.listeCall\n },\n {\n topic: msg.topic + \"listeConnect\",\n payload: context.global.fbVars.listeConnect\n },\n {\n topic: msg.topic + \"listeAlle\",\n payload: context.global.fbVars.listeAlle\n },\n {\n topic: msg.topic + \"button.startDemo\",\n payload: context.global.fbVars.config.button.startDemoInaktiv\n },\n {\n topic: msg.topic + \"button.stopDemo\",\n payload: context.global.fbVars.config.button.stopDemoInaktiv\n },\n// {\n// topic: msg.topic + \"button.verpasstLöschen\",\n// payload: 'seit dem
    ' + context.global.fbVars.zustand.verpasstSeit + \"
    löschen\"\n// },\n {\n topic: msg.topic + \"deltaZeitMeldungSystemOK\",\n payload: true\n }\n\n];\n// return [msgiobroker,msg];\nreturn [msgiobroker,msg];\n\n\n/*\n\n*/","outputs":"2","valid":true,"x":556.5,"y":1145.5,"z":"64b98f40.9b467","wires":[["f7a978ae.085688","12104269.edefbe"],["3144616a.cebb9e"]]},{"id":"f7a978ae.085688","type":"debug","name":"","active":false,"console":"false","complete":"false","x":944.5,"y":1143.5,"z":"64b98f40.9b467","wires":[]},{"id":"c115de3b.3eea2","type":"function","name":".adapterInit","func":"\nmsg.payload = 1;\nmsg.topic = context.global.fbVars.config.topic_prefix + \"adapterInit\"; // Variablenname\n\nreturn msg;","outputs":1,"valid":true,"x":512.5,"y":1243.5,"z":"64b98f40.9b467","wires":[["f9289a46.06d768","12104269.edefbe","322d7a63.cdd286"]]},{"id":"f9289a46.06d768","type":"delay","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":508.5,"y":1277.5,"z":"64b98f40.9b467","wires":[["344e2412.cbb1dc"]]},{"id":"344e2412.cbb1dc","type":"function","name":".adapterInit","func":"\nmsg.payload = 0;\nmsg.topic = context.global.fbVars.config.topic_prefix + \"adapterInit\"; // Variablenname\n\nreturn msg;","outputs":1,"valid":true,"x":644.5,"y":1275.5,"z":"64b98f40.9b467","wires":[["f7a978ae.085688","12104269.edefbe"]]},{"id":"12104269.edefbe","type":"ioBroker out","name":"[Pfad aus der Konfig].*","topic":"","ack":"true","autoCreate":"true","x":980.5,"y":1187.5,"z":"64b98f40.9b467","wires":[]},{"id":"3144616a.cebb9e","type":"delay","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":506.5,"y":1211.5,"z":"64b98f40.9b467","wires":[["c115de3b.3eea2"]]},{"id":"c830b9f0.37cf48","type":"function","name":"call-- & Buttons","func":"context.global.fbVars.callgenerator.testcalls--; // aktuell laufende Calls um eins reduzieren\nif (context.global.fbVars.callgenerator.testcalls == 0) {\n var msgbuttons = [\n {\n topic: context.global.fbVars.config.topic_prefix + \"button.startDemo\",\n payload: context.global.fbVars.config.button.startDemoInaktiv\n },\n {\n topic: context.global.fbVars.config.topic_prefix + \"button.stopDemo\",\n payload: context.global.fbVars.config.button.stopDemoInaktiv\n }\n ];\n\n if (context.global.fbVars.callgenerator.testcount >0) {\n return [msg,null];\n } else {\n return [null,msgbuttons];\n }\n}\nreturn [msg,null];\n","outputs":"2","valid":true,"x":1260.5,"y":3277.5,"z":"64b98f40.9b467","wires":[["14694b7e.eb96b5","8a1e1dc8.75e1e"],["88ec1bb8.7713e8","df08f41c.20f708"]]},{"id":"322d7a63.cdd286","type":"function","name":"Init Meldung","func":"msg.payload = \"Fritzbox Adapter Init\";\nreturn msg;","outputs":1,"valid":true,"x":1438.5,"y":1249.5,"z":"64b98f40.9b467","wires":[["3951e22b.c6ae1e"]]},{"id":"14694b7e.eb96b5","type":"debug","name":"","active":false,"console":"false","complete":"payload","x":1568.5,"y":3267.5,"z":"64b98f40.9b467","wires":[]},{"id":"88ec1bb8.7713e8","type":"debug","name":"","active":false,"console":"false","complete":"false","x":1568.5,"y":3301.5,"z":"64b98f40.9b467","wires":[]},{"id":"6305090e.9cfaf8","type":"ioBroker out","name":"[Pfad aus der Konfig].*","topic":"","ack":"true","autoCreate":"true","x":912.5,"y":3015.5,"z":"64b98f40.9b467","wires":[]},{"id":"fd1a661.f02e598","type":"function","name":"buttons Demo","func":"//msg.topic = context.global.fbVars.config.topic_prefix + \"button.startDemo\";\n//msg.payload = 'Demo läuft';\n\nvar msgbuttons = [\n {\n topic: context.global.fbVars.config.topic_prefix + \"button.startDemo\",\n payload: context.global.fbVars.config.button.startDemoAktiv\n },\n {\n topic: context.global.fbVars.config.topic_prefix + \"button.stopDemo\",\n payload: context.global.fbVars.config.button.stopDemoAktiv\n }\n];\n\nreturn [msgbuttons];\n","outputs":"1","valid":true,"x":702.5,"y":3015.5,"z":"64b98f40.9b467","wires":[["6305090e.9cfaf8"]]},{"id":"d0cd2e4.f2f32d","type":"function","name":"Stop Button \"gestoppt\"","func":"msg.topic = context.global.fbVars.config.topic_prefix + \"button.stopDemo\";\nmsg.payload = context.global.fbVars.config.button.stopDemoGestoppt;\n\nvar msg2 = {};\nmsg2.topic = context.global.fbVars.config.topic_prefix + \"button.startDemo\";\nmsg2.payload = context.global.fbVars.config.button.startDemoGestoppt;\n\n\nif (context.global.fbVars.callgenerator.testcalls > 0) {\n return [msg,msg2];\n} \n\nreturn [null,null];\n\n","outputs":"2","valid":true,"x":502.5,"y":3529.5,"z":"64b98f40.9b467","wires":[["df08f41c.20f708","8a36eb63.75c918"],["df08f41c.20f708"]]},{"id":"e7821d5e.187de","type":"ioBroker out","name":"[Pfad aud der Konfig] + Variablenname","topic":"","ack":"true","autoCreate":"true","x":578.5,"y":955.5,"z":"64b98f40.9b467","wires":[]},{"id":"9726285.f68d9d8","type":"debug","name":"","active":false,"console":"false","complete":"true","x":1542.5,"y":1197.5,"z":"64b98f40.9b467","wires":[]},{"id":"76724988.898db8","type":"debug","name":"","active":false,"console":"false","complete":"infoPushover","x":1572,"y":348,"z":"64b98f40.9b467","wires":[]},{"id":"968ea821.697158","type":"debug","name":"","active":false,"console":"false","complete":"infoEmail","x":1560,"y":384,"z":"64b98f40.9b467","wires":[]},{"id":"8a36eb63.75c918","type":"debug","name":"","active":true,"console":"false","complete":"false","x":766,"y":3522,"z":"64b98f40.9b467","wires":[]},{"id":"4458fd8a.bba704","type":"ioBroker out","name":"[Pfad aud der Konfig] + Variablenname","topic":"","ack":"true","autoCreate":"true","x":2540,"y":372,"z":"64b98f40.9b467","wires":[]},{"id":"83fef4b9.7c0108","type":"function","name":"verpasste Anrufe Button ändern","func":"context.global.fbVars = context.global.fbVars || {}; // wenn es das Objekt context.global.fbVars noch nicht gibt, wird dieses hier leer angelegt\ncontext.global.fbVars.zustand = context.global.fbVars.zustand || {};\n\n\nvar datum = new Date();\n\nvar year = datum.getFullYear();\nvar month = datum.getMonth()+1; \nvar day = datum.getDate();\nvar hour = datum.getHours();\nvar minute = datum.getMinutes();\nvar second = datum.getSeconds(); \nif(month.toString().length == 1) {\nvar month = '0'+month;\n}\nif(day.toString().length == 1) {\nvar day = '0'+day;\n} \nif(hour.toString().length == 1) {\nvar hour = '0'+hour;\n}\nif(minute.toString().length == 1) {\nvar minute = '0'+minute;\n}\nif(second.toString().length == 1) {\nvar second = '0'+second;\n} \n \ncontext.global.fbVars.zustand.verpasstSeit = (day + \".\" + month + \". \" + hour + \":\" + minute);\n\n\nmsg.topic = context.global.fbVars.config.topic_prefix + \"button.verpasstLöschen\";\n\nmsg.payload = 'seit dem
    ' + context.global.fbVars.zustand.verpasstSeit + \"
    löschen\";\n\n\nreturn msg;","outputs":"1","valid":true,"x":2258,"y":372,"z":"64b98f40.9b467","wires":[["4458fd8a.bba704","67496251.98b69c"]]},{"id":"a9dc66c1.562398","type":"function","name":"anzahlAlle (Summe der aktuellen Anrufer)","func":"msg.payload = context.global.fbVars.zustand.anzahlAlle;\nmsg.topic = msg.topic + \"anzahlAlle\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3264.0000915527344,"y":2241.9999980926514,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"bda72cb2.4258d","type":"function","name":"ringLetzter (für Wahlwiederholung letzte gewählte Rufnummer)","func":"context.global.fbVars.zustand.callLetzter = context.global.fbVars.zustand.callLetzter || \"\";\n\nmsg.payload = context.global.fbVars.zustand.callLetzter;\nmsg.topic = msg.topic + \"callLetzter\"; // Variablenname\n \nreturn msg;","outputs":1,"valid":true,"x":3322,"y":2100,"z":"64b98f40.9b467","wires":[["d11b4023.2ee4c"]]},{"id":"67496251.98b69c","type":"debug","name":"","active":true,"console":"false","complete":"false","x":2594,"y":412,"z":"64b98f40.9b467","wires":[]}]