[gelöst] BlockingCall forkt mit PPID1/Anzahl der BlockingCalls begrenzen

Begonnen von abc2006, 13 Oktober 2017, 00:33:28

Vorheriges Thema - Nächstes Thema

abc2006

Hi,
zum Senden und empfangen von UDP-Paketen habe ich mir in der MyUtils ein paar Subroutinen zusammengebaut. (siehe unten)

Diese Routinen werden von verschiedenen PID's aufgerufen, die Mischer regeln (hin und her fahren).

Solange hier nur ein PID arbeitet (max. alle 60 Sekunden ein Aufruf), läuft alles einwandfrei.
Sobald ich den zweiten PID starte, der alle 15 Sekunden die Routine aufruft, kann ich im Prozessmanager zusehen, wie die anzahl der parallel laufenden FHEM-Instanzen ansteigt ( alle mit PPID 1) bis der Rechner nicht mehr kann. Wie kann das kommen? "geforkte" Prozesse haben doch üblicherweise die PPID des Elternprozesses - also die vom FHEM-Prozess selbst. Und selbst wenn die Anfragen nicht erfolgreich sind, müssten diese Prozesse doch einmal aufgerufen werden und spätestens nach dem Timeout von 5 Sekunden sterben?


Um dies zu umgehen, habe ich nach dem Wiki-Vorbild eine Prüfung eingeführt, die durch eine Variable feststellt, ob noch ein BlockingCall läuft.
Würde das so zuverlässig funktionieren?

Dabei habe ich festgestellt, dass bestimmte Anweisungen, die nach "BlockingCall()" kommen, nicht mehr ausgeführt werden.
Meine Log-Anweisung funktioniert nicht, fhem("set remotebot message ...") hingegen schon. Warum?





our $anzahlBlockingCalls = 0;

sub nb_udpsend {
 
my $blockingFn = "udpsend";
my $finishFn = "finishFn";
my $timeout = 5;
my $abortFn = "abortFn";
my $abortArg = "nb_udpsend_errorArg: did not receive acknowledge from|$_[0]|$_[1]|$_[2]";
##     $order        $ip           $port
my $args = $_[0] . "|" . $_[1] . "|" . $_[2];

log_telegram("3",$log_name,"laufende BC: $anzahlBlockingCalls","remotebot");
if ($anzahlBlockingCalls == 0){
BlockingCall($blockingFn,$args,$finishFn,$timeout,$abortFn,$abortArg);
$anzahlBlockingCalls++;
} else {
log_telegram("4",$log_name,"zu viele calls","remotebot"); ## wurde noch nie ausgeführt
                fhem("set remotebot message zu viele Calls");## funktioniert
}
log_telegram("4",$log_name,"_BlockingCall FN: $blockingFn ARG: $args FIN: $finishFn TO:$timeout AFN:$abortFn AARG: $abortArg _","remotebot");## wurde auch nie ausgeführt
return;
}

sub udpsend {

my ($parameters) = @_;
my ($order,$ip,$port) = split("\\|",$parameters);
my $answer;
my $now = strftime "%Y-%m-%d %T",localtime();
my $sock = IO::Socket::INET->new(
        Proto   => 'udp',
        PeerPort => $port,
        PeerAddr => $ip,
) or die "could not create Socket: $!\n";
$sock->send($order) or die "Send error $!\n";
$sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 2, 0))
    or die "setsockopt: $!";
$sock->recv($answer,1024)
or die "Could not receive an answer: $!";
$sock->close();

$answer =~ s/(.*)\n.*/$1/g;
return $answer . "|" . $parameters;
}


sub abortFn {
my $log_name = "abortFn(S)";

my ($errArg,$errorder,$errip,$errport) = split("\\|",@_);
my $log_name = "nb_ardsend(S)";
my $subloglevel = 3;

log_telegram("3",$log_name,"function aborted: $errArg " . $errip . ":" . $errport,"remotebot");
log_telegram("5",$log_name,"OUTPUT BEGIN","remotebot");
log_telegram("5",$log_name,"$errip","remotebot");
log_telegram("5",$log_name,"$errport","remotebot");
log_telegram("5",$log_name,"$errorder","remotebot");
log_telegram("5",$log_name,"OUTPUT END","remotebot");
log_telegram("3",$log_name,"laufende BC bevor: $anzahlBlockingCalls","remotebot");
$anzahlBlockingCalls--;
log_telegram("3",$log_name,"laufende BC danach: $anzahlBlockingCalls","remotebot");
}
sub finishFn {
my $log_name = "finishFn(S)";
my ($parameters) = @_;
my ($answer,$order,$ip,$port) = split("\\|",$parameters);

if($answer == $order){
log_telegram("3",$log_name,"function finished: $parameters","remotebot");
} else {
log_telegram("1",$log_name,"function finished: $parameters but:\n$answer is not equal to $order","remotebot");
}
log_telegram("3",$log_name,"laufende BC bevor: $anzahlBlockingCalls","remotebot");
$anzahlBlockingCalls--;
log_telegram("3",$log_name,"laufende BC danach: $anzahlBlockingCalls","remotebot");
}

FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

CoolTux

Guten Morgen,

Hab Mal heute Morgen beim Zähneputzen drüber nachgedacht ob das überhaupt irgendwie zu überprüfen ist. Ich müsste aber Deinen Code erstmal in mein Testsystem beim laufen anschauen.
Allerdings kannst Du es ja auch genau so machen wie im Wiki. Irgend ein Device wird ja Deine Sub aufrufen, an dieses Device bindest Du den BlockingCall in dem Du den Hash von dem Device mit gibst. Bei mir ist es zum Beispiel ein Notify.



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

abc2006

Danke fürs Nachdenken...

meinst du so ?

PID.HV_RLA:actuation:.* {controlRLA_ARD($hash)}

das ergibt folgenden Fehler:
"Global symbol "$hash" requires explicit package name (did you forget to declare "my $hash"?) at (eval 3039) line 1."

Falls ich das richtig verstanden habe, wird doch auch bei dem Hash *nur* die PID in das Array geschrieben und dann geprüft, wenn schon eine vorhanden ist, wird kein zweiter BlockingCall gestartet.


Im Moment hab ich das massive Problem, dass (gefühlt, ich weiss nicht, wie ich das debuggen soll) wenn der BlockingCall abbricht, eine neue Fhem-Instanz mit der PPID 1 gestartet wird. Und ich weiss nicht, warum.

Grüße,
Stephan

FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

rudolfkoenig

die() ist keine gute Idee, da BlockingCall auf eine Rueckgabe wartet.
Generell ist die(), exit() oder Vergleichbares keine gute Idee in einem FHEM-Modul.

rudolfkoenig

Um die im Betreff gestellte Frage zu beantworten: attr global blockingCallMax 5

CoolTux

Zitat von: abc2006 am 13 Oktober 2017, 12:00:27
Danke fürs Nachdenken...

meinst du so ?

PID.HV_RLA:actuation:.* {controlRLA_ARD($hash)}

das ergibt folgenden Fehler:
"Global symbol "$hash" requires explicit package name (did you forget to declare "my $hash"?) at (eval 3039) line 1."

Falls ich das richtig verstanden habe, wird doch auch bei dem Hash *nur* die PID in das Array geschrieben und dann geprüft, wenn schon eine vorhanden ist, wird kein zweiter BlockingCall gestartet.


Im Moment hab ich das massive Problem, dass (gefühlt, ich weiss nicht, wie ich das debuggen soll) wenn der BlockingCall abbricht, eine neue Fhem-Instanz mit der PPID 1 gestartet wird. Und ich weiss nicht, warum.

Grüße,
Stephan

Nee. Nun mal ganz langsam.
PID.HV_RLA:actuation:.* {controlRLA_ARD($hash)}
Hast Du denn ein $hash zu dem Zeitpunkt? Nein hast Du nicht.
Notify gibt uns ein $NAME und ein $EVENT und die Einzelteile des Events (aber das ist unwichtig) des auslösenden Devices.

Wenn dann machst Du das am Notify fest,
PID.HV_RLA:actuation:.* {controlRLA_ARD('NAMEVOMNOTIFY')}

Und in Deiner Funktion machst Du dann

sub nb_udpsend($) {
    my ($name) = @_;
    my $hash = $defs{$name};
  .....






@Rudi
Danke





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

CoolTux

Ich gebe Dir mal meine Lösungen. Schau mal ob Du da was für Dich findest


Notify

buttonIsabelFWstatus.(erlaubt|verboten) { systemCommand("notifyFirewall_IsabelHandy","$EVENT") }



99_myUtils

sub systemCommand($$;$) {

    my ($name,$command,$timeOut) = @_;
    my $hash = $defs{$name};
   
    $timeOut = 30 if( !defined($timeOut) );
   
    Log3 $name, 4, "(Sub systemCommand - $name) - Starte Subroutine systemCommand";
   
   
    if( lc $name eq 'notifycontrolwlan0'
    || lc $name eq 'notifyfirewallsshinet'
            || lc $name eq 'notifyfirewallfheminet'
            || lc $name eq 'notifyfirewall_isabelhandy'
            || lc $name eq 'notifyinternet_isabel'
    || lc $command eq 'gtagbattery') {
       
        BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));

        $hash->{helper}{RUNNING_PID} = BlockingCall("systemCommand_Run", $name."|".$command, "systemCommand_Done", $timeOut, "systemCommand_Aborted", $hash) unless(exists($hash->{helper}{RUNNING_PID}));
        Log3 $name, 4, "(Sub systemCommand - $name) - Starte Blocking Call";
    }
}

sub systemCommand_Run($) {

    my ($string) = @_;
    my ( $name, $command ) = split("\\|", $string);
    my $state;
   
    Log3 $name, 4, "(Sub systemCommand - $name) - Führe Systemkommando im nonBlocking Mode aus: $command";
   
   
    #####################################
    ### Wlan0 auf proxy01 #####
    if( $name eq "notifyControlWlan0" ) {
        Log3 $name, 4, "(Sub systemCommand - $name) - Starte $name";
       
        if( $command eq "inet up" ) {
            qx(ssh proxy01 'sudo /sbin/ifup wlan0');
            Log3 $name, 3, "(Sub systemCommand - $name) - wlan0 wird gestartet";
        }
   
        elsif( $command eq "inet down" ) {
            qx(ssh proxy01 'sudo /sbin/ifdown wlan0');
            Log3 $name, 3, "(Sub systemCommand - $name) - wlan0 wird beendet";
        }
   
        elsif( $command eq "inet reconnect" ) {
            qx(ssh proxy01 'sudo /sbin/ifdown wlan0');
            sleep 5;
            qx(ssh proxy01 'sudo /sbin/ifup wlan0');
            Log3 $name, 3, "(Sub systemCommand - $name) - wlan0 wird neu gestartet";
        }
       
        ### Check is wlan0 alive
        $state = qx(ssh proxy01 'cat /sys/class/net/wlan0/carrier');
        Log3 $name, 3, "(Sub systemCommand - $name) - Check is wlan0 alive";
    }
   
    #######################################
    #### Firewall Skripte auf proxy01 ###
    elsif( $name =~ /notifyFirewall/ ) {
       
        Log3 $name, 4, "(Sub systemCommand - $name) - Starte $name";

       
        if ( $command eq "erlaubt" ) {
       
            while ( qx(ps ax | grep -v grep | grep iptables) ) {
                Log3 $name, 4, "(Sub systemCommand - $name) - iptables noch aktiv, wait 0.5s for new check";
                sleep 0.5;
            }
           
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/ssh_inbound_inet.sh allow') if( $name eq "notifyFirewallSshInet" );
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/fhem_inbound_inet.sh allow') if( $name eq "notifyFirewallFhemInet" );
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/isabel_handy_tablet.sh allow') if( $name eq "notifyFirewall_IsabelHandy" );
            Log3 $name, 3, "(Sub systemCommand - $name) - Zugriff erlaubt für $name";
        }
   
        elsif( $command eq "verboten" ) {
           
            while ( qx(ps ax | grep -v grep | grep iptables) ) {
                Log3 $name, 3, "(Sub systemCommand - $name) - iptables noch aktiv, wait 0.5s for new check";
                sleep 0.5;
            }
       
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/ssh_inbound_inet.sh deny') if( $name eq "notifyFirewallSshInet" );
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/fhem_inbound_inet.sh deny') if( $name eq "notifyFirewallFhemInet" );
            $state = qx(ssh proxy01 'sudo /etc/iptables/rules.scripts/isabel_handy_tablet.sh deny') if( $name eq "notifyFirewall_IsabelHandy" );
            Log3 $name, 3, "(Sub systemCommand - $name) - Zugriff verboten für $name";
        }
    }
   
    #######################################
    #### Isabel Internetfreigabe über SquidGuard auf proxy01 ###
    elsif( $name =~ /notifyInternet_Isabel/ ) {
       
        Log3 $name, 4, "(Sub systemCommand - $name) - Starte $name";
       
       
        if ( $command eq "holidayToNormal" ) {
       
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh holidayToNormal');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Normal geändert.";
        }
   
        elsif( $command eq "normalToHoliday" ) {
           
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh normalToHoliday');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Holiday geändert.";
        }
       
        elsif ( $command eq "holidayToBlocked" ) {
       
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh holidayToBlocked');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Blocked geändert.";
        }
       
        elsif( $command eq "normalToBlocked" ) {
           
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh normalToBlocked');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Blocked geändert.";
        }
       
         elsif ( $command eq "blockedToHoliday" ) {
       
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh blockedToHoliday');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Holiday geändert.";
        }
       
        elsif( $command eq "blockedToNormal" ) {
           
            $state = qx(ssh proxy01 'sudo /usr/local/bin/squidGuard_SetIsabelInternet.sh blockedToNormal');
            Log3 $name, 3, "(Sub systemCommand - $name) - Internetzugriff von SquidGuard für Isabel auf Normal geändert.";
        }
    }
   
    ##########################################
    #### G-Tag Batterie Status ############### 
    elsif( $command eq "gtagbattery" ) {
       
        my %btmac = (
            wd_GTagBatterieMarko => '7C:2F:80:98:B8:3D',
            wd_GTagBatterieNadin => '7C:2F:80:98:B7:F2',
            wd_GTagBatterieIsabel => '7C:2F:80:98:B7:F8',
            wd_GTagBatterieSteven => '7C:2F:80:98:B8:61',
            wd_GTagBatterieAnna => '7C:2F:80:AA:5E:28'
        );
       
        while ( qx(ps ax | grep -v grep | grep gatttool) ) {
            Log3 $name, 4, "(Sub systemCommand - $name) - gatttool noch aktiv, wait 0.5s for new check";
            sleep 0.5;
        }
       
        $state = qx(gatttool -b $btmac{$name} --char-read --handle=0x001b);
        Log3 $name, 3, "(Sub systemCommand - $name) - Rufe Batteriestatus vom GTag ab. MAC: $btmac{$name}";
    }
   

   
   
   
    #################################################
    #### Weiterverarbeitung der Rückgabewerte ######
    Log3 $name, 4, "(Sub systemCommand - $name) - Rückgabe an Auswertungsprogramm beginnt Name: $name, Command: $command, State: $state";
    $state = encode_base64($state,"");
    return "$name|$command|$state";
}

sub systemCommand_Done($) {

    my ($string) = @_;
    my @a = split("\\|",$string);
    my $hash = $defs{$a[0]};
    my $name = $hash->{NAME};
    my $command = $a[1];
    my $state = $a[2];
   
   
    delete($hash->{helper}{RUNNING_PID});
   
    Log3 $name, 3, "(Sub systemCommand_Done - $name) - Der Helper ist diabled. Daher wird hier abgebrochen" if($hash->{helper}{DISABLED});
    return if($hash->{helper}{DISABLED});
   
   
    $state = decode_base64($state);
   
    Log3 $name, 4, "(Sub systemCommand_Done - $name) - State gleich: $state und command: $command";
    Log3 $name, 3, "(Sub systemCommand_Done - $name) - Abschluss vom Systemkommandoaufruf im nonBlocking Mode. Auswertungsteil beginnt.";
   
   
   
    ##############################################################
    #########   Auswertungsteil   ############
   
   
    ####################################################
    ##### wlan0 stop, start, restart, status
    if( ($name eq "notifyControlWlan0") and ($state) ) {
   
            fhem "set buttonProxy01Wlan0Status $state";
    }

    ####################################################
    ####### Firewall Skripte auf proxy01 ###########
    elsif( ($name =~ /notifyFirewall/) and (!$state) ) {
   
        fhem "set buttonSshInetFWstatus fehler" if($name eq "notifyFirewallSshInet" );
        fhem "set buttonFhemInetFWstatus fehler" if($name eq "notifyFirewallFhemInet" );
        fhem "set buttonSshInetFWstatus fehler" if( $name eq "notifyFirewall_IsabelHandy" )
    }
   
    ####################################################
    ####### Isabel Internetfreigabe über SquidGuard auf proxy01 ###########
    elsif( ($name =~ /notifyInternet_Isabel/) and (!$state) ) {
   
        fhem "set buttonIsabelInternetStatus fehler";
    }
   
    ####################################################
    #### G-Tag Batterie Status ###############
    elsif( ($name =~ /wd_GTagBatterie/) and ($state) ) {
   
        my %DEVICE = (
            wd_GTagBatterieMarko => 'presenceMarko',
            wd_GTagBatterieNadin => 'presenceNadin',
            wd_GTagBatterieIsabel => 'presenceIsabel',
            wd_GTagBatterieSteven => 'presenceSteven',
            wd_GTagBatterieAnna => 'presenceAnna'
        );
       
        my $dhash = $defs{$DEVICE{$name}};
        my $dname = $dhash->{NAME};
       
        my @blevel = split(": ",$state);
        my $blevel = hex("0x".$blevel[1]);
       
        readingsBeginUpdate($dhash);
        readingsBulkUpdate($dhash,"device_batteryLevel",$blevel);
       
        if( $blevel < 20 ) {
            readingsBulkUpdate($dhash,"device_battery","low");
        } else {
            readingsBulkUpdate($dhash,"device_battery","ok");
        }
       
        readingsEndUpdate($dhash,1);
    }
       
}

sub systemCommand_Aborted($) {

    my ($hash) = @_;
    my $name = $hash->{NAME};

    delete($hash->{helper}{RUNNING_PID});
    Log3 $name, 3, "($name) - The BlockingCall Process terminated unexpectedly. Timedout";

}
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: rudolfkoenig am 13 Oktober 2017, 12:04:35
die() ist keine gute Idee, da BlockingCall auf eine Rueckgabe wartet.
Generell ist die(), exit() oder Vergleichbares keine gute Idee in einem FHEM-Modul.

Ja da wollte ich den Stephan vorsichtig hinführen das er ein bisschen mehr mit Sorgfalt seinen Code schreibt.
Es ist besser wenn Du Dir angewöhnst wenn Du eine Subroutine erstellst das Du auch gleich fest legst wie viele Parameter und welcher Parametertype mit übergeben wird. Ist sauberer und andere können Deinen Code so besser lesen

sub Routinenname($$)

sub Routinenname($@)


und so weiter.
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

abc2006

Zitat von: CoolTux am 13 Oktober 2017, 12:22:19
Ja da wollte ich den Stephan vorsichtig hinführen das er ein bisschen mehr mit Sorgfalt seinen Code schreibt.
Es ist besser wenn Du Dir angewöhnst wenn Du eine Subroutine erstellst das Du auch gleich fest legst wie viele Parameter und welcher Parametertype mit übergeben wird. Ist sauberer und andere können Deinen Code so besser lesen

sub Routinenname($$)

sub Routinenname($@)


und so weiter.

Äh. Hm.
ZitatIst sauberer und andere können Deinen Code so besser lesen
Fand ich auch, deshalb hatte ich die auch drin (und hab sie bei manchen immer noch).
Warum ich diese klammern und dollars extra weg gemacht habe:

http://www.perlmonks.org/?node_id=861966 <- da schwitz ich heut noch ...
https://stackoverflow.com/questions/297034/why-are-perl-5s-function-prototypes-bad
https://www.effectiveperlprogramming.com/2011/10/understand-why-you-probably-dont-need-prototypes/
usw...

kannst du mir sagen, warum ich sie besser *doch* verwenden sollte? (Anscheinend hab ich diese Informationen ja auch glorreich falsch verstanden)


@rudi:
klingt nachvollziehbar, also schreibe ich anstatt die() besser "setze variable auf Fehlerwert" und gebe die Variable als return zurück?

Ich schau mir nachher genau an, was ihr geschrieben habt, und versuche das umzusetzen, jetzt muss ich erstmal auf Arbeit. Danke schonmal für eure Hilfe.

Bei allen Forks und Abbrüchen und Wiederaufrufen ist mir aber leider immer noch nicht klar, warum manche BlockingCalls dann unter der PPID 1 laufen und meinem (Haupt) FHEM konkurrieren...

Bis später,
Stephan
FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

abc2006

So, jetzt hab ich dreimal angefangen, Fragen zu formulieren, und dann jetzt doch so lange gebastelt, bis es irgendwie funktioniert.

Erstmal mein Code:


controlVL_ARD ist die funktion, die mir die vom PID vorgegebene Fahrzeit in kompatible Syntax wandelt und noch ein paar Checks durchführt, sowie etwas entschwingt:
sub controlVL_ARD($) {
my $log_name = "controlVL_ARD";
my $subloglevel = 3;
my $previous_loglevel = AttrVal("global","verboseTelegram",0);
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $subloglevel");
}
log_telegram("5",$log_name,"debug aktiviert","remotebot");

my ($name) = @_;
my $hash = $defs{$name};
my $warmRelais = 1;
my $kaltRelais = 2;
my $tuwas = ReadingsVal("PID.FUBO","actuation","-5");;
my $VL = ReadingsVal("RE_TEMP_VorlaufHK","temperature","100");
my $VLSoll = ReadingsVal("PID.FUBO","desired","0");
my $SpeicherOben = ReadingsVal("RE_TEMP_Speicher_09","temperature","0");
my $KesselVL = ReadingsVal("RE_TEMP_Vorlauf_Kessel","temperature","0");
my $KesselRL = ReadingsVal("RE_TEMP_Ruecklauf_Kessel","temperature","0");
my $literpromin = ReadingsNum("KNX10.I06_Heizungszaehler_main","literpromin",1);
my $pidstate = ReadingsVal("DF_Heizschleifenfunktion","status","error");
my $order = 0;
my $ip = "192.168.0.98";
my $port = "8887";


my $readingsAge = ReadingsAge("KNX10.I06_Heizungszaehler_main","literpromin",0);
if ($readingsAge > 90 && $literpromin !=0) {
log_telegram("5",$log_name,"_literpromin $literpromin ist bereits $readingsAge Sekunden alt, setze Reading auf 0_","remotebot");
log_telegram("3",$log_name,"_literpromin $literpromin ist bereits $readingsAge Sekunden alt, setze Reading auf 0_","alarmbot");
fhem("setreading KNX10.I06_Heizungszaehler_main literpromin 0");
}elsif($literpromin == 0) {
log_telegram("5",$log_name,"_literpromin $literpromin ==0_","remotebot");
}else {
log_telegram("5",$log_name,"_literpromin $literpromin ist erst $readingsAge Sekunden alt_","remotebot");
}

## muss nach reparatur des Durchflussmessers entfernt werden
##my $literpromin = 1;
## muss nach reparatur des Durchflussmessers entfernt werden

my $message = "VL-ist:$VL VL-soll:$VLSoll";
log_telegram("4",$log_name,"N_changeVL: wurde aufgerufen","remotebot");

if ($VL > 40){
$tuwas = -50;
log_telegram("5",$log_name,"N_changeVL: RE_TEMP_VorlaufHK: [RE_TEMP_VorlaufHK:temperature]°C, fahre $tuwas Sek!","remotebot");
} elsif($literpromin == 0 && $tuwas < 0) { # und $VL < 45 {
log_telegram("5",$log_name,"tue nichts, weil literpromin = $literpromin und tuwas = $tuwas","remotebot");
$tuwas = 0;
}
if ( $pidstate eq "uebergang" && ($tuwas > 0.2 || $tuwas < -0.5) )
{

log_telegram("4",$log_name,"_tuwas : $tuwas ; pidstate: $pidstate _","remotebot");
if($tuwas > 0){
$order = $warmRelais . "R" . abs($tuwas)*1000;
} else {
$order = $kaltRelais . "R" . abs($tuwas)*1000;
}
nb_udpsend($name,$order,$ip,$port);
##fhem("setreading ardsend sent $order");
$message .= " :=> $order";
} elsif (($tuwas >= 0.7 && $SpeicherOben > $VLSoll) || $tuwas <= -0.7 )
{   
log_telegram("4",$log_name,"_tuwas : $tuwas _","remotebot");
if($tuwas > 0){
$order = $warmRelais . "R" . abs($tuwas)*1000;
} else {
$order = $kaltRelais . "R" . abs($tuwas)*1000;
}
nb_udpsend($name,$order,$ip,$port);
##fhem("setreading ardsend sent $order");
$message .= " :=> $order";
} else {
$message .= " :=> $tuwas < 0.7\n keine Änderung";
}## end if
log_telegram("3",$log_name,$message,"remotebot");
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $previous_loglevel");
}
}## end sub


nb_udpsend ist die funktion, die den BlockingCall vorbereitet, und im nächsten Schritt dann auch von controlRLA_ARD aufgerufen werden soll, um einen zweiten Mischer zu fahren ( und irgendwann dann noch von controlVL_HK, um einen dritten Heizkreis für Heizkörper zu steuern)

sub nb_udpsend($$$$) {
my $log_name = "nb_udpsend()";
my $subloglevel = 3;
my $previous_loglevel = AttrVal("global","verboseTelegram",0);
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $subloglevel");
}log_telegram("5",$log_name,"debug aktiviert","remotebot");
 
    my ($name,$order,$ip,$port) = @_;
my $hash = $defs{name};
my $blockingFn = "udpsend";
my $finishFn = "finishFn";
my $timeout = 5;
my $abortFn = "abortFn";
my $abortArg = $hash;
##     $order        $ip           $port
my $args = "$name|$order|$ip|$port";



log_telegram("4",$log_name,"_BlockingCall FN: $blockingFn ARG: $args FIN: $finishFn TO:$timeout AFN:$abortFn AARG: $abortArg _","remotebot");

##if ($anzahlBlockingCalls == 0){
BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID}));
$hash->{helper}{RUNNING_PID} = BlockingCall($blockingFn,$args,$finishFn,$timeout,$abortFn,$abortArg) unless(exists($hash->{helper}{RUNNING_PID}));
## $anzahlBlockingCalls++;
##} else {
## fhem("set remotebot message zu viele calls: $anzahlBlockingCalls");
##}




if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $previous_loglevel");
}
return;
}



udpsend ist die Funktion, die blockierend läuft und auf eine Antwort wartet

sub udpsend($) {

my ($parameters) = @_;
my ($name,$order,$ip,$port) = split("\\|",$parameters);
my $answer="";
my $now = strftime "%Y-%m-%d %T",localtime();
my $sock = IO::Socket::INET->new(
        Proto   => 'udp',
        PeerPort => $port,
        PeerAddr => $ip,
) or die "could not create Socket: $!\n";
$sock->send($order) or die "Send error $!\n";
$sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 2, 0))
    or die "setsockopt: $!";
$sock->recv($answer,1024)
or die "Could not receive an answer: $!";
$sock->close();
##
$answer =~ s/(.*)\n.*/$1/g;
return "$name|$answer|$order|$ip|$port";
}


finishFn und abortFn

sub abortFn($) {
my $log_name = "abortFn(S)";
my ($hash) = @_;
my $name = $hash->{NAME};

delete($hash->{helper}{RUNNING_PID});

log_telegram("3",$log_name,"function aborted: $name","remotebot");

}
sub finishFn($) {
my $log_name = "finishFn(S)";
my ($parameters) = @_;
my ($irgendwasmitname,$answer,$order,$ip,$port) = split("\\|",$parameters);
my $hash = $defs{$irgendwasmitname};
my $name = $hash->{NAME};

delete($hash->{helper}{RUNNING_PID});


my $subloglevel = 5;
my $previous_loglevel = AttrVal("global","verboseTelegram",0);
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $subloglevel");
}
log_telegram("5",$log_name,"OUTPUT BEGIN","remotebot");
log_telegram("5",$log_name,"$answer","remotebot");
log_telegram("5",$log_name,"$order","remotebot");
log_telegram("5",$log_name,"$ip","remotebot");
log_telegram("5",$log_name,"$port","remotebot");
log_telegram("5",$log_name,"OUTPUT END","remotebot");

if($answer == $order){
log_telegram("3",$log_name,"function finished: $parameters","remotebot");
} else {
log_telegram("1",$log_name,"function finished: $parameters but:\n$answer is not equal to $order","remotebot");
}

if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $previous_loglevel");
}


}
FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

abc2006

So, hab jetzt blockingCallMax auf 2 gestellt.
Lief auch soweit zufriedenstellen, bis gerade:
Da sehe ich 5 fhem-Prozesse, obwohl es meiner Meinung nach maximal 3 sein dürften...

Grüße,
Stephan
FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

CoolTux

Guten Morgen,

Du hast doch den BlockingCall Aufruf an ein Device gebunden!?
Wie kannst Du dann mehr wie einen Aufruf schaffen bei einem

unless(exists($hash->{helper}{RUNNING_PID}));

Mach mal bitte ein list von dem Device an dem der BlockingCall gebunden ist wenn einer läuft.
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

abc2006

Hi,
bitte hilf mir nochmal bei
Zitatvon dem Device an dem der BlockingCall gebunden ist
Ich weiss nämlich nicht genau, welches du meinst. Ist es DF_controlVL?


###############################################################
Ich habe einen PID. Der aktualisiert sein Reading PID.FUBO:actuation.

Darauf höre ich ( im moment grade) mit einem DOIF:
Internals:
   DEF        ([PID.HV_RLA:actuation])({
##controlRLA_ARD("DF_controlVL");
})
DOELSEIF
([PID.FUBO:actuation])({
controlVL_ARD("DF_controlVL");
})
   NAME       DF_controlVL
   NR         718
   NTFY_ORDER 50-DF_controlVL
   STATE      cmd_2
   TYPE       DOIF
   READINGS:
     2017-10-14 02:39:56   192.168.0.95    1503883
     2017-10-14 13:37:45   Device          PID.FUBO
     2017-10-14 13:37:45   cmd             2
     2017-10-14 13:37:45   cmd_event       PID.FUBO
     2017-10-14 13:37:45   cmd_nr          2
     2017-10-14 13:37:45   e_PID.FUBO_actuation -1.8
     2017-10-14 13:37:45   state           cmd_2
   condition:
     0          ReadingValDoIf($hash,'PID.HV_RLA','actuation')
     1          ReadingValDoIf($hash,'PID.FUBO','actuation')
   devices:
     0           PID.HV_RLA
     1           PID.FUBO
     all         PID.HV_RLA PID.FUBO
   do:
     0:
       0          {  }
     1:
       0          { controlVL_ARD("DF_controlVL"); }
     2:
   helper:
     event      desired: 24.4,measured: 25.12,p_p: -0.712800000000002,p_d: 0.0142290613320757,p_i: -1.14420000000033,actuation: -1.8,actuationCalc: -1.84277093866825
     globalinit 1
     last_timer 0
     sleeptimer -1
     timerdev   PID.FUBO
     timerevent desired: 24.4,measured: 25.12,p_p: -0.712800000000002,p_d: 0.0142290613320757,p_i: -1.14420000000033,actuation: -1.8,actuationCalc: -1.84277093866825
     triggerDev PID.FUBO
     timerevents:
       desired: 24.4
       measured: 25.12
       p_p: -0.712800000000002
       p_d: 0.0142290613320757
       p_i: -1.14420000000033
       actuation: -1.8
       actuationCalc: -1.84277093866825
     timereventsState:
       desired: 24.4
       measured: 25.12
       p_p: -0.712800000000002
       p_d: 0.0142290613320757
       p_i: -1.14420000000033
       actuation: -1.8
       actuationCalc: -1.84277093866825
     triggerEvents:
       desired: 24.4
       measured: 25.12
       p_p: -0.712800000000002
       p_d: 0.0142290613320757
       p_i: -1.14420000000033
       actuation: -1.8
       actuationCalc: -1.84277093866825
     triggerEventsState:
       desired: 24.4
       measured: 25.12
       p_p: -0.712800000000002
       p_d: 0.0142290613320757
       p_i: -1.14420000000033
       actuation: -1.8
       actuationCalc: -1.84277093866825
   internals:
   itimer:
   readings:
     0           PID.HV_RLA:actuation
     1           PID.FUBO:actuation
     all         PID.HV_RLA:actuation PID.FUBO:actuation
   regexp:
     0:
     1:
     all:
   state:
     STATE:
   trigger:
Attributes:
   do         always
   room       Heizung,HolzVergaser,x_devel
   wait       3


Dieses DOIF ruft die sub controlVL auf (die andere ist ja gerade auskommentiert)
und die ruft nb_udpsend auf (das ist dann die sub, in der der BlockingCall gestartet wird).

Soweit läuft alles prima.

Wenn ich jetzt hingehe, und im DOIF
den Aufruf von controlRLA_ARD("DF_controlVL");  aktiviere, fangen die Probleme mit den Threads an.
Ich *glaube*, dass die Probleme erst auftreten, wenn die abortFn aufgerufen wird. Solange der Aufruf nicht fehlschlägt und die finishFn genutzt wird, ist alles okay.

Vielleicht liegt es an der Funktion controlRLA_ARD(), obwohl ich mir größte Mühe gegeben habe, sie weitestgehend mit controlVL gleich zu halten...

sub controlRLA_ARD($) {
my $log_name = "controlRLA_ARD";
my $subloglevel = 3;
my $previous_loglevel = AttrVal("global","verboseTelegram",0);
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $subloglevel");
}
log_telegram("5",$log_name,"debug aktiviert","remotebot");

my ($name) = @_;
my $hash = $defs{$name};
my $warmRelais = 2;
my $kaltRelais = 1;
my $tuwas = ReadingsVal("PID.HV_RLA","actuation","-5");
my $RLA_Soll = ReadingsVal("PID.HV_RLA","desired","0");
my $RLA = ReadingsVal("RE_TEMP_HV_RLA","temperature","0");
my $order;
my $ip = "192.168.0.95";
my $port = "8888";



my $message = "RLA ist: $RLA, soll: $RLA_Soll","remotebot";

if ($tuwas >= 500 || $tuwas <= -500 )
{   
log_telegram("4",$log_name,"_tuwas : $tuwas _","remotebot");
if($tuwas > 0){
$order = $warmRelais . "R" . abs($tuwas);
} else {
$order = $kaltRelais . "R" . abs($tuwas);
}

nb_udpsend($name,$order,$ip,$port);
##nb_ardsendHV($order);
$message .= " :=> $order";
} else {
$message .= " :=> $tuwas < 500\n keine Änderung";
}## end if
log_telegram("3",$log_name,$message,"remotebot");
if ($previous_loglevel != $subloglevel){
fhem("attr global verboseTelegram $previous_loglevel");
}
}## end sub
FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

abc2006

jetzt habe ich ein anderes interessantes Phänomen:
Fhem hat einen subprozess, und der forkt ...

FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX

abc2006

So, ich nochmal. Sorry, manche Gedankengänge dauern bei mir einfach länger.

ich übergebe der funktion den Namen von meinem DOIF (oder notify).
dann mache ich aus dem Namen den Hash und schreibe in helper-RunningPID
Wenn ich jetzt den timeout (deutlich) länger mache, müsste ich im list unter "helper" einen Punkt "runningpid" finden, in dem... irgendwas drin steht(sorry, so weit bin ich noch nicht).
Ah, und hier ist auch der Punkt, warum ich auf ein DOIF umgebaut habe:
ich hätte sonst zwei notifies mit zwei namen, die zwei funktionen aufrufen, und dann bekomm ichs nicht unter einen Hut.

Ich .. versuch jetzt erstmal, diesen runningpid zu finden...


PS: ist dir bewusst, dass es sich bei mir *noch* nicht um ein Modul handelt, sondern um subs in der 99myUtils?
Nicht dass du davon ausgehst, ich würde in einem Modul arbeiten ...

Grüße.
Stephan
FHEM nightly auf Intel Atom (lubuntu) mit VDSL 50000 ;-)
Nutze zur Zeit OneWire und KNX