FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: HoTi am 10 Juni 2015, 14:01:14

Titel: [gelöst] InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 10 Juni 2015, 14:01:14
Hallo zusammen,

ich versuche ich gerade an Perl. Ich habe ein Code von Elektroluch aus diesem Forum. Diesen möchte ich von 1 auf mehrere Rollos erweitern.

Eine codezeile habe ich nicht verstanden. Hier wird eine Sub Funktion aufgerufen:

ZitatInternalTimer(gettimeofday()+ $fahrzeit, "Markise_Stop", $hash, 0);

Markise_Stop. Wie kann ich jetzt dieser Funktion noch Variablen übergen? Irgendwie mit dem Hash, aber da habe ich nicht so viele Anfängertauglichen Infos gefunden.

Wenn ich das richtig verstanden habe soll ich meinen eigenen Hash machen und den FHEM Hash da integrieren.

Und da weiß ich nicht mehr weiter.
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 10 Juni 2015, 15:17:00
Wenn du ein eigenes Modul geschrieben hast, hast  du ein $hash schon zur Verfügung.

Mit

$hash->{key1} = "Wert1";
$hash->{key2} = "Wert2";


kannst du dir Dinge in $hash (assoziatives Array, in perl halt Hash genannt) merken.

Markise_Stop ist so zu diefinieren:


sub Markise_Stop ($) {
my ($hash) = @_;

print  $hash->{key1};   # liefert "Wert1"
...
}


Wenn du kein Modul gebaut hast kannst du in 99_util $hash so erzeugen(genau genommén handelt es sich um eine Refferenz auf ein leeres Hash):


my $hash = {};


zu Hash gibt es im Netz viel Dokumentation im Netz.
Einfach nach perl Hash suchen.
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 10 Juni 2015, 15:37:11
Danke, das funktioniert! Aber wir verarbeite ich das weiter? Bekomme ja nur die Adressen

Zitatsub Ga_Schalter2_not($$$$)
{
my ($name,$event,$device_down,$device_up) = @_;
#my $hash = $defs{$name},$defs{$device_down},$defs{$device_up};
my $hash = {};
$hash->{NAME} = $defs{$name};
$hash->{DEVICE_DOWN} = $defs{$device_down};
$hash->{DEVICE_UP} = $defs{$device_up};
...

Zitat...
InternalTimer(gettimeofday()+ $fahrzeit, "Markise_Stop", $hash, 0);
...

Zitatsub Markise_Stop($$$)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my $device_down = $hash->{DEVICE_DOWN};
my $device_up = $hash->{DEVICE_UP};
Log3($name,3,"ACHTUNG 99: name $name device_down $device_down device_up $device_up");
...
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 10 Juni 2015, 15:51:02
was meinst du nur die Adressen?
Welche Adressen?
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 10 Juni 2015, 15:59:31
ich glaube ich habe es verstanden:


my $device_down = $hash->{DEVICE_DOWN};
print  $device_down->{NAME};


$device_down  ist auch wieder ein hash, das je nach Inhalt(muss man wissen) abgefragt werden kann.
in Perl/fhem werden die Daten in einem riesigen hash of hash of hash of hash (beliebige Tiefe) abgelegt.

mit Log 3, keys %{$hash} kann man sich die Schlüssel eines hash ausgeben lassen und ggf. darüber iterieren. Ich hoffe die Syntax stimmt.
mit Dumper kann man sich ganze hash Bäume ausgeben - Syntax etwas wie Log 3, Dumper dump $hash oder  Log 3, Dumper dump \%hash (Google befragen oder fhem Code absuchen)
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 10 Juni 2015, 16:00:29
ZitatACHTUNG 99: name HASH(0x88edb8) device_down HASH(0x87af20) device_up HASH(0x88e830)

Ich habe die 0x8... jetzt als adresse interpretiert. Sorry wenn das nicht stimmt.

Die 0x8... ist ja das Gerät. Wie bekomme ich jetzt den inhalt?
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 10 Juni 2015, 16:01:05
Zitat von: RettungsTim am 10 Juni 2015, 16:00:29


Ich habe die 0x8... jetzt als adresse interpretiert. Sorry wenn das nicht stimmt.

Die 0x8... ist ja das Gerät. Wie bekomme ich jetzt den inhalt?

ja, stimmt - siehe oben
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 10 Juni 2015, 16:04:27
Danke das war fast zeitgleich. Bin jetzt nur noch am handy da dauert es etwas länger.

Kann leider erst morgen weiter machen. Aber mit den tipps komme ich schon mal weiter.

Vielen dank! Ich melde mich ob es klappt oder wo ich wieder was nicht verstanden habe.
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Elektrolurch am 10 Juni 2015, 16:17:50
Hallo,

my $device_down = $hash->{DEVICE_DOWN};
würde ich vorsichtshalber aber so schreiben:
my $device_down = $hash->{'DEVICE_DOWN'};


Das $device_down ist ein String, und kein hash.
Und zwar ist das eine Kopie des Strings, der im  hash
$hash->{'DEVICE_DOWN'}
steht.


Elektrolurch
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 10 Juni 2015, 16:35:09
Hallo Elektrolurch,
Schön von dir zur lesen.

Wie kommst du darauf das das ein String sein soll? Ich bin schon der Meinungen das es so wie ich dein code umgeschrieben habe (lese oben ) ein Hash habe.

Habe es am Handy gerade ausprobiert. Oh man ist das ne tipper rei.
Aber es geht,  ohne die Anführungszeichen.

Jetzt muss ich mich um die anderen Probleme kümmen.

1. Position merken bei fhem neustart (z.b. Stromausfall)
2. Slider soll da stehen bleiben wo er ist.
3. Code vollständig verstehen. Hab heut schon viel gelernt.

Ich befürchte euch noch öffters zu brauchen.

Vielen dank euch beiden!
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 10 Juni 2015, 19:38:06
http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/hash/ (http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/hash/)
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Elektrolurch am 10 Juni 2015, 21:55:06
Hallo,
Zitat:
Aber es geht,  ohne die Anführungszeichen.

ein Hash wird mit einem (fast) beliebigen Text indiziert. Du könntest z.B. auch so was schreiben:

$hash->{mein_Vorname}

wenn Du aber das z.B. so schreibst:
$hash->{mein-Vorname}

versucht perl hier eine Substraktion durchzuführen.
Sobald Du also Irgendwelche Sonderzeichen in dem Indexs für den hash verwendest, würde ich den index in ' ' oder " " setzen, ihn also eindeutig als Stringkonstante kennzeichnen.
Das Du die Stringzeichen weglasssen kannst in bestimten Konstellationen, ist reine Freundlichkeit von perl.
Jetzt muss ich mich um die anderen Probleme kümmen.
Zitat:
1. Position merken bei fhem neustart (z.b. Stromausfall)
Wenn die Position in einem reading (bei mir ist es für die Markise ja ein dummy) steht, wird sie automatisch mit dem "save" - Befehl in das statefile geschrieben.

Das gilt aber grundsätzlich für alle devices in fhem.
Wenn Du das "save" automatisch auslösen möchtest, damit der letzte Status auch nach Neujstart wieder stimmt, dann  fügst Du entweder nach Abschluß einer Positionierung in den Code

fhem("save");
ein oder
definierst Dir z.B. ein at

define fhem_save_at at +01:00 save

oder
define fhem_save_at at +01:00 {fhem('save');; Log(1,"Konfig gesichert um $hour");;}

Mal so als Anregung.


2. Slider soll da stehen bleiben wo er ist.
Position des sliders = reading
Elektrolurch (auch aus OBB)
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 11 Juni 2015, 11:31:36
Danke euch beiden, ich denke ich habe jetzt schon viel gelernt aber es fehlt noch sehr viel.

Diesen Code finde ich jetzt mit euren Anmergungen irgenwie unschön. Das muss doch einfacher und besser gehen.
Perl meckert auch die dopplete Namensbenennung von $device_down und $device_up an, weil ich diese in sub Ga_Schalter2_not($$$$) schon habe :

Zitat
sub Markise_Stop($$$)
{
my ($hash,$device_down,$device_up) = @_;
my $name_hash = $hash->{NAME};
my $device_down_hash = $hash->{"DEVICE_DOWN"};
my $device_up_hash = $hash->{"DEVICE_UP"};

my $name = $name_hash->{NAME};
my $device_down = $device_down_hash->{NAME};
my $device_up = $device_up_hash->{NAME};

#Log3($name,3,"ACHTUNG 99: name $name device_down $device_down device_up $device_up");

my $mup = Value($device_up);
my $mdown = Value($device_down);
my $dt = 0;
my $aktpos = ReadingsVal($name,'Pos',0);
my $newpos;
#Log3($name,3,"ACHTUNG 3: mup $mup mdown $mdown");
if($mup =~m/(ein|on).*/)
{
$dt = time() - time_str2num(ReadingsTimestamp($device_up,'state',0));
fhem("set $device_up aus");
$newpos = $aktpos - (100 * $dt / ReadingsVal($name,'Einfahrzeit',0));
} # Die Markiese fährt bereis
elsif($mdown =~m/(ein|on).*/)
{
$dt = time() - time_str2num(ReadingsTimestamp($device_down,'state',0));
fhem("set $device_down aus");
$newpos = $aktpos + (100 * $dt / ReadingsVal($name,'Ausfahrzeit',0));
} # Die Markiese fährt bereis

$newpos = sprintf("%d",$newpos); # runden
$newpos = 0 if($newpos < 0);
$newpos = 100 if($newpos > 100);
#Log3($name,3,"$name _stop: dt $dt newpos $newpos");
readingsSingleUpdate($hash,'Pos',$newpos,0);
readingsSingleUpdate($hash,'state',"Pos $newpos",0);
# alle timer löschen
RemoveInternalTimer($hash);   
return undef;
} # end sub Markise_Stop
###########################
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Dietmar63 am 11 Juni 2015, 12:51:23
dopplete Namensbenennung von $device_down und $device_up
ist dann kein Fehler mehr wenn du innerhalb eines Subs bei der zweiten Zuweisung das my weglässt.


if($mup =~m/(ein|on).*/) {
   $dt = time() - time_str2num(ReadingsTimestamp($device_up,'state',0));
   fhem("set $device_up aus");
   $newpos = $aktpos - (100 * $dt / ReadingsVal($name,'Einfahrzeit',0)); 
} elsif($mdown =~m/(ein|on).*/){ # Die Markiese fährt bereis
   $dt = time() - time_str2num(ReadingsTimestamp($device_down,'state',0));
   fhem("set $device_down aus");
   $newpos = $aktpos + (100 * $dt / ReadingsVal($name,'Ausfahrzeit',0));
} # Die Markiese fährt bereis
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 11 Juni 2015, 13:04:52
Ah Super!

Kannst du auch was dazu sagen?

Zitat
PERL WARNING: Subroutine myUtils_Initialize redefined at ./FHEM/99_MyUtils.pm line 15.
PERL WARNING: Subroutine LastEvent redefined at ./FHEM/99_MyUtils.pm line 21.
PERL WARNING: Subroutine Markise_Stop redefined at ./FHEM/99_MyUtils.pm line 38.
PERL WARNING: Subroutine Ga_Schalter2_not redefined at ./FHEM/99_MyUtils.pm line 84.
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: Elektrolurch am 11 Juni 2015, 13:18:00
Dont worry.
PERL WARNING: Subroutine myUtils_Initialize redefined at ./FHEM/99_MyUtils.pm line 15.
PERL WARNING: Subroutine LastEvent redefined at ./FHEM/99_MyUtils.pm line 21.
PERL WARNING: Subroutine Markise_Stop redefined at ./FHEM/99_MyUtils.pm line 38.
PERL WARNING: Subroutine Ga_Schalter2_not redefined at ./FHEM/99_MyUtils.pm line 84.


heißt nur, das perl intern die Namen der per reload geladenen Module, bzw. deren Subroutinen in einer Tabelle verwaltet und dass sich die Definitionen Deiner subroutinen durch den reload - Befehl ja geändert haben.
Titel: Antw:InternalTimer -> Lerne Perl anhang eines Codes
Beitrag von: HoTi am 11 Juni 2015, 13:30:08
Perfekt! Das habe ich verstanden.

zu meinen Punkten:

1. Position merken bei fhem neustart (z.b. Stromausfall)
- Das funktiniert jetzt. Ist schon in Elektroluchs code enthalten. Als ich ihn mehr verstanden habe und vorallem verstanden habe was ein hash ist habe ich den fehler gefunden.

2. Slider soll da stehen bleiben wo er ist.
- Das hat sich natürlich mit Punkt eins erledigt

3. Code vollständig verstehen. Hab heut schon viel gelernt.
- Da bin ich noch dran

Da kommt gleich schon die Erweiterung die ich machen möchte.
Manuelles fahren über externen Taster (Im Beispiel die Dummys EG_ez_RO_runter, EG_ez_RO_hoch usw.)

Ich stelle mir das so vor:
Wenn Manuell fahre bekommt FHEM das über den Rückkanal von Homematic mit, im Dummy Beispiel: wenn EG_ez_RO_runter oder EG_ez_RO_hoch gesetzt wurde.
Also heißt das: Zeit merken, umrechnen in die Position und das Reading des Sliders ändern.