[gelöst] Syntax zur Verwendung von $hms in Userreadings

Begonnen von Wolle02, 06 Juli 2022, 14:52:20

Vorheriges Thema - Nächstes Thema

Wolle02

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?

Beta-User

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?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Wolle02

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.

MadMax-FHEM

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
FHEM PI3B+ Bullseye: HM-CFG-USB, 40x HM, ZWave-USB, 13x ZWave, EnOcean-PI, 15x EnOcean, HUE/deCONZ, CO2, ESP-Multisensor, Shelly, alexa-fhem, ...
FHEM PI2 Buster: HM-CFG-USB, 25x HM, ZWave-USB, 4x ZWave, EnOcean-PI, 3x EnOcean, Shelly, ha-bridge, ...
FHEM PI3 Buster (Test)

Wolle02

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.

Beta-User

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]!
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Wolle02

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?

Beta-User

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.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

betateilchen

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.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Wolle02

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?

Beta-User

#10
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 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), 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
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

Wolle02


Wolle02

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?

betateilchen

#13
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.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

#14
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...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files