Array Übergabe bei Test von BlockingCall

Begonnen von Init, 26 Juni 2017, 14:45:40

Vorheriges Thema - Nächstes Thema

Init

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

dev0

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

justme1968

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.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

Init

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

justme1968

eine referenz auf array oder hash die dann beliebig verschachtelt sein können. der inhalt ist völlig frei.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

CoolTux

Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

dev0

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.

justme1968

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.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

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

Init

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

nils_

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...  ::)
viele Wege in FHEM es gibt!

Init

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

CoolTux

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.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

CoolTux

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
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net

Init

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

CoolTux

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.
Du musst nicht wissen wie es geht! Du musst nur wissen wo es steht, wie es geht.
Support me to buy new test hardware for development: https://www.paypal.com/paypalme/MOldenburg
My FHEM Git: https://git.cooltux.net/FHEM/
Das TuxNet Wiki:
https://www.cooltux.net