Die Einbindung des Shelly Wall Displays in den ioBroker gehört bei mir zu einem der existenziellen Dinge, die ein jedes Smart Home Device bereitstellen muss. Aufgrund der Tatsache, dass das Shelly Wall Display MQTT bereitstellt, ist die Grundvoraussetzung der Integration gegeben. 

Klassisch greife ich für die Integration auf den Adapter Shelly im ioBroker zurück. Zum Zeitpunkt der Erstellung des Beitrags war das Shelly Wall Display darin noch nicht implementiert. Aus diesem Grund habe ich mich ans Werk gemacht und den Code entsprechend angepasst. Die Herausforderung dabei bestand darin, dass es von Hersteller bisher keine Information in der Knowledge Base dazu gibt. Aus diesem Grund musste ich mir vieles selbst erarbeiten. 

Doch was lange währt, wird endlich gut und seit drei Wochen habe ich das Wall Display bei mir in den ioBroker integriert. Wie ich es hinbekommen habe und wir ihr euer Shelly Wall Display in den ioBroker bekommt, zeige ich euch in diesem Beitrag.

Verfügbare Datenpunkte

Im ersten Schritt habe ich das Wall Display direkt per MQTT in den ioBroker eingebunden und geschaut, welche Werte ich überhaupt geliefert bekomme. Dazu habe ich den MQTT Adapter verwendet, welcher bereits beim Auslesen meines Gaszähler mittels AI on the Edge verwendet habe.

Auf dem Shelly Wall Display habe ich mich auf der Weboberfläche angemeldet und bin im Menü auf Settings → MQTT navigiert. Anschließend musste ich nur noch die IP-Adresse meiner ioBroker Instanz inkl. dem Port angeben. Ebenso den Benutzernamen und das Kennwort. Bezogen auf die Checkboxen sind alle bis auf “Use MQTT version 5” aktiviert. Mit dem bestätigen über den Button “Save settings” tauchten wenige Sekunden später die ersten Werte im ioBroker auf.

Shelly Wall Display MQTT

Wie auf dem Bild zu erkennen ist, bekommen wir eine Menge an Informationen vom Shelly Wall Display geliefert. Daraus habe ich abgeleitet, dass ich den Code soweit anpassen muss, dass ich die Temperatur, Helligkeit, Luftfeuchtigkeit und den Schalter des Displays als Datenpunkte angezeigt bekomme. Obendrein natürlich auch die die ganzen Datenpunkte, wie Firmwareversion, IP-Adresse die standardmäßig vom Shelly mitgegeben werden.

Anpassung des Codes

Insgesamt habe ich drei Dateien im Shelly Adapter angepasst. Dadurch, dass mein ioBroker im Docker Container auf der Synology NAS läuft konnte ich einfach durch die File Station navigieren und im folgenden Pfad node_modules/iobroker.shelly/lib/devices/gen2/ eine neue datei mit dem Namen “shellywalldisplay” erzeugen. Hierbei habe ich einfach die Datei „shellyplus1pm“ dupliziert und umbenannt. Womit auch die passenden Inhalte bereits in der neuen Datei vorhanden sind.

Weiterhin mussten Anpassungen in der datapoints.js unter node_modules/iobroker.shelly/lib/, sowie eine ebene tiefer node_modules/iobroker.shelly/lib/devices in der gen2-helper.js vorgenommen werden. Aber beginnen wir am Anfang.

shellywalldisplay.js

In der gerade erzeugten Datei shellywalldisplay.js habe ich alle Einträge mit dem Namen „shellyplus1pm“ durch “shellywalldisplay” ersetzt. Dadurch das es bereits Shelly Geräte gibt, welche die Temperatur und Luftfeuchtigkeit anzeigen habe ich direkt die vorhanden Funktionen in der gen2-helper aufgerufen indem ich die folgenden beiden Einträge eingefügt habe:

  • shellyHelperGen2.addTemperatureSensorToGen2Device(shellywalldisplay,0)
  • shellyHelperGen2.addHumiditySensorToGen2Device(shellywalldisplay,0)

Anschließend habe ich nach der Funktion für die Helligkeit gesucht, welche ich jedoch nicht finden konnte und kurzerhand die entsprechende Anpassung in der gen2-helper vorgenommen. Hierbei bin ich beim Namensschema treu geblieben und habe diese addIlluminanceSensorToGen2Device genannt. Ebenso habe ich das Wall Display über eine separate Funktion “addWallDisplay” eingefügt. Beide Funktionen müssen in der shellywalldisplay.js aufgerufen werden. Schlussendlich sieht die shellywalldisplay.js nun wie folgt aus.

'use strict';

const shellyHelperGen2 = require('../gen2-helper');

/**
 * Shelly Wall Display / shellywalldisplay
 *
 * Aktuell keine Dokumentation vorhanden
 */
const shellywalldisplay = {

};

shellyHelperGen2.addWallDisplay(shellywalldisplay, 0, true);
shellyHelperGen2.addHumiditySensorToGen2Device(shellywalldisplay,0);
shellyHelperGen2.addTemperatureSensorToGen2Device(shellywalldisplay,0);
shellyHelperGen2.addIlluminanceSensorToGen2Device(shellywalldisplay,0);

module.exports = {
    shellywalldisplay,
};
Angebot
Shelly Wall Display Schwarz | WLAN & Bluetooth Bedienfeld mit integriertem 5-A-Schalter und Farbdisplay | Hausautomation | Leistungsüberwachung | iOS Android App | Feuchtigkeits…
  • Shelly Wall Display ist ein Ein intelligentes Bedienfeld mit integriertem 5-A-Schalter und Farbdisplay, Thermostat-Funktionalität,Integrierter Schalter: Shelly Wall Display ist ein intuitives…
  • NAVIGIEREN SIE IHR SMART HOME! -Das Shelly Wall Display ist ein hochentwickeltes 4-Zoll-Display, das intuitive Steuerung und nahtlose Überwachung in jeden Winkel Ihres intelligenten Zuhauses bringt….
  • EIN INTELLIGENTES THERMOSTAT FÜR IHR ZUHAUSE – Das Shelly Wall Display kann auch als Thermostat fungieren und bietet eine intuitive Schnittstelle zur Überwachung, Verwaltung und Feinjustierung Ihrer…
  • SHELLY KUNDENSERVICE – Shelly ist eine der am schnellsten wachsenden Smart Home Marken der Welt mit Geräten, die Lösungen für die Automatisierung von Privathäusern, Gebäuden und Unternehmen…
  • Mit der SHELLY SMART CONTROL APP können Sie Ihre Shelly-Geräte aus der Ferne steuern und werden über alle automatisierten Ereignisse in Ihrem Haus benachrichtigt. Sie können die Geräte ganz…

Letzte Aktualisierung am 2024-12-26 / Affiliate Links (*) / Eine Veränderung des ausgewiesenen Preises ist nach der letzten Aktualisierung möglich / Bilder von der Amazon Product Advertising API

datapoints.js

In der datepoints.js habe ich wie schon bei der Anpassung des Shelly Plus PM Mini die entsprechende Datenpunkte eingefügt. Da es aktuell noch keinen Knowledge Base Artikel zum Wall Display gibt, habe ich diesen nicht eingebaut. Dementsprechend habe ich vier Zeilen ergänzt. Zum besseren Verständnis habe ich euch den Code in reduzierter Form hinzugefügt, hierbei habe ich zum einfacheren Verständnis die Kommentare und den Aufbau unverändert gelassen. An den Stellen, wo Code entfernt wurde, befinden sich „…“. Wichtig, der Code darf nicht entfernt werden, da sonst die anderen Geräte nicht mehr funktionieren. Die Entfernung dient rein der Reduzierung hier im Beitrag.

'use strict';

// Defaults
const defaultsgen1 = require(__dirname + '/devices/default').defaultsgen1;
const defaultsgen2 = require(__dirname + '/devices/default').defaultsgen2;

// Gen 1
...

// Gen 2
...
const shellywalldisplay = require(__dirname + '/devices/gen2/shellywalldisplay').shellywalldisplay;

const devices = {
    // Gen 1
    ...
    // Gen 2
    ...
    'shellywalldisplay': shellywalldisplay,
};

const deviceTypes = {
    // '<deviceClass>': ['<deviceType>', '<deviceType>'],
    // Gen 1
    ...
    // Gen 2
   ...
    'shellywalldisplay': ['shellywalldisplay'],
};

const deviceGen = {
    // Gen 1
    ...
    // Gen 2
    ...
    'shellywalldisplay': 2,
};

...

gen2-helper.js

Zu Beginn habe ich in der gen2-helper Datei die funktion addWallDisplay erstellt. Darunter wird ausschließlich die Steuerung des Relays konfiguriert. Genauer gesagt das Ein- und Ausschalten sowie die Autotimer für das Ein- und Ausschalten. Dazu habe ich mich an bereits bestehenden Codezeilen bedient und diese wie im folgenden zusehen zusammen kopiert.

function addWallDisplay(deviceObj, switchId) {

    deviceObj[`Relay${switchId}.Switch`] = {
        device_mode: 'switch',
        mqtt: {
            mqtt_publish: `<mqttprefix>/status/switch:${switchId}`,
            mqtt_publish_funct: value => JSON.parse(value).output,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.Set',
                    params: {id: switchId, on: value},
                });
            },
        },
        common: {
            name: {
                en: 'Switch',
                de: 'Schalter',
                ru: 'Переключить',
                pt: 'Interruptor',
                nl: 'Vertaling:',
                fr: 'Interrupteur',
                it: 'Interruttore',
                es: 'Interruptor',
                pl: 'Switch',
                'zh-cn': '目 录',
            },
            type: 'boolean',
            role: 'switch',
            read: true,
            write: true,
            def: false,
        },
    };
    deviceObj[`Relay${switchId}.InitialState`] = {
        device_mode: 'switch',
        mqtt: {
            http_publish: `/rpc/Switch.GetConfig?id=${switchId}`,
            http_publish_funct: value => value ? JSON.parse(value).initial_state : undefined,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.SetConfig',
                    params: {id: switchId, config: {initial_state: value}},
                });
            },
        },
        common: {
            name: {
                en: 'Initial state',
                de: 'Ausgangszustand',
                ru: 'Начальное состояние',
                pt: 'Estado inicial',
                nl: 'Initiële staat',
                fr: 'État initial',
                it: 'Stato iniziale',
                es: 'Estado inicial',
                pl: 'Państwo inicjalne',
                'zh-cn': '初次报告',
            },
            type: 'string',
            role: 'state',
            read: true,
            write: true,
            states: {
                'on': 'on',
                'off': 'off',
                'restore_last': 'restore_last',
                'match_input': 'match_input',
            },
        },
    };
deviceObj[`Relay${switchId}.AutoTimerOn`] = {
        device_mode: 'switch',
        mqtt: {
            http_publish: `/rpc/Switch.GetConfig?id=${switchId}`,
            http_publish_funct: value => value ? JSON.parse(value).auto_on : undefined,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.SetConfig',
                    params: {id: switchId, config: {auto_on: value}},
                });
            },
        },
        common: {
            name: 'Auto Timer On',
            type: 'boolean',
            role: 'switch.enable',
            def: false,
            read: true,
            write: true,
        },
    };

    deviceObj[`Relay${switchId}.AutoTimerOnDelay`] = {
        device_mode: 'switch',
        mqtt: {
            http_publish: `/rpc/Switch.GetConfig?id=${switchId}`,
            http_publish_funct: value => value ? JSON.parse(value).auto_on_delay : undefined,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.SetConfig',
                    params: {id: switchId, config: {auto_on_delay: value}},
                });
            },
        },
        common: {
            name: 'Auto Timer On Delay',
            type: 'number',
            role: 'level.timer',
            def: 0,
            unit: 's',
            read: true,
            write: true,
        },
    };

    deviceObj[`Relay${switchId}.AutoTimerOff`] = {
        device_mode: 'switch',
        mqtt: {
            http_publish: `/rpc/Switch.GetConfig?id=${switchId}`,
            http_publish_funct: value => value ? JSON.parse(value).auto_off : undefined,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.SetConfig',
                    params: {id: switchId, config: {auto_off: value}},
                });
            },
        },
        common: {
            name: 'Auto Timer Off',
            type: 'boolean',
            role: 'switch.enable',
            def: false,
            read: true,
            write: true,
        },
    };

    deviceObj[`Relay${switchId}.AutoTimerOffDelay`] = {
        device_mode: 'switch',
        mqtt: {
            http_publish: `/rpc/Switch.GetConfig?id=${switchId}`,
            http_publish_funct: value => value ? JSON.parse(value).auto_off_delay : undefined,
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Switch.SetConfig',
                    params: {id: switchId, config: {auto_off_delay: value}},
                });
            },
        },
        common: {
            name: 'Auto Timer Off Delay',
            type: 'number',
            role: 'level.timer',
            def: 0,
            unit: 's',
            read: true,
            write: true,
        },
    };
}

Wie vorher schon angekündigt, musste ich Anpassungen vornehmen, um die Werte des Helligkeitssensors in den ioBroker zu bekommen. Dafür habe ich einfach von der Funktion  “addTemperatureSensorToGen2Device” den Code übernommen und wie im folgenden aufgeführt angepasst. Die Funktion habe ich abschließend addIlluminanceSensorToGen2Device genannt.

/**
 * Adds a generic Illuminance sensor definition for gen 2 devices
 * @param {object} deviceObj
 * @param {number} sensorId
 */
function addIlluminanceSensorToGen2Device(deviceObj, sensorId) {

    deviceObj[`Illuminance${sensorId}.ChannelName`] = {
        mqtt: {
            http_publish: `/rpc/Illuminance.GetConfig?id=${sensorId}`,
            http_publish_funct: async (value, self) => {
                return value ? await shellyHelper.setChannelName(self, `Illuminance${sensorId}`, JSON.parse(value).name) : undefined;
            },
            mqtt_cmd: '<mqttprefix>/rpc',
            mqtt_cmd_funct: (value, self) => {
                return JSON.stringify({
                    id: self.getNextMsgId(),
                    src: 'iobroker',
                    method: 'Illuminance.SetConfig',
                    params: {id: sensorId, config: {name: value}},
                });
            },
        },
        common: {
            name: {
                en: 'Channel name',
                de: 'Kanalname',
                ru: 'Имя канала',
                pt: 'Nome do canal',
                nl: 'Kanaalnaam',
                fr: 'Nom du canal',
                it: 'Nome del canale',
                es: 'Nombre del canal',
                pl: 'Channel imię',
                'zh-cn': '姓名',
            },
            type: 'string',
            role: 'text',
            read: true,
            write: true,
        },
    };

    deviceObj[`Illuminance${sensorId}.Lux`] = {
        mqtt: {
            mqtt_publish: `<mqttprefix>/status/illuminance:${sensorId}`,
            mqtt_publish_funct: value => JSON.parse(value).lux,
        },
        common: {
            name: {
                en: 'Illuminance',
                de: 'Helligkeit',
       		ru: 'Освещенность',
                pt: 'Iluminancia',
                nl: 'Verlichtingssterkte',
                fr: 'lumineuse',
                it: 'Illuminazione',
                es: 'Iluminancia',
                pl: 'Podświetlenie',
                'zh-cn': '照度',
            },
            type: 'number',
            role: 'value.illuminance',
            read: true,
            write: false,
            unit: 'lx',
        },
    };
}

Zum Schluss habe ich am Ende der Datei noch „addWallDisplay,“ und „addIlluminanceSensorToGen2Device,“ ergänzt. Damit sind alle Anpassungen vorgenommen und die Dateien können wieder in die entsprechenden Ordner des IoBrokers auf der NAS übertragen werden.

module.exports = {
    addSwitchToGen2Device,
    addInputToGen2Device,
    addCoverToGen2Device,
    addDevicePowerToGen2Device,
    addTemperatureSensorToGen2Device,
    addHumiditySensorToGen2Device,
    addEnergyMeterToGen2Device,
    addEnergyMeterDataToGen2Device,
    addPM1ToGen2Device,
    addPlusAddon,
    addWallDisplay,
    addIlluminanceSensorToGen2Device,

Die Herausforderung

Nachdem ich alle Anpassungen vorgenommen und die Dateien im entsprechenden Pfad eingesetzt habe, musste der Shelly Adapter neu gestartet werden. Wenn ihr das Wall Display noch nicht über die Weboberfläche mit den MQTT Daten konfiguriert habt, müsst ihr dies, wie im Beitrag beschrieben, konfigurieren. Nach dem Neustart des Shelly Wall Display wurde dieses direkt erkannt und die Datenpunkte sind wie durch Zauberhand gefüllt worden.

Komischerweise wird das Display beim ersten Mal problemlos erkannt, jedoch noch kurzer Zeit treten Probleme mit der http Authentifizierung auf. Die Meldung kennt bestimmt jeder von euch. An dieser Stelle habe ich versucht, das Problem irgendwie zu lösen, jedoch reichen meine Programmierkenntnisse hier nicht mehr aus. 

Shelly Wall Display http Fehler

Die Übergangslösung ist an dieser Stelle ist die Deaktivierung des http Passworts in der Weboberfläche des Shelly Wall Displays. Dadurch bekommt ihr zwar etliche Einträge im Log bezüglich des nicht gesetzten Passworts, jedoch ist das Wall Display damit problemlos im ioBroker zu verwenden. Die ganze Konfiguration könnt ihr wie gewohnt auf meinem Youtube Kanal im folgenden Video entnehmen oder die Dateien direkt auf Github herunterladen.

Sie sehen gerade einen Platzhalterinhalt von YouTube. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.

Mehr Informationen

Fazit

Nach fast drei Wochen im Einsatz läuft die Integration des Shelly Wall Displays zuverlässig in meiner ioBroker Instanz. Natürlich bin ich schon etwas Stolz, dass ich mit meinem Wissen die Integration hinbekommen haben, wobei mich die Problematik mit dem http Passwort ziemlich nervt. Nach jedem Firmware Update teste ich erneut, ob die http Authentifizierung funktioniert, jedoch sieht es aktuell nicht danach aus. Möglicherweise findet ein pfiffiger Entwickler *hust* Matthias *hust* :), aufbauend auf den von mir angepassten Codezeilen eine gute Lösung.

In der Zwischenzeit habe ich meine Änderungen auch in GitHub als Pull Request gestellt und hoffe, dass die Anpassungen in den Shelly Adapter aufgenommen werden. Möglicherweise könnt ihr künftig alles direkt über den Adapter bekommen.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein