NEWS
Datum und Zeitverarbeitung mit NodeRed
-
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
@rewenode Ja das wollte ich eigentlich verhindern - mit der externen Einbindung - da musst Du wieder an der settings.js rumbasteln, dass Du externe Bibliotheken verfügbar machst.
Konnte Deinen Flow auch nicht einbinden - da irgendein parse Error - aber Dank Deiner Erklärung konnte ich es auch nachvollziehen - allerdings auch nur in der Standalone Version:Ja, sorry. hatte es in einer stand alone version getestet.
Hier nochmal für die ioBroker Version.
Da gehts dann ganz einfach, wenn man einmal die moment.js eingebunden hat. Ein function-node ist dann nicht mehr nötig.- binde die moment.js über die settings.js ein.
Die befindet sich in
/opt/iobroker/node_modules/iobroker.node-red/settings.js
Dort muss di function functionGlobalContext um den Eintrag
moment:require("moment")
erweitert werden.
Beispiel aus meiner settings.ja
functionGlobalContext: { moment:require("moment") //'%%functionGlobalContext%%' // os:require('os'), // jfive:require("johnny-five"), // j5board:require("johnny-five").Board({repl:false}) },
Dann die node-red instanz neu starten.
Das wars.moment.duration kann in JSONata immer mit
$globalContext('moment.duration')
verwendet werden.
moment steht dann natürlich auch in function-nodes zur Verfügung.
Gruß
Reiner - binde die moment.js über die settings.js ein.
-
@rewenode Vielen Dank - die Anleitung ist sicher nützlich - wobei ich deswegen nun keine externe Bibliotheken einbinden würde. Aber in meiner Standalone Konfig habe ich das Duration Teil auch mal getestet, wie Du es wieder aufgelöst bekommst und es funktioniert !!!! - wenn man keine Wochen benutzt.
aber dann ist das Duration doch ganz nützlich - hier mal der Code:
( $b := $moment(timeB,['DD.MM.YYYY HH:mm:ss','x'],'de'); $a := $moment(timeA,['DD.MM.YYYY HH:mm:ss','x'],'de'); /* $b.diff($a) */ $d := $globalContext('md')($b.diff($a)); $difference := { "years" : $d.years(), "months":$d.months(), "weeks": $d.weeks(), "days": $d.days(), "hours":$d.hours(), "minutes":$d.minutes(), "seconds": $d.seconds() }; )
Das gute ist ja dass das richtig umgerechnet wird und wirklich Schaltjahre etc. alles berücksichtig wird.
Ausgangspunkt: 9.12.2021, 21:51:50
Als zu addierenden Zeitraum habe ich bewußt mal einen etwas redundanten Zeitraum genommen (2 Wochen und 30 Tage){ "years": 5, "months": 1, "weeks": 2, "days": 30, "hours": 3, "minutes": 47, "seconds": 28 }
Also dieser Zeitraum wird addiert und das Ergebnis ist verifiziert:
9.12.2021 + 5 Jahre = 9.12.2026
9.12.2026 + 1 Monat = 9.1.2027
9.1.2027 + 2 Wochen = 23.1.2027
23.1.2027 + 30 Tage = 22.2.2027 21:51:50
22.2.2027 21:51:50 + 3 Std. = 23.2.2027 0:51:50
23.2.2027 0:51:50 + 47 Minuten = 23.2.2027 1:38:50
23.2.2027 1:38:50 + 28 Sekunden = 23.2.2027 1:39:18Ausgangspunkt: 9.12.2021, 21:51:50
Das Duration Objekt liefert (wie gesagt - Wochen muss man rausnehmen){ "years": 5, "months": 2, "days": 13, "hours": 3, "minutes": 47, "seconds": 28 }
9.12.2021 + 5 Jahre = 9.12.2026
9.12.2026 + 2 Monate = 9.2.2027
9.2.2027 + 1 Woche = 16.2.2027
16.2.2027 + 13 Tage = 1.3.2027 ?????????
9.2.2027 + 13 Tage = 22.2.2027 21:51:50
22.2.2027 21:51:50 + 3 Std. = 23.2.2027 0:51:50
23.2.2027 0:51:50 + 47 Minuten = 23.2.2027 1:38:50
23.2.2027 1:38:50 + 28 Sekunden = 23.2.2027 1:39:18 -
@rewenode In Zukunft wäre es hilfreich Spoiler und CodeTags zu nutzen - sonst muss man immer scrollen um den Code zu kopieren.
Der Import geht aber im Moment trotzdem nicht - manche Flows mögen irgendwie nicht.
Aber egal - ich hab das ja erst mal miteinbinden können und auch testen können mit dem Durations Objekt - also vielen Dank Dir dafür.
-
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
@rewenode In Zukunft wäre es hilfreich Spoiler und CodeTags zu nutzen - sonst muss man immer scrollen um den Code zu kopieren.
Ah, sorry. Bin halt zu selten hier. Hab's grad korrigiert und einen Reimport getestet, also bei mir gehts.
Gruß
Reiner -
@rewenode sagte in Datum und Zeitverarbeitung mit NodeRed:
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
@rewenode In Zukunft wäre es hilfreich Spoiler und CodeTags zu nutzen - sonst muss man immer scrollen um den Code zu kopieren.
Ah, sorry. Bin halt zu selten hier. Hab's grad korrigiert und einen Reimport getestet, also bei mir gehts.
Gruß
ReinerJa mit den CodeTags geht es - da funkt der Browser nicht dazwischen. Das ist ja die Version ohne function Node aber global verfügbarer moment Bibliothek - aber wie gesagt ich habe es ja nun ausprobiert - und mit Deiner Anleitung geht es ja direkt.
( $b := $moment(timeB,['DD.MM.YYYY HH:mm:ss','x'],'de'); $a := $moment(timeA,['DD.MM.YYYY HH:mm:ss','x'],'de'); /* $b.diff($a) */ /* $moment.duration($b.diff($a)); */ $globalContext('moment.duration')($b.diff($a)).humanize() )
Aber wie gesagt - nur dafür würde ich moments nicht extra einbinden. Im Prinzip ist es halt nur die exakte Umrechnung von Zeitperioden erforderlich - ansonsten war ja gerade der Sinn des Postings - was alles mit Boardmitteln geht.
Für die eigentliche Umrechnung - für die aus meiner Sicht das Duration Objekt nützlich ist, habe ich ja unten gepostet.
-
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
Aber wie gesagt - nur dafür würde ich moments nicht extra einbinden. Im Prinzip ist es halt nur die exakte Umrechnung von Zeitperioden erforderlich - ansonsten war ja gerade der Sinn des Postings - was alles mit Boardmitteln geht.
Ja, wollte nur eine Möglichkeit zeigen, moment.duration in node-red JSONata zugänglich zu machen.
Kann ja mal hilfreich sein, zumal man sich über diesen Trick nahezu beliebige Bibliotheken in JSONata zugänglich machen kann.Ja, und was Bordmittel angeht, sind bei mir immer die die ich zur Lösung des Problems unbedingt brauche und die in node-red prinzipiell möglich sind;-)
Aber generell stimme ich zu, auch wenn man Vieles nicht so eng sehen darf.
Ich glaube nicht, dass eine komplexe JSONata-Funktion im change-node weniger undurchsichtig ist, wie die gleiche Funktionalität per Javascript im function-node.Gruß
Reiner -
@rewenode sagte in Datum und Zeitverarbeitung mit NodeRed:
Ja, und was Bordmittel angeht, sind bei mir immer die die ich zur Lösung des Problems unbedingt brauche und die in node-red prinzipiell möglich sind;-)
Aber generell stimme ich zu, auch wenn man Vieles nicht so eng sehen darf.
Ich glaube nicht, dass eine komplexe JSONata-Funktion im change-node weniger undurchsichtig ist, wie die gleiche Funktionalität per Javascript im function-node.Grundsätzlich stimme ich Dir zu - wobei ich function Nodes wirklich nur nutze, wenn alles andere sehr umständlich ist - weil ich eben denke, dass man sich die ganze Genialität von Node Red zunichte machen kann, wenn man zuviel in function Nodes packt. Sehe ich leider sehr häufig auch in Beispielen. Letzlich kannst jeden Flow in eine function Node packen - aber dann brauche ich Node Red nicht - sondern kann ja - zumindest im iobroker - Javascript original schreiben. - OK als Standaloneversion hat man mit Node Red halt noch die Hardwareanbindung zur Verfügung. Aber die Klärung philosophischer Fragen sind dann wohl eher OT.
-
So noch ein paar Ergänzungen bzw. neue Erkenntnisse - wenn man es braucht.
Um Switch Nodes mit Zeitfenstern zu definieren - kann man die moments Bibliothek wie folgt nutzen:
Ohne 3. Parameter bei dem Moments Funktion isBetween() - kann man dann über eckige bzw. runde Klammern noch angeben, ob die Anfangs- bzw. Endzeiten aus bzw. eingeschlossen sind in dem definierten Zeitraum.
Ohne Angabe ist die Anfangszeit eingeschlossen, die Endzeit ausgeschlossen!!!Braucht man wieder über Nachtzeiträume negiert man das entweder oder nutzt den false Ausgang.
Am sichersten ist man, wenn man 2 moments Objekte vergleicht und dann auch noch die Genauigkeit spezifiziert:
$moment().isBetween($moment("10:48", "HH:mm"),$moment("17:05", "HH:mm"),'minute')
Das 1. moments Objekt ist Anfangszeit mit Format zu richtigen Interpretation, das 2. moments Objekt die Endzeit mit Format zur richtigen Interpretation und die Genauigkeit ist auf Minute gesetzt.
-
@mickym Wieder ein Test der positiv verlief mit der Moment Bibliothek.
Auch die Verarbeitung von Monatsnamen um moment-Objekte zu erstellen, funktioniert einwandfrei:
$moment(payload,'DD.MMMM YYYY','de').format('DD.MM.YY - HH:mm')
Auch Umlaute wie März werden korrekt verarbeitet.
Bei abgekürzten Monatsnamen muss man im Deutschen darauf achten, dass die Strings immer mit 4 Zeichen abgekürzt werden.
$moment(payload,'DD.MMM. YYYY','de').format('DD.MM.YY - HH:mm')
Sind die Monatsnamen 4 Buchstaben oder kürzer werden sie voll ausgeschrieben (wichtig also März ausschreiben), ansonsten die ersten 3 Buchstaben + Punkt. Eine ähnliche Absonderlichkeit ergab sich bei 3stelligen Wochentagsnamen die immer 2 Buchstaben + Punkt enthalten:
-
Einen weitere Anwendung bzw. Flow - um Zeitspannen der moments- Bibliothek zu nutzen, um sich in seiner Visualisierung nicht den Zeitstempel der letzten Meldung, sondern die Zeitspanne seit der letzten Meldung ausgeben zu lassen.
etwas später:
Die Texte werden automatisch durch die Humanize Funktion ausgegeben und sind also nicht änderbar und folgen folgendem Schema:
Ich gebe es hier direkt im NR-Dashboard aus, man könnte es aber auch natürlich in eigene Datenpunkte schreiben lassen und diese dann im VIS oder einer anderen Visualisierung ausgeben lassen. Es werden ja Strings zurückgegeben.
Alle Geräte der letzte Meldungstatus man anzeigen lassen will, leiten man in einen zentralen Flow:
Die Daten werden alle im Flowtext gesammelt und momentan nicht mit einem festen zeitlichen Trigger ausgegeben, sondern sobald sich ein Gerät meldet, werden alle anderen mit aktualisiert. Das belastet das System weniger. Man könne aber einen zeitlichen Trigger leicht realisieren, indem man die Inject-Node triggern lässt. Ansonsten triggert für Node-Red Dashboard Nutzer natürlich auch ein Wechsel der Seiten.
Hiermal der Kern des Flows - für Ein- und Ausgang muss man selbst sorgen. Für die einzelnen Geräte wird immer das topic zur Identifikation genutzt (ggf. muss man der Nachricht halt selbst ein Topic verpassen).
-
Hier mal wieder eine genial, einfache Methode, wie man verschiedene Bestandteile eines Datums mit Hilfe der moments library analysieren und als Objekt zur Verfügung stellen kann - um sie ggf. auch dann wieder in einzelne Datenpunkte zu zerlegen.
Als erstes nutzt man halt den Formatstring, um verschiedene Bestandteile des Datums zu ermitteln und trennt diese mit Kommas.
Zum Beispiel:
$moment().format('YYYY,Q,M,DDD,W,e,H')
Das Ganze soll auch noch in Zahlenwerte konvertiert werden - deshalb habe ich alles vermieden, was Wörter ausspuckt.
YYYY = gibt die 4 stellige Jahreszahl an
Q = das Quartal (1-4)
M = der Monat (1-12)
DDD = Tag des Jahres (1-365(bzw. 366))
W = Kalenderwoche europäisch
e = Wochentag beginnend mit 0 = So.
H = Stunde (0-23)Der Trick ist nun, dass man einfach eine CSV Node zur Konvertierung nutzt.
Mit Zahlenwerte ermitteln wird automatisch die Konvertierung durchgeführt und mit den Namen als Spalte werden die Objekteigenschaften gleich richtig benannt.
Somit ergibt dieser Flow - ein Objekt mit den entsprechenden Eigenschaften:
Hier der einfache Flow:
-
Hier mal wieder eine neue Anwendung mit der $moments Bibliothek um zu überprüfen ob der aktuelle Zeitpunkt in einem von mehreren definierten Zeitfenstern liegt.
Praktische Anwendung könnte zum Beispiel sein, dass ein Gerät oder Heizung zu bestimmten Zeit innerhalb eines Tages eingeschaltet werden soll oder nicht. Dies habe ich gerade als Lösungsvorschlag für einem Beispielflow erstellt.
Die Prüfung der Zeitfenster speichert man in einem Array:
Zum Schluss verknüpft man alle Arraywerte mit ODER, um zu überprüfen, ob aktuell eines der definierten Zeitfenster WAHR ist und gibt das Ergebnis als ein Boolean aus.
Außerdem wird hier die Anwendung des Ein- und Ausschlusses der Zeitgrenzen gezeigt. Normalerweise sind die angegebenen Zeitgrenzen ausgeschlossen. Mit eckigen Klammern schließt man diese ein, mit runden Klammern schließt man sie aus.
Das Beispiel
[)
schließt also den Anfang ein, das Ende aus.Ergänzung: Man kann das ganze natürlich auch in einen Ausdruck verfrachten, dann schaut das noch schöner aus:
-
Hallo zusammen, ich habe auch ein Problem mit der Zeit... wer hat das nicht
Ich möchte in der Regelung meiner Solaranlage den Wechselrichter abschalten, wenn er eine bestimmte Zeit keine Werte mehr über meinen DTU Adapter zu meinem Flow gesendet hat. Das kommt manchmal vor und um zu verhindern, daß mein Solarakku zu tief entladen wird, soll der Wechselrichter abgeschaltet werden. Dazu möchte ich den " timestamp of last inverter statistics udpate" mit der aktuellen Uhrzeit vergleichen und wenn die Differenz der beiden z.B. größer als 10 min ist, soll der Befehl zum Abschalten erfolgen. Ich weiß, wie ich den " timestamp of last inverter statistics udpate" mit einer iobroker Node auslese und wie ich abschalte, aber wie ich die beiden Zeiten verwenden und daraus eine Differenzüberschreitung ermitteln kann ist mir noch unklar.
Vielleicht kann mir ja hier jemand helfen... besten Dank im Voraus...
-
@bernhard59 Für so was nutzt man eine trigger Node und führt keine Berechnungen durch.
-
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
@bernhard59 Für so was nutzt man eine trigger Node und führt keine Berechnungen durch.
Danke für die schnelle Antwort... und wie funktioniert das ?
-
@bernhard59 sagte in Datum und Zeitverarbeitung mit NodeRed:
@mickym sagte in Datum und Zeitverarbeitung mit NodeRed:
@bernhard59 Für so was nutzt man eine trigger Node und führt keine Berechnungen durch.
Danke für die schnelle Antwort... und wie funktioniert das ?
und halt vorne dran die Node oder die Nachrichten die Du sonst empfängst, also parallel schalten. Sind die 10 Minuten abgelaufen, wird der trigger automatisch wieder scharf-
-
Danke... dann versuche ich das mal...
-
Perfekt, es funktioniert und soooo einfach... DANKE
-
@bernhard59 sagte in Datum und Zeitverarbeitung mit NodeRed:
Perfekt, es funktioniert und soooo einfach... DANKE
Ja Node-Red halt.
-
Jetzt habe ich das nächste Problem und vielleicht kannst du mir wieder helfen...
Ich möchte mir, wenn die Datenübertragung mit der DTU längere Zeit nicht funktioniert eine Mail schicken. Das habe ich auch an anderen Stellen im Flow schon gemacht und es funktioniert einwandfrei.
Ich lese ja den Unix-Zeitstempel der letzten Aktualisierung der Wechselrichterstatistik mit einem iobroker In Nodes ein und werte diesen dann mit einen Trigger aus und wenn dann eine bestimmte Zeit keine Aktualisierung stattgefunden hat, möchte ich eine Mail bekommen. Das funktioniert auch alles, nur die Mail Nodes sagt dann "Senden fehlgeschlagen" und bringt folgende Fehlermeldung:
"Error: Mail command failed: 550-Requested action not taken: mailbox unavailable 550 Sender address is not allowed."Wenn ich aber mit einem Injekt Nodes vor dem Trigger einen Timestamp schicke, geht die Mail einwandfrei raus... ich habe schon alle möglichen Einstellungen probiert... kein Erfolg.
Kennst du dich da aus?