Übergabe Variable von perl in fhem Ebene

Begonnen von Fritz Muster, 21 Februar 2023, 12:20:58

Vorheriges Thema - Nächstes Thema

Fritz Muster

Hallo Zusammen,

ich habe mir eine kleine subroutine (myutils) gebaut die ich nicht zum laufen bekomme und wäre für Tipps/Anregungen dankbar. Ich möchte bei true einer if Schleife nach 5 Sekunden die identische Abfrage der ersten if Schleife erneut machen und in dessen true Fall den Wert off detected zurückgeben. Der code sieht so aus:

mysub
{
my ($device, $state,) = @_;
my $devstate = ReadingsVal("$device","$state",0);
if ($devstate eq "off") {fhem('sleep 5;; {if ($devstate eq "off"){return ("off detected")}}')}
return "sleeping";
}


In einem device habe ich folgendes userreading zum aufruf der Routine angelegt
watchdog {mysub ($name,"state")}

Das Ganze funktioniert nicht, im log steht

ERROR evaluating {if ($devstate eq "off"){return ("off detected")}}: Global symbol "$devstate" requires explicit package name (did you forget to declare "my $devstate"?) at (eval 4271727) line 1.
After sleep: Global symbol "$devstate" requires explicit package name (did you forget to declare "my $devstate"?) at (eval 4271727) line 1.


Jetzt ist meine Vermutung das ich durch den Wechsel von der perl Ebene in die fhem Ebene {fhem('...} die in perl definierte Variable $devstate verliere bzw. nicht mit "rüber nehme". Kann meine Vermutung jemand bestätigen und wenn ja hat jemand eine Idee wie ich die Variable beim Wechsel von perl zu fhem "mit nehmen kann".

Vielen Dank und viele Grüße
Fritz
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Wenn Du den Inhalt von Variablen ausgeben möchtest, dann musst Du diese in doppelte Anführungszeichen setzen.
Bei einfachen wird die Variable nicht durch ihren Wert ersetzt oder Du musst die Variable aus den einfachen Anführungszeichen herausnehmen und dann mit einem Punkt hinten dran verknüpfen.

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

DeeSPe

#2
z.B.:
if ($devstate eq "off") {fhem("sleep 5;; {if ($devstate eq 'off'){return ('off detected')}}")}

oder

if ($devstate eq "off") {fhem('sleep 5;; {if ('.$devstate.' eq "off"){return ("off detected")}}')}

oder

if ($devstate eq "off") {fhem("sleep 5;; {if ($devstate eq \"off\"){return (\"off detected\")}}")}

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Fritz Muster

Danke für die schnelle Antwort!!

if ($devstate eq "off") {fhem('sleep 5;; {if ('.$devstate.' eq "off"){return ("off detected")}}')}

führt im log zu folgendem

sleep 5;; {if (off eq "off"){return ("off detected")}} : Last parameter must be quiet

und bei

if ($devstate eq "off") {fhem("sleep 5;; {if ($devstate eq 'off'){return ('off detected')}}")}

kommt

sleep 5;; {if (off eq 'off'){return ('off detected')}} : Last parameter must be quiet

und bei

if ($devstate eq "off") {fhem("sleep 5;; {if ($devstate eq \"off\"){return (\"off detected\")}}")}

ist die log Ausgabe

sleep 5;; {if (off eq "off"){return ("off detected")}} : Last parameter must be quiet

Jetzt scheint es so das die die if Abfrage nach dem sleep nicht als "neue Zeile" interpretiert wird sondern noch dem sleep Befehl zugeordnet wird. Und da wird ja wenn überhaupt nur ein "quiet" akzeptiert. lautet nun die Frage wie bekomme ich das hin das die if Abfrage nach dem sleep als "neue Zeile" interpretiert wird?
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Zitat von: Fritz Muster am 21 Februar 2023, 12:48:24
lautet nun die Frage wie bekomme ich das hin das die if Abfrage nach dem sleep als "neue Zeile" interpretiert wird?

Das brauchst du nicht!
Warum fügst du nicht mal das angemahnte 'quiet' hinzu?
Also:
if ($devstate eq "off") {fhem('sleep 5 quiet;; {if ......


Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Fritz Muster

Zitat von: DeeSPe am 21 Februar 2023, 12:55:05
Warum fügst du nicht mal das angemahnte 'quiet' hinzu?
[/code]

Habe ich mal gemacht! Ergebnis
sleep 5 quiet;; {if (off eq "off"){return ("off detected")}} : Last parameter must be quie

:(
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

Fritz Muster

#6
Habe jetzt noch ein wenig probiert. Nach dem einfügen eines weiteren Semikolion nach dem sleep

my ($device, $state,) = @_;
my $devstate = ReadingsVal("$device","$state",0);
if ($devstate eq "off") {fhem("sleep 5;;; {if ($devstate eq \"off\"){return (\"off detected\")}}")}
return "sleeping";


erscheint jetzt keine Fehlermeldung mehr im log. Allerdings wird die if Abfrage nicht true (obwohl $devstate eq "off" ist) und der Rückgabewert der Routine ist "sleeping"
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Klar, die Funktion gibt am Ende immer "sleeping" zurück!
Ich dachte das war so gewollt.
Sonst musst du das in den else Zweig legen:

my $devstate = ReadingsVal($device,$state,0);
if ($devstate eq 'off')
{
  fhem "sleep 5 quiet; {if ($devstate eq 'off'){return 'off detected'}else{return 'sleeping'}")};
}


Somit wird nach 5 Sekunden der Status erneut geprüft und wenn wieder true dann 'off detected' oder bei false 'sleeping'.

Das mit den ;;; ist Quatsch! Ein Semikolon reicht an der Stelle.

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Fritz Muster

Zitat von: DeeSPe am 21 Februar 2023, 13:22:20
Klar, die Funktion gibt am Ende immer "sleeping" zurück!
Ich dachte das war so gewollt.

Aber die Routine kommt ja nicht immer bis zum Ende, da es ja sein kann das die if Schleife(n) true werden und dann mit dem return wert beendet werden ohne das die Routine bis zum Ende durchläuft und das "sleeping" zurückgibt.
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Ich verstehe den Sinn irgendwie noch nicht so wirklich.
Zumal die eigentliche Frage des Themas hinreichend beantwortet wurde.

Durch wen/was wird denn die Funktion aufgerufen?
Und vor allem was soll das Ziel sein? Bitte nicht den Programmcode beschreiben.

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Fritz Muster

#10
Zitat von: DeeSPe am 21 Februar 2023, 16:56:42
Zumal die eigentliche Frage des Themas hinreichend beantwortet wurde.

Entschuldige bitte aber ich habe alle Deine Hinweise entprechend ausprobiert, leider funktionierte das aber alles nicht. Entsprechendes Feedback bzw. log Meldungen habe ich ja hier auch gepostet.

Ziel ist eine Routine zu bauen die als Art watchdog regelmäßig prüft (Event basiert) ob der state vom device sich geändert hat. Wenn das der Fall ist soll zunächst eine Wartezeit von 5 Sekunden laufen und danach soll der state erneut geprüft werden. Hat sich der state in den 5 Sekunden nicht geändert dann soll das device geschaltet werden. So ist der Plan. Ich möchte das Ganze über myutils / userreading machen da ich die identische Funktion für unterschiedliche devices benötige.

Bitte nicht wundern, im Rahmen des rum probierens arbeite ich in den Anweisungen der if Schleifen zunächst mit Rückgabewerten, wenn dann mal alles funktioniert ersetze ich das entsprechend mit den Schaltbefehlen. 
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Zitat von: Fritz Muster am 21 Februar 2023, 17:06:22
Entschuldige bitte aber ich habe alle Deine Hinweise entprechend ausprobiert, leider funktionierte das aber alles nicht. Entsprechendes Feedback bzw. log Meldungen habe ich ja hier auch gepostet.

Zitat von: Fritz Muster am 21 Februar 2023, 13:01:06
erscheint jetzt keine Fehlermeldung mehr im log. Allerdings wird die if Abfrage nicht true (obwohl $devstate eq "off" ist) und der Rückgabewert der Routine ist "sleeping"

Das widerspricht sich irgendwie.
Und an meiner Bereitschaft zu helfen liegt es ja offenbar auch nicht!
Es ist immer schwer zu helfen wenn man keine oder zu wenig Informationen bekommt.

Ich würde das evtl. so lösen:
sub myStateCheck
{
  my ($name,$count) = @_;
  my $state = ReadingsVal($name,'state','');
  $count = $count?$count:0;
  if ($state eq 'off' && !$count)
  {
    # wenn off dann prüfe in 5 Sekunden wieder
    $count++;
    fhem "sleep 5 quiet; {myStateCheck('$name',$count)}";
  }
  elsif ($state eq 'off' && $count)
  {
    # mach was du machen willst wenn das Device nicht mehr off ist
    fhem "set $name on";
  }
  return;
}


Die Funktion wird nur mit dem Namen des zu prüfenden Devices aufgerufen.
Sie setzt bei 'off' den Zähler hoch und ruft sich dann selbst nach 5 Sekunden wieder auf.
Nach der ersten Rekursion landet sie gleich im elsif Zweig und schaltet das Gerät ein.
Sind beide Zweige false passiert überhaupt nichts.

Ich hoffe das ist das was Du erreichen wolltest.

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Fritz Muster

Respekt!!

Als noob muss ich das jetzt erst einmal sacken lassen und dann versuchen umzusetzen.

Vielen Dank.
RasPi 3B+, Stretch, Fhem 5.9, DBlog SQLite
HMLAN, mapleCUN MAX/WMBus, mapleSduino 868/433/868
HM Sensoren/Aktoren ,Technoline TX 29 DTH-IT, TFA 30.3155WD, MAX!
Hour Counter, Astro, EletricityCounter, Statistics, Charting Frontend, TabletUI, Modbus

DeeSPe

Zitat von: Fritz Muster am 21 Februar 2023, 17:38:44
Als noob muss ich das jetzt erst einmal sacken lassen und dann versuchen umzusetzen.

Ist doch bereits fertig umgesetzt!
Habs jetzt nicht getestet, aber ich denke das sollte so gehen.
Wenn Du es benötigst musst Du jetzt nur noch die Funktion mit dem Namen des entsprechenden Gerätes aufrufen und schon geht die einmalig wiederholte Prüfung los.
Willst Du das öfter prüfen, dann musst Du im if Zweig nur auf den entsprechend größeren Zähler prüfen:
if ($state eq 'off' && $count<2)

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

DeeSPe

#14
Hier noch eine Version mit in Variablen ausgelagerter Konfiguration der Anzahl der Prüfungen und der Zeitspanne.
Das macht das nachträgliche Anpassen noch einfacher.
Hier kannst du als optionalen zweiten Parameter noch die Anzahl der maximalen Prüfungen mit übergeben, im optionalen dritten Parameter die Zeitspanne und das somit für jedes geprüfte Device individuell bestimmen.
sub myStateCheck
{
  my ($name,$max,$tim,$count) = @_;
  ##### CONFIG START #####
  my $maxi = 1; # Maximale Anzahl an wiederholten Prüfungen wenn keine vorgegeben wurde
  my $time = 5; # Zeit nach der die wiederholte Prüfung stattfinden soll
  ##### CONFIG END #####
  my $state = ReadingsVal($name,'state','');
  $max = $max?$max:$maxi;
  $tim = $tim?$tim:$time;
  $count = $count?$count:0;
  if ($state eq 'off' && $count<$max)
  {
    # wenn offline und Zähler kleiner als Vorgabe dann prüfe in $tim Sekunden wieder
    $count++;
    fhem "sleep $tim quiet; {myStateCheck('$name',$max,$tim,$count)}";
  }
  elsif ($state eq 'off' && $count)
  {
    # mach was du machen willst wenn das Device nicht mehr off ist, aber vorher offline war
    fhem "set $name on";
  }
  # sonst tue nichts
  # Ende immer mit return
  return;
}


Der Erstaufruf der Funktion wäre dann entweder:
myStateCheck(<NAME>)
dabei werden die Werte für Anzahl und Wiederholungen aus der Konfiguration in der Funktion genommen,
oder:
myStateCheck(<NAME>,5,10)
Damit startet die Funktion mit max. 5 Wiederholungen im Abstand von 10 Sekunden.

Gruß
Dan

EDIT: Hab die Reihenfolge der Parameter nochmal geändert, somit ist der Funktionsaufruf einen Parameter kürzer.
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe