Korrekte Syntax FHEM-Befehl in Perl im ...notify... in myUtils auslagern

Begonnen von TomLee, 10 Juli 2020, 12:34:40

Vorheriges Thema - Nächstes Thema

TomLee

Fakt ist aber auch das es ohne Hochkommata nicht richtig sein kann weil dann bei jedem Aufruf der sub die Befehle in den Variablen ausgeführt werden.




(Und nein ich brauch/mag kein Popcorn) Hilfe !!!

Otto123

Das ist korrekt, ich mache immer Schritt für Schritt :)
{my $var="3+4";;return $var}
{my $var="3+4";;eval $var}

Also anstatt return $cmnd machst Du eval $cmnd und er führt es aus?

ZitatWarum aber escapen und nicht einfach qq nehmen ?
Das ist doch am Ende Geschmacksache ;)
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

Oh, ein Fuchsbau  :P

Unabhängig jetzt mal davon wie ich aneinanderkette klappts so:


sub cube {
my $NAME = shift;
my $EVENT = shift;
my $EVTPART0 = shift;
my $EVTPART1 = shift;
my $echo = shift;
chop($EVTPART0);
my $sr = ReadingsNum($NAME,'side',0);
my $sound = qq(;fhem("set $echo sounds Glocken"));
my $gzg = qq(system ('/opt/fhem/vouchergzg.sh &'));
$gzg .= $sound;
my $gzg1 = qq(system ('/opt/fhem/vouchergzg1.sh &'));
$gzg1 .= $sound;

#my $var = sub {return $_[0].';'.$sound};
#my $gzg = var((system ("/opt/fhem/vouchergzg.sh &")));
#my $gzg1 = (system ('/opt/fhem/vouchergzg1.sh &'));


Log3(undef, 3, "Das ist $NAME, $EVENT, $EVTPART0, $EVTPART1");


my %sr2cmnd = (
'0' => "$gzg",
'1' => "$gzg1"
);
my $cmnd = $sr2cmnd{$sr};

return if !$cmnd;
eval $cmnd;

}



Spricht auch wirklich nix dagegen mit eval statt return den Wert zurückzugeben ?

Danke Otto


Otto123

Du kannst auch erst return und dann im Aufruf das eval machen?
return gibt den String zurück  eval evaluiert und führt ihn aus.

also im Aufruf eval {cube ...}
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

Zitat von: Otto123 am 27 Februar 2021, 19:32:00
Du kannst auch erst return und dann im Aufruf das eval machen?
return gibt den String zurück  eval evaluiert und führt ihn aus.

Bis dahin dacht ich erst kann ich folgen.

Nach

Zitatalso im Aufruf eval {cube ...}

bin ich am zweifeln. Wo meinst du jetzt ? direkt im notify? oder am Ende der sub wo der Wert zurückgegeben wird ?

Otto123

Zitat von: TomLee am 27 Februar 2021, 19:44:41
Bis dahin dacht ich erst kann ich folgen.

Nach

bin ich am zweifeln. Wo meinst du jetzt ? direkt im notify? oder am Ende der sub wo der Wert zurückgegeben wird ?
Ich bin spät eingestiegen.  ;D
Entweder machts Du {cube()} und lässt die Ausführung (eval) in der Sub machen, oder Du machst {eval cube()} beim Aufruf und die Sub gibt den String zurück?
Die geschweiften in meinem Einwand waren wahrscheinlich falsch ...
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

Ich nehm erstmal (für die gestellte Frage hier, ich erweitere das noch) die Variante im notify.

Wenn das irgendwann irgendwem mal weiterhilft (und in Zukunft für mich), so klappts jetzt (ohne die zusätzliche anonyme sub, zu der ich mich noch beschäftigen muss):

defmod not_MQTT2_Cube notify MQTT2_Cube:action:.tap {eval cube($NAME,"EG_Echo_Kueche")}

sub cube {
my $NAME = shift;
my $echo = shift;
my $sr = ReadingsNum($NAME,'side',0);
my $sound = qq(;fhem("set $echo sounds Glocken"));
my $gzg = qq(system ('/opt/fhem/vouchergzg.sh &')).$sound;
my $gzg1 = qq(system ('/opt/fhem/vouchergzg1.sh &')).$sound;
my $g17d = qq(system ('/opt/fhem/voucher.sh &')).$sound;
my $g121d = qq(system ('/opt/fhem/voucher21.sh &')).$sound;

my %sr2cmnd = (
'0' => "$gzg",
'1' => "$gzg1",
'2' => "$g17d",
'4' => "$g121d"
);

return $sr2cmnd{$sr};

}


DANKE

Irgendwelche Einwände ?

Otto123

Den Abschluss versteh ich nicht ganz:
      my $cmnd = $sr2cmnd{$sr};
      
         return if !$cmnd;
         return $cmnd;
würde ich final ersetzen durch return $sr2cmnd{$sr}
Weil: was bringt die Umwidmung in eine neue Variable?
Was bringt das return if !$cmnd; ?
Viele Grüße aus Leipzig  ⇉  nächster Stammtisch an der Lindennaundorfer Mühle
RaspberryPi B B+ B2 B3 B3+ ZeroW,HMLAN,HMUART,Homematic,Fritz!Box 7590,WRT3200ACS-OpenWrt,Sonos,VU+,Arduino nano,ESP8266,MQTT,Zigbee,deconz

TomLee

ZitatWas bringt das return if !$cmnd; ?

Das war meine Frage hier.

Die kann ich auch direkt beantworten, mein ich, dadurch würde eine Meldung verhindert werden wenn es keinen Key geben sollte, hier aber gar nicht nötig weil in $sr ein default-Wert angegeben ist und damit das return if !$cmnd; überflüssig ist, weil es halt immer einen Key gibt.

Zitatwürde ich final ersetzen durch return $sr2cmnd{$sr}

muss ich ausprobieren später, eigentlich ja, du verunsicherst mich jetzt aber ob ich was übersehe.

TomLee

Zitat von: Otto123 am 27 Februar 2021, 20:37:00
würde ich final ersetzen durch return $sr2cmnd{$sr}
Weil: was bringt die Umwidmung in eine neue Variable?

Korrekt erkannt, hab oben nochmal editiert.

Beta-User

Zitat von: TomLee am 27 Februar 2021, 20:04:22
Irgendwelche Einwände ?
Wenn ich irgendwo "eval" lese, habe ich den "kann das weg?!?"-Reflex.

Und ein qq+concat ist "komisch"...

Nicht fertig, aber evtl. als "Steinbruch" brauchbar:
sub myUptime {
  my $param = shift;
  my $uptime = q{fheminfo};
  my $sound1 = qq(;" FHEM: ".fhem($uptime));
  my $sound2 = sub  { qx($uptime) . q{ } . fhem($uptime);  };
  $uptime = q{uptime};
  my $a1 = qq(system ('uptime &')$sound1);
  my $a2 = sub  { qx($uptime).$sound1 };
  my $a3 = sub  { my $r = qx($uptime &); $r .= " FHEM: ".fhem($uptime); return $r};
  my $sr2cmnd = {
    0 => $sound1,
    1 => \&$sound2,
    2 => $a1,
    4 => \&$a2,
    8 => \&$a3
  };
  my $ret;
  if (ref $sr2cmnd->{$param} eq 'CODE') {
     $ret = $sr2cmnd->{$param}->();
  } elsif (ref $sr2cmnd->{$param} eq 'SCALAR')  {
     $ret = 'via eval: ' . eval {$sr2cmnd->{$param}};
  }
  return $ret;
}

Die (teilweise enthaltenen) Referenzierungen vermeiden auch, das Dinge kopiert werden, ist effizienter...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

TomLee

Das du aber auch immer wieder noch einen draufsetzen musst. ;D

Oben war nur die Rede von einer anonymem sub.

Jetzt sind plötzlich noch anonyme Verweise im Spiel.

Verstehe nur Bahnhof und das wird mein ich auch noch eine ganze Weile so bleiben.

Ganz so schwer scheint es teilweise aber gar nicht zu sein, mir fehlt aber einfach dazu Basiswissen.

Selbst wenn ich mich dazu einlesen würde/werde hab ich große Zweifel ob da wirklich in meiner Birne was hängen bleibt/auf Dauer was verfestigt.

Hab mir das jetzt zusammengereimt, das kein Steinbruch, das ein einfach nur ein Riesenloch vergleichbar mit dem Krater den der Meteorit der die Dinosaurier aussterben ließ beim Einschlag verursachte, weil die Zusammenhänge nicht begriffen und bedingt "einfach mal irgendwas gemacht" :

sub cube {
my $NAME = shift;
my $echo = shift;
my $sr = ReadingsNum($NAME,'side',0);
my $sound = qq(;fhem("set $echo sounds Glocken"));
my $gzg = sub {qq(system ('/opt/fhem/vouchergzg.sh &')$sound)};
my $gzg1 = sub {qq(system ('/opt/fhem/vouchergzg1.sh &')$sound)};
my $g17d = sub {qq(system ('/opt/fhem/voucher.sh &')$sound)};
my $g121d = sub {qq(system ('/opt/fhem/voucher21.sh &')$sound)};

my $sr2cmnd = {
'0' => "$gzg",
'1' => "$gzg1",
'2' => "$g17d",
'4' => "$g121d"
};


my $ret;
if (ref $sr2cmnd->{$sr} eq 'CODE') {
$ret = $sr2cmnd->{$sr}->();
}
elsif (ref $sr2cmnd->{$sr} eq 'SCALAR')
{$ret = eval {$sr2cmnd->{$sr}};
}
return $ret;

}



ZitatWenn ich irgendwo "eval" lese, habe ich den "kann das weg?!?"-Reflex.

Du benutzt doch in deinem Steinbruch in dem elsif-Zweig auch eval ?
Aber wie gesagt Null verstanden wann da CODE(...) und wann SCALAR(...) zurückkommt.


Wzut

Zitat von: Beta-User am 28 Februar 2021, 10:20:25
Wenn ich irgendwo "eval" lese, habe ich den "kann das weg?!?"-Reflex.
und ich habe den Reflex inzwischen wenn ich elsif in Verbindung mit return lese :)
Warum machst du den unteren Teil ab my $ref nicht auch noch schlank ?
return $sr2cmnd->{$param}->()                   if (ref $sr2cmnd->{$param} eq 'CODE');
return 'via eval: ' . eval {$sr2cmnd->{$param}} if (ref $sr2cmnd->{$param} eq 'SCALAR');
return; # Gürtel zum Hosenträger ?

oder habe ich jetzt etwas übersehen ?
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

TomLee

Ok, irgendwo muss ich ja anfangen zu verstehen, zu ref bin ich wieder mal  ::)  hier gelandet.

Anhand dem Code:

my $ret;
if (ref $sr2cmnd->{$sr} eq 'CODE') {
$ret = $sr2cmnd->{$sr}->();
}
elsif (ref $sr2cmnd->{$sr} eq 'SCALAR')
{$ret = eval {$sr2cmnd->{$sr}};
}
return $ret;


müsste was in $a1 stehen das SCALAR zurückgeliefert werden soll ?

Egal was ich reinschreibe, es ist immer CODE ?

    use strict;
    use warnings;
    use 5.010;
   
my $param = "8";
my $uptime = q{fheminfo};
#my $a1 = "Das,ist,ein,Testtext";
my $a1 = "Das ist ein Testtext";
#my $a1 = "5";
#my $a1 = sub  { my $r = qx($uptime &); $r .= " FHEM: ".fhem($uptime); return $r};
    my $sr2cmnd = {
    8 => \&$a1
  };

print  ref $sr2cmnd->{$param}, "\n";

Beta-User

OK, vielleicht mal der Reihe nach...

Zitat von: Wzut am 28 Februar 2021, 17:59:49
und ich habe den Reflex inzwischen wenn ich elsif in Verbindung mit return lese :)
Absolut berechtigt...

"Eigentlich" wollte ich nur auf "quotes in Perl" (siehe z.B. https://www.perlmonks.org/?node_id=401006) ein wenig zur Irreführung rumreiten, nebenbei den Hinweis einflechten, dass es auch noch "qx" gibt und unter den ganzen Schotter dann noch die m.E. korrekte Lösung für das angefragte Problem verstecken...

Und sorry, dass ich da überhaupt ein "eval" reingemauschelt hatte, das war selbstredend weitgehend überflüssig bzw. nur deswegen (vielleicht) erforderlich, weil der (unnötige) Teil der Textoperationen sonst eben kein "Funktions"-Ergebnis geliefert hätte :P . (Macht auch keinen Sinn, diesen Teil zu vertiefen, denn das so zu machen ist m.E. nicht die beste Variante, das "Problem" zu lösen.

(Bevor einer mosert: ja, das ist hier wirklich nichts mehr, was bei den Anfängerfragen gut aufgehoben ist...)

Da wären wir als erstes bei der Frage von Otto:
Zitat von: Otto123 am 27 Februar 2021, 15:37:06
was das genaue Ziel
denn eigentlich war:

Es ging darum, einen funktionierenden Ausgangscode "eleganter" zu schreiben und so zu dynamisieren, dass man ihn "variabel" nutzen kann, so jedenfalls meine Interpretation von dem hier:
Zitat von: TomLee am 27 Februar 2021, 12:38:58
Ich war der Meinung das es so einfach ist das ich es auch ohne zu fragen hinbekomme ::)

Sitz da jetzt schon Stunden dran mit allen mir erdenklichen Variationen von qq,Hochkommata und Verkettungen

defmod not_MQTT2_Cube notify MQTT2_Cube:action:.tap {cube($NAME,$EVENT,$EVTPART0,$EVTPART1,"EG_Echo_Kueche")}

setstate not_MQTT2_Cube 2021-02-27 11:56:04
setstate not_MQTT2_Cube 2021-02-26 19:26:05 state active


sub cube {
   my $NAME = shift;
   my $EVENT = shift;
   my $EVTPART0 = shift;
   my $EVTPART1 = shift;
   my $echo = shift;
   chop($EVTPART0);
   my $sr = ReadingsNum($NAME,'side',0);
   my $sound = fhem("set $echo sounds Glocken");
   my $gzg = (system ('/opt/fhem/vouchergzg.sh &'));$sound;   
   #my $gzg1 = (system ('/opt/fhem/vouchergzg1.sh &'));$sound;
   
   Log3(undef, 3, "Das ist $NAME, $EVENT, $EVTPART0, $EVTPART1");
   
     
      my %sr2cmnd = (
      '0' => "$gzg"
      );
      my $cmnd = $sr2cmnd{$sr};
     
         return if !$cmnd;
         return $cmnd;

   }


Wie lautet die richtige Definition der Variablen $gzg/$gzg1 ?

Ist $gzg1 auskommentiert wird einmal beim Event tap vouchergzg.sh und $sound ausgeführt allerdings unabhängig vom Key (Reading side), es reicht also einfach nur der Aufruf der sub.

Nehm ich die Variablendefinition $gzg1 mit rein wird beim Event tap (und auch unabhängig vom Key) zweimal vouchergzg1.sh und einmal $sound ausgeführt ? ? ?

Was hab ich noch nicht verstanden, hat es was mit der Definition eines Systemaufruf in einer Variablen zu tun ?

edit:

mit if und einer IT-Fernbedienung klappt mein Vorhaben bisher problemlos so:

   if ($NAME eq "FB_433_2_TasteC" && $EVENT eq "on")
   {(system ('/opt/fhem/vouchergzg.sh &'));fhem("set EG_Echo_Kueche sounds Glocken")}
   
   if ($NAME eq "FB_433_2_TasteC" && $EVENT eq "off")
   {(system ('/opt/fhem/vouchergzg1.sh &'));fhem("set EG_Echo_Kueche sounds Glocken")}

Insbesondere der letzte Code-Block gibt also das Ziel vor: Es soll abhängig von einem bestimmten Event ein bestimmter Code ausgeführt werden.

Ergo verpacken wir den Code in eine anonyme sub, das war der Vorschlag.

Läßt man aus meine Code jetzt das ganze "Blendwerk" weg, bleibt für {myUptime( 8 )} noch folgender Code übrig:
sub myUptime {
  my $param = shift;
  my $uptime = q{uptime};
  my $a3 = sub  { my $r = qx($uptime &); $r .= " FHEM: ".fhem($uptime); return $r};
  my $sr2cmnd = {
    8 => \&$a3
  };
  my $ret;
  return $ret = $sr2cmnd->{$param}->() if ref $sr2cmnd->{$param} eq 'CODE';
  return "Da ist was schief gegangen";
}

Wir haben
- eine Parameter-Übergabe (als Beispiel);
- einen intern ermittelten Parameter (das Wörtchen "uptime", das man hier selbstredend auch "hart" hätte in den Code schreiben können, oder bei längerem Code auch aufwändig ermitteln kann - wie gesagt, geht nur um die Prinzipdarstellung...);
- unsere "anonyme sub". Da steht alles drin, was sonst auch eine sub ausmacht, nur eben mit der Besonderheit, dass sie etwas speziell aufgerufen wird und Parameter dann bei der Ausführung aus demselben lexical scope gefüllt werden...  (an diese "Kleinigkeit" hatte ich erst nicht gedacht, und daher erst mal geschrieben, das ginge so nicht). Nach diesem Muster wären dann eben für obige Aufgabe zwei subs zu bilden;
- unseren Beispiel-Hash, jetzt hat nur noch mit einem lookup, bei mehr subs dann halt mit mehr Inhalt...
- die Absicherung, dass wir wirklich nur Code ausführen...

Das war's dann auch schon.

PS: Interessantes script, aber auf welcher Seite soll die Lösung stehen ;) ?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files