Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Praktische Anwendungen (Showcase)
  4. OpenEpaperLink - Script für Tastenabfrage

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    1.0k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    699

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.0k

OpenEpaperLink - Script für Tastenabfrage

Geplant Angeheftet Gesperrt Verschoben Praktische Anwendungen (Showcase)
5 Beiträge 2 Kommentatoren 468 Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • EisbaeeerE Offline
    EisbaeeerE Offline
    Eisbaeeer
    Developer
    schrieb am zuletzt editiert von Eisbaeeer
    #1

    Es kam schon öfter die Frage auf, wie man die Tasten an einem EPaper Display für OpenEpaperLink abfragen kann.
    Leider funktioniert der Open-Epaper-Link Adapter derzeit eher mäßig, deshalb habe ich die Funktion des TCP Sockets in das Script übernommen (Danke an @Beowolf ).

    Also was macht das Script?

    • Man erstellt sich mehrere Views, die auf dem Display angezeigt werden sollen.
    • Im Script gibt man die Parameter an
    • Mit den Tasten am Display kann man dann die Seiten "hoch und runterblättern".

    Ich verwende hier ein 4" Touch Display mit integriertem Accesspoint. Das geht aber natürlich auch mit jedem anderen Epaper Display mit Taster.
    Die Uhr wird jede Minute aktualisiert. Macht also nur auf einem Accesspoint Sinn. ;-)
    Das Laden der nächsten Seite dauert etwa 5-6 Sekunden. Ganz unten gibt es auch ein Video.

    0d73277b-679b-43e4-b845-21727960e4f4-Clock.png

    2fa511c0-50d2-4cd7-b78f-98b8a9e6e490-Views.png


    {
    "settings": {
    "style": {
    "background_class": ""
    },
    "theme": "redmond",
    "sizex": "480",
    "sizey": "480",
    "gridSize": "",
    "snapType": null,
    "useAsDefault": false,
    "useBackground": false
    },
    "widgets": {
    "e00001": {
    "tpl": "tplScreenResolution",
    "data": {
    "g_fixed": false,
    "g_visibility": false,
    "g_css_font_text": false,
    "g_css_background": false,
    "g_css_shadow_padding": false,
    "g_css_border": false,
    "g_gestures": false,
    "g_signals": false,
    "g_last_change": false,
    "visibility-cond": "==",
    "visibility-val": 1,
    "visibility-groups-action": "hide",
    "signals-cond-0": "==",
    "signals-val-0": true,
    "signals-icon-0": "/vis/signals/lowbattery.png",
    "signals-icon-size-0": 0,
    "signals-blink-0": false,
    "signals-horz-0": 0,
    "signals-vert-0": 0,
    "signals-hide-edit-0": false,
    "signals-cond-1": "==",
    "signals-val-1": true,
    "signals-icon-1": "/vis/signals/lowbattery.png",
    "signals-icon-size-1": 0,
    "signals-blink-1": false,
    "signals-horz-1": 0,
    "signals-vert-1": 0,
    "signals-hide-edit-1": false,
    "signals-cond-2": "==",
    "signals-val-2": true,
    "signals-icon-2": "/vis/signals/lowbattery.png",
    "signals-icon-size-2": 0,
    "signals-blink-2": false,
    "signals-horz-2": 0,
    "signals-vert-2": 0,
    "signals-hide-edit-2": false,
    "lc-type": "last-change",
    "lc-is-interval": true,
    "lc-is-moment": false,
    "lc-format": "",
    "lc-position-vert": "top",
    "lc-position-horz": "right",
    "lc-offset-vert": 0,
    "lc-offset-horz": 0,
    "lc-font-size": "12px",
    "lc-font-family": "",
    "lc-font-style": "",
    "lc-bkg-color": "",
    "lc-color": "",
    "lc-border-width": "0",
    "lc-border-style": "",
    "lc-border-color": "",
    "lc-border-radius": 10,
    "lc-zindex": 0
    },
    "style": {
    "left": "16px",
    "top": "512px"
    },
    "widgetSet": "basic"
    },
    "e00002": {
    "tpl": "tplSvgClock",
    "data": {
    "g_fixed": false,
    "g_visibility": false,
    "g_css_font_text": false,
    "g_css_background": true,
    "g_css_shadow_padding": false,
    "g_css_border": false,
    "g_gestures": false,
    "g_signals": false,
    "g_last_change": false,
    "visibility-cond": "==",
    "visibility-val": 1,
    "visibility-groups-action": "hide",
    "signals-cond-0": "==",
    "signals-val-0": true,
    "signals-icon-0": "/vis/signals/lowbattery.png",
    "signals-icon-size-0": 0,
    "signals-blink-0": false,
    "signals-horz-0": 0,
    "signals-vert-0": 0,
    "signals-hide-edit-0": false,
    "signals-cond-1": "==",
    "signals-val-1": true,
    "signals-icon-1": "/vis/signals/lowbattery.png",
    "signals-icon-size-1": 0,
    "signals-blink-1": false,
    "signals-horz-1": 0,
    "signals-vert-1": 0,
    "signals-hide-edit-1": false,
    "signals-cond-2": "==",
    "signals-val-2": true,
    "signals-icon-2": "/vis/signals/lowbattery.png",
    "signals-icon-size-2": 0,
    "signals-blink-2": false,
    "signals-horz-2": 0,
    "signals-vert-2": 0,
    "signals-hide-edit-2": false,
    "lc-type": "last-change",
    "lc-is-interval": true,
    "lc-is-moment": false,
    "lc-format": "",
    "lc-position-vert": "top",
    "lc-position-horz": "right",
    "lc-offset-vert": 0,
    "lc-offset-horz": 0,
    "lc-font-size": "12px",
    "lc-font-family": "",
    "lc-font-style": "",
    "lc-bkg-color": "",
    "lc-color": "",
    "lc-border-width": "0",
    "lc-border-style": "",
    "lc-border-color": "",
    "lc-border-radius": 10,
    "lc-zindex": 0,
    "quadSize": "80",
    "textSize": "0",
    "isSeconds": false,
    "quadTickColor": "white",
    "quadColor": "white",
    "textColor": "white",
    "tickColor": "white",
    "handsColor": "white",
    "handsColorLine": "white"
    },
    "style": {
    "left": "0px",
    "top": "0px",
    "width": "480px",
    "height": "480px",
    "background": "black",
    "z-index": "0"
    },
    "widgetSet": "timeandweather"
    },
    "e00003": {
    "tpl": "tplTwSimpleDate",
    "data": {
    "g_fixed": false,
    "g_visibility": false,
    "g_css_font_text": true,
    "g_css_background": false,
    "g_css_shadow_padding": false,
    "g_css_border": false,
    "g_gestures": false,
    "g_signals": false,
    "g_last_change": false,
    "visibility-cond": "==",
    "visibility-val": 1,
    "visibility-groups-action": "hide",
    "prependZero": "true",
    "signals-cond-0": "==",
    "signals-val-0": true,
    "signals-icon-0": "/vis/signals/lowbattery.png",
    "signals-icon-size-0": 0,
    "signals-blink-0": false,
    "signals-horz-0": 0,
    "signals-vert-0": 0,
    "signals-hide-edit-0": false,
    "signals-cond-1": "==",
    "signals-val-1": true,
    "signals-icon-1": "/vis/signals/lowbattery.png",
    "signals-icon-size-1": 0,
    "signals-blink-1": false,
    "signals-horz-1": 0,
    "signals-vert-1": 0,
    "signals-hide-edit-1": false,
    "signals-cond-2": "==",
    "signals-val-2": true,
    "signals-icon-2": "/vis/signals/lowbattery.png",
    "signals-icon-size-2": 0,
    "signals-blink-2": false,
    "signals-horz-2": 0,
    "signals-vert-2": 0,
    "signals-hide-edit-2": false,
    "lc-type": "last-change",
    "lc-is-interval": true,
    "lc-is-moment": false,
    "lc-format": "",
    "lc-position-vert": "top",
    "lc-position-horz": "right",
    "lc-offset-vert": 0,
    "lc-offset-horz": 0,
    "lc-font-size": "12px",
    "lc-font-family": "",
    "lc-font-style": "",
    "lc-bkg-color": "",
    "lc-color": "",
    "lc-border-width": "0",
    "lc-border-style": "",
    "lc-border-color": "",
    "lc-border-radius": 10,
    "lc-zindex": 0,
    "shortYear": true,
    "shortWeekDay": false,
    "showWeekDay": false,
    "monthWord": false,
    "shortMonth": false,
    "noClass": true
    },
    "style": {
    "left": "19px",
    "top": "22px",
    "color": "white",
    "font-size": "xx-large",
    "z-index": "1"
    },
    "widgetSet": "timeandweather"
    }
    },
    "name": "Tag4Zoll1",
    "filterList": []
    }


    // #############################################
    // Author: Eisbaeeer
    // Date: 20250519
    //
    // Dieses Script ermöglicht es, mit einem OpenEpaperTag und Tastern an dem Display (oder touch mit 4" Display), mehrere View´s durchzublättern. Die Tasten werden zum vor- bzw. zurückblättern
    // verwendet. Bevor das Script verwendet werden kann, müssen die Views angelegt werden. Die Views werden durchnummeriert, beginnend bei 1. Der "Basis" Name der View muss unten konfiguriert werden.
    // Die Anzahl der verwendeten Seiten werden mit "pageCount" konfiguriert.
    // Für jede View muss noch der Selektor 'waitForSelectorArray' definiert werden. Im Beispiel wartet puppettier beim View1 auf den Selector '#w00042'.
    // Die Erste View ist eine Uhr, welche jede Minute aktualisiert wird.
    //
    // In dem Script wird die Socket-Verbindung von Beowolf verwendet (https://forum.iobroker.net/topic/66380/e-ink-display-openepaperlink-displayanzeige-mit-batterie/809?_=1747419968864)
    //
    // Version: 0.4 : 20250519 Added socket
    // Version: 0.3 : 20250518 AP-4" kann in Verbindung mit iobroker.open-epaper-llink Adapter mehrere Ansichten durchblättern
    // Version 0.2 : Bugfix async pictures
    // Version: 0.1 : Convert from Blockly to js
    //
    // Benötigt:
    // - Puppeteer Adapter
    // - Chrome Headless
    //
    // #############################################
    // Hier die Anpassungen vornehmen!

    const urlOfVISView = 'http://192.168.1.200:8082/vis/index.html?OpenEpaper#Tag4Zoll'; // Eure View oder URL vom Bild + Nummer der View beginnend bei 1
    const targetWidth = 480; // Breite des Displays
    const targetHeight = 480; // Höhe des Displays
    const cutoutX = 0; // Abstand Pixel von links für Screenshot
    const cutoutY = 0; // Abstand Pixel von oben für Screenshot
    const pquality = 100; // Bildqualität
    const pageCount = 3; // Anzahl der Seiten zum Durchblättern
    const waitForSelectorArray = ["","#w00042","#w00044","#w00053"]; // Letztes Element auf das Peppeteer wartet als Array
    const inputPath = "/tmp/Tag01_480x480"; // Screenshot temporär Format: /Pfad/prefix
    const accesspointIP = '192.168.1.78'; // Accesspoint IP Adresse
    const macAddress = '0000840B822F3728'; // MAC-Adresse des Displays anpassen
    const ditherValue = 1; // Setze den Dither-Wert (Farbanpassungen: 0 = View hat gleiche Farben | 1 = View hat andere Farben als das Display
    const autostart = true; // Websocket automatisch starten? true|false

    // ENDE Anpassungen! Ab hier nichts mehr ändern!
    // #############################################

    var buttons = '0_userdata.0.open-epaper-link.Tag_Buttons.' + macAddress + '.page';
    createState(buttons,1);
    var uploadUrl = 'http://' + accesspointIP + '/imgupload';
    var wakeupR = '0_userdata.0.open-epaper-link.Tag_Buttons.' + macAddress + '.wakeupReason';
    var wakeup = '0_userdata.0.open-epaper-link.Tag_Buttons.' + macAddress + '.lastseen';

    schedule("* * * * *", function() {
    console.log("Send clock page every minute if pageVal is 1");
    var pageVal = getState(buttons).val;
    console.log("Page: " + pageVal);
    let waitForSelector = waitForSelectorArray[pageVal];
    console.log("waitForSelector: " + waitForSelector);
    var view = urlOfVISView+pageVal;
    console.log("View: " + view);
    if ( pageVal == 1 ) {
    takeScreenshots(pageVal,waitForSelector,view);
    }
    });

    on(wakeup,function() {
    var pageVal = getState(buttons).val;
    if ( getState(wakeupR).val == 5 ) {
    if (pageVal >= pageCount) {
    setState(buttons, 1 );
    pageVal = 1;
    } else {
    pageVal++;
    setState(buttons,pageVal);
    }
    let waitForSelector = waitForSelectorArray[pageVal];
    console.log("waitForSelector: " + waitForSelector);
    var view = urlOfVISView+pageVal;
    console.log("View: " + view);
    takeScreenshots(pageVal,waitForSelector,view);
    }
    if ( getState(wakeupR).val == 4 ) {
    if (pageVal <= 1 ) {
    setState(buttons,pageCount);
    pageVal = pageCount;
    } else {
    pageVal--;
    setState(buttons,pageVal);
    }
    let waitForSelector = waitForSelectorArray[pageVal];
    console.log("waitForSelector: " + waitForSelector);
    var view = urlOfVISView+pageVal;
    console.log("View: " + view);
    takeScreenshots(pageVal,waitForSelector,view);
    }
    setState(wakeupR,0);
    });

    // Requirements
    const puppeteer = require('puppeteer');
    const axios = require('axios');
    const fs = require('fs');
    const FormData = require('form-data');

    async function takeScreenshots(pageVal,waitForSelector,view) {
    console.log("*** function takeScreenshot");
    sendTo('puppeteer.0', 'screenshot', {
    url: view,
    path: inputPath+macAddress+pageVal+'.jpg',
    width: targetWidth,
    height: targetHeight,
    quality: pquality,

        waitOption: {
            waitForSelector: waitForSelector,  
            waitForTimeout: 10000              
        },
     
        fullPage: false,                       
     
        clip: {         
            x: cutoutX,                        
            y: cutoutY,                        
            width: targetWidth,                
            height: targetHeight               
        }
    }, obj => {
      if (obj.error) {
        log(`Error taking screenshot: ${obj.error.message}`, 'error');
      } else {
        // the binary representation of the image is contained in `obj.result`
        log(`Successfully took screenshot: ${obj.result}`);
        console.log("*** upload Image");
        // uploading Screenshot
        async function uploadImage() {
    	try {
    		// Prüfen, ob die Datei existiert
    		if (!fs.existsSync(inputPath+pageVal+'.jpg')) {
    		throw new Error(`Datei nicht gefunden: ${inputPath+macAddress+pageVal+'.jpg'}`);
    	}
    // FormData erstellen
    const form = new FormData();
    form.append("mac", macAddress);
    form.append("dither", ditherValue); // Dither-Parameter hinzufügen
    form.append("file", fs.createReadStream(inputPath+macAddress+pageVal+'.jpg'));
    // POST-Anfrage senden
    const response = await axios.post(uploadUrl, form, {
    headers: {
    	...form.getHeaders(),
    },
    });
    
    console.log('Upload erfolgreich:', response.data);
    } catch (error) {
    if (error.response) {
    	console.error('Server-Antwort:', error.response.status, error.response.data);
    } else if (error.request) {
    	console.error('Keine Antwort erhalten:', error.request);
    } else {
    	console.error('Fehler beim Hochladen:', error.message);
    }
    }
    }
    uploadImage();
    }
    })
    

    }

    const WebSocket = require('ws');
    const http = require('http');
    const wsUrl = ws://${accesspointIP}/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.open-epaper-link.Start'; // Datenpunkt zur Steuerung des Skripts - anhalten oder starten

    function ensureOpenEPaperLinkFolderExists(callback) {
    const OpenEPaperLinkFolderPath = '0_userdata.0.open-epaper-link.Tag_Buttons';
    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://${accesspointIP}/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.open-epaper-link.Tag_Buttons.${tag.mac.replace(/:/g, '')};
    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() {
    if (autostart == true) {
    ensureOpenEPaperLinkFolderExists(connectWebSocket);
    }
    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();

    6807aa39-be12-4cbf-85e1-666b3c46749b-20250519_202102.jpg
    64c057dd-e8d9-428f-80c0-c3d6e928ddc0-20250519_202121.jpg
    674ec975-4bd9-482d-81b0-7e96eabf10ce-20250519_202136.jpg

    https://youtube.com/shorts/G4g4ynx-t_k?feature=share

    Kein support per PM. Bitte im Forum Fragen stellen!

    1 Antwort Letzte Antwort
    1
    • B Offline
      B Offline
      Beowolf
      schrieb am zuletzt editiert von
      #2

      @eisbaeeer

      Fein, fein. Danke dafür.

      Ich habe das Skript jetzt noch nicht probiert.

      Besteht mit dem Skript auch die Möglichkeit, das ich mit den Tasten auch eine z.B. Lampe über ioBroker schalten kann?

      Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

      EisbaeeerE 1 Antwort Letzte Antwort
      0
      • B Beowolf

        @eisbaeeer

        Fein, fein. Danke dafür.

        Ich habe das Skript jetzt noch nicht probiert.

        Besteht mit dem Skript auch die Möglichkeit, das ich mit den Tasten auch eine z.B. Lampe über ioBroker schalten kann?

        EisbaeeerE Offline
        EisbaeeerE Offline
        Eisbaeeer
        Developer
        schrieb am zuletzt editiert von Eisbaeeer
        #3

        @beowolf So direkt erstmal nicht. Dazu müsstest du das Script umbauen. Vorstellbar wäre, dass du nur eine Taste zum durchblättern benutzt und die andere zum Toggeln oder schalten.
        Im Code findest du das Abfragen der Tasten hier:

        on(wakeup,function() {
        var pageVal = getState(buttons).val;
        if ( getState(wakeupR).val == 5 ) {
        if (pageVal >= pageCount) {
        setState(buttons, 1 );
        pageVal = 1;
        } else {
        pageVal++;
        setState(buttons,pageVal);
        }
        let waitForSelector = waitForSelectorArray[pageVal];
        console.log("waitForSelector: " + waitForSelector);
        var view = urlOfVISView+pageVal;
        console.log("View: " + view);
        takeScreenshots(pageVal,waitForSelector,view);
        }
        if ( getState(wakeupR).val == 4 ) {
        if (pageVal <= 1 ) {
        setState(buttons,pageCount);
        pageVal = pageCount;
        } else {
        pageVal--;
        setState(buttons,pageVal);
        }
        let waitForSelector = waitForSelectorArray[pageVal];
        console.log("waitForSelector: " + waitForSelector);
        var view = urlOfVISView+pageVal;
        console.log("View: " + view);
        takeScreenshots(pageVal,waitForSelector,view);
        }
        setState(wakeupR,0);
        });
        

        "wakeupR" : 4 ist die linke Taste, 5 die rechte Taste.

        if ( getState(wakeupR).val == 4 ) {
        

        Kein support per PM. Bitte im Forum Fragen stellen!

        1 Antwort Letzte Antwort
        0
        • B Offline
          B Offline
          Beowolf
          schrieb am zuletzt editiert von Beowolf
          #4

          Habe das Skript mal NUR für die Button geändert. Es wird kein Inhalt an die TAGs gesendet.

          //
          // #############################################
          //
          // Dieses Script ermöglicht die Buttonabfrage.
          //
          // In dem Script wird die Socket-Verbindung von Beowolf verwendet (https://forum.iobroker.net/topic/66380/e-ink-display-openepaperlink-displayanzeige-mit-batterie/809?_=1747419968864)
          //
          // Ein erweitertes Skript von Eisbaeeer ist hier (https://forum.iobroker.net/topic/81101/openepaperlink-script-für-tastenabfrage )
          //
          // Die Button-States werden unter dem konfigurierten basePathPrefix erzeugt.
          //
          // #############################################
          
          // #############################################
          //
          // Konfigurierbare Variablen - Hier die Anpassungen vornehmen!
          //
          
          const controlStatePath = '0_userdata.0.Buttons-DG-TAGs';   // Basis für controlState und basePath
          const controlState = `${controlStatePath}.Start`;          // Skript starten oder beenden
          const basePathPrefix = `${controlStatePath}.Tag_Buttons`;  // Basis-Pfad für Button-States
          const accesspointIP = '192.168.49.187';                    // Accesspoint IP Adresse
          
          //
          // ENDE Anpassungen! Ab hier nichts mehr ändern!
          // #############################################
          
          
          
          
          
          const wsUrl = `ws://${accesspointIP}/ws`;
          const WebSocket = require('ws');
          
          let ws;
          let pingInterval;
          let scriptStopping = false;
          
          function connectWebSocket() {
              if (scriptStopping) return;
              ws = new WebSocket(wsUrl);
          
              ws.on('open', () => {
                  console.log('WebSocket verbunden');
                  startHeartbeat();
              });
          
              ws.on('message', (data) => {
                  try {
                      const parsed = JSON.parse(data);
                      handleData(parsed);
                  } catch (err) {
                      // Parsing-Fehler ignorieren
                  }
              });
          
              ws.on('close', () => {
                  clearInterval(pingInterval);
                  if (!scriptStopping) setTimeout(connectWebSocket, 5000);
              });
          
              ws.on('error', () => {
                  // WebSocket-Fehler ignorieren
              });
          }
          
          function startHeartbeat() {
              pingInterval = setInterval(() => {
                  if (ws.readyState === WebSocket.OPEN) {
                      ws.ping();
                  }
              }, 10000);
          }
          
          function handleData(parsedData) {
              if (!parsedData.tags || !Array.isArray(parsedData.tags) || parsedData.tags.length === 0) {
                  return;
              }
          
              parsedData.tags.forEach(tag => {
                  if (!tag.mac) return;
          
                  const macClean = tag.mac.replace(/:/g, '');
                  const basePath = `${basePathPrefix}.${macClean}`;
          
                  ensureChannelExists(basePath, tag.alias || tag.name || 'Unbenannt', () => {
                      if ('wakeupReason' in tag) {
                          const statePath = `${basePath}.wakeupReason`;
                          updateStateIfChanged(statePath, tag.wakeupReason);
                      }
                  });
              });
          }
          
          function ensureChannelExists(id, name, callback) {
              getObject(id, (err, obj) => {
                  if (!obj) {
                      setObject(id, {
                          type: 'channel',
                          common: {
                              name: name
                          },
                          native: {}
                      }, callback);
                  } else {
                      callback();
                  }
              });
          }
          
          function updateStateIfChanged(id, value) {
              if (value === null || value === undefined) return;
          
              const isPrimitive = val => ['string', 'number', 'boolean'].includes(typeof val);
          
              let storedValue = value;
              let valueType = typeof value;
          
              if (!isPrimitive(value)) {
                  try {
                      storedValue = JSON.stringify(value);
                      valueType = 'string';
                  } catch {
                      return;
                  }
              }
          
              getState(id, (err, state) => {
                  if (err || !state) {
                      setObject(id, {
                          type: 'state',
                          common: {
                              name: id.split('.').pop(),
                              type: valueType,
                              role: 'value',
                              read: true,
                              write: false
                          },
                          native: {}
                      }, () => setState(id, storedValue, true));
                  } else if (state.val !== storedValue) {
                      setState(id, storedValue, true);
                  }
              });
          }
          
          function disconnectWebSocket() {
              if (ws) {
                  ws.close();
                  ws = null;
              }
              clearInterval(pingInterval);
          }
          
          function setupControl() {
              setObject(controlState, {
                  type: 'state',
                  common: {
                      name: 'EPaper Script Control',
                      type: 'boolean',
                      role: 'switch',
                      read: true,
                      write: true,
                      def: true
                  },
                  native: {}
              });
          
              on({ id: controlState, change: 'ne' }, (obj) => {
                  if (obj.state.val === true) {
                      scriptStopping = false;
                      connectWebSocket();
                  } else {
                      scriptStopping = true;
                      disconnectWebSocket();
                  }
              });
          
              getState(controlState, (err, state) => {
                  if (!err && state && state.val === true) {
                      connectWebSocket();
                  }
              });
          }
          
          setupControl();
          

          Hier wird jetzt nur der Datenpunkt "wakeupReason" angelegt.

          Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

          1 Antwort Letzte Antwort
          1
          • B Offline
            B Offline
            Beowolf
            schrieb am zuletzt editiert von Beowolf
            #5

            Hier ein geändertes Skript für die, die mehrere APs haben.

            //
            // #############################################
            //
            // Dieses Script ermöglicht die Buttonabfrage.
            //
            // In dem Script wird die Socket-Verbindung von Beowolf verwendet (https://forum.iobroker.net/topic/66380/e-ink-display-openepaperlink-displayanzeige-mit-batterie/809?_=1747419968864)
            //
            // Ein erweitertes Skript von Eisbaeeer ist hier (https://forum.iobroker.net/topic/81101/openepaperlink-script-für-tastenabfrage )
            //
            // Die Button-States werden unter dem konfigurierten basePathPrefix erzeugt.
            //
            // #############################################
            
            // #############################################
            //
            // Konfigurierbare Variablen - Hier die Anpassungen vornehmen!
            //
            
            
            const rootPath = '0_userdata.0'; // Bei Bedarf anpassen
            const controlRoot = 'EPaperControl'; // Oberordner für Steuerung
            const buttonRoot = 'Buttons'; // Unterordner für Buttons
            
            const accesspoints = [
                { location: 'Erdgeschoss', ip: '192.168.49.185' }, // Accesspoint IP Adresse
                { location: 'Obergeschoss', ip: '192.168.49.186' }, // Accesspoint IP Adresse
                { location: 'Dachgeschoss', ip: '192.168.49.187' }, // Accesspoint IP Adresse
                { location: 'Hühnerhaus', ip: '192.168.49.139' } // Accesspoint IP Adresse
            ];
            
            //
            // ENDE Anpassungen! Ab hier nichts mehr ändern!
            // #############################################
            //
            
            // Automatisch generierte Pfade für jeden Accesspoint
            accesspoints.forEach(ap => {
                ap.name = `${ap.location}-AP`;
                ap.controlState = `${rootPath}.${controlRoot}.${ap.location}.Start`;
                ap.buttonPathPrefix = `${rootPath}.${controlRoot}.${ap.location}.${buttonRoot}`;
            });
            
            const WebSocket = require('ws');
            
            let wsConnections = {};
            let pingIntervals = {};
            let scriptStatus = {};
            
            // Initialisierung der Steuerobjekte
            accesspoints.forEach(ap => {
                scriptStatus[ap.name] = false;
            
                setObject(ap.controlState, {
                    type: 'state',
                    common: {
                        name: `Start/Stop ${ap.name}`,
                        type: 'boolean',
                        role: 'switch',
                        read: true,
                        write: true,
                        def: false
                    },
                    native: {}
                });
            
                on({ id: ap.controlState, change: 'ne' }, (obj) => {
                    if (obj.state.val === true) {
                        scriptStatus[ap.name] = true;
                        connectWebSocket(ap.name, ap.ip);
                    } else {
                        scriptStatus[ap.name] = false;
                        disconnectWebSocket(ap.name);
                    }
                });
            
                getState(ap.controlState, (err, state) => {
                    if (!err && state && state.val === true) {
                        scriptStatus[ap.name] = true;
                        connectWebSocket(ap.name, ap.ip);
                    }
                });
            });
            
            function connectWebSocket(name, ip) {
                if (wsConnections[name]) return;
            
                const url = `ws://${ip}/ws`;
                const ws = new WebSocket(url);
                wsConnections[name] = ws;
            
                ws.on('open', () => {
                    console.log(`WebSocket ${name} verbunden (${ip})`);
                    pingIntervals[name] = setInterval(() => {
                        if (ws.readyState === WebSocket.OPEN) {
                            ws.ping();
                        }
                    }, 10000);
                });
            
                ws.on('message', (data) => {
                    try {
                        const parsed = JSON.parse(data);
                        handleData(name, parsed);
                    } catch {
                        // Parsing-Fehler ignorieren
                    }
                });
            
                ws.on('close', () => {
                    clearInterval(pingIntervals[name]);
                    delete wsConnections[name];
                    if (scriptStatus[name]) {
                        setTimeout(() => connectWebSocket(name, ip), 5000);
                    }
                });
            
                ws.on('error', () => {
                    // Fehler ignorieren
                });
            }
            
            function disconnectWebSocket(name) {
                if (wsConnections[name]) {
                    wsConnections[name].close();
                    clearInterval(pingIntervals[name]);
                    delete wsConnections[name];
                    delete pingIntervals[name];
                }
            }
            
            function handleData(apName, parsedData) {
                const ap = accesspoints.find(a => a.name === apName);
                if (!ap || !scriptStatus[ap.name]) return;
            
                if (!parsedData.tags || !Array.isArray(parsedData.tags) || parsedData.tags.length === 0) return;
            
                parsedData.tags.forEach(tag => {
                    if (!tag.mac) return;
            
                    const macClean = tag.mac.replace(/:/g, '');
                    const basePath = `${ap.buttonPathPrefix}.${macClean}`;
            
                    ensureChannelExists(basePath, tag.alias || tag.name || 'Unbenannt', () => {
                        if ('wakeupReason' in tag) {
                            const statePath = `${basePath}.wakeupReason`;
                            updateStateIfChanged(statePath, tag.wakeupReason);
                        }
                    });
                });
            }
            
            function ensureChannelExists(id, name, callback) {
                getObject(id, (err, obj) => {
                    if (!obj) {
                        setObject(id, {
                            type: 'channel',
                            common: { name: name },
                            native: {}
                        }, callback);
                    } else {
                        callback();
                    }
                });
            }
            
            function updateStateIfChanged(id, value) {
                if (value === null || value === undefined) return;
            
                const isPrimitive = val => ['string', 'number', 'boolean'].includes(typeof val);
            
                let storedValue = value;
                let valueType = typeof value;
            
                if (!isPrimitive(value)) {
                    try {
                        storedValue = JSON.stringify(value);
                        valueType = 'string';
                    } catch {
                        return;
                    }
                }
            
                getState(id, (err, state) => {
                    if (err || !state) {
                        setObject(id, {
                            type: 'state',
                            common: {
                                name: id.split('.').pop(),
                                type: valueType,
                                role: 'value',
                                read: true,
                                write: false
                            },
                            native: {}
                        }, () => setState(id, storedValue, true));
                    } else if (state.val !== storedValue) {
                        setState(id, storedValue, true);
                    }
                });
            }
            

            Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

            1 Antwort Letzte Antwort
            0
            Antworten
            • In einem neuen Thema antworten
            Anmelden zum Antworten
            • Älteste zuerst
            • Neuste zuerst
            • Meiste Stimmen


            Support us

            ioBroker
            Community Adapters
            Donate

            730

            Online

            32.6k

            Benutzer

            82.0k

            Themen

            1.3m

            Beiträge
            Community
            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
            ioBroker Community 2014-2025
            logo
            • Anmelden

            • Du hast noch kein Konto? Registrieren

            • Anmelden oder registrieren, um zu suchen
            • Erster Beitrag
              Letzter Beitrag
            0
            • Home
            • Aktuell
            • Tags
            • Ungelesen 0
            • Kategorien
            • Unreplied
            • Beliebt
            • GitHub
            • Docu
            • Hilfe