[Wunsch] 90.at.pm - timespec Definition als timestamp ermöglichen

Begonnen von betateilchen, 06 November 2015, 08:30:48

Vorheriges Thema - Nächstes Thema

betateilchen

Da Weihnachten vor der Tür steht, schreibe ich mal Folgendes auf den Wunschzettel :)



define advent at 1448751600 set Weihnachtsbaum on



Damit könnte man auf einfach Art ein at zu einem bestimmten Datum vorprogrammieren, ohne die timespec erst umständlich in +hh:mm umrechnen zu müssen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

ok, ich bin grade dabei, einen vernünftigen patch vorzubereiten :)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Patch 1 - in fhem.pl wird die Funktion GetTimeSpec() angepaßt


Index: fhem.pl
===================================================================
--- fhem.pl (Revision 9804)
+++ fhem.pl (Arbeitskopie)
@@ -2919,6 +2919,8 @@
     ($hr, $min, $sec) = ($1, $2, $3);
   } elsif($tspec =~ m/^([0-9]+):([0-5][0-9])$/) {
     ($hr, $min, $sec) = ($1, $2, 0);
+  } elsif($tspec =~ y/0-9// == length($tspec)) {
+      ($hr, $min, $sec) = (0, 0, $tspec);
   } elsif($tspec =~ m/^{(.*)}$/) {
     $fn = $1;
     $tspec = AnalyzeCommand(undef, "{$fn}");
@@ -2926,6 +2928,8 @@
       ($hr, $min, $sec) = ($1, $2, $3);
     } elsif(!$@ && $tspec =~ m/^([0-9]+):([0-5][0-9])$/) {
       ($hr, $min, $sec) = ($1, $2, 0);
+    } elsif(!$@ && ($tspec =~ y/0-9// == length($tspec))) {
+      ($hr, $min, $sec) = (0, 0, $tspec);
     } else {
       $tspec = "<empty string>" if(!$tspec);
       return ("the at function \"$fn\" must return a timespec and not $tspec.",


Patch 2 - in der 90_at.pm


Index: 90_at.pm
===================================================================
--- 90_at.pm (Revision 9804)
+++ 90_at.pm (Arbeitskopie)
@@ -65,6 +65,21 @@
   my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($tspec);
   return $err if($err);

+  if($sec > 60) {
+    # $tspec ist rein numerisch -> timestamp
+    return "Wrong timespec, timestamp must describe a future time"
+        if time() >= $sec;
+    my $val = FmtDateTime($sec);
+    $hash->{TRIGGERTIME} = $sec;
+    $hash->{TRIGGERTIME_FMT} = $val;
+    $hash->{COMMAND} = $command;
+    RemoveInternalTimer($hash);
+    InternalTimer($sec, "at_Exec", $hash, 0);
+    readingsSingleUpdate($hash, "state", $val,
+          !$hash->{READINGS}{state} || $hash->{READINGS}{state}{VAL} ne $val);
+    return undef;
+  }
+
   $rel = "" if(!defined($rel));
   $rep = "" if(!defined($rep));
   $cnt = "" if(!defined($cnt));
@@ -386,9 +401,9 @@
       executed <i>repeatedly</i>.<br>
       The optional <code>{N}</code> after the * indicates,that the command
       should be repeated <i>N-times</i> only.<br>
-      &lt;timedet&gt; is either HH:MM, HH:MM:SS or {perlfunc()}, where perlfunc
-      must return a HH:MM or HH:MM:SS date. Note: {perlfunc()} may not contain
-      any spaces or tabs.
+      &lt;timedet&gt; is either HH:MM, HH:MM:SS, timestamp or {perlfunc()}, <br/>
+      where perlfunc must return a HH:MM or HH:MM:SS date or a future timestamp.<br/>
+      Note: {perlfunc()} may not contain any spaces or tabs.
     </ul>
     <br>

@@ -399,6 +414,7 @@
     define a2 at 17:00:00 { Log 1, "Teatime" }                   # Perl command
     define a3 at 17:00:00 "/bin/echo "Teatime" > /dev/console"   # shell command
     define a4 at *17:00:00 set lamp on                           # every day
+    define a5 at 1448751600 set lamp on                          # timestamp must describe a future time

     # relative ones
     define a5 at +00:00:10 set lamp on                 # switch on in 10 seconds


Damit wird es möglich, einen timestamp im DEF zu verwenden. Die Angabe kann sowohl als absoluter Wert als auch per perlfunc errechnet erfolgen.
Es wird geprüft, ob der timestamp in der Zukunft liegt, falls nicht, wird eine entsprechende Fehlermeldung ausgegeben.

Ich hoffe, nix wichtiges vergessen/übersehen zu haben :)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Markus Bloch

Ich versteh nicht, warum es umbedingt ein Timestamp sein muss? Ist jetzt nicht so, dass man den sich mal eben aus dem Finger saugen kann, es sei denn man ist Mathe-Autist.

Wäre eine optionale Angabemöglichkeit von Datum nicht interessanter? Dann kannst du folgendes machen (beispielhaft)


define advent at 2015-12-24/18:00 set Weihnachtsbaum on


oder so ähnlich. Ich hab mir da jetzt keine weiteren Gedanken zur Syntax gemacht.

Nur so als Idee  ;)

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

betateilchen

#4
Ich arbeite leichter mit timestamps als mit irgendwelchen Datums-/Zeitformaten, von denen Du dann entweder wieder unzählige prüfen oder ein bestimmtes vorgeben müsstest.

Ausserdem arbeitet at intern ohnehin mit timestamps, um Ausführungszeitpunkte abzuspeichern.

Nachtrag: fhem bringt ja von Haus aus einige Funktionen mit, um Strings in timestamps zu konvertieren. Insofern ist das, was Du vorschlägst, mit meinen Patches ebenfalls durchführbar.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

justme1968

#5
ich denke auch ein lesbares datum wäre besser als ein timestamp.

was spricht denn gegen das gute alte iso 8601 format:define advent at 2015-12-24T18:00 set Weihnachtsbaum on

wenn man sich den standard anschaut findet man vermutlich noch ein paar andere nützliche dinge wie Zeitspannen, relative angaben oder kalender wochen. die könnte man nach und nach auch einbauen.

z.b. wäre es relativ leicht möglich dinge wie 'jedes jahr am 24.12.' oder 'eine woche vor weihnachten bis eine woche nach neujahr' abzubilden.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

justme1968

ZitatIch arbeite leichter mit timestamps als mit irgendwelchen Datums-/Zeitformaten
ich wette auch du kannst ohne nachsehen nicht den timestamp für weihnachten nächstes jahr sagen.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

betateilchen

fhem bringt ja von Haus aus einige Funktionen mit, um Strings in timestamps zu konvertieren. Insofern ist das, was von Euch vorgeschlagen wird, mit meinen Patches ebenfalls durchführbar.

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Zitat von: justme1968 am 07 November 2015, 16:26:07
wenn man sich den standard anschaut findet man vermutlich noch ein paar andere nützliche dinge wie Zeitspannen, relative angaben oder kalender wochen. die könnte man nach und nach auch einbauen.

z.b. wäre es relativ leicht möglich dinge wie 'jedes jahr am 24.12.' oder 'eine woche vor weihnachten bis eine woche nach neujahr' abzubilden.

Das kann ja gerne irgendjemand irgendwann auch noch einbauen.

Aber die reinen timestamps bräuchte ich trotzdem :)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

Eigentlich gehoeren Wuensche in die Wunschliste, das lese ich naemlich nicht. :)

Der Patch gefaellt mir nicht: es aendert das Interface. GetTimeSpec wird z.Zt in 11 Dateien verwendet und ich will nicht anfangen alle Module zu testen und Patches vorzuschlagen. Ich habe eine Alternative ohne Interface-Aenderung in fhem.pl eingebaut, allerdings ohne Hintertuer fuer Datumspezifikation. Eine kompatible Erweiterung der GetTimeSpec Interface mit Datum (Stichwort 8601) ist zwar nicht sehr aufwendig, eine konsequente Anpassung von at ist mir aber jetzt zu aufwendig. Und ob die anderen Module das beachten ist auch fragwuerdig.

Weiterhin ruft jetzt die {} Variante GetTimeSpec rekursiv auf, damit kein Code wiederholt wird.

betateilchen

Hallo Rudi,

die Änderung in der jetzigen Form ist aber nicht wirklich hilfreich.

define advent at 1448751600 set Weihnachtsbaum on

liefert als Ergebnis:

(http://up.picr.de/23639781ga.png)

was schlichtweg falsch ist.

Und was Du mit 8601 meinst, weiss ich genausowenig wie ich Deine Aussage "Interface von GetTimeSpec ändert sich" nicht verstehe. Bei meinem vorgeschlagenen Patch hatte ich extra darauf geachtet, den Funktionsaufruf NICHT zu verändern.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Zitat von: rudolfkoenig am 07 November 2015, 20:07:55
Eigentlich gehoeren Wuensche in die Wunschliste, das lese ich naemlich nicht. :)

Was denkst Du, warum ich den Wunsch hier reingeschrieben hatte  8)
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

Zitatdie Änderung in der jetzigen Form ist aber nicht wirklich hilfreich.
Wenn deine Absicht war, via at etwas zu definieren, was nicht innerhalb der naechsten 24 Stunden ausloest, dann sorry, das geht nicht, und bleibt erstmal auch so.

ZitatBei meinem vorgeschlagenen Patch hatte ich extra darauf geachtet, den Funktionsaufruf NICHT zu verändern.
Mag sein, aber das, was zureuckgeliefert wird, ist nicht das was die anderen 10 Anwender von GetTimeSpec erwarten.

betateilchen

#13
Zitat von: rudolfkoenig am 07 November 2015, 20:46:30
Wenn deine Absicht war, via at etwas zu definieren, was nicht innerhalb der naechsten 24 Stunden ausloest,

Genau DAS steht als Hintergrund meines Wunsches in meinem ersten Beitrag hier im Thread:

Zitat von: betateilchen am 06 November 2015, 08:30:48
Damit könnte man auf einfach Art ein at zu einem bestimmten Datum vorprogrammieren,

Zitat von: rudolfkoenig am 07 November 2015, 20:46:30
aber das, was zureuckgeliefert wird, ist nicht das was die anderen 10 Anwender von GetTimeSpec erwarten.

Ok, dann bleiben immer noch zwei Möglichkeiten:


  • den timestamp als "neuen" Rückgabewert zu liefern (kompatibel zu bestehenden Anwendungen, da zusätzliche Rückgabewerte kein Problem darstellen)
  • die Behandlung von timestamps ausschließlich in 90_at.pm abzubilden und GetTimeSpec dazu nicht zu verwenden.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Hier noch ein neuer Vorschlag, der auch Deine Bedenken bezüglich anderer Verwendungsstellen von GetTimeSpec berücksichtigt und trotzdem Zeitpunkte > 24 Stunden zulässt.


Index: fhem.pl
===================================================================
--- fhem.pl (Revision 9810)
+++ fhem.pl (Arbeitskopie)
@@ -2913,7 +2913,7 @@
GetTimeSpec($)
{
   my ($tspec) = @_;
-  my ($hr, $min, $sec, $fn);
+  my ($hr, $min, $sec, $fn, $timestamp) = (0,0,0,'',0);

   if($tspec =~ m/^([0-9]+):([0-5][0-9]):([0-5][0-9])$/) { # HH:MM:SS
     ($hr, $min, $sec) = ($1, $2, $3);
@@ -2923,7 +2923,7 @@

   } elsif($tspec =~ m/^([0-9]{10})$/) {                   # seconds-since-1970
     my @a = localtime($1);
-    ($hr, $min, $sec) = ($a[2],$a[1],$a[0]);
+    ($hr, $min, $sec, $timestamp) = ($a[2],$a[1],$a[0],$tspec);

   } elsif($tspec =~ m/^{(.*)}$/) {                        # {function}
     $fn = $1;
@@ -2930,15 +2930,15 @@
     $tspec = AnalyzeCommand(undef, "{$fn}");
     $tspec = "<empty string>" if(!$tspec);
     my ($err, $fn2);
-    ($err, $hr, $min, $sec, $fn2) = GetTimeSpec($tspec);
+    ($err, $hr, $min, $sec, $fn2, $timestamp) = GetTimeSpec($tspec);
     return ("the function \"$fn\" must return a timespec and not $tspec.",
-                undef, undef, undef, undef) if($err);
+                undef, undef, undef, undef, undef) if($err);

   } else {
     return ("Wrong timespec $tspec: either HH:MM:SS or {perlcode}",
-                undef, undef, undef, undef);
+                undef, undef, undef, undef, undef);
   }
-  return (undef, $hr, $min, $sec, $fn);
+  return (undef, $hr, $min, $sec, $fn, $timestamp);
}






Index: FHEM/90_at.pm
===================================================================
--- FHEM/90_at.pm (Revision 9810)
+++ FHEM/90_at.pm (Arbeitskopie)
@@ -62,9 +62,23 @@
   return "Wrong timespec, use \"[+][*[{count}]]<time or func>\""
                                         if($tm !~ m/^(\+)?(\*({\d+})?)?(.*)$/);
   my ($rel, $rep, $cnt, $tspec) = ($1, $2, $3, $4);
-  my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($tspec);
+  my ($err, $hr, $min, $sec, $fn, $timestamp) = GetTimeSpec($tspec);
   return $err if($err);

+  if ($timestamp) {
+    return "Wrong timespec, timestamp must describe a future time"
+        if time() >= $timestamp;
+    my $val = FmtDateTime($timestamp);
+    $hash->{TRIGGERTIME} = $timestamp;
+    $hash->{TRIGGERTIME_FMT} = $val;
+    $hash->{COMMAND} = $command;
+    RemoveInternalTimer($hash);
+    InternalTimer($timestamp, "at_Exec", $hash, 0);
+    readingsSingleUpdate($hash, "state", $val,
+          !$hash->{READINGS}{state} || $hash->{READINGS}{state}{VAL} ne $val);
+    return undef;
+  }
+
   $rel = "" if(!defined($rel));
   $rep = "" if(!defined($rep));
   $cnt = "" if(!defined($cnt));
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!