FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: Schuggi am 29 Juli 2013, 10:19:40

Titel: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 10:19:40
Wie kann ich InternalTimer am einfachsten mit einer absoluten Zeit also zum Beispiel auf heute um 23:00 setzen?
Bei allen Beispielen die ich gefunden habe, wird der Timer immer auf eine relative Zeit gesetzt.

Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: bugster_de am 29 Juli 2013, 11:22:09
Hi,

setzt den Timer einmalig heute um 23:00:00 Uhr:
define myTimer at 23:00:00 set irgendwas

setzt den Timer jeden Tag um 23:00:00 Uhr:
define myTimer at *23:00:00 set irgendwas

setzt den Timer in einer Stunde:
define myTimer at +01:00:00 set irgendwas

setzt den Timer jede Stunde:
define myTimer at +*01:00:00 set irgendwas
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 11:25:01
Danke für die Antwort, da ich das aber in ein Modul einbauen will,
möchte ich den "InternalTimer" verwenden.

Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 11:32:59
timestamp für den gewünschten Zeitpunkt errechnen und diesen als ersten Funktionswert an Internaltimer übergeben. Wenn Du dann innerhalb der ersten Ausführung mit gettimeofday+86400 triggerst, wird der Zeitpunkt am nächsten Tag wieder aktiviert.

InternalTimer($timestamp, "tueIrgendwas", $hash, 0);



Converting DMYHMS to Epoch Seconds
#-----------------------------
use Time::Local;
$TIME = timelocal($sec, $min, $hours, $mday, $mon, $year);
$TIME = timegm($sec, $min, $hours, $mday, $mon, $year);
#-----------------------------
# $hours, $minutes, and $seconds represent a time today,
# in the current time zone
use Time::Local;
$time = timelocal($seconds, $minutes, $hours, (localtime)[3,4,5]);
#-----------------------------
# $day is day in month (1-31)
# $month is month in year (1-12)
# $year is four-digit year e.g., 1967
# $hours, $minutes and $seconds represent UTC time
use Time::Local;
$time = timegm($seconds, $minutes, $hours, $day, $month-1, $year-1900);
#-----------------------------
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 12:35:13
Hallo betateilchen,
prinzipiell funktioniert es:
InternalTimer(timelocal(0, 23, 12, (localtime)[3,4,5]),"Solarlog_Tagesergebnis",$hash, 0);

Ich dachte allerdings das ich auf die Zeit einfach einen Wert in Sekunden aufaddieren kann.
 my $next = timelocal(0, 23, 12, (localtime)[3,4,5])+120;
  InternalTimer($next ,"Solarlog_Tagesergebnis",$hash, 0);


Ich hätte gedacht das der Timer dann um 12:25 zuschlägt, das macht er aber nicht.
Wo liegt mein Denkfehler?

Das oben ist nur ein Test später wollte ich den Timer wie folgt setzen damit er morgen um 23:00 zuschlägt
 my $next = timelocal(0, 0, 23, (localtime)[3,4,5])+86400;
  InternalTimer($next ,"Solarlog_Tagesergebnis",$hash, 0);


Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 12:52:24
Hallo :)

Eigentlich müsste es mit diesem Ablaufschema funktionieren:

1. Der InternalTimer wird bei der ersten Initialisierung auf einen von Dir gesetzten Wert eingestellt.
2. Zum eingestellten Zeitpunkt ruft er die Funktion "Solarlog_Tagesergebnis" auf.
3. Innerhalb dieser Funktion (!) musst Du den InternalTimer dann mit (gettimeofday()+interval) neu setzen.

Ich würde übrigens auch den ersten Zeitpunkt mit (gettimeofday()+offset) definieren und dabei das offset ausgehend von der aktuellen Uhrzeit einmalig berechnen.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 12:59:59
Prinzipiell will ich ganau das machen.
Die Funktion soll jeden Tag um 23:00 aufgerufen werden um den Tagesertrag der Solaranlage umzukopieren.
Ich bin noch nicht so fitt in Perl daher wollte ich mir die Sache möglichst einfach machen.
Leider sind vile Funktionen nicht wirklich gut dokumentiert oder ich tu mich da einfach noch etwas schwer.

Aber warum funktioniert das Aufaddieren und den Zeitstempel nicht?

sub
Solarlog_Tagesergebnis($)
{
  my ($hash) = @_;
  $hash->{READINGS}{ErtragTag}{TIME} = TimeNow();
  $hash->{READINGS}{ErtragTag}{VAL} = $hash->{READINGS}{Ertrag}{VAL};
  my $next = timelocal(0, 23, 12, (localtime)[3,4,5])+120;
  InternalTimer($next ,"Solarlog_Tagesergebnis",$hash, 0);
  return undef;
}


Ich hab nicht nur eine zeitliche Verschiebung sondern der Timer wird immer wieder ständig aufgerufen.

Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 14:01:15
Das macht man so nicht:

  my ($hash) = @_;
  $hash->{READINGS}{ErtragTag}{TIME} = TimeNow();
  $hash->{READINGS}{ErtragTag}{VAL} = $hash->{READINGS}{Ertrag}{VAL};


sondern so:

my ($hash) = @_;
my $name = $hash->{NAME};
readingsSingleUpdate($hash, "ErtragTag", ReadingsVal($name,"Ertrag",0), 1);


ZitatLeider sind viele Funktionen nicht wirklich gut dokumentiert

am besten versteht man sie, wenn man sie sich in der fhem.pl anschaut.

Zitatoder ich tu mich da einfach noch etwas schwer.

das ist nicht schlimm, dafür gibts ja das Forum.

ZitatAber warum funktioniert das Aufaddieren und den Zeitstempel nicht?

Weil Du das Prinzip des InternalTimers noch nicht ganz verstanden hast.

Nochmal - so nicht:


sub
Solarlog_Tagesergebnis($)
{
... was auch immer da gemacht wird;

InternalTimer($next ,"Solarlog_Tagesergebnis",$hash, 0);
}


sondern:


sub
Solarlog_Tagesergebnis($)
{
... was auch immer da gemacht wird;

RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+86400,"Solarlog_Tagesergebnis",$hash, 0);
}


Und NUR in der *_Define() Deines Moduls musst Du den InternalTimer EINMALIG auf den Timestamp für das nächste 23:00:00 einstellen.
Eigentlich müsste man das RemoveInternalTimer sogar weglassen können - aber es schadet auch nicht.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Dietmar63 am 29 Juli 2013, 14:37:31
bereite das Feld $next vor dem Setzen des InternalTimers mit
Log 3, "next: " . strftime('%d.%m.%Y %H:%M:%S',localtime($next));
auf. Dann wirst du das Problem schnell lokalisieren.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 14:38:59
 my ($hash) = @_;
  $hash->{READINGS}{ErtragTag}{TIME} = TimeNow();
  $hash->{READINGS}{ErtragTag}{VAL} = $hash->{READINGS}{Ertrag}{VAL};


Das war so in dem Modul drinnen, das ich gerade anpasse.
Das werde ich dann mal umstellen.

InternalTimer(gettimeofday()+86400,"Solarlog_Tagesergebnis",$hash, 0);
Bei dieser Lösung hatte ich bedenken, das sich der Zeitpunkt langsam verschiebt und dann langsam wegläuft.
Daher wollte ich den Zeitpunkt anhand einer absoluten Zeitangabe setzen.

RemoveInternalTimer($hash);
Bisher hab ich das auch so verstanden, dass man den Remove nicht braucht, da der Timer nicht automatisch wiederholt wird.

Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 14:43:20
Zitat von: Schuggi schrieb am Mo, 29 Juli 2013 14:38Bei dieser Lösung hatte ich bedenken, das sich der Zeitpunkt langsam verschiebt und dann langsam wegläuft.

Wenn Du in Deinem Modul mit Time::Hires arbeitest, bewegst Du Dich da maximal im Millisekundenbereich. Und nicht vergessen: mit jedem Neustart (z.B. nach einem Update) wird das Ganze ja wieder neu getriggert. Ich denke, das Weglaufen kannst Du vernachlässigen. Probier diesen Ansatz doch einfach erstmal aus.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Dietmar63 am 29 Juli 2013, 14:44:42
wenn man

InternalTimer(gettimeofday()+86400,"Solarlog_Tagesergebnis",$hash, 0);

programmiert, landet man nicht immer exakt bei 23:00 Uhr. Man muss immer die Sekunden bis 23:00 ausrechen und auf time() addieren.

Ich glaube
my $next = timelocal(0, 0, 23, (localtime)[3,4,5])+86400;

ist schon richtig gedacht. Wie schon geschrieben mit strftime   die berechnete Zeit ausgeben. Dann ist der Fehler schnell gefunden.

Ich meine, dass wenn man einen InternalTimer in die Vergangenheit setzt, dann kann man sich leicht eine Endlosschleife basteln, weil die alten Timer alle immer wieder abgearbeitet werden - In der Testphase vielleicht mit $next > time() sicherstellen.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 14:52:09
Zitat von: Dietmar63 schrieb am Mo, 29 Juli 2013 14:44wenn man
...
programmiert, landet man nicht immer exakt bei 23:00 Uhr.

Ich arbeite NUR so, und bisher bewege ich mich immer noch im gleichen stabilen Raum-Zeit-Kontinuum ohne jegliche Verschiebung.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 14:56:57
Habs mal probiert.
hier der Code:

 my $next = timelocal(0, 0, 23, (localtime)[3,4,5]);
  Log 1, "next1: " . strftime('%d.%m.%Y %H:%M:%S',localtime($next));
  $next = $next+86400;
  Log 1, "next2: " . strftime('%d.%m.%Y %H:%M:%S',localtime($next));

 und hier die Ausgabe:

2013.07.29 14:53:00.027 1: next1: 29.07.2013 23:00:00
2013.07.29 14:53:00.028 1: next2: 30.07.2013 23:00:00


Sieht ja alles richtig aus. Ich hab jetzt auch den RemoveTimer drinnen. Eventuell lags daran.

Gruß und Dank
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 15:00:11
na dann teste mal...
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 15:06:00
Ich han nun mal
$hash->{READINGS}{ErtragTag}{TIME} = TimeNow();
$hash->{READINGS}{ErtragTag}{VAL} = $hash->{READINGS}{Ertrag}{VAL};


gegen dei Variante mit
readingsSingleUpdate($hash,...
umgebaut.
da sind aber noch ein paar Zeilen die ich nicht verstehe bzw. nicht weiss ob man die nocht braucht bzw ob man die auch ersetzen kann.

$hash->{CHANGED}[0] = $text;
 $hash->{STATE} = $text;
...
...
   DoTrigger($name, undef) if($init_done);    
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 15:10:43
Das DoTrigger() kannst Du weglassen, das sollte schon die 1 am Ende des readingsSingleUpdate() machen.

Die anderen zwei Zeilen: wenn Du dieses Werte setzen willst, kannst Du das so machen. Zwingend notwendig sind sie nicht.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 29 Juli 2013, 15:41:50
Durch die Umstellung auf
readingsSingleUpdate($hash,...
hat sich ein neues Problem ergeben.

Beim Regex meines Filelogs habe ich nur den Namen meines defines angegeben und bisher wurde da nur das was im STATE steht geloggt.(und das wollte ich auch so heben) Nun werden alle sich ändernden "readings" ins Log geschrieben.
Wie muss der Regex aussehen, damit er nur einzelne readings bzw den Stat schreibt?
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Dietmar63 am 29 Juli 2013, 16:17:20
glaub' mir, ich habe es schon mal geschafft InternalTimer in die Vergangeheit zu setzen - wenn es passiert, dann hast du Probleme und weißt nicht woher sie kommen.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 29 Juli 2013, 19:53:35
Zitat von: Schuggi schrieb am Mo, 29 Juli 2013 15:41Wie muss der Regex aussehen, damit er nur einzelne readings bzw den Stat schreibt?

Du musst halt das Reading mit angeben. Ich kann leider nicht hellsehen und weiß nicht, wie Deine FileLog Definition aktuell aussieht und was Du dort geändert haben möchtest...
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Dietmar63 am 29 Juli 2013, 20:33:07
define HeizungKuecheChart     FileLog ./log/HeizungKueche.log HeizungKueche:.*
vielleicht so:
define HeizungKuecheChart     FileLog ./log/HeizungKueche.log HeizungKueche:(reading1|reading2|reading3).*
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 30 Juli 2013, 08:03:02
Das hab ich nun hinbekommen.
Nun die nächste Frage:
Wie kann ich eine interne Variable anlegen die einen Neustart überdauert.
Geht das ohne Reading oder Attribut?

Hintergrund ist, dass ich Tageswerte jeden Abend um 23:00 aufsummieren möchte um die
Summe dann am letzten Tag des Monats in ein Reading zu schreiben.
Diese Summe muss natürlich einen Neustart überdauern können.

Gruß
  Schuggi
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: betateilchen am 30 Juli 2013, 09:22:56
Leg ein Reading "Summe" an, das ist die einfachste Lösung.
Titel: Aw: InternalTimer mit absoluter Zeit
Beitrag von: Schuggi am 30 Juli 2013, 10:16:35
Hab ich momentan auch so gemacht.