Es gibt ja immer wieder den Wunsch, am Monatsletzten um 23:59 Uhr irgendwelche Aufgaben von FHEM erledigen zu lassen (z.B. bestimmte Monatswerte loggen).
Bisher ist der gerne zitierte Lösungsweg "prüfe jeden Tag um 23:59, ob morgen ein neuer Monat ist. Wenn nicht, mache nix."
Dafür existiert dann ein at, das 30 von 31 Mal im Monat überhaupt nix zu tun hat. Effektiv ist das nicht.
Mit der hier beschriebenen Funktion ultimo() wird die Aufgabe eleganter gelöst.
Die Funktion kann man in die 99_myUtils.pm einbauen und dann verwenden.
sub ultimo {
my ($h,$m,$s) = @_;
$h //= 23;
$m //= 59;
$s //= 0;
my $add = $data{AT_RECOMPUTE} == 1 ? DAYSECONDS : 0;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time+$add);
my ($nm, $ny) = ($mon == 11) ? (0,$year+1) : ($mon+1,$year);
return timelocal($s,$m,$h,1,$nm,$ny) - DAYSECONDS;
}
Man definiert einmalig ein wiederholendes at device, bei dem das Ergebnis aus der Funktion als Zeitangabe verwendet wird.
defmod at_ultimo at *{ultimo} {}
Damit wird ein at angelegt, das jeweils am letzten Tag des Monats um 23:59 Uhr irgendwas ausführt (im Beispiel wird nix gemacht, deshalb stehen da nur die zwei geschweiften Klammern).
Internals:
COMMAND {}
DEF *{ultimo} {}
FUUID
NAME at_ultimo
NR 269
PERIODIC yes
RELATIVE no
REP -1
STATE Next: 2021-01-31 23:59:00
TIMESPEC {ultimo}
TRIGGERTIME 1612133940
TRIGGERTIME_FMT 2021-01-31 23:59:00
TYPE at
READINGS:
2020-12-31 23:59:00 state Next: 2021-01-31 23:59:00
Attributes:
Wie man am reading "state" erkennt, wurde das at gestern Abend um 23:59 Uhr ausgeführt und dann der nächste Ausführungszeitpunkt für den 31.01.2021 ermittelt.
Für Fortgeschrittene: man kann den Funktionsaufruf auch um eine Uhrzeit ergänzen. ultimo(17,23,45) würde ein at anlegen, das am Monatsletzten um 17:23:45 Uhr ausgeführt wird. Die Angabe ist optional, standardmäßig wird 23:59 Uhr verwendet.
Mein Vorschlag/Wunsch wäre, dass die Funktion innerhalb von FHEM bereitgestellt wird, entweder im at-Modul selbst oder in der 99_Utils.pm.
Sollte dies befürwortet werden, wird der fehlende commandref-Teil zur Funktion natürlich noch von mir nachgeliefert.
--
Wenn die Aufnahme auch von Anderen gewuenscht wird, dann werde ich es machen.
Vorschlag: 90_at.pm, es sei denn jemandem faellt es ein, wie es mit anderen Modulen verwendbar ist.
Eine flexiblere aber auch aufwendigere Variante ist die Abfrage einer selbstdefinierten holiday-Instanz.
Zitat von: rudolfkoenig am 01 Januar 2021, 12:51:34
Eine flexiblere aber auch aufwendigere Variante ist die Abfrage einer selbstdefinierten holiday-Instanz.
Dazu bräuchte man aber mindestens zwei devices, zum Einen die holiday Instanz selbst und zum Anderen ein notify oder at oder irgendwas anderes, um die holiday Instanz auszuwerten.
Außerdem müsst das holiday-file regelmäßig (z.B. Schaltjahr) manuell gepflegt werden.
Ich dachte eher an etwas wie
define myAt at *17:23:45 { fhem("set lamp on") if(Value("MyHoliday") eq "ultimo") }
Aber ich will es gar nicht als die bessere Loesung anpreisen, man muss definitiv ein holiday definieren und die Datei manuell fuellen.
Genau DIESES Vorgehen hatte ich doch eingangs beschrieben, und genau das wollte ich ändern: Dein at wird jeden Tag ausgeführt und hat 30 von 31 Mal pro Monat nix zu tun 8)
Zitat von: betateilchen am 01 Januar 2021, 12:09:53
EBisher ist der gerne zitierte Lösungsweg "prüfe jeden Tag um 23:59, ob morgen ein neuer Monat ist. Wenn nicht, mache nix."
Dafür existiert dann ein at, das 30 von 31 Mal im Monat überhaupt nix zu tun hat.
Das ist richtig, die Konfiguration moechte ich aber sehen, wo man das merkt.
Zitat von: betateilchen am 01 Januar 2021, 12:09:53
wird der fehlende commandref-Teil zur Funktion natürlich noch von mir nachgeliefert.
für den Fall der Fälle :)
Index: 90_at.pm
===================================================================
--- 90_at.pm (Revision 23474)
+++ 90_at.pm (Arbeitskopie)
@@ -445,7 +445,7 @@
any spaces or tabs.<br>
<datespec> is either ISO8601 (YYYY-MM-DDTHH:MM:SS) or number of
- seconds since 1970.
+ seconds since 1970 or {perlfunc()}.
</ul>
<br>
@@ -502,6 +502,16 @@
cron or filter the date in a perl expression, see the last example and
the section <a href="#perl">Perl special</a>.
</li>
+ <li>To execute a FHEM command on every last day of the month,<br/>
+ the function <code>ultimo()</code> can be used as perlfunc for datespec.</br>
+ <code>define at_ultimo at *{ultimo()} set lamp1 off</code><br/>
+ This will create an at device which will be executed at 23:59:00
+ on the last day of month.</br>
+ ultimo() can take additional parameters to specify an other time on this day<br/>
+ <code>define at_ultimo at *{ultimo(12,23,45)} set lamp1 off</code><br/>
+ This will create an at device which will be executed ad 12:34:45
+ on the last day of month.<br/>
+ </li>
</ul>
<br>
</ul>
@@ -632,7 +642,7 @@
{perlfunc()} darf keine Leerzeichen enthalten.<br>
<datespec> ist entweder ISO8601 (YYYY-MM-DDTHH:MM:SS) oder Anzahl
- der Sekunden seit 1970.
+ der Sekunden seit 1970 oder {perlfunc()}.
</ul>
<br>
@@ -690,6 +700,18 @@
filtern. Siehe hierzu das letzte Beispiel und das <a href="#perl">Perl
special</a>. </li>
+ <li>Um einen FHEM Befehl immer am letzten Tag des Monats auszuführen,
+ kann die Funktion <code>ultimo()</code> als perlfunc für eine datespec
+ verwendet werden.</br>
+ <code>define at_ultimo at *{ultimo()} set lamp1 off</code><br/>
+ Hiermit wird ein at device erzeugt, der immer am letzten Tag des Monats
+ um 23:59:00 Uhr ausgeführt wird.<br/>
+ ultimo() kann drei optionale Parameter verarbeiten, um eine andere Uhrzeit
+ anzugeben.<br/>
+ <code>define at_ultimo at *{ultimo(12,23,45)} set lamp1 off</code><br/>
+ Es wird ein at device erzeugt, das immer um 12:34:45 am Monatsletzten
+ ausgeführt wird.<br/>
+ </li>
</ul>
<br>
</ul>
genial. Bin beeindruckt. :)
Ich wollte es als at_ultimo() in 90_at.pm einbauen.
Beim Testen gabs aber eine Fehlermeldung:
fhem> define at_ultimo at {at_ultimo} BLA
the function "at_ultimo" must return a timespec and not Undefined subroutine &main::timelocal called at ./FHEM/90_at.pm line 424.
.
fhem>
ups...
In meiner 99_myUtils.pm steht dazu (schon lange, nicht wegen dieser neuen Funktion)
use Time::Local;
Ich hoffe, dass das im perl Standard vorhanden ist, ansonsten sollten wir die Funktion vielleicht aus 90_at.pm rauslassen, um keine neuen Abhängigkeiten zu schaffen.
Soweit ich sehe, entspricht timelocal in diesem Fall dem bereits eingesetzten mktime, ich habe es ausgetauscht. Bei mir fuehrt das trotzdem zu:
PERL WARNING: Use of uninitialized value $data{"AT_RECOMPUTE"} in numeric eq (==) at ./FHEM/90_at.pm line 420.
Das habe ich durch Weglassen der == 1 gefixt. Gabs bei Dir damit keine Probleme?
Habe die Funktion als at_ultimo samt Doku eingecheckt. Damit ist sie als
defmod at_ultimo at *{at_ultimo} {}
aufzurufen
Zitat von: rudolfkoenig am 12 Januar 2021, 20:47:41
Das habe ich durch Weglassen der == 1 gefixt. Gabs bei Dir damit keine Probleme?
Das war mir nicht aufgefallen.
Zitat von: rudolfkoenig am 12 Januar 2021, 20:47:41
Habe die Funktion als at_ultimo samt Doku eingecheckt.
super, Danke!
Ich versetehe den Quellcode leider nicht 100%, aber funktioniert die vorgestellte ultimo Funktion auch mit Schaltsekunden (https://de.wikipedia.org/wiki/Schaltsekunde)?
*duckundwegrenn*
Hast Du vor dem Schreiben Deiner Frage wenigstens mal die Suchfunktion hier im Forum benutzt?
Die Frage bezüglich Schaltsekunden in FHEM hat Rudi schon vor zwei Jahren beantwortet.
Zitat von: rudolfkoenig am 05 Februar 2019, 11:37:38
Zitat von: Christoph Morrison am 05 Februar 2019, 11:01:10
Darf ich anmerken, dass Tage nicht immer (https://de.wikipedia.org/wiki/Schaltsekunde) exakt 86400 Sekunden lang sind?
Aus Sicht von FHEM ist das aber egal, die Bibliotheken ignorieren die Schaltsekunde, wenn es um das Konvertieren der Zeit seit 1970 geht.
In der Berechnungen zugrundeliegenden "Anzahl Sekunden seit 1970" sind Schaltsekunden nicht vorhanden. Wenn eine Schaltsekunde hinzugefuegt/weggenommen wird, dann streckt/verkuerzt NTP/etc den Taktgeber leicht, so dass nach eine Weile die Uhrzeit wirder stimmt. D.h. der Computer duerfte nie 23:59:60 anzeigen, und auch ein 23.59:59 gibts immer.
Hallo, in der Umsetzung des Moduls stelle ich mich wahrscheinlich nur zu dumm an:
Ich habe zunächst die Datei 90_at.pm in das entsprechende Verzeichnis kopiert und FHEM neu gestartet und eine neue Variable "Heizdatenversand" definiert.
Im UI habe ich unter 'Change the timespec:' das Feld 'Use perl function for timespec' angeklickt und im folgenden Eingabefeld die Funktion
{at_ultimo}
eingegeben.
Will ich abspeichern (Change the timespec) erhalte ich die Fehlermeldung:
the function "{at_ultimo}" must return a timespec and not 1619819940.
Wo liegt mein Fehler?
Klar, der Fehler liegt im falschen Format, aber wie ist er zu beseitigen?
Zitat von: uron am 01 April 2021, 12:10:11
Ich habe zunächst die Datei 90_at.pm in das entsprechende Verzeichnis kopiert
warum, die gibt es doch da schon und sie wird beim Update aktualisiert?
Bei mir funktioniert sowohl
defmod test_at at *{at_ultimo} {}
als auch die Bedienung mit dem Widget (auf die Idee wäre ich nie gekommen) problemlos
Hmmmm, bei mir will es nicht klappen. Zur Fehleranalyse habe ich mal 2 Screenshots gemacht:
Einmal mit fester Zeit und einmal mit der at_ultimo-Funktion.
Bei letzterem kommt die genannte Fehlermeldung
the function "at_ultimo" must return a timespec and not 1619819940.
Du versuchst, ein vorhandenes at von einer absoluten Zeitangabe auf perl Code zu ändern. Da kann es schon sein, dass das über das widget nicht funktioniert.
Hast Du schon versucht, ein solches at direkt per Befehl neu anzulegen, siehe meinen vorherigen Beitrag?
@betateilchen: Hab es jetzt versucht, allerdings ohne Erfolg (siehe 2 Screenshots). Natürlich habe ich die alte Definition gelöscht!
Noch eine andere Idee?
@uron
Was liefert denn:
version at
Und beachte bitte: https://forum.fhem.de/index.php/topic,71806.0.html
Das sollte ein Datum nach dem 12 Januar 2021 stehen - wenn nicht hilft update.
Gruß Otto
version at
liefert
File Rev Last Change
90_at.pm 23512 2021-01-12 19:37:27Z rudolfkoenig
98_autocreate.pm 21659 2020-04-13 10:08:36Z rudolfkoenig
98_update.pm 20778 2019-12-18 17:46:44Z rudolfkoenig
AttrTemplate.pm 22928 2020-10-06 15:37:51Z rudolfkoenig
doif.js 15546 2017-12-03 09:57:42Z Ellert
fhemweb.js 22618 2020-08-17 16:21:28Z rudolfkoenig
.. also kein Datum nach dem 12.1., einupdate restart
bringt aber keine Änderung!?
Naja - 12.1. sollte passen: https://forum.fhem.de/index.php/topic,117269.msg1121228.html#msg1121228
Aber update restart ist kein sinnvolles Kommando :-[
Meine ist vom 14.3.
90_at.pm 23964 2021-03-14 09:26:44Z rudolfkoenig
Und es funktioniert wie im Beispiel ::)
Danke Otto123 für den Hinweis zu 'update restart'. Das hatte sich bei mir so mit der Zeit eingebürgert - warum auch immer ::).
Es hat sich nun aber als falsch herausgestellt!
Ein einfaches 'update' brachte die Aktualisierung und die gewünschte Funktionalität des at-Befehls.
Zitat von: uron am 02 April 2021, 07:48:05
...zu 'update restart'. Das hatte sich bei mir so mit der Zeit eingebürgert - warum auch immer ::).
Du hast damit dann immer versucht die Datei restart zu aktualisieren. Das hätte doch mal auffallen müssen? ::)
Ich schäme mich auch >:(