Generelle Frage zu BlockingCall()

Begonnen von Sailor, 28 Oktober 2014, 16:13:01

Vorheriges Thema - Nächstes Thema

rudolfkoenig

Du sollst ja auch nicht 148 Anfragen auf einmal stellen, sondern nur eine. Wenn sie beantwortet wurde, dann wird ja dein Callback aufgerufen, und der kann dann die zweite Anfrage stellen. Um zu wissen, an welcher Stelle du gerade bist, kannst du im $param hinterlegen. Und statt konkrete Funktionsaufrufe wuerde ich eine Tabelle mit Aufrufparametern bauen, und diese der Reihe nach abarbeiten.

Markus Bloch

Also, angenommen es existiert die folgende URL:

http://www.foo.de/ 

diese gibt als  Seiteninhalt nur das Wort "bar" zurück (ohne Anführungszeichen).

Um diese URL non-blocking Aufzurufen würde man in einem Modul (z.B. deinem k200) wie folgt vorgehen.



sub km200_GetData($)
{

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

    my $param = {
                    url        => "http://www.foo.de",
                    timeout    => 5,
                    hash       => $hash,  # muss gesetzt werden, damit die Callback funktion wieder $hash hat
                    callback   =>  \&km200_parseHttpResponse # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
                };
                             
    HttpUtils_NonBlockingGet($param);  # Starten der HTTP Abfrage. Es gibt keinen Return-Code.
   
}



# Die Callback-Funktion
sub km200_parseHttpResponse($)
{

    my ($param, $err, $data) = @_;
    my $hash = $param->{hash};
    my $name = $hash->{NAME};

    if($err ne "") # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
    {
        Log3 $name, 3, "error while requesting ".$param->{url}." - $err";
       
        # Readings erzeugen
        readingsSingleUpdate($hash, "fullResponse", "ERROR");
    }
    elsif($data ne "") # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
    {
       
        Log3 $name, 3, "url ".$param->{url}." returned: $data";
       
        # Antwort parsen / verarbeiten mit $data
       
        # Readings erzeugen
        readingsSingleUpdate($hash, "fullResponse", $data);
    }
   
    # Damit ist die Abfrage zuende.
   
    # evtl. einen InternalTimer neu schedulen
   
}



Im Erfolgsfall hättest du im Log nun folgenden Eintrag

2014.10.31 17:40:35.625 3: km200 url http://www.foo.de returned: bar

und du hättest in deiner Definition ein Reading "fullResponse" mit dem Wert "bar" (was ja dem Seiteninhalt) entspricht.

Im Fehlerfall hättest du folgenden Logeintrag:

2014.10.31 17:40:35.625 3: km200 error while requesting http://www.foo.de - connect to http://www.foo.de timed out

und du hättest in deiner Definition ein Reading "fullResponse" mit dem Wert "ERROR" (was einen Fehler bei der Abfrage bedeuten soll)


Generell kann man den $param-Hash mit weiteren Werten frei füllen, die man evtl. in der Callback-Funktion benötigt um die Antwort einem vorausgehenden set-Kommando oder dem ursprünglichen Request zuzuordnen usw.

Ich hoffe das Beispiel ist soweit verständlich.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Sailor

Hallo Markus

das ist ein sehr anschaulichhes Beispiel welches ich nachvollziehen kann.
Ich denke ich werde es umsetzen koennen.

Danke dafuer!

Ich werde berichten!

Gruss
    Sailor
******************************
Man wird immer besser...

Sailor

Hallo Rudi, Markus

Es hat geklappt: http://forum.fhem.de/index.php/topic,25540.msg215277.html#msg215277

Danke für das anschauliche Beispiel von Markus und die entscheidene Ergänzung von Rudi
Zitateine Tabelle mit Aufrufparametern bauen, und diese der Reihe nach abarbeiten


Wenn das OK ist, hänge ich Markus' Beispiel inklusiver kleiner Korrekturen an das WIKI


use HttpUtils;

sub X_GetHttpResponse($)
{

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

    my $param = {
                    url        => "http://www.foo.de",
                    timeout    => 5,
                    hash       => $hash,                                                                                                     # Muss gesetzt werden, damit die Callback funktion wieder $hash hat
                    method     => "GET",                                                                                                     # Lesen
                    header     => "agent: TeleHeater/2.2.3\r\nUser-Agent: TeleHeater/2.2.3\r\nAccept: application/json",                     # Den Header gemäss abzufragender Daten ändern
                    callback   =>  \&X_ParseHttpResponse                                                                                     # Diese Funktion soll das Ergebnis dieser HTTP Anfrage bearbeiten
                };
                             
    HttpUtils_NonblockingGet($param);  # Starten der HTTP Abfrage. Es gibt keinen Return-Code.
   
}



# Die Callback-Funktion
sub X_ParseHttpResponse($)
{

    my ($param, $err, $data) = @_;
    my $hash = $param->{hash};
    my $name = $hash->{NAME};

    if($err ne "") # wenn ein Fehler bei der HTTP Abfrage aufgetreten ist
    {
        Log3 $name, 3, "error while requesting ".$param->{url}." - $err";
       
        # Readings erzeugen
        readingsSingleUpdate($hash, "fullResponse", "ERROR");
    }
    elsif($data ne "") # wenn die Abfrage erfolgreich war ($data enthält die Ergebnisdaten des HTTP Aufrufes)
    {
       
        Log3 $name, 3, "url ".$param->{url}." returned: $data";
       
        # Antwort parsen / verarbeiten mit $data
       
        # Readings erzeugen
        readingsSingleUpdate($hash, "fullResponse", $data);
    }
   
    # Damit ist die Abfrage zuende.
   
    # evtl. einen InternalTimer neu schedulen
   
}


In dem Link oben, ist noch eine kleine Problemstellung beschrieben... Vielleicht habt Ihr ja auch ähnliche Erfahrung gemacht.

Ansonsten Danke nochmal und bis zum nächsten mal!

Gruss
    Sailor
******************************
Man wird immer besser...