Javascript innerhalb von FHEM ausführen und das Ergebnis weitersenden?

Begonnen von andies, 25 Februar 2024, 19:10:38

Vorheriges Thema - Nächstes Thema

andies

Ich habe eine Funktion, die ein Bild mit Javascript erzeugt. Der Code sieht in etwa so aus,
data <div id="eCharts_myChart" style="width: 800px;height:400px;"></div>
<script type="text/javascript">
var myChart_myChart = echarts.init(document.getElementById('eCharts_myChart'));
var option_myChart={"dataZoom":[{"end":"90","start":"30","type":"inside"},{"end":"90","start":"30"}],"toolbox":{"feature":{"saveAsImage":{}},"backgroundColor":"transparent","pixelRatio":2,"name":"Gartentor Raspberry Kerntemp"},"xAxis":{"name":"Zeit","type":"time"},"series":[{"markPoint":{"data":[{"type":"max","name":"Max"}],"itemStyle":{"color":"black"}},"name":"Kern","markLine":{"data":[{"type":"average","name":"Avg"}],"itemStyle":{"color":"black"}},"data":[["2024-02-24 20:03:50","44.5"],["2024-02-24 20:12:45","45.6"],["2024-02-24 20:13:18","47.2"],["2024-02-24 21:13:23","44.5"],["2024-02-24 22:13:25","43.5"],["2024-02-24 23:01:36","45.1"],["2024-02-24 23:58:30","45.6"],["2024-02-25 00:58:33","42.9"],["2024-02-25 01:58:36","42.4"],["2024-02-25 02:58:39","41.9"],["2024-02-25 03:58:42","40.8"],["2024-02-25 04:58:45","40.8"],["2024-02-25 05:58:49","40.8"],["2024-02-25 06:58:51","41.3"],["2024-02-25 07:58:54","40.8"],["2024-02-25 07:59:01","41.9"],["2024-02-25 08:29:29","45.1"],["2024-02-25 09:29:32","43.5"],["2024-02-25 10:29:50","47.8"],["2024-02-25 11:29:38","49.4"],["2024-02-25 11:49:14","52.6"],["2024-02-25 11:52:30","53.2"],["2024-02-25 12:42:57","53.2"],["2024-02-25 12:48:02","53.7"],["2024-02-25 12:51:29","57.5"],["2024-02-25 12:53:21","53.7"],["2024-02-25 13:53:24","52.6"],["2024-02-25 14:53:27","51.5"],["2024-02-25 15:10:22","53.7"],["2024-02-25 15:10:54","54.8"],["2024-02-25 16:10:57","49.4"],["2024-02-25 16:21:34","51.0"],["2024-02-25 16:22:59","54.2"],["2024-02-25 17:23:02","48.9"],["2024-02-25 18:23:05","46.2"]],"lineStyle":{"color":"black","width":2},"yAxisIndex":"0","symbol":"none","type":"line"}],"yAxis":[{"name":"rechts"},{"type":"value","axisLabel":{"formatter":"{value}"},"name":"Temperatur"}],"grid":{"show":"true"},"tooltip":{"axisPointer":{"type":"cross"},"trigger":"axis"},"title":{"text":"Gartentor Raspberry Kerntemp"}};myChart_myChart.setOption(option_myChart);
</script>
Sende ich den Code an FW_summaryFn (zum Beispiel), so wird ein Bild korrekt erzeugt. Ich möchte jetzt gern dieses Bild mit einem TelegramBot weitersenden. Mir ist nicht klar, wie ich diesen Code ausführen lassen kann und ihn damit zu einem png oder jpg transferiere und so in der Lage bin, ihn mit einem TelegramBot zu versenden.

Kann mir da jemand einen Tipp geben, wo ich weitersuchen kann?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Also ich sehe schon, meine Frage kapiert keiner. Noch ein Versuch.

FHEM hat einen eigenen Webserver. Wenn ich an den "Texte" sende, werden sie angezeigt. Das geschieht, wenn ich das richtig sehe, beispielsweise durch $<Modulname>_FwF und die Zuweisung my $data =. Sende ich beispielsweise ein Bild, das mit javascript erzeugt wird, zeigt der FHEM-Webserver es an.

Ich hoffe, ich habe das halbwegs richtig verstanden, dass das so abläuft.

Nun möchte ich gern diesen Webserver verwenden, um Bilder zu rendern. Dazu muss ich erstens wieder dieses javascript an den Server senden. Dann aber möchte ich, dass der Server nicht das Bild anzeigt, sondern es erzeugt und "an mich" (also eine Variable) zurücksendet, die ich dann weiterverarbeiten kann. ZB mit Telegram senden.

Leider stehe ich völlig auf dem Schlauch, wie das gehen könnte. Wäre nett, wenn mir hier jemand einen Tipp geben kann.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Ich habe das mal hierhin verschoben, vielleicht ist das zu speziell für Anfänger?
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

betateilchen

#3
Zitat von: andies am 26 Februar 2024, 10:17:56Nun möchte ich gern diesen Webserver verwenden, um Bilder zu rendern. Dazu muss ich erstens wieder dieses javascript an den Server senden. Dann aber möchte ich, dass der Server nicht das Bild anzeigt, sondern es erzeugt und "an mich" (also eine Variable) zurücksendet

Sowas ist eigentlich nicht die Aufgabe des FHEM-internen Webservers.
Für solche Aufgaben gibt es eigene perl (und andere externe) libraries, die Du beispielsweise in Deiner 99_myUtils.pm verwenden kannst.

Ich geh mal Popcorn holen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

andies

Kannst du mir vorher einen Begriff geben, wo ich nachlesen kann?

(Ich zeige mich dann gern erkenntlich - salzig oder süß?)
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

betateilchen

Was Du tun möchtest, ist halt einfach kein FHEM-spezifisches Thema.
Du möchtest per JavaScript Code ein Bild erzeugen, das Ergebnis soll die Datenmenge sein, die das Bild repräsentiert. Du musst also eine Umgebung finden, die das tun kann.

Spontan fällt mir da beispielsweise Node.js ein.
Wikipedia sagt dazu:

ZitatNode.js ist eine plattformübergreifende Open-Source-JavaScript-Laufzeitumgebung, die JavaScript-Code außerhalb eines Webbrowsers ausführen kann.

Die erzeugte Datenmenge (das, was Du "in einer Variablen" nennst) kannst Du dann natürlich wieder in FHEM verwursten.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

andies

OK, ich verstehe. Das wäre also unsystematisch und passt da nicht hinein.

Mein Problem ist jetzt, dass ich dann ein weiteres System installieren und auf dem aktuellen Stand halten müsste. Ich dachte mir, da der FHEM-Webserver die Grafiken sowieso rendert (sie werden ja angezeigt) und damit auch nicht überfordert ist, kann man den gleich fürs png-erstellen und weitersenden mit Telegram nehmen.

Aber ich sehe schon, da trifft mich die Wucht der Systematik und so werde ich nicht geholfen. Leider nachvollziehbar.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

betateilchen

Zitat von: andies am 27 Februar 2024, 10:36:53Ich dachte mir, da der FHEM-Webserver die Grafiken sowieso rendert (sie werden ja angezeigt)

Genau hier liegt aber Dein grundsätzlicher Denkfehler.

Die Grafik wird nicht vom Webserver (egal welcher) gerendert, sondern erst in und von Deinem Browser, der den von der Webseite erhaltenen JavaScript-Code (!) ausführt.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

andies

Ach so, der Browser rendert (ich dachte, FHEM macht server-side-Rendering). Ok, dann muss ich eine andere Lösung finden.

Danke, das wusste ich nicht. Wieder was gelernt.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

Prof. Dr. Peter Henning

#9
Das muss nicht so sein. Zunächst einmal würde ich Grafiken niemals durch JavaScript erzeugen - das ist viel zu unflexibel.

Sehr viel besser geht das, indem man die Kommandozeilensteuerung des ImageMagick-Paketes aufruft. Es gibt also auf dem Server ein Shell-Script, das (z.B. von FHEM) mit entsprechenden Parametern aufgerufen wird und dann, voilà, eine PNG_Datei ausspuckt. Das habe ich 2016 in Kapitel 7 der SmartHome Hacks ausführlich dokumentiert und erläutert, unten habe ich eine Beispieldatei für die Erzeugung einer Datumsanzeige als Bild, sowie ein Bild mit Datumsanzeige und Balkendiagramm angehängt. Vor etlichen Jahren habe ich das benutzt, um die Anzeige meiner Verbrauchsdaten auf einem (ziemlich dummen) digitalen Bilderrahmen zu realisieren.

Inzwischen sind meine Wanddisplays (einigermaßen intelligente) Tablets, die Bilder werden daher im jeweiligen Browser gerendert. Das bedeutet, dass man den Server entlasten kann - er sendet einfach nur noch SVG-Daten, die in der jeweiligen Webseite eingebettet sind. Auch damit kann man tolle Diagramme machen, die dann eben einfach als SVG-Widgets definiert sind. Wie Anleitung dazu habe ich 2020 im Buch SmartHome mit FHEM veröffentlicht, auch dazu unten ein Bild.

Und wie das dann aussehen kann, z.B. mit einem Schemabild des Hauses und live eingeblendeten Temperaturen etc. sieht man auf dem letzten angehängten Screenshot.

LG

pah

(Edit: In dem Screenshot vom Tablet ist mein Stromverbrauch derzeit Null, weil meine neue "Moderne Messeinrichtung" noch nicht richtig ausgelesen wird ...)


betateilchen

#10
Zitat von: Prof. Dr. Peter Henning am 29 Februar 2024, 10:11:32Das muss nicht so sein. Zunächst einmal würde ich Grafiken niemals durch JavaScript erzeugen - das ist viel zu unflexibel.

Natürlich nicht. Und Deine Ausführungen sind grundsätzlich auch alle richtig.

Wenn man aber den Hintergrund kennt, in dem die gestellte Frage aufgetaucht war, hilft Deine Antwort nicht viel weiter, weil sie am Thema und der eigentlichen Fragestellung vorbeigeht.

Es geht um die Integration von eCharts in FHEM. Und da ist es halt doch so, dass die "Bilder" im Browser gerendert werden.


(offtopic:
Die "Werbung" für Deine Bücher an jeder passenden und unpassenden Stelle fängt an, störend zu wirken.
Aber das ist natürlich nur mein ganz persönliches Empfinden)


---
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

rudolfkoenig

ZitatIch habe eine Funktion, die ein Bild mit Javascript erzeugt
[...]
Ich möchte jetzt gern dieses Bild mit einem TelegramBot weitersenden.
Haengt davon ab, mit welcher Methode das Bild erstellt wurde:
- wenn es Canvas ist, dann kann man den Inhalt der Canvas per JavaScript dumpen (z.Bsp. canvas.toDataURL("image/jpeg", 0.7)), und das Ergebnis zu FHEM schicken.
- wenn es SVG ist, dann kann man dieses SVG zu FHEM schicken, was wiederum per externe Bibliothek in was "Telegram-Kompatibles" umgewandelt werden kann (siehe plotAsPng in 98_SVG.pm).

andies

Zitat von: rudolfkoenig am 29 Februar 2024, 13:47:50Haengt davon ab, mit welcher Methode das Bild erstellt wurde:
Leider wurde es in Javascript erzeugt bzw der Browser erzeugt das, nicht FHEM. Das hat mir betateilchen beigebracht. Insofern muss ich da Umwege gehen.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

Ok, dann mit mehr Text:

Haengt davon ab, mit welcher im Browser implementierten Methode das Bild von der JavaScript Bibliothek eCharts erstellt wurde.
Laut https://echarts.apache.org/v4/en/api.html#echarts:
ZitatOptional chart configurations; which may contain:
[...]
renderer
Supports 'canvas' or 'svg'. See Render by Canvas or SVG.
[...]

Prof. Dr. Peter Henning

ZitatDie "Werbung" für Deine Bücher an jeder passenden und unpassenden Stelle fängt an, störend zu wirken.
Die Bücher sind in allen zitierten Teilen kostenfrei zugänglich, also mach mal langsam.

LG

pah

andies

Es ist canvas, das weiß ich inzwischen (geht leider immer noch nicht, aber ich befürchte, dass ich mit meiner Unkenntnis inzwischen die Nerven strapaziere; ich kriege bei
var myChart_myChart = echarts.init(document.getElementById('eCharts_myChart'), null, {renderer: 'canvas'});
 ...
var img = myChart_myChart.toDataURL("image/jpeg", 1.0);
console.log(img);
den Fehler
Uncaught TypeError: myChart_myChart.toDataURL is not a function
    at fhem?detail=myChart:224:27
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

rudolfkoenig

Dein myChart_myChart ist kein Canvas, es ist ein eCharts Objekt, was selbst wiederum ein Canvas verwendet.
Habs auf die schnelle nicht rausgekriegt, mit welcher eCharts Methode man den Canvas rauskriegt.

Mit jQuery waere das sowas wie $("canvas").get(0).toDataURL(...), damit greifst Du auf dem ersten Canvas auf der Seite zu.
Eine bessere Methode ist, wenn man eCharts in einem div mit myID rendert, dann gilt $("div#myID canvas").get(0)...

andies

Danke, habe es gefunden. Hast du noch ein hilfreiches Schlagwort wie man das "zu FHEM schickt"
Zitat von: rudolfkoenig am 29 Februar 2024, 13:47:50- wenn es Canvas ist, dann kann man den Inhalt der Canvas per JavaScript dumpen (z.Bsp. canvas.toDataURL("image/jpeg", 0.7)), und das Ergebnis zu FHEM schicken.
Für diejenigen, die es interessiert, wie der Ablauf innerhalb von JavaScript ist
  eCharts_pO 'daten = <hier der Name der eChartsinstanz>.getDataURL({"pixelRatio": "2","backgroundColor": "#fff"});';  # jetzt ist das Bild in der Variablen daten
  eCharts_pO 'const blob = new Blob([daten], {type: "image/png"});'; # TODO das ist noch base64!!
  eCharts_pO 'const a = document.createElement("a");'; # als Beispiel wird das mal heruntergeladen
  eCharts_pO 'a.href = URL.createObjectURL(blob);a.download = "downloadfile";';
  eCharts_pO 'document.body.appendChild(a);a.click();document.body.removeChild(a);'; 
wobei eCharts_pO genau so definiert ist wie SVG_pO.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

PS ChatGPT 4 kann das, erstaunlich, und ich hoffe, das ist nicht so falsch
function sendToFHEM(device, state) {
  const fhemUrl = 'http://fhem-server:8083/fhem?cmd=set ' + encodeURIComponent(device) + ' ' + encodeURIComponent(state) + '&XHR=1';
  fetch(fhemUrl, {
    method: 'GET', // or 'POST'
    headers: {
      // If you have basic authentication enabled for FHEM
      'Authorization': 'Basic ' + btoa('username:password')
    },
    credentials: 'include' // Required for cookies, authorization headers with HTTPS
  })
  .then(response => response.text())
  .then(data => console.log('Response from FHEM:', data))
  .catch(error => console.error('Error sending data to FHEM:', error));
}

// Example usage
sendToFHEM('myDevice', 'on');
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

So, die Sache ist geklärt, vielen Dank nochmal an alle. Kurze Info: Man kann in eCharts SVG (statt canvas) rendern und das sogar so gestalten, dass auch nodejs das Bild erzeugt. Intern wird dann "renderToSVG()" aufgerufen und ich bekomme so eine SVG, die ich dann mit Bordmitteln weiter bearbeiten kann. Jetzt muss das "nur" noch aufgeschrieben werden.
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann

andies

Noch ein Tipp, falls das jemand liest. Echtes Server-Side-Rendering geht nicht, also habe ich einen umständlichen Ausweg für's erste gefunden:
hier
FHEM 6.1 auf RaspPi3 (Raspbian:  6.1.21-v8+; Perl: v5.32.1)
SIGNALduino (433 MHz) und HM-UART (868 MHz), Sonoff, Blitzwolf, Somfy RTS, CAME-Gartentor, Volkszähler, Keyence-Sensor, Homematic-Sensoren und -thermostat, Ferraris-Zähler für Wasseruhr, Openlink-Nachbau Viessmann