Wohl nicht so ganz Anfängerfrage, aber ich habs mal hier rein gestellt.
Ich möchte gern fhem etwas erweitern, kann auch gut programmieren, nur kein Perl. Ich möchte gern ein paar Dinge mit der Uhrzeit berechnen wie z.B.
if(uhrzeit1 < uhrzeit2)
oder
uhrzeit1 + 3 std.
usw. Allerdings weiß ich nicht so recht, in welchen Datentypen die Uhrzeit in fhem genutzt wird. In einigen Snippets die ich gesehen habe (z.B. http://www.fhemwiki.de/wiki/Uhrzeit:_Offset_berechnen (//www.fhemwiki.de/wiki/Uhrzeit:_Offset_berechnen)), wird das Uhrzeitobjekt zerlegt, dann mühsam mit den "Einzelteilen" davon gerechnet und dann als String wieder zurück gegeben. Geht das auch einfacher / besser? Oder ist das der Weg unter Perl/fhem?
Oder gibt es wenigstens eine integrierte Methode, mit der ich das Datum in einen Unix-Timestamp (damit lässt sich dann ja einfach rechnen / vergleichen) konvertieren (und wieder zurück) kann?
In der FHEM Console eingegeben ergibt das bei mir aktuelle Zeit + 3Stunden.
{strftime "%H:%M", localtime time+3600*3;}
15:44
{time+3600*3;}
1367156676
Danke, das hilft mir schonmal. Wie ich sehe, gibt z.B. sunset die Uhrzeit allerdings "human readable" aus (21:30:21)?
D.h. fhem arbeitet mit diesen lesbaren Uhrzeitformaten? Wenn ich also eine Berechnung auf Basis von sunset machen will, muss ich das erst per mktime in einen Timestamp umwandeln, dann rechnen und dann per strftime wieder in die Form für fhem bringen?
Sunset kann direkt ein offset in Sekunden einrechnen.
Perl hat ähnlich wie c++ nur ein oo - Aufsatz, der aber in vielen Fällen nicht genutzt wird. Such mal nach 'perl bless' im Netz. In fhem wird oo nicht genutzt. Es gibt aber viele Bibliotheken, die man in der Regel über cpan nachladen kann.
Fhem läuft aber auf vielen schwachbrustiger Hardware(FB, nas,... ) auf der das nun wieder auch nicht funktioniert.
Bevor du loslegst, such dir in den Sourcen von fhem Beispiele.
time() liefert epoch
Localtime, gmtime bereiten epoch als array auf - damit kann man nicht gut rechnen(alles zu Fuß) .
Trotzdem ist Perl ein Hammer!
Nur ein Offset bei sunset reicht mir nicht. Ich möchte noch das Wochenende mit einbauen und vor allem einen Min-/Max Wert (derzeit ist Sonnenaufgang um 5.24 Uhr, da sollen aber die Rolläden noch nicht hoch fahren, ein starres Offset funktioniert aber nicht, weil dann im Winter die Rolläden erst um 11 Uhr hoch fahren würden).
Trotzdem danke für den Hinweis.
Also wenn ich die Uhrzeit von sunset bekomme, muss ich per String-Zerlegung und mktime eine Unix-Zeit drauß machen?
Z.B. so, Stunde & Minute aus dem String und den rest aus der aktuellen Uhrzeit?
my $TimeP = mktime(0,substr($PtimeOrg,3,2),substr($PtimeOrg,0,2),$mday,$month,$year,$wday,$yday,$isdst);
Glaub gerne, dass Perl ein Hammer ist, wenn man es kann. ;) Also Java Programmierer sieht vieles erstmal recht gruselig aus. ;)
im Prinzip richtig - aber localtime bzw. timelocal_nocheck nutzen. So(s.u.) hat es bei mir funktioniert als ich mal das Datum der Sommerzeitumstellung ermitteln wollte. Mit localtime() bzw. timelocal_nocheck wird der Zeitversatz zur utc eingerechnet(mktime habe ich nicht probiert):
use Time::Local 'timelocal_nocheck';
...
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($now);
# compute epoch of last day of March, Oktober
my $letzterTagImMaerzZweiUhr = timelocal_nocheck(0,0,2,31,2,$year);
Perl:
richtig gut sind hashs - vergleichbar mit hashmaps in Java.
werden ganz einfach wie Arrays mit Werten gefüllt - gibt noch mehr Möglichkeiten(goolge hilft immer).
my %hash = ();
$hash{eins} = "one";
$hash{zwei} = "two";
...
# hash of hash of hash of hash ...
$hash{ID1}{ID2}{ID3}{ID4} = "wasauchimmer";
oder:
mit dieser Zeile:
my @ret = &{$fn}($hash);
wird in der folgenden Schleife für alle Definitionen von Heating_Control in fhem die Funktion "Heating_Control_Update" aufgerufen. Der dynamische Aufruf von Funktionen wird in fhem vielfach genutzt und macht mit so wenig Code soviel möglich.
foreach my $hc ( sort keys %{$modules{Heating_Control}{defptr}} ) { # Schleife über alle defs von HC
my $hash = $modules{Heating_Control}{defptr}{$hc}; # so etwas wie eine Instanz von Heating_Control
my $val;
my $cond = $hash->{helper}{CONDITION}; # Bedingung(Perlcode)
$val = eval $cond; # Bedingung ausführen
next if (!$val);
$fn = "Heating_Control_Update";
no strict "refs";
my @ret = &{$fn}($hash); # Heating_Control_Update mit $hash als Parameter
}
der Code:
$val = eval $cond;
führt den Code in $cond (z.Bsp: (heizungAnAus("An", 0)) ) dynamisch aus(wird über fhem.cfg oder die Oberfläche gesetzt, muss perl-syntaktisch richtig sein).
Der Aufruf von "Heating_Control_Update" wird nur dann ausgeführt, wenn $val true wird.
Danke, ich habs jetzt (erstmal) über diese beiden Methoden gelöst:
sub
fromFhemDate($)
{
my $in = shift;
my $h = substr($in, 0,2);
my $m = substr($in, 3,2);
my $s = substr($in, 6,2);
my ($csec, $cmin, $chour, $cmonth, $cyear, $cwday, $cyday, $cisdst) = localtime;
my $needADay = 0;
while($h > 24) {
$h = $h - 24;
$needADay++;
}
my $t = mktime($s, $m, $h, $cmonth, $cyear, $cwday, $cyday, $cisdst);
# Tage wieder drauf addieren
#$t = $t + $needADay * 60 * 60 * 24;
return $t;
}
sub
toFhemDate($)
{
my $in = shift;
my ($Psec,$Pmin,$Phour,$Pmday,$Pmonth,$Pyear,$Pwday,$Pyday,$Pisdst) = localtime($in);
return sprintf("%02d:%02d:%02d", $Phour, $Pmin, $Psec);
}
Sicher nicht ganz schön und nicht ganz safe (erwartet die Zeit in der Form hh:mm:ss), aber für meine Zwecke reicht es derzeit. Brauche das ja hauptsächlich, um mit dem sunset/sunrise Datum weiter zu rechnen. Und das liefert mir genau dieses Format.
Perl:
Dass es in einigen Fällen ganz toll ist, glaube ich. Ist ja ähnlich PHP. Aber es fehlt halt auch einiges an "Compiler-Sicherheit". Und so konstrukte wie
return $u if(int(@a) < 3);
sind zwar gewissermaßen "menschenlesbar" (tue etwas, wenn...), aber wenn man aber Programmierer und die "Computersprache" gewöhnt ist, ist das erstmal total verwirrend. ;-)
Zitat von: Marcus schrieb am Di, 30 April 2013 16:14Dass es in einigen Fällen ganz toll ist, glaube ich. Ist ja ähnlich PHP. Aber es fehlt halt auch einiges an "Compiler-Sicherheit". Und so konstrukte wie
return $u if(int(@a) < 3);
sind zwar gewissermaßen "menschenlesbar" (tue etwas, wenn...), aber wenn man aber Programmierer und die "Computersprache" gewöhnt ist, ist das erstmal total verwirrend. ;-)
In gewisser Weise trifft's das Wesen, aber auch wieder nicht. Ich war seinerzeit (2000) beim 2. Deutschen Perl-Workshop dabei - inzwischen gab es den 15. - wir bekamen damals u.a. auch ein T-Shirt mit einem Zitat von Larry Wall, Tom Christiansen Und Randal L. Schwartz (Vorwort zu "Programming Perl"):
ZitatPerl is a language to getting your job done.
Of course, if your job is programming, you can get your job done with any 'complete' computer language, theoretically speaking. But we know from experience that computer languages differ not so much in what they make possible, but in what they make easy. At one extreme, the so-called "fourth generation" languages" make it easy to do some things, but nearly impossible to do other things. At the other extreme, certail well-known, "industrial-strength" languages make it equally difficult to do almost everything.
Perl is different. In a nutshell, Perl is designed to make the easy jobs easy, without making the hard jobs impossible.
Und das ist meine Erfahrung aus vielen Jahren Entwicklung: Du kannst Perl "mal schnell" eben nutzen, ein Problemchen zu lösen (Logfile-Analyse, Auswertung von Web-Seiten, Code-Generierung etc.), wo es nicht darauf ankommt, wie Du Dein Programm entwirfst oder dokumentierst:
perl -pe 's/(\d\d\d\d)\.(\d\d)\.(\d\d)/$3.$2.$1/' fhem-2013-04.log | less
formatiert Dir z.B. mal schnell Dein Datum um, falls Du so etwas brauchst.
Das ist m.M.n. der Vorteil von Perl: Du kannst mal eben ganz schnell...
Und am anderen Ende findest Du solche Sachen wie FHEM oder bbbike.de in Perl programmiert..."
Aber wenn man aber Programmierer und die "Computersprache" gewöhnt ist, ist das erstmal total verwirrend." Was verwirrt dich? Dass du auf einmal so programmieren kannst, wie du auch denkst? Dass sich Dein Programm wie ein Text liest? Ist doch schön. Aber wenn du nicht
(Ampel{rot, gelb, grün}=(\&halt, \&attention, \&go);
# hier würde ich gleich die Subroutinen definieren, aber es soll erst mal nicht zu "kompliziert" wirken
nebst
Ampel{$farbe}->($arg1, $arg2)
schreiben magst, sondern das etwas länger übersichtlicher empfindest, kannst du das in Perl natürlich auch. TIMTOWTDI(*). Lass das Computer-Stottern sein, unterhalte dich (auch) in Perl! :-)
(Das musste ich mal sagen, 'tschuldigung, dass es kein Problem löst)
<F>
P.S.: Perl war so universell, dass es seinerzeit als verbreitetste Skript-Sprache im Web eingesetzt wurde, nur kann man mit Perl natürlich viel mehr als nur dynamische Webseiten generieren. Da kam jemand daher, hat alles, was man im Web gemeinhin nicht braucht, aus der Sprache entfernt, dafür andere Sachen besser(?), gezielter(?) unterstützt und das ganze PHP genannt. Daher die "Ähnlichkeit".
(*) there is more than one way to do it. - Perl-Entwickler kennen keine "guten" und "schlechten" Lösungen.
Hallo,
die Qualität eines Programms hängt nicht von der Programmierspache sondern von Disziplin und Fähigkeiten des Programmierers ab... Perl ist schon eine geniale Sprache, aber die Freiheiten können auch zu total unlesbaren Code führen.
Zurück zum Thema. Aktionen kannst Du z.B. per at mit variablen Zeiten definieren
# 15 min vor Sonnenuntergang - nicht vor 18:00, nach 20:00
define at_Abends_Rolladen_Zu at *{sunset(-600,"18:00","20:00")} { \
Wenn Du wirklich mit Zeiten rechnen willst, am besten alles auf epoch, d.h. forlaufende Sekunden umrechnen
# 2013-04-30 19:28:21
my $locked_tstamp = ReadingsTimestamp($name,"actor_locked",0);
my @locked = split(" ",$locked_tstamp);
my @locked_day = split("-",$locked[0]);
my @locked_time = split(":",$locked[1]);
my $locked_time = fhemTimeLocal($locked_time[2],$locked_time[1],$locked_time[0],$locked_day[2],$locked_day[1],$locked_day[0]);
my $now_tstamp = TimeNow();
my @now = split(" ",$now_tstamp);
my @now_day = split("-",$now[0]);
my @now_time = split(":",$now[1]);
my $now_time = fhemTimeLocal($now_time[2],$now_time[1],$now_time[0],$now_day[2],$now_day[1],$now_day[0]);
my $del_minutes = int(($now_time - $locked_time)/60);
In fhem.pl findest Du schon time-Funktionen, z.B. TimeNow(), FmtDateTime(), FmtTime(), SecondsTillTomorrow, ReadingsTimestamp(), fhemTzOffset(), fhemTimeGm(), fhemTimeLocal().
Gute Code-Beispiele für Perl findest Du bei Tante Gockle...
Jan
Zitat von: jsb73 am 01 Mai 2013, 11:32:19
In fhem.pl findest Du schon time-Funktionen, z.B. TimeNow(), FmtDateTime(), FmtTime(), SecondsTillTomorrow, ReadingsTimestamp(), fhemTzOffset(), fhemTimeGm(), fhemTimeLocal().
wie geil ist das denn !
Der Thread ist 1,5 Jahre alt
Sowas hätt' ich schon des öfteren gebraucht.
Egal, klasse, endlich kann ich "frühr oder später" gescheit auswerten
PS.
Das steht in keiner commandref
Cheers
mi.ke
Da ich auch gerade mal wieder das Rad neu erfunden habe (ohne hier zuerst zu gucken), werfe ich einfach mal mein Ergebnis hinterher, mit dem man prima mit Sonnenauf- und Sonnenuntergang rechnen kann:
my ($seconds, $minutes, $hours, $day, $month, $year) = localtime(time);
my ($sunrise_hours, $sunrise_minutes, $sunrise_seconds) = split(":", sunrise_abs());
my ($sunset_hours, $sunset_minutes, $sunset_seconds) = split(":", sunset_abs());
my $ts_sunrise = mktime($sunrise_seconds, $sunrise_minutes, $sunrise_hours, $day, $month, $year);
my $ts_sunset = mktime($sunset_seconds, $sunset_minutes, $sunset_hours, $day, $month, $year);
Log 1, $ts_sunrise;
Log 1, $ts_sunset;
Das Ganze lässt sich natürlich beliebt hin und her bauen (unabhängig von sunset und sunrise), aber in meinem Fall brauchte ich den Timestamp vom Sonnenuntergang.
Danke! - das war wirklich eine Erkenntnis für mich.