ReadingsVal in while schleife funktioniert nicht

Begonnen von arokh12, 14 März 2020, 18:15:17

Vorheriges Thema - Nächstes Thema

arokh12

Hallo,
ich habe in den mySubs eine While-Schleife. In dieser While-Schleife will ich mittels ReadingsVal den Wert eines Readings abrufen.

Leider klappt das nicht. Er ruft die Variable am Anfang einmal ab und danach nicht mehr. Die Variable wird zwischendurch geändert. Diese Änderung übernimmt er nicht.

Der Sub wird mittels Blockingcall aufgerufen, also wird FHEM auch nicht blockiert.

Hier mal der Code:
sub Ueberwachung_OFF($) {
my ($string) = @_;
my ($Name,$Reading,$Vergleich,$Verzoegerung,$Verbraucher) = split("\\|", $string);
my $zeitalt = time();
my $Status = 1;

while(1) {
my $i = ReadingsVal($Name,$Reading,999);
$i =~ tr/[0-9]//cd;

if ($i > $Vergleich) {
last;
}

if (time() - $zeitalt > $Verzoegerung) {
$Status = 0;
last;
}}

return "$Name|$Verbraucher|$Status";
}


Woran kann das liegen?

Vielen Dank im voraus
arokh12

Wzut

#1
Dein Non Blocking Aufruf ist ein Fork und bei einem Fork wird alles kopiert und dann nur noch mit der Kopie gearbeitet.
D.h. dein Fork (child) bekommt nie mit wenn sich das Reading im Hauptprozess (parent) ändert.
Um Nachrichten zwischen Parent & Child Prozess auszutauschen ist etwas mehr Aufwand nötigt. I.d.R. "informiert" das Kind seine Eltern,
bestimmte Module lösen das via Telnet und der sub BlockingInformParent. K.A. ob es schon eine bestehene Routine für die andere Richtung gibt.
Maintainer der Module: MAX, MPD, UbiquitiMP, UbiquitiOut, SIP, BEOK, readingsWatcher

arokh12

Zitat von: Wzut am 14 März 2020, 18:28:04
Dein Non Blocking Aufruf ist ein Fork und bei einem Fork wird alles kopiert und dann nur noch mit der Kopie gearbeitet.
D.h. dein Fork (child) bekommt nie mit wenn sich das Reading im Hauptprozess (parent) ändert.
Um Nachrichten zwischen Parent & Child Prozess auszutauschen ist etwas mehr Aufwand nötigt. I.d.R. "informiert" das Kind seine Eltern,
bestimmte Module lösen das via Telnet und der sub BlockingInformParent. K.A. ob es schon eine bestehene Routine für die andere Richtung gibt.
Super, danke für die Antwort. Dann kann das natürlich auch nicht funktionieren.

Also muss ich dann in der While-Schleife irgendeine Verbindung zu FHEM herstellen, um den aktuellen Status abzufragen. Muss diese Verbindung über Telnet laufen oder geht auch eine HTTP-Abfrage?

Gibt es irgendwelche Nachteile durch HTTP?


Gesendet von iPad mit Tapatalk

DS_Starter

#3
Moin ihr zwei,

ZitatMuss diese Verbindung über Telnet laufen oder geht auch eine HTTP-Abfrage?
Mir fällt da noch etwas dazu ein.
Du könntest in deiner while-Schleife eine Routine mit

BlockingInformParent("writeFromBlocking", [$name, "<Reading>"], 0);

ansprechen. writeFromBlocking ist dabei eine Subroutine die den Readingwert in ein (temporäres) File schreibt

sub writeFromBlocking($$) {
  my ($name,$reading) = @_;
  my $hash            = $defs{$name};
 
  ..... schreibe ReadingsVal in File ...

return;
}


In deiner While-Schleife kannst du nach dem BlockingInformParent Aufruf diesen Fileinhalt lesen und danach das File löschen wenn gewünscht.
In FHEM gibt es schon fertige Routinen für File schreiben,lesen und löschen im Wiki:

https://wiki.fhem.de/wiki/DevelopmentModuleAPI#Daten_dauerhaft_schreiben.2Flesen

Damit könntest du sogar eine configDB dafür verwenden wenn du diese im Einsatz hättest.

Grüße,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

arokh12

#4
Das hört sich auch gut an. Ich habe das jetzt mal Schritt für Schritt ausprobiert, allerdings ohne While-Schleife (die kommt später dazu), damit ich es richtig verstehe. Hier mal der aktuelle Code:


sub Test($) {
my ($string) = @_;
my ($Name,$Reading,$Vergleich,$Verzoegerung,$Verbraucher) = split("\\|", $string);
my $zeitalt1 = time();
my $zeitalt2 = time();
my $error;
my @Status;
my $wert;

BlockingInformParent("writeFromBlocking",["Test","Einspeisung"],0);
($error, @Status) = FileRead("/opt/fhem/Subs.cfg");
FileDelete("/opt/fhem/Subs.cfg");

if ($Status[0] > 0) {
$wert = 1;
} else {
$wert = 0;
}

return "$Name|$Verbraucher|$wert";
}

sub writeFromBlocking($$) {
my ($name,$reading) = @_;
my $hash            = $defs{$name};

my @i = ReadingsVal("Test","Einspeisung",999);
FileWrite("/opt/fhem/Subs.cfg", @i);

return;
}


2 Fragen habe ich dazu:

1. Das File wird nicht gelöscht. Warum?
2. Wenn ich eine Wertänderung an dem Reading wird diese erst eingelesen, nachdem ich die Routine das 2 Mal aufgerufen habe. Diese Verhalten wäre ja in der while-schleife nicht schlimm, nur mich würde gerade interessieren, ob ich auf die Ausführung vom Blockinginformparent "warten" kann.
3. Wofür steht denn die 0 als 3. Argument beim Blockinginformparent?

Danke,
arokh12

MadMax-FHEM

Hallo,

mal ganz andere Frage:

muss das in einer ausgelagerten While-Schleife sein!?

Denn obwohl ausgelagert, also zumindest nicht blickierend: sie rennt ja ohne irgendwelche Pausen -> CPU dürfte ziemlich hoch gehen...

OBWOHL: sich das Vergleichsergebnis doch erst ändern kann, wenn sich auch das abgefragte Reading geändert hat, oder!?

Warum also nicht (wie sonst üblich in fhem ;)  ): Notify auf Readingsänderung -> Vergleich und Aktion!?

Also nur mal so...

Gruß, Joachim
FHEM PI3B+ Bullseye: HM-CFG-USB, 40x HM, ZWave-USB, 13x ZWave, EnOcean-PI, 15x EnOcean, HUE/deCONZ, CO2, ESP-Multisensor, Shelly, alexa-fhem, ...
FHEM PI2 Buster: HM-CFG-USB, 25x HM, ZWave-USB, 4x ZWave, EnOcean-PI, 3x EnOcean, Shelly, ha-bridge, ...
FHEM PI3 Buster (Test)

DS_Starter

ZitatDas File wird nicht gelöscht. Warum?
Keine Ahnung.  ;)
Nimm doch

$error = FileDelete("/opt/fhem/Subs.cfg");

Und sieh dir die Var $error an.

Zitatnur mich würde gerade interessieren, ob ich auf die Ausführung vom Blockinginformparent "warten" kann.
Die Frage verstehe ich irgendwie nicht. Blockinginformparent  wird direkt aufgerufen und abgearbeitet.
Möglicherweise meinst du indirekt das Verhalten in der nächsten Antwort.

ZitatWofür steht denn die 0 als 3. Argument beim Blockinginformparent?
Schau dir mal die sub BlockingInformParent in Blocking.pm an. Dort siehst du was damit passiert. Wenn ich es richtig lese, kann man die Sub bei Lesevorgängen "warten" lassen bis ein Ergebnis eingelesen ist und mit return zurückgegeben werden kann.
Vielleicht kann man damit auch den Umweg über das Schreiben in ein File umgehen und den Wert direkt zurück liefern.
Aber das must du austesten. Ich habe BlockingInformParent  bisher nur in Richtung Hauptprozess verwendet um dort den Hash zu ändern.

Und ja, Joachim hat sicherlich recht wenn er das ganze Verfahren kritisch hinterfragt.  :)

LG,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

frober

Das File wird nicht gelöscht. Warum?


Ich bin zwar kein Perlexperte, aber muss das File nach dem Lesen nicht erst geschlossen werden, bevor es gelöscht werden kann?
Raspi 3b mit Raspbian Bullseye und relativ aktuellem Fhem,  FS20, LGW, PCA301, Zigbee, MQTT, MySensors mit RS485(CAN-Receiver) und RFM69, etc.,
einiges umgesetzt, vieles in Planung, smile

********************************************
...man wächst mit der Herausforderung...

arokh12

Leider steht in dem Error nichts drin. Ich werde das Schreiben in dem File aber weglassen, da ich es nicht mehr brauche. Wie du schon angedeutet hast, funktioniert es auch ohne das Schreiben eines Files, indem ich den Wert direkt aus dem BlockingInformParent zurückgebe. Das funktioniert super.

Ich denke nicht, dass die noch geschlossen werden muss. Zumindest im Wiki steht nichts davon.

Theoretisch wäre das auch möglich. Zur späteren Funktion:
Ich habe eine PV-Anlage (SMAPortal). Wenn jetzt die Einspeisung hoch genug ist, dann sollen bestimmte Verbraucher eingeschaltet werden. In der While-Schleife wird dann die Einspeisung regelmäßig abgerufen und dann später der Verbraucher geschaltet.
Ich könnte natürlich auch ein DOIF nehmen mit dem WAIT. Das war mir aber zu einfach und wollte selber mal was basteln ;)

Ich probiere es mal über den Tag aus und melde mich später nochmal.



DS_Starter

Zitat
Wie du schon angedeutet hast, funktioniert es auch ohne das Schreiben eines Files, indem ich den Wert direkt aus dem BlockingInformParent zurückgebe. Das funktioniert super.

Danke für die Rückinfo. Gut zu wissen dass auch dieser Weg funktioniert. Kann man gut gebrauchen.  8)

Aber in dem beschriebenen Fall könntest du wirklich einfach nur auf das Event L1_FeedIn triggern.  ;)

LG,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter