FHEM Forum

FHEM => Codeschnipsel => Thema gestartet von: Torxgewinde am 04 September 2023, 21:29:31

Titel: 🌈 Bild herunterladen, direkt aus Reading darstellen,keine Datei, parseFunction1
Beitrag von: Torxgewinde am 04 September 2023, 21:29:31
Hallo,
Ich wollte eine Bilddatei als Reading haben, ohne den Umweg über das Dateisystem nehmen zu müssen. HTTPMOD kann generell was herunterladen und blockiert FHEM auch nicht, allerdings kann man an den BODY der HTTP-response mit Hausmitteln als Internal heran. Ich hätte es aber gerne als Reading, und das auch direkt als BASE64 encodiert.

Damit das gelingt bemüht man eine nicht gut dokumentierte Funktion "parseFunction1" oder "parseFunktion2". Minimal implementieren kann man eine Funktion in z.B. der 99_myUtils.pm:

  ###############################################################################
  #
  #  for HTTPMOD, keep the raw body of the HTTP response as reading ".body"
  #
  ###############################################################################
  sub myParseFunction_rawResponseAsReadingDotBody {
    use LWP::UserAgent;
    use HTTP::Response;
    use MIME::Base64;

    my ($hash, $buffer) = @_;

    # Entferne die HTTP-Header, wir wollen nur den "Body", auch wenn es Binärdaten sind
    my $http_response_obj = HTTP::Response->parse($buffer);

    # Da ein Bild Binärdaten sind, konvertiere ich es nach BASE64. FHEM kam aber auch damit klar,
    # wenn man es binär belässt, ich brauche es aber eh später als BASE64
    my $body = encode_base64($http_response_obj->content);

    # Speichere den Wert als Reading ".body".
    # Der Punkt sorgt dafür, dass das Reading bei den üblichen Settings nicht angezeigt wird.
    readingsSingleUpdate($hash, ".body", $body, 1);
  }

Jetzt zum eigentlichen Download mit HTTPMOD. Wir laden hier einfach mal alle 12h die Wettervorhersage für morgen herunter:
defmod WeatherForecast HTTPMOD https://www.dwd.de/DWD/wetter/wv_allg/deutschland/film/vhs_deutschland.jpg 43200
attr WeatherForecast parseFunction1 main::myParseFunction_rawResponseAsReadingDotBody
attr WeatherForecast stateFormat {\
my $img_base64 = ReadingsVal($name, ".body", undef);;\
return "keine Antwort" if !defined($img_base64);;\
$img_base64 =~ s/\n//g;;\
return "<html><img src=\"data:image/jpg;;base64, $img_base64\"></img></html>";;\
}
attr WeatherForecast timeout 20
attr WeatherForecast webCmd reread


So sieht es dann aus:
Bildschirmfoto_2023-09-04_21-09-36_1200.jpg

Warum das ganze? Ich wollte eigentlich das Wetterradar-GIF in FHEM cachen und nicht immer wieder vom DWD aus einem <iframe> herunterladen. Da FHEMWEB aber beim Ausliefern von großen Seiten (mit BASE64 aufgeblasen auf >=15MB) blockiert, habe ich von diesem Plan Abstand genommen. Ich denke die Verwendung von "parseFunction1" bedarf aber eines Codeschnipsels, falls jemand mal eine andere Idee verwirklichen möchte.

Viel Spaß!
Titel: Aw: 🌈 Bild herunterladen, direkt aus Reading darstellen,keine Datei, parseFunction1
Beitrag von: Torxgewinde am 13 April 2025, 16:23:57
Die ParseFunction1 und ParseFunction2 ist auch praktisch wenn man sowohl an die Header als auch den Body gelangen möchte. Das hatte ich in einem anderem HTTPMOD genutzt um den HTTP-Code (üblicherweise 200, bei Loginfragen auch mal 403 oder 401, bei Servererror 500 etc.) auslesen zu können.

Definieren kann man die Funktion auch ohne eine 99_myUtils.pm, zum Beispiel aus einem Userreading:
if (!defined &HTTPMOD::handleAuthErrors) {
    *HTTPMOD::handleAuthErrors = sub {
      my ($hash, $header, $body, $request) = @_;
      my $name = $hash->{NAME};
      my $status;

      if ($header =~ m{^HTTP/\d\.\d\s+(\d+)}m) {
        $status = $1;
      }

      Log3($name, 4, "$name: HTTP status code is $status");

      if ( $status == 401 || $status == 403 || $status == 500 ) {
        Log3($name, 3, "$name: auth-error or servererror ($status), calling doAuth()");
        HTTPMOD::DoAuth($hash);
      }
    };
  }

Genutzt habe ich das für ein HTTPMOD für Matrix-Synapse: https://forum.fhem.de/index.php?topic=120834.msg1339315#msg1339315