Hallo zusammen,
ich teste gerade den BlockingCall.
Hierbei hatte ich das Problem, dass ich ein Array an die non-blocking Funktion übergeben muss.
Komischerweise ist nach der Übergabe des Arrays an die Funktion das Array "kaputt"
Hier mein Code:
sub
test
{
my $param1 = shift;
my $devName = "";
my @devNames = ();
push @devNames, 'AAA';
push @devNames, 'BBB';
push @devNames, 'CCC';
for(@devNames) {
$devName = $_;
print "\$devName A: $devName\n";
}
BlockingCall("testNB", "$param1|@devNames", "", "", "", "");
}
sub
testNB
{
my ($string) = @_;
my $devName = "";
my ($param1, @devNames) = split("\\|", $string);
for(@devNames) {
$devName = $_;
print "\$devName B: $devName\n";
}
#return "Body|Test"
}
Und hier das Ergebnis auf der Console:
$devName A: AAA
$devName A: BBB
$devName A: CCC
$devName B: AAA BBB CCC
Wie man sehen kann, ist in Funktion test die Ausgabe in Ordung und in der Funktion testNB funktioniert die for Schleife nicht mehr.
Ich vermute, dass ich bei dem split etwas falsch mache.
Kann mir jemand sagen, wo ich den Fehler gemacht habe?
Vorab vielen Dank.
VG
Marc
Auf den ersten Blick würde ich @devNames zB. mit join("|",@devNames) in ein String umwandeln und dann an BlockingCall() übergeben. Optional Parameter solltest Du nicht auf "" setzen, sondern einfach weglassen oder undef verwenden. https://wiki.fhem.de/wiki/Blocking_Call#Benutzung
um ein array in einen string zu konvertieren musst du join verwenden. das macht perl nicht automatisch. wenn es komplexer wird bietet sich an json zu verwenden.
für die richtung fhem -> blockingCall bist du aber nicht auf einen string beschränkt. du kannst hier auch eine referenz auf eine beliebige datenstruktur verwenden. d.h. du kannst alles in verschachtelte arrays und hashes stecken.
nur für die gegenrichtung musst du die rückgabe in einen string verpacken. wenn du hier komplexere datenstrukturen übergeben geht das ebenfalls mit json sehr gut.
Danke für Eure Antworten. Ich bin in Perl wirklich noch am Anfang...
Zitat von: dev0 am 27 Juni 2017, 09:07:49
Auf den ersten Blick würde ich @devNames zB. mit join("|",@devNames) in ein String umwandeln und dann an BlockingCall() übergeben. Optional Parameter solltest Du nicht auf "" setzen, sondern einfach weglassen oder undef verwenden. https://wiki.fhem.de/wiki/Blocking_Call#Benutzung
Also wäre der Aufruf so zu empfehlen:
BlockingCall("testNB", "$param1|@devNames");
oder
BlockingCall("testNB", "$param1|@devNames", undef, undef, undef, undef);
Wobei ich dann natürlich Variante 1 bevorzugen würde und die undef nur, wenn ich beispielsweise noch den letzten Parameter füllen möchte.
Zitat von: justme1968 am 27 Juni 2017, 09:22:46
um ein array in einen string zu konvertieren musst du join verwenden. das macht perl nicht automatisch. wenn es komplexer wird bietet sich an json zu verwenden.
für die richtung fhem -> blockingCall bist du aber nicht auf einen string beschränkt. du kannst hier auch eine referenz auf eine beliebige datenstruktur verwenden. d.h. du kannst alles in verschachtelte arrays und hashes stecken.
nur für die gegenrichtung musst du die rückgabe in einen string verpacken. wenn du hier komplexere datenstrukturen übergeben geht das ebenfalls mit json sehr gut.
Dann könnte ich bei der Nutzung der Funktion BlockingCall als 2. Parameter verschachtelte arrays und hashes nutzen.
Beim return aus der Aufgerufenen Funktion (Übergabe an die finishFn) muss dann allerding ein String verwendet werden.
Habe ich das richtig verstanden?
Kann ich in Perl in ein Array oder Hash unterschiedliche Datentypen packen?
VG
Marc
eine referenz auf array oder hash die dann beliebig verschachtelt sein können. der inhalt ist völlig frei.
Zum Thema Array Referenzen hat mir das hier damals sehr geholfen.
http://www.cis.uni-muenchen.de/~micha/kurse/perlII-WS0809/literatur/perl_skript.pdf
Zitat von: Init am 27 Juni 2017, 10:32:51
Also wäre der Aufruf so zu empfehlen:
BlockingCall("testNB", "$param1|@devNames");
Nein, wenn Du keine Referenz auf das Array verwenden möchtest, dann so:
BlockingCall("testNB", "$param1|".join("|",@devNames);
Mit Zeigern aka References würde es so aussehen:
BlockingCall("testNB", "$param1|".\@devNames);
In testNB() dann etwa so:
my ($string) = @_;
my ($param1, $refDevs) = split("\\|", $string);
foreach my $dev ( @{ $refDevs } ) {
doSomethingWith( $dev );
}
#oder
doSomethingElseWith( $refDevs->[0] );
Alles ungetestet.
nicht ganz. die referenz kannst du nur direkt und alleine übergeben. nicht an einen string hängen. und auf empfänger seite ist dann auch kein split nötig da es ja kein string ist.
Vielen Dank!
Das Beispiel werde ich versuchen mit einer Referenz zu bauen (ohne split) und "PERL für Fortgeschrittene" durcharbeiten, danach habe ich bestimmt ein bessere Verständnis im Bereich Perl
unter https://wiki.fhem.de/wiki/Blocking_Call#Benutzung
ZitatDie Funktion BlockingCall() gibt bei Erfolg eine Hashreferenz mit mehreren Items zurück. Dieser Hash ist folgendermaßen aufgebaut.
$hash->{pid} → Die Prozess-Id, unter der dieser Aufruf abgearbeitet wird.
$hash->{fn} → Der Name der blockigen, der mit diesem Aufruf abgearbeitet wird.
$hash->{finishFn} → Der Name der finishFn, die diesen Aufruf nach Erfolg verarbeiten wird.
$hash->{abortFn} → Der Name der abortFn, die im Fehlerfall aufgerufen wird.
$hash->{abortArg} → Das Argument, das im Fehlerfall an die abortFn übergeben werden soll.
ist damit die aufrufende methode gemeint?
ist irgendwie komisch beschrieben... ::)
Nochmal ich...
Habe mir noch bisschen gelesen und getestet.
Wollte mir jetzt einen hash als Argument (CALL BY VALUE) übergeben, aber bekomme diesen irgendwie nicht in der Sub entgegengenommen.
Wie würde ich den hash richtig entgegennehmen?
Hier mein Code:test
{
my $param1 = shift;
my $devName = "";
my @devNames = ();
push @devNames, 'AAA';
push @devNames, 'BBB';
push @devNames, 'CCC';
push @devNames, 'DDD';
for(@devNames) {
$devName = $_;
print "\$devName A: $devName\n";
}
my %ParamsNB = (
param1 => $param1,
devNames => @devNames
);
BlockingCall("testNB", %ParamsNB);
}
sub
testNB
{
my (%arg) = @_;
print "** devNames: $arg{'param1'} \n";
}
VG
Marc
Zitat von: nils_ am 27 Juni 2017, 15:35:33
unter https://wiki.fhem.de/wiki/Blocking_Call#Benutzung
ist damit die aufrufende methode gemeint?
ist irgendwie komisch beschrieben... ::)
Damit ist die Funktion BlockingCall gemeint. Ja.
Zitat von: Init am 27 Juni 2017, 15:45:12
Nochmal ich...
Habe mir noch bisschen gelesen und getestet.
Wollte mir jetzt einen hash als Argument (CALL BY VALUE) übergeben, aber bekomme diesen irgendwie nicht in der Sub entgegengenommen.
Wie würde ich den hash richtig entgegennehmen?
Hier mein Code:test
{
my $param1 = shift;
my $devName = "";
my @devNames = ();
push @devNames, 'AAA';
push @devNames, 'BBB';
push @devNames, 'CCC';
push @devNames, 'DDD';
for(@devNames) {
$devName = $_;
print "\$devName A: $devName\n";
}
my %ParamsNB = (
param1 => $param1,
devNames => @devNames
);
BlockingCall("testNB", %ParamsNB);
}
sub
testNB
{
my (%arg) = @_;
print "** devNames: $arg{'param1'} \n";
}
VG
Marc
Nicht den Hash sondern die Hashreferenz übergeben
\%ParamsNB
Grüße
Irgendwie drehe ich mich im Kreis.
Habe jetzt den Hash als Referenz übergeben, aber jetzt ist mein Array wieder ein String:
test
{
my $param1 = shift;
my $devName = "";
my @devNames = ();
push @devNames, 'AAA';
push @devNames, 'BBB';
push @devNames, 'CCC';
push @devNames, 'DDD';
for(@devNames) {
$devName = $_;
# print "\$devName A: $devName\n";
}
my %ParamsNB = (
param1 => "$param1",
devNames => "@devNames"
);
my $testParam = "AAA";
testNB(\%ParamsNB);
print "$ParamsNB{'param1'} \n";
}
sub
testNB
{
my $arg = shift;
my %argRef = %$arg;
for( $argRef{'devNames'}) {
print "\$devName A: $_\n";
}
}
Geändert habe ich zusätzlich noch die Zuweisung des Arrays zum Hash
Vorher
my %ParamsNB = (
param1 => $param1,
devNames => @devNames
);
Hier hatte ich das Problem, dass ich folgende Meldung bekommen habe, da AAA devNames zugeordnet wird und dann BBB => CCC und DDD =>
Nachher
my %ParamsNB = (
param1 => "$param1",
devNames => "@devNames"
);
Wahrscheinlich wird jetzt devNames zu einem String gewandelt.
Kann mir noch jemand einen Hinweis geben?
VG
Marc
Wieso machst Du nicht einfach ein Array Referenz? Oder lieber gleich als JSON.
Versuche mal das verlinkte PDF von mit zu lesen. Dann erstellst Du eine ganz einfache Perldatei mit 2 Funktionen und schaust erstmal das Du dort mit Referenzen arbeiten kannst. Völlig weg von FHEM. Erstmal nur Perl. So bekommst Du ein Gefühl für das ganze.
Als Array Referenz hatte ich gerade das gleiche Problem. Lese schon die ganze Zeit parallel im PDF, aber teste auch dabei und will halt auch mein Problem verstehen und lösen.
Es funktioniert, wenn ich die Variablen selbst in der Zuweisung zum Hash oder Array als Referenz zuweise.
So funktioniert es, aber ich frage mich halt, warum ich die Variable als Referenz zuweisen muss und nicht die Variable selbst. (Speicherverbrauch/-belegung mal außen vor)
Wenn es in Perl nur als Referenz geht, dann bin ich zufrieden, wenn es aber auch anders geht, dann würde ich halt gerne meinen Fehler verstehen.
Zitat von: Init am 27 Juni 2017, 21:18:26
Geändert habe ich zusätzlich noch die Zuweisung des Arrays zum Hash
Vorher
my %ParamsNB = (
param1 => $param1,
devNames => @devNames
);
Hier hatte ich das Problem, dass ich folgende Meldung bekommen habe, da AAA devNames zugeordnet wird und dann BBB => CCC und DDD =>
Nachher
my %ParamsNB = (
param1 => "$param1",
devNames => "@devNames"
);
Wahrscheinlich wird jetzt devNames zu einem String gewandelt.
So, habe heute Abend noch ein bisschen gelesen.
Die Zuweisung müsste so sein, wenn ich das Array nicht als Referenz mitgeben möchte:
my %ParamsNB = (
param1 => $param1,
devNames => [@devNames]
);
VG
Marc
Bedeutet so funktioniert es nun?
Ja, so funktioniert es. War halt das letzte, was ich noch testen bzw. verstehen wollte.
Hierbei ist es auch egal, ob das Array in einem Hash oder einem Array steckt. Auch ist es egal, ob als Referenz oder "Kopie".
Mir war persönlich wichtig, dass ich verstehe, wie ich in allen Variationen alles ansprechen kann.
Super. Und ich denke Mal wenn man sich so durchgeboxt hat behält man es besser im Kopf ;D
Und was genau willst Du dann später damit zaubern?
Genauso sehe ich das auch...
Momentan noch nichts konkretes.
Hatte überlegt etwas zum Thema NINA zu machen, aber bin mir nicht sicher, ob ich das zeitlich leisten kann.
Um ein richtiges FHEM-Modul zu bauen gehört wahrscheinlich schon einiges mehr an PERL Kenntnissen dazu.
Kennst du ein Modul, welches sehr einfach gehalten ist und sich zum verstehen der benötigten Strukturen eignet?
Zitat von: Init am 29 Juni 2017, 09:01:57
Kennst du ein Modul, welches sehr einfach gehalten ist und sich zum verstehen der benötigten Strukturen eignet?
Persönlich habe ich das Problem das ich immer ein Projekt brauche, ein Vorhaben, eine Idee welche ich umsetzen möchte. Erst dann verstehe ich auch und mache mir Gedanken.
Um generell in die FHEM Modulprogrammierung rein zu kommen kannst Du den Developer Guide lesen und einfach mal versuchen Sinnvolle 99_myUtils Scripte zu schreiben.
Natürlich wäre ein richtiges Modul zum lernen besser. Aber ohne konkretes Projekt/Vorhaben/Idee ist es einfach doof. Ich hatte damals einfach nur Glück mit meinem AMAD. Ohne das Glück wäre ich heute nicht soweit drin in der FHEM Modul Entwicklung.
Suche Dir etwas wo Du denkst das kannst Du gut gebrauchen, das ist was größeres und mache ein Modul daraus. Und wenn es einfach erstmal nur was für Dich ist, ist ja egal.
Danke für deinen Rat!
Persönlich habe ich schon sehr viele 99_myUtils Skripte. Habe eine Jalousiesteuerung, Bewässerungssteuerung und zahlreiche kleine Skripte.
Auslöser dieses Threads war, dass ich ein Skript für die Bewegungsmelder gebaut habe und jeder Bewegungsmelder abhängige Devices hat und ich anhand des Devicetyps unterschiedliche Aktionen ansteuere.
Hier wäre ein richtiges Modul wahrscheinlich besser und bei den beiden anderen Themen auch. Diese sind wahrscheinlich nicht für andere interessant, da es solche Module schon gibt.
Vielleicht baue ich erstmal eins für mich und wenn das klappt, dann ist vielleicht eine Schnittstelle zu NINA oder wenigstens zu MoWas verfügbar. Dann würde ich vielleicht mal versuchen eins für die Allgemeinheit zu bauen.