NEWS
E-INK Display OpenEPaperLink - Displayanzeige mit Batterie
-
@diwoma oder über discord atc1441 anschreiben. Das ist Aaron.
-
Gibt es einen einfachen Weg um einen Grafana-Diagramm auf ein Display zu bekommen?
Ich bin mir nicht sicher, ob das mit dem Grafana Image Renderer geht. Läuft der auf einem Raspberry pi4?
Grüße
-
@beowolf Danke, er hat schon geantwortet.
-
@beowolf sagte in E-INK Display OpenEPaperLink - Displayanzeige mit Batterie:
Gibt es einen einfachen Weg um einen Grafana-Diagramm auf ein Display zu bekommen?
Ich bin mir nicht sicher, ob das mit dem Grafana Image Renderer geht. Läuft der auf einem Raspberry pi4?
Grüße
Ich nutze VIS mit snapshot wie oben beschrieben. Geht wunderbar. Einfach im VIS die Werte auf der View ablegen und es wird auf dem Display dargestellt. Geht auch mit Graphen.
-
@eisbaeeer
Ich glaube aber, das wird nicht mit Grafana gehen, so wie die Frage war.
Da müsssen sicher Vis-spezifische Graphen gebaut werden -
@diwoma Solange der Grafana eine Webseite macht, geht das genauso. Mit Chrome Headless einen screenshot machen und als Bild auf den Tag laden.
chrome --headless --disable-gpu --screenshot https://meine-grafana-seite.html
Für rpi und andere gibt es auch das Paket puppeteer.
-
Ich mache ja alle anderen Darstellungen mit VIS und dann weiter mit puppeteer.
Nur wenn ich eine Darstellung von Grafana in VIS einbinde wir es auf den Displays nicht angezeigt.
Allerding sind die Grafana-Sachen auch etwas farbig. Event. liegt es daran.
-
@beowolf
Ich glaube, Grafana kannst Du nur direkt von grafana holen, so wie es @Eisbaeeer geschrieben hat.
Mit einem iFrame in die Vis eingebunden geht es wahrscheinlich nicht. -
Es scheint so. Mit einem iFrame geht es nicht.
-
Ich habe ab chatgpt wieder ein wenig gequält.
Es geht um die Abfrage der Buttons bei den schwarzen Displays.
Diese meine ich
https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/2.9″-EL029H3WRA
Hier das Skript
// HIER DIE IP ADRESSE VOM OEPL ACCESS POINT EINTRAGEN const serverIP = '192.168.49.185'; // z.B. 192.168.1.71 //Im Skript müssen noch zwei weiter Einträge event. der eigenen Umgebung angepasst werden // Zeile 17 - "Datenpunkt zur Steuerung des Skripts" // Zeile 21 - "Datenordner der empfangenen TAGs" // Zeile 176 - "Diesen Eintrag auch noch entsprechend der eigenen Umgebung anpassen" // AB HIER NICHTS MEHR ÄNDERN! const WebSocket = require('ws'); const http = require('http'); const wsUrl = `ws://${serverIP}/ws`; // WebSocket-URL let ws; let pingInterval; let scriptStopping = false; // Flag, um zu prüfen, ob das Skript gestoppt wird const controlState = '0_userdata.0.Tag_Buttons.Button_Skript_Steuerung.Button_Tags_Erdgeschoss'; // Datenpunkt zur Steuerung des Skripts function ensureOpenEPaperLinkFolderExists(callback) { const OpenEPaperLinkFolderPath = '0_userdata.0.Tag_Buttons.Erdgeschoss'; // Datenordner der empfangenen TAGs getObject(OpenEPaperLinkFolderPath, (err, obj) => { if (err || !obj) { setObject(OpenEPaperLinkFolderPath, { type: 'channel', common: { name: 'Open E-Paper Link' }, native: {} }, callback); } else { callback(); } }); } function ensureChannelExists(path, alias, callback) { getObject(path, (err, obj) => { if (err || !obj) { setObject(path, { type: 'channel', common: { name: alias || 'Unbekanntes Gerät' }, native: {} }, callback); } else if (obj.common.name !== alias) { extendObject(path, { common: { name: alias } }, callback); } else { callback(); } }); } function createStateAndSet(statePath, value) { setObject(statePath, { type: 'state', common: { name: statePath.split('.').pop(), type: 'string', role: 'value', read: true, write: true }, native: {} }, (err) => { if (!err) { setState(statePath, String(value), true); } }); } function updateStateIfChanged(statePath, value) { getState(statePath, (err, state) => { if (err || !state) { createStateAndSet(statePath, String(value)); } else if (state.val !== String(value)) { setState(statePath, String(value), true); } }); } function fetchDimensions(hwType, callback) { const hwTypeHex = hwType.toString(16).padStart(2, '0').toUpperCase(); // Convert hwType to two-digit uppercase hexadecimal const url = `http://${serverIP}/tagtypes/${hwTypeHex}.json`; http.get(url, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => { if (res.statusCode === 200) { try { const dimensions = JSON.parse(data); callback(null, dimensions); } catch (e) { callback(`Error parsing JSON from ${url}: ${e}`); } } else { callback(`HTTP Error ${res.statusCode} from ${url}`); } }); }).on('error', (err) => { callback(`Error fetching ${url}: ${err.message}`); }); } function handleHWType(basePath, hwType) { createStateAndSet(`${basePath}.hwType`, String(hwType)); // Save hwType as a state fetchDimensions(hwType, (err, dimensions) => { if (!err && dimensions) { createStateAndSet(`${basePath}.height`, String(dimensions.height)); createStateAndSet(`${basePath}.width`, String(dimensions.width)); createStateAndSet(`${basePath}.name`, String(dimensions.name)); if (dimensions.colors) { createStateAndSet(`${basePath}.colors`, String(dimensions.colors)); } if (dimensions.colortable) { createStateAndSet(`${basePath}.colortable`, JSON.stringify(dimensions.colortable)); } } else { console.error(`Failed to fetch or set dimensions for hwType ${hwType}: ${err}`); } }); } function connectWebSocket() { if (scriptStopping) { return; // Wenn das Skript gestoppt wird, keine Verbindung mehr herstellen } ws = new WebSocket(wsUrl); ws.on('open', function open() { console.log('Verbunden mit WebSocket'); startHeartbeat(); }); ws.on('message', function incoming(data) { console.log('Daten empfangen:', data); if (data) { try { let parsedData = JSON.parse(data); console.log('Verarbeitete Daten:', JSON.stringify(parsedData, null, 2)); handleData(parsedData); } catch (err) { console.error('Fehler bei der Verarbeitung der Daten:', err); } } else { console.log('Keine Daten oder leere Nachricht empfangen'); } }); ws.on('close', function close() { if (!scriptStopping) { console.log('WebSocket-Verbindung geschlossen, versuche neu zu verbinden...'); clearInterval(pingInterval); setTimeout(connectWebSocket, 5000); } }); ws.on('error', function error(err) { console.error('WebSocket-Fehler:', err); }); } function startHeartbeat() { pingInterval = setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.ping(() => console.log('Ping sent')); } }, 10000); // Send ping every 10 seconds ws.on('pong', () => { console.log('Pong received'); }); } function handleData(parsedData) { if (parsedData.tags && Array.isArray(parsedData.tags)) { parsedData.tags.forEach(tag => { let basePath = `0_userdata.0.Tag_Buttons.Erdgeschoss.${tag.mac.replace(/:/g, '')}`; //Diesen Eintrag auch noch entsprechend der eigenen Umgebung anpassen ensureChannelExists(basePath, tag.alias, () => { Object.keys(tag).forEach(key => { let statePath = `${basePath}.${key}`; let value = tag[key]; updateStateIfChanged(statePath, value); if (key === 'hwType') { handleHWType(basePath, tag.hwType); } }); }); }); } } function disconnectWebSocket() { if (ws) { ws.close(); ws = null; } clearInterval(pingInterval); } // Skript-Start und -Stopp basierend auf einem Datenpunkt steuern function setupScriptControl() { setObject(controlState, { type: 'state', common: { name: 'EPaper Script Control', type: 'boolean', role: 'switch', read: true, write: true, def: false }, native: {} }); on({id: controlState, change: 'ne'}, (obj) => { const state = obj.state.val; if (state) { // Skript starten scriptStopping = false; ensureOpenEPaperLinkFolderExists(connectWebSocket); } else { // Skript stoppen scriptStopping = true; disconnectWebSocket(); console.log('Skript beendet durch Steuer-Datenpunkt'); } }); } // Initiale Einrichtung setupScriptControl();
Jetzt kann das Skript durch Setzen des Datenpunkts 0_userdata.0.ScriptControl.EPaperScript auf true oder false gestartet und gestoppt werden.
Bei mir funktioniert es.
Bitte die Einstellung im Skript beachten !!!
Die Fehlermeldungen bei dem ersten Durchlauf sind wohl normal.
-
Hat schon jemand das Blockly zum Screenshotten von request befreit?
Nach update auf die neuste Version vom Controller wird request nicht mehr akzeptiert. -
@eisbaeeer ich hatte es versucht ... aber nicht hinbekommen. Zur Zeit triggere ich playwright alle 3 Minuten an, die Bilder landen in einem Ordner meines Webservers (läuft mit auf dem ioBroker Server auf Port 80) und die Tags stehen auf
Image URL
Dazu habe ich ein Python-Skript hinterlegt das 3 VIS-Seiten besucht und die Screenshots hinterlegt:
#!/usr/bin/python3 # -*- coding: utf-8 -*- import subprocess from playwright.sync_api import sync_playwright, Page, expect playwright = sync_playwright().start() #browser = playwright.chromium.launch() #browser = playwright.webkit.launch() browser = playwright.firefox.launch() context = browser.new_context( viewport={"width":800, "height":600}, device_scale_factor=4, ) page = context.new_page() # Schritt 1: Kühlschrank page.goto("http://192.168.1.8:60008/vis/index.html?openepaper#Kuehlschrank01") expect(page.get_by_text("Kuehlschrank01")).to_be_visible() #page.screenshot(path="/var/www/html/openepaper/Kuehlschrank01_4x.jpg",clip={"x":0,"y":0,"width":296,"height":128},quality=100,type="jpeg") page.screenshot(path="/var/www/html/openepaper/Kuehlschrank01_4x.png",clip={"x":0,"y":0,"width":296,"height":128},type="png") myconvert=subprocess.call(['/usr/bin/convert', '/var/www/html/openepaper/Kuehlschrank01_4x.png', '-sample', '296x128', '-quality', '100', '-sampling-factor', '4:4:4', '-brightness-contrast', '0x99', '/var/www/html/openepaper/Kuehlschrank01.jpg' ]) # Schritt 2: Pylontech page.goto("http://192.168.1.8:60008/vis/index.html?openepaper#Pylontech") expect(page.get_by_text("Pylontech")).to_be_visible() #page.screenshot(path="/var/www/html/openepaper/Pylontech_4x.jpg",clip={"x":0,"y":0,"width":296,"height":128},quality=100,type="jpeg") page.screenshot(path="/var/www/html/openepaper/Pylontech_4x.png",clip={"x":0,"y":0,"width":296,"height":128},type="png") myconvert=subprocess.call(['/usr/bin/convert', '/var/www/html/openepaper/Pylontech_4x.png', '-sample', '296x128', '-quality', '100', '-sampling-factor', '4:4:4', '-brightness-contrast', '0x99', '/var/www/html/openepaper/Pylontech.jpg' ]) # Schritt 3: Briefkasten page.goto("http://192.168.1.8:60008/vis/index.html?openepaper#Briefkasten") expect(page.get_by_text("Briefkasten")).to_be_visible() #page.screenshot(path="/var/www/html/openepaper/Briefkasten_4x.jpg",clip={"x":0,"y":0,"width":296,"height":128},quality=100,type="jpeg") page.screenshot(path="/var/www/html/openepaper/Briefkasten_4x.png",clip={"x":0,"y":0,"width":296,"height":128},type="png") myconvert=subprocess.call(['/usr/bin/convert', '/var/www/html/openepaper/Briefkasten_4x.png', '-sample', '296x128', '-quality', '100', '-sampling-factor', '4:4:4', '-brightness-contrast', '0x99', '/var/www/html/openepaper/Briefkasten.jpg' ]) # Schritt 4: Fenster und Türen page.goto("http://192.168.1.8:60008/vis/index.html?openepaper#EingangstuerV2") expect(page.get_by_text("FensterTueren")).to_be_visible() #page.screenshot(path="/var/www/html/openepaper/FensterTueren_4x.jpg",clip={"x":0,"y":0,"width":400,"height":300},quality=100,type="jpeg") page.screenshot(path="/var/www/html/openepaper/FensterTueren_4x.png",clip={"x":0,"y":0,"width":400,"height":300},type="png") myconvert=subprocess.call(['/usr/bin/convert', '/var/www/html/openepaper/FensterTueren_4x.png', '-sample', '400x300', '-quality', '100', '-sampling-factor', '4:4:4', '-brightness-contrast', '0x99', '/var/www/html/openepaper/FensterTueren.jpg' ]) browser.close() playwright.stop()
und das ich per Blockly alle 3 Minuten triggere:
In dem Skript gibt es Zeilen für alle 3 Browser, Firefox sah bei mir am besten aus. Playwright installiert alle 3 Engines.
Die Screenshots werden doppelt so groß gefertigt und dann herunterskaliert, dafür muss Imagemagick evenfalls installiert sein (für den Befehlconvert
) -
@eisbaeeer sagte in E-INK Display OpenEPaperLink - Displayanzeige mit Batterie:
Hat schon jemand das Blockly zum Screenshotten von request befreit?
Nach update auf die neuste Version vom Controller wird request nicht mehr akzeptiert.Was ist daran falsch? Oder meinst du ein anderes Skript?
Grüße
-
@beowolf Mit dem neusten js-controller läuft request und somit das Blockly Script nicht mehr.
-
Muß jetzt mal unwissend fragen. Mit js-controller meinst du den javaskript Adapter?
-
hat mit dem js-controller weniger zu tun, nur der Javascript-Adapter unterstuetzt das lange depricated request nicht mehr im Blockly, dafuer gibts ja fuer Blockly httpget und post usw.. also genug alternativen.
Einfach mal in der Doku und hier im Forum nachlesen, da gibts auch genug Anleitungen zum umbauen.
-
Genau für den Fall, weil "request" nicht mehr geht, hatte ich doch das Skript geändert.
Hier läuft es ohne Probleme mit der Java-Skriptversion 8.3.1
-
@beowolf sagte in E-INK Display OpenEPaperLink - Displayanzeige mit Batterie:
Genau für den Fall, weil "request" nicht mehr geht, hatte ich doch das Skript geändert.
Hier läuft es ohne Probleme mit der Java-Skriptversion 8.3.1
Top! Einfach ausgetauscht und läuft.
Danke! -
Aber bitte beachten. Ich hatte das Skript durch Chatgpt ändern lassen.
Ich habe keine Ahnung ob das "programmiertechnisch" alles so Top in Ordnung ist.
Nur weil es funktioniert bedeutet es nicht, das es komplett richtig ist.
-
@beowolf sagte in [E-INK Display OpenEPaperLink - Displayanzeige mit Batterie]
Nur weil es funktioniert bedeutet es nicht, das es komplett richtig ist.
Ich schau mir es noch an. Der erste Blick sah gut aus.
--- EDIT ---
Im Code ist nichts problematisches. Alles gut!