Hauptmenü

Weblink mit dynamsicher URL

Begonnen von Heiner, 23 Oktober 2024, 20:19:42

Vorheriges Thema - Nächstes Thema

Heiner

Hallo,

Ich moechte gern in fhem ein aktuelles Webcam Bild einer fremden Webseite einbinden.
Das ist im Prinzip einfach z.B. so:
define Kluesserathcam weblink image https://api.holfuy.com/cam/s242.jpg
Nun habe ich eine andere WebcamQuelle die leider eine dynamische Zuweisung hat sprich der Dateiname der letzten aufnahme aendert sich staendig.

die Idee waere nun (nonblocking get zu nutzen um die aktuelle Adresse zu erhalten (Danke TomLee), aber wie genau?

define Zeltingencam weblink image { HttpUtils_NonblockingGet( { url=>"http://www.moselfalken.de/zeltingen-rachtig/img.img-fluid", callback=>sub($$$) { my ($hash, $err, $data) = @_;; Log 1, "$err/$data" } }) }

klappt aber natuerlich nicht, ich habe auch nur geraten was die Suche auf der Webseite angeht.

und vermutlich noch mehr nicht stimmt.

Kann jemand helfen?

Heiner
--------------------------------
fhem auf Pi3+
CUL 868MHz, Signalduino 434MHz, HM-CFG-USB
HM, THZ, Kostal, Somfy, Conbee, Pytonbinding, FritzBox, FTUI, MQTT2

TomLee

#1
Hallo,

ZitatKann jemand helfen?

Beim Verständnis helfen wenn genaue Fragen sind gerne, aber hier nen halben Roman schreiben und alles kurz und knapp erklären liegt mir nicht.

Ich hab mir darüber Gedanken gemacht.
Wie ich vorgeschlagen habe, es im htmlCode-"Modus" mit HttpUtils_NonblockingGet zu versuchen, bekomme ich selbst nicht "vernünftig" hin. Die Rückgabe des callback direkt verwenden ist mein/das Problem ? Dazu hab ich evtl. zu wenig bisher verstanden.

Wenn es wie im anderen Thread auch, darum geht, das Bild im Dashboard anzuzeigen hab ich mir eine Lösung mit einer einfachen at-Definition überlegt. Damit wird allerdings der Devicename der Definition links vom Bild im Dashboard angezeigt, vmtl. wolltest Du ja gerade deswegen die weblink-Variante weil dort nur das Bild gezeigt wird ?


Die auskommentierte Variante holt zwar immer die Daten neu, schreibt das Reading aber nur bei Änderung.
Die aktive Variante, mit attr,  wird alle Zeit x ausgeführt, mit silent bekommt man davon aber nix mit.
Bei beiden Varianten aktualisiert sich das Bild in der Raumansicht bei Änderung automatisch, der einzige Unterschied zu weblink ist das der Devicename links neben dem Bild steht.
Zitatdefmod at_test at +*00:00:30 {\
HttpUtils_NonblockingGet({\
url=>'https://www.moselfalken.de/zeltingen-rachtig',\
callback=>sub($$$){\
    my $hash = $defs{$SELF};;\
    return readingsSingleUpdate($hash, "picname", "Fehler: $_[1]", 1) if($_[1]);;\
    my $ret = $_[2];;\
    $ret =~ m,.*(\w+.\w+.csm_camimg_\d{6}_\d{6}_\w+\.jpg)..width="930".height="697".title="".alt="">,s;;\
    #$ret = qq(<img width="720" height="480" style="border: 2px solid red;;border-radius: 10px;;" src="https://www.moselfalken.de/fileadmin/_processed_/$1">);;\
    #readingsBeginUpdate($hash);;\
    #readingsBulkUpdateIfChanged($hash,'html',$ret);;\
    #readingsEndUpdate($hash,0);;\

    fhem("attr -silent $SELF stateFormat <img width='720' height='480' style='border: 2px solid red;;;;border-radius: 10px;;;;' src='https://www.moselfalken.de/fileadmin/_processed_/$1'>");;\
}
})
}
attr at_test group Dash
attr at_test stateFormat <img width='720' height='480' style='border: 2px solid red;;border-radius: 10px;;' src='https://www.moselfalken.de/fileadmin/_processed_/8/b/csm_camimg_241023_182239_7d57bfe018.jpg'>

setstate at_test <img width='720' height='480' style='border: 2px solid red;;border-radius: 10px;;' src='https://www.moselfalken.de/fileadmin/_processed_/8/b/csm_camimg_241023_182239_7d57bfe018.jpg'>
setstate at_test 2024-10-23 17:20:39 html <img width="720" height="480" style="border: 2px solid red;;border-radius: 10px;;" src="https://www.moselfalken.de/fileadmin/_processed_/8/8/csm_camimg_241023_171706_618bf35dd0.jpg">
setstate at_test 2024-10-23 21:30:25 state Next: 21:30:55


edit:

Bei der ersten Variante muss man stateFormat dann so definieren:
attr at_test stateFormat {ReadingsVal($name,'html','')}



Heiner

wau, super vielen Dank. Ich brauch ein bischne bis ich alles verstehe

du hast nun 2 Varianten mit At gebaut

die aktive mit regelmaessigem update des Readings
die auskomentierte die das Reading nur updated wenn eine Aenderung vorliegt

Ist somit nicht die 2te die eigentlich elgantere und inteligentere das sie das Reading nicht unnoetig ueberschriebt solange sich nix aendert - oder gibts einen Grund die andere Variante zu bevorzugen?

Der Filter ueber die bildgroesse  hinter dem link ist genial, ich hab mich die ganze Zeit auch gefragt auf was ich filtern koennte da ich den html code der url sehr schwierig fand.

"Weblink" oder "at" ist ein kleiner Neben-aspekt, aber ja nur das Bild waere noch schoener. Hier bin ich zuversichtlich selbst eine Loesung zu finden

Nochmals vielen Dank.
Heiner
--------------------------------
fhem auf Pi3+
CUL 868MHz, Signalduino 434MHz, HM-CFG-USB
HM, THZ, Kostal, Somfy, Conbee, Pytonbinding, FritzBox, FTUI, MQTT2

TomLee

#3
ZitatHier bin ich zuversichtlich selbst eine Loesung zu finden
Ich meine so einfach ist das nicht und man müsste dazu dann im jeweiligen Modulcode eingreifen, weiß es aber nicht.

Und weil es vermutlich nicht so einfach ist, kam mir der Gedanke auf ob das überhaupt sein muss die Abfrage nicht blockierend auszuführen ? Ich vermute nicht.

Das wäre dann problemlos in dem weblink umzusetzen:

defmod wl_test weblink htmlCode {\
my $ret = GetFileFromURL("https://www.moselfalken.de/zeltingen-rachtig");;\
return if !$ret;;\
$ret =~ m,.*(\w+.\w+.csm_camimg_\d{6}_\d{6}_\w+\.jpg)..width="930".height="697".title="".alt="">,s;;\
return qq(<img width="720" height="480" style="border: 2px solid red;;border-radius: 10px;;" src="https://www.moselfalken.de/fileadmin/_processed_/$1">);;\
}

setstate wl_test initialized

aber das automatisch das aktuelle Bild angezeigt wird, ist hier halt ohne die Seite zu aktualisieren nicht

Heiner

Hi,

perfekt, funktioniert super. Besten Dank :)
Heiner
--------------------------------
fhem auf Pi3+
CUL 868MHz, Signalduino 434MHz, HM-CFG-USB
HM, THZ, Kostal, Somfy, Conbee, Pytonbinding, FritzBox, FTUI, MQTT2

Torxgewinde

#5
Guck dir vielleicht auch dies hier mal an, ein HTTPMOD genügt dafür eigentlich. Als Test habe ich es auf Cooltux Demoserver erstellt:

  • HTTPMOD ruft die Seite im Hintergrund ab,
  • sucht nach der Regex wie @TomLee ihn auch verwendet und
  • ein Userreading macht daraus ein HTML-Reading
  • das wir direkt mit Stateformat nutzen um es als Status anzuzeigen.

Da das Userreading "bild" ein Reading ist, kümmert sich FHEMWEB darum es zu aktualisieren, wenn ein Event zu dem Reading ausgelöst wurde. Damit dies nicht unnötigerweise passiert ist event-on-change-reading gesetzt.

defmod PM HTTPMOD https://www.moselfalken.de/zeltingen-rachtig 600
attr PM reading01Name WebcamURL
attr PM reading01Regex (fileadmin\/_processed_\/\w+\/\w+\/csm_camimg_\d{6}_\d{6}_\w+\.jpg)
attr PM room Experimente
attr PM event-on-change-reading .*
attr PM stateFormat bild
attr PM userReadings bild:WebcamURL:.* {\
    my $URL = "https://www.moselfalken.de/". ReadingsVal($name, "WebcamURL", "???");;\
    \
    return "<html><img src=\"$URL\"></html>";;\
}
attr PM webCmd start:stop

Torxgewinde

#6
Um den Devicenamen in der Darstellung auszublenden kann man auch CSS oder wie hier ein JS Schnipsel nutzen und die Zelle vor dem Bild adressieren und unsichtbar machen:

defmod PM HTTPMOD https://www.moselfalken.de/zeltingen-rachtig 600
attr PM reading01Name WebcamURL
attr PM reading01Regex (fileadmin\/_processed_\/\w+\/\w+\/csm_camimg_\d{6}_\d{6}_\w+\.jpg)
attr PM room Experimente
attr PM event-on-change-reading .*
attr PM stateFormat bild
attr PM userReadings bild:WebcamURL:.* {\
    my $URL = "https://www.moselfalken.de/". ReadingsVal($name, "WebcamURL", "???");;\
    \
    # JavaScript snippet with checks to ensure elements exist before applying styles\
    my $JS = "let td=this.closest('td');;";;\
    $JS .= "if(td && td.previousElementSibling) {";;\
    $JS .= "td.previousElementSibling.style.visibility='hidden';;";;\
    $JS .= "td.previousElementSibling.style.padding='0 0 0 0';;";;\
    $JS .= "td.previousElementSibling.style.width='0';;";;\
    $JS .= "}";;\
    \
    return '<html><img src="'.$URL.'" onload="'.$JS.'"></html>';;\
    \
}
attr PM webCmd start:stop

Sieht dann so aus:
Du darfst diesen Dateianhang nicht ansehen.


Edit #1:
Wenn man will kann man auch Zeit und Datum über dem Bild einblenden, steht ja in der URL mit drin:
defmod PM HTTPMOD https://www.moselfalken.de/zeltingen-rachtig 600
attr PM event-on-change-reading .*
attr PM group Dash
attr PM reading01Name WebcamURL
attr PM reading01Regex (fileadmin\/_processed_\/\w+\/\w+\/csm_camimg_\d{6}_\d{6}_\w+\.jpg)
attr PM room Experimente
attr PM stateFormat bild
attr PM userReadings bild:WebcamURL:.* {\
    my $URL = "https://www.moselfalken.de/". ReadingsVal($name, "WebcamURL", "???");;\
    my $DateTime = "???";;\
    \
    if ($URL =~ /fileadmin\/_processed_\/\w+\/\w+\/csm_camimg_(\d{6})_(\d{6})_\w+\.jpg$/) {\
        my ($date, $time) = ($1, $2);;\
        \
        # Format date (241028 to "2024-10-28") and time (100552 to "10:05:52")\
        my $formatted_date = "20" . substr($date, 0, 2) . "-" . substr($date, 2, 2) . "-" . substr($date, 4, 2);;\
        my $formatted_time = substr($time, 0, 2) . ":" . substr($time, 2, 2) . ":" . substr($time, 4, 2);;\
        \
        $DateTime = $formatted_date.' '.$formatted_time;;\
    }\
    \
    # JavaScript snippet with checks to ensure elements exist before applying styles\
    my $JS = "let td=this.closest('td');;";;\
    $JS .= "if(td && td.previousElementSibling) {";;\
    $JS .= "td.previousElementSibling.style.visibility='hidden';;";;\
    $JS .= "td.previousElementSibling.style.padding='0 0 0 0';;";;\
    $JS .= "td.previousElementSibling.style.width='0';;";;\
    $JS .= "}";;\
    \
    return '<html><img src="'.$URL.'" onload="'.$JS.'"><div style="position: relative;; top: -2em;; left: 1em;; font-size: 2em;;">'.$DateTime.'</div></html>';;\
    \
    }

So sieht es dann aus:
Du darfst diesen Dateianhang nicht ansehen.

Heiner

#7
Das sieht Klasse aus, vielen Dank.

die Anzeige Groesse des Bildes muestte ich doch eigentlich innerhalb der letzten Zeile dachte ich funktioniert, tuts aber nicht. Wo ist mein Fehler?

vorher:
return '<html><img src="'.$URL.'" onload="'.$JS.'"><div style="position: relative;; top: -2em;; left: 1em;; font-size: 2em;;">'.$DateTime.'</div></html>';;\
nachher:
return '<html><img src="'.$URL.'" onload="'.$JS.'"><div style="position: relative;; top: -2em;; left: 1em;; width: 200px;; font-size: 2em;;">'.$DateTime.'</div></html>';;\
und noch eine Frage: Webseiten inhalte die durch ein script produziert werden und somit nicht direct im sourcecode der Webseite zu finden sind, kann ich den auch irgendwie extrahieren?
z.b.   www.moselfalken.de/ogn zeigt oben "OGN Dashboard  und dann in Klammern einen Script output.  Weiter unten auf der Seite gibts auch noch "Unique pilots" das komplett inklusive dem Wert ein script output ist.

Heiner
--------------------------------
fhem auf Pi3+
CUL 868MHz, Signalduino 434MHz, HM-CFG-USB
HM, THZ, Kostal, Somfy, Conbee, Pytonbinding, FritzBox, FTUI, MQTT2

Torxgewinde

Hallo Heiner,
Du bist im falschen HTML Tag, du bist da im <div> mit dem der Zeitstempel umschlossen ist. So kann man es besser sehen und editieren:
defmod PM HTTPMOD https://www.moselfalken.de/zeltingen-rachtig 600
attr PM group Dash
attr PM reading01Name WebcamURL
attr PM reading01Regex (fileadmin\/_processed_\/\w+\/\w+\/csm_camimg_\d{6}_\d{6}_\w+\.jpg)
attr PM room Experimente
attr PM stateFormat bild
attr PM userReadings bild:WebcamURL:.* {\
    my $URL = "https://www.moselfalken.de/". ReadingsVal($name, "WebcamURL", "???");;\
    my $DateTime = "???";;\
    \
    if ($URL =~ m{fileadmin/_processed_/\w+/\w+/csm_camimg_(\d{2})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})_\w+\.jpg$}) {\
        my ($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3, $4, $5, $6);;\
        \
        my $formatted_date = "20$year-$month-$day";;\
        my $formatted_time = "$hour:$minute:$second";;\
        \
        $DateTime = "$formatted_date $formatted_time";;\
    }\
    \
    # JavaScript snippet with checks to ensure elements exist before applying styles\
    my $JS = "let td=this.closest('td');;";;\
    $JS .= "if(td && td.previousElementSibling) {";;\
    $JS .= "td.previousElementSibling.style.visibility='hidden';;";;\
    $JS .= "td.previousElementSibling.style.padding='0 0 0 0';;";;\
    $JS .= "td.previousElementSibling.style.width='0';;";;\
    $JS .= "}";;\
    \
    ##return '<html><img src="'.$URL.'" onload="'.$JS.'"><div style="position: relative;; top: -2em;; left: 1em;; font-size: 2em;;">'.$DateTime.'</div></html>';;\
    \
    my $html = qq{\
    <html>\
        <img src="$URL" onload="$JS" style="max-width: 200px;; height: auto">\
        <div style="position: relative;; top: -2em;; left: 10px;; font-size: 1em;;">\
            $DateTime\
        </div>\
    </html>\
    };;\
    \
    $html =~ s/\n//g;;\
    return $html;;\
}

Die Live Daten, ja, auch sowas kann man nutzen, allerdings muss man da ohne Doku schon eingiges an Zeit investieren. Also, ja - es geht, ich werde mich da allerdings nicht reinknien. Im Browser kannst du die Entwicklerkonsole nutzen um da an Details zu kommen, vielleicht hilft der Wegweiser bereits...