FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: Wolle02 am 06 Juli 2022, 14:52:20

Titel: [gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 06 Juli 2022, 14:52:20
In der CommanRef steht folgendes:
ZitatUm die Verwendung von Datum und Zeitangaben zu vereinfachen, wurden die Variablen $sec, $min, $hour, $mday, $month, $year, $wday, $yday, $isdst und $hms für die Verwendung in PERL-"oneliners" eingeführt (s. unter perldoc -f localtime). Ausnahmen: $month hat einen Wertebereich von 1 bis 12 und $year ist korrigiert von 1900. Weiterhin enthält $hms die Zeit in dem HH:MM:SS Format und $today das aktuellen Datum in YYYY-MM-DD Format.

Ich verstehe mal wieder nicht wie ich $hms jetzt in einem Userreading verwenden kann, damit ich damit weiterrechnen kann. Wenn ich einfach $hms verwende, bekomme ich natürlich folgende Fehlermeldung:
Zitat2022.07.06 14:33:15 1: Error evaluating openWB_LP1 userReading kWhExported_day_init: Global symbol "$hms" requires explicit package name (did you forget to declare "my $hms"?) at (eval 9615721) line 1.
Global symbol "$hms" requires explicit package name (did you forget to declare "my $hms"?) at (eval 9615721) line 1.

Ich muss also $hms erst deklarieren. Nur wie?
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 06 Juli 2022, 15:02:55
Vielleicht zeigst du, wie du weiterrechnen willst; diese Variablen sind nicht in allen "Kontexten" verfügbar (u.a., weil sie erst "teuer erzeugt" werden müßten). Wenn du einfach einen Sekundenwert haben willst, wäre ggf. "gettimeofday" (iVm. int) eine Lösung?
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 06 Juli 2022, 15:49:12
Tja, das Weiterrechnen ist auch nicht wirklich schön gelöst (wenn es überhaupt so funktioniert). Folgendes habe ich mir vorgestellt:
kWhExported_day_init {my $Ei = (ReadingsVal($name,"WhExported",0))/1000; if ($hms gt "00:00:00" && $hms lt "00:00:30") {return $Ei}}

Ziel soll sein, dass das Reading kWhExported_day_init zwischen 00:00:00 Uhr und 00:00:30 Uhr den aktuellen Wert vom Reading WhExported/1000 annimmt. Da ein Event, das das Userreading triggert wahrscheinlich nie genau um 00:00:00 Uhr kommt, aber die Wahrscheinlichkeit, dass eines innerhalb der ersten 30 Sekunden des Tages kommt, habe ich mir dieses "Konstrukt" überlegt. Aber dafür brauche ich halt $hms.
Wenn du einen besseren Weg hast -> sehr gerne.
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: MadMax-FHEM am 06 Juli 2022, 15:55:09
Zitat von: Wolle02 am 06 Juli 2022, 15:49:12
Da ein Event, das das Userreading triggert wahrscheinlich nie genau um 00:00:00 Uhr kommt, aber die Wahrscheinlichkeit, dass eines innerhalb der ersten 30 Sekunden des Tages kommt, habe ich mir dieses "Konstrukt" überlegt. Aber dafür brauche ich halt $hms.
Wenn du einen besseren Weg hast -> sehr gerne.

Ein Event, das zu einer bestimmten Uhrzeit kommt: at ;)

Dort dann einfach ein: setreading Devicename Readingname ReadingsNum("Devicename","Readingname",Ersatzwert)/1000

Gruß, Joachim
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 06 Juli 2022, 16:01:00
Manchmal sieht man den Wald vor lauter Bäumen nicht. Das ist natürlich ein bestechendes Argument von dir.  ::) Das einzige was mir dabei nicht gefällt ist, dass ich dafür wieder ein neues Device brauche. Ich versuche immer möglichst alles in einem Device zu lösen.

Aber so ist das schön im Forum; da kommen einfach andere Sichtweisen auf das Problem.

Vielen Dank.
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 06 Juli 2022, 16:18:23
Hmmm, falls du doch noch mit userReadings weitermachen willst:
Wirf mal das hier in die FHEM-Kommandozeile
{(localtime)[1]}
Abfrage wäre dann: keine Stunde, keine Minute, Sekunde kleiner 30, und ReadingsAge vom userReading > 30...

userReadings ohne trigger sind übrigens [denk dir was]!
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 06 Juli 2022, 17:28:30
Sehr gerne würde ich auch mit Userreading weitermachen, wenn das da auch lösbar ist.

ZitatWirf mal das hier in die FHEM-Kommandozeile
Code:
{(localtime)[1]}

Ok, da kommt jetzt 24 raus. Was die 24 aussagt weiß ich aber nicht.

ZitatAbfrage wäre dann: keine Stunde, keine Minute, Sekunde kleiner 30, und ReadingsAge vom userReading > 30...

Das verstehe ich nicht.

ZitatuserReadings ohne trigger sind übrigens [denk dir was]!

Warum soll das [denk dir was] sein? Laut CommandRef ist der Trigger optional. In diesem Fall habe ich ihn auch bewusst weggelassen, weil ich ja nicht auf ein bestimmtes Event triggern kann, weil ich ja nicht weiß welches Event in dem Zeitraum kommt.
Gibts einen tieferen Grund für [denk dir was] oder ist das eher Religion?
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 06 Juli 2022, 17:40:17
Zitat von: Wolle02 am 06 Juli 2022, 17:28:30
Sehr gerne würde ich auch mit Userreading weitermachen, wenn das da auch lösbar ist.

ZitatOk, da kommt jetzt 24 raus. Was die 24 aussagt weiß ich aber nicht.
Mit https://perldoc.perl.org/functions/localtime sollte sich erschließen lassen, welches Element des Arrays da abgegriffen wird.

ZitatDas verstehe ich nicht.
in Code wäre das dann in die Richtung:
return if ((localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,<selber machen>) < 30)

ZitatWarum soll das [denk dir was] sein? Laut CommandRef ist der Trigger optional. [...] oder ist das eher Religion?
Es ist eine Frage der Effizienz. Meine allerdringlichste Empfehlung: Mach ÜBERALL an userReadings einen Trigger hin!

Wir hatten hier schon haufenweise Fälle, in denen jemand meinte, es sei "optional" und sich dann gewundert hat, warum alles mögliche nicht klappt, was er mit dem userReading vorgehabt hatte...
Das ist vor allem dann ein Problem, wenn es sich um sehr gesprächige Devices handelt (Geräte zur Ermittlung des Energieverbrauchs fallen häufig darunter!) und die Events nicht als "Stapel" kommen.

Zitat
In diesem Fall habe ich ihn auch bewusst weggelassen, weil ich ja nicht auf ein bestimmtes Event triggern kann, weil ich ja nicht weiß welches Event in dem Zeitraum kommt.
Meine Empfehlung wäre, das rauszufinden...
Lieber den Zeitraum (und die ReadingsAge-Abfrage) etwas großzügiger fassen.
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: betateilchen am 06 Juli 2022, 19:28:44
Zitat von: Wolle02 am 06 Juli 2022, 15:49:12
if ($hms gt "00:00:00" && $hms lt "00:00:30")

Wenn du einen besseren Weg hast -> sehr gerne.

klar...
if (secondsFromMidNight() < 30)

die Funktion secondsFromMidnight() kann problemlos in der 99_myUtils.pm untergebracht werden:


sub secondsFromMidnight{
my @time = localtime();
return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
}


offtopic: in meiner 99_myUtils.pm gibt es auch noch das Gegenstück dazu:


sub secondsToMidnight{
return DAYSECONDS - secondsFromMidnight();
}


Das macht die Berechnung innerhalb eines Tages an vielen Stellen einfacher.
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 07 Juli 2022, 15:18:42
Vielen Dank @Beta-User und @betateilchen für Eure Lösungsvorschläge. Das werd ich alles ausprobieren und umsetzen. Da ist die Lernkurve mal wieder steil; nur leider die Halbwertszeit auch.

Nur der Vollständigkeit halber wegen meiner Ausgangsfrage und falls jemand mal auch so ein Problem hat: Wie könnte ich die Variable $hms, die laut der CommanRef ja vorhanden ist auch verfügbar machen?
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 07 Juli 2022, 15:31:36
Zitat von: Wolle02 am 07 Juli 2022, 15:18:42
Nur der Vollständigkeit halber wegen meiner Ausgangsfrage und falls jemand mal auch so ein Problem hat: Wie könnte ich die Variable $hms, die laut der CommanRef ja vorhanden ist auch verfügbar machen?
Code in userReadings dürfte eher nicht in die Kategorie "Perl-oneliner" fallen, die in der commandref genannt ist. Das taucht in fhem.pl an genau einer Stelle auf: https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L1154 (https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L1154) und gehört in den Kontext von AnalyzePerlCommand(). userReadings werden darüber aber nicht evaluiert, sondern über ein "simples" (string-) eval (https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L4906 (https://svn.fhem.de/trac/browser/trunk/fhem/fhem.pl#L4906)), was etwas weniger teuer ist.

Kurz: Es geht nicht, es sei denn, du machst es selbst verfügbar oder rufst explizit diesen Umweg auf... (und das wäre beides "durch die Brust..."). Die Varianten von betateilchen und mir sind da deutlich effizienter, wobei ersterer $dst nicht berücksichtigt (*duck und weg*)...

EDIT - Nachtrag noch zu
Zitat von: Wolle02 am 06 Juli 2022, 17:28:30
Laut CommandRef ist der Trigger optional.
Das würde vermutlich auch hier helfen: https://forum.fhem.de/index.php/topic,12655.msg1226662.html#msg1226662 (https://forum.fhem.de/index.php/topic,12655.msg1226662.html#msg1226662)
Titel: Antw:Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 07 Juli 2022, 18:12:39
Danke. Ich markiere mal als [gelöst].
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 09 Juli 2022, 09:41:51
Jetzt hab ich doch nochmal ein paar Fragen:

@Beta-User:
Ich habe initial deine vorgeschlagene Bedingung ausprobiert.
return if ((localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,<selber machen>) < 30)
Hierbei wird das Userreading dann permanent neu gesetzt; egal welche Zeit es ist. Eigentlich auch nachvollziehbares Verhalten, da ja eine ODER-Verknüpfung verwendet wird, die irgendwie immer wahr ist. Ich habe dann rumexperimentiert und einen genauen Zeitrahmen in die Bedingung gepackt und mit einer UND-Verknüpfung versehen:
kWhExported_day_init:Timestamp.* {my $Ei = (ReadingsVal($name,"WhExported",0))/1000; if ((localtime)[1] == 14 && (localtime)[2] == 9 && (localtime)[0] < 29 && ReadingsAge($name,"kWhExported_day_init",0) > 30)  {return $Ei}},

Jetzt wird die Bedingung gar nicht mehr wahr und das Userreading bleibt leer.

Wenn ich in der Bedingung das ReadingsAge weglasse:
kWhExported_day_init:Timestamp.* {my $Ei = (ReadingsVal($name,"WhExported",0))/1000; if ((localtime)[1] == 18 && (localtime)[2] == 9 && (localtime)[0] < 29)  {return $Ei}},
dann wird die Bedingung im eingestellten Zeitraum wahr und das Userreading gefüllt.
Komisch ist nur, dass wenn der Zeitraum nicht mehr wahr ist, dann bleibt das Userreading nicht mit dem letzten Wert gefüllt, sondern wird geleert. Dieses Verhalten verstehe ich nicht.


@betateilchen:
ich habe deine Sub in meine 99_myUtils übernommen:
sub secondsFromMidnight {
my @time = localtime();
return (($time[2] * HOURSECONDS) + ($time[1] * MINUTESECONDS) + $time[0]);
}


Im Userreading habe ich folgendes stehen:
kWhExported_day_init:Timestamp.* {my $Ei = (ReadingsVal($name,"WhExported",0))/1000; if (secondsFromMidnight() < 30) {return $Ei}},

Leider wird auch hier das Userreading ständig aktualisiert, egal wieviele Sekunden seit Mitternacht vergangen sind. Irgendwie wird die Bedingung ignoriert.

Wo sind meine Denkfehler?
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: betateilchen am 09 Juli 2022, 10:19:10
Zitat von: Wolle02 am 09 Juli 2022, 09:41:51
@betateilchen:

Im Userreading habe ich folgendes stehen:
kWhExported_day_init:Timestamp.* {my $Ei = (ReadingsVal($name,"WhExported",0))/1000; if (secondsFromMidnight() < 30) {return $Ei}},

Leider wird auch hier das Userreading ständig aktualisiert, egal wieviele Sekunden seit Mitternacht vergangen sind. Irgendwie wird die Bedingung ignoriert.

Wo sind meine Denkfehler?

Irgendwie finde ich Deine verwendete perl Syntax fürchterlich kompliziert und stellenweise durch zu viele Klammern sogar falsch.

kWhExported_day_init:Timestamp.* {ReadingsVal($name,"WhExported",0)/1000 if (secondsFromMidnight() < 30)}

sollte meiner Meinung nach funktionieren.
Wenn das nicht klappt, solltest Du mal auf verbose 4 oder 5 stellen und dann das Log posten, damit man sieht, wo die korrekte Berechnung des userreading scheitert.
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 09 Juli 2022, 11:15:11
Zitat von: Wolle02 am 09 Juli 2022, 09:41:51
@Beta-User:
Ich habe initial deine vorgeschlagene Bedingung ausprobiert.
return if ((localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,<selber machen>) < 30)
Hierbei wird das Userreading dann permanent neu gesetzt; egal welche Zeit es ist. [...]
Wo sind meine Denkfehler?
Du hast das mit dem return an der falschen Stelle eingebaut bzw. missverstanden:
kWhExported_day_init:Timestamp.* {return if (localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,'hWhExported',31) < 30; return ReadingsVal($name,'WhExported',0)/1000}
Erklärung: sobald entweder die Minute nicht 0 ist (59/60 Fälle!) oder dasselbe für Stunde gilt (23/24 der verbleibenden Fälle!) => mach nichts! Ergo: nur in 1/60/24 Fällen wird überhaupt irgendwas weitergerechnet...
Dann dasselbe nochmal für die Minutenberachtung und das (relativ teure) Alter des userReadings...
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: betateilchen am 09 Juli 2022, 11:21:57
Zitat von: Wolle02 am 09 Juli 2022, 09:41:51
Leider wird auch hier das Userreading ständig aktualisiert, egal wieviele Sekunden seit Mitternacht vergangen sind. Irgendwie wird die Bedingung ignoriert.

Wo sind meine Denkfehler?

Ok, ich habe das jetzt mal hier mit dem vorgeschlagenen Weg nachgebaut. Das userReading wird tatsächlich immer aktualisiert, aber die Berechnung des Wertes, der in das Userreading geschrieben wird, funktioniert korrekt mit secondsFromMidnight().

Man muss dafür sorgen, dass im "Negativfall" ein undef als Ergebnis geliefert wird, dann bleibt die Aktualisierung des userReadings aus.

attr test userReadings kWhExported_day_init:Timestamp.* {(secondsFromMidnight() < 30) ? ReadingsVal($name,"WhExported",0)/1000 : undef }
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 09 Juli 2022, 11:29:27
Zitat von: betateilchen am 09 Juli 2022, 11:21:57
Man muss dafür sorgen, dass im "Negativfall" ein undef als Ergebnis geliefert wird, dann bleibt die Aktualisierung des userReadings aus.
Jein. Es braucht eigentlich kein explizites undef, nur wird eben in dem postfix-if-Fall wohl das Ergebnis der letzten Prüfung zurückgemeldet, und die dürfte eben "0" sein...
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: betateilchen am 09 Juli 2022, 11:47:40
Zitat von: Beta-User am 09 Juli 2022, 11:29:27
Es braucht eigentlich kein explizites undef

Doch. Wenn Du es nicht glaubst, probier es einfach aus.
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Beta-User am 09 Juli 2022, 12:56:11
Zitat von: betateilchen am 09 Juli 2022, 11:47:40
probier es einfach aus.
done:
defmod tdummy dummy
attr tdummy userReadings kWhExported_day_init:Timestamp.* {return if (localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,'kWhExported',31) < 30;; return ReadingsVal($name,'WhExported',0)/1000},\
kWhExported_day_init2:Timestamp.* {if ((localtime)[1] || (localtime)[2] || (localtime)[0] > 29 || ReadingsAge($name,'kWhExported2',31) < 30) {return;;} return ReadingsVal($name,'WhExported',0)/1000},\
kWhExported_day_init3:Timestamp.* {if (!(localtime)[1] || !(localtime)[2] || ReadingsAge($name,'kWhExported3',31) < 30) {return;;} return ReadingsVal($name,'WhExported',0)/1000}

setstate tdummy 2022-07-09 12:55:21 Timestamp 1
setstate tdummy 2022-07-09 12:51:45 WhExported 222
setstate tdummy 2022-07-09 12:55:21 kWhExported_day_init3 0.222
Titel: Antw:[gelöst] Syntax zur Verwendung von $hms in Userreadings
Beitrag von: Wolle02 am 10 Juli 2022, 09:37:55
Vielen Dank @Beta-User und @betateilchen für eure Unterstützung und Erklärungen. Das Userreading wird mit der Variante von betateilchen nun korrekt befüllt. Bei der Varainte von Beta-User muss ich zugegebenermaßen noch etwas rumexperimentieren bis ich die Logik wirklich kapiert habe.
Jedenfalls glaube ich wieder was gelernt zu haben.  :D