Nachdem wir uns näher mit ESPHome und den Möglichkeiten mit ESP32 und ESP8266 Modulen beschäftigt haben, sind wir der Idee eines E-Paper Displays im Ikea-Rahmen für die Darstellung von Wetter und ioBroker Smarthome Status-Details gefolgt. Die Anzeige auf Basis eines OLED-Displays war wie beschrieben schnell umgesetzt, uns störte die kontinuierliche Stromversorgung, auch wenn das Display durch einen Bewegungsmelder ausgeschaltet wurde und der Strombedarf eines ESP32 eher gering ausfällt.

Die Idee: Mit einem E-Paper-Display die relevanten Informationen nur 1x oder 2x pro Stunde aktualisieren und den ESP32 zwischendurch schlafen legen. Das E-Paper-Display hält die Anzeige bis zum nächsten Update aktiv. Die Daten sollen wir schon im OLED-Beispiel beschrieben über MQTT über ioBroker abgerufen werden.

Das Projekt hat eine gewisse Komplexität und der fertige Zustand von Display und ESPHome-YAML hat einige Stunden testen und ausprobieren benötigt. Insbesondere die Platzierung der einzelnen Elemente auf dem Display über die x- und y-Koordinaten mit den Update-notwendigen Kompilierungen verschlingt Zeit.

Was benötigen wir für das Dashboard im Bilderrahmen und was müssen wir für die Umsetzung beachten:

Hardware:

  • Waveshare E-Paper-Driver Board ESP32
    • Wir benötigen auf jeden Fall die CPU-Power und den Speicher eines ESP32, der kleinere Bruder mit ESP8266 reicht für die meisten Anwendungsfälle nicht aus. Der Vorteil am Driver Board von Waveshare: Bei Nutzung eines Waveshare Displays kann dieses direkt auf dem Board mit dem flachen Kabel ohne weitere PinOuts angeschlossen werden.
  • Waveshare E-Paper Display 7.5inch V2
    • Dieses Display passt perfekt in 13cmx18cm Rahmen, um einigermaßen optisch ansprechend aufgestellt oder aufgehängt zu werden.
  • 13cm x 18cm Bilderrahmen

Mit allen Bestandteilen und Zubehör belaufen sich die Kosten auf ca. 100€.

ESPHome, YAML:

  • Wetterdaten
    • Wir müssen die Wetterdaten für unseren Standort über einen ioBroker-Adapter beziehen. Praktisch wäre die Vorschau über die nächsten Stunden des aktuellen Tages und auch die nächsten Tage.
    • Die Vorschau soll nicht nur durch Text sondern auch durch Grafiken dargestellt werden können.
    • Wir sind letztendlich bei Accuweather fündig geworden
    • Problem: Accuweather bildet über knapp 40 Icons die grafische Wettervorhersage ab, wir benötigen eine smarte und ressourcenschonende Lösung für die Einbindung der Wetter-Grafiken.
  • Vorhersage-Grafiken
    • Nach einige Tests ist unserer Meinung nach der schnellste und ressourcenschonendste Weg die vorhandenen Accuweather-SVG-Grafiken in einen Webfont zu konvertieren und diesen in ESPHome einzubinden.
  • Betrieb mit Akku/Batterie nur mit deepsleep des ESP32
    • deepsleep zu aktivieren ist in ESPHime eine Kleinigkeit, die Logik den deepsleep zu unterbrechen, um Updates auf den ESP32 zu spielen, benötigt etwas mehr Auseinandersetzung mit dem Thema, um die Steuerung über MQTT abzubilden
  • Auswahl der Batterie oder des Akkus
    • Ein ESP32 wird typischerweise mit 3,3 Volt betrieben. LiPos liegen im Bereich von 3,7 bis 4,2 Volt, 3x AA-Batterien bei 4,5 Volt, 3x AA NiMh-Akkus bei 3,6 Volt. Spannung über 3,3 Volt muss im ESP32 auf 3,3 Volt kontinuierlich reduziert werden und bedeutet Akku-Kapazität-Ineffizienz. Nach einigen Test fällt unsere Empfehlung auf 3,2 Volt LiFePo4-Akkus.
  • Berechnung und Bereitstellung der benötigten Informationen über Blockly-Script in ioBroker

Unser YAML für ESPHome bildet folgende logische Blöcke ab:

  1. Grundkonfiguration für WLAN, MQTT und Display
  2. MQTT-Topics
  3. Automatische Aktualisierung des E-Paper-Display bei Start
  4. Deepsleep-Logik inkl. Unterbrechung durch MQTT-Topic
  5. Batterie-Spannung Messen
  6. Definition der Schriftarten
  7. Mapping der Wettergrafiken-ID zu den Symbolen der Schriftart
  8. Platzierung der Dashboard Elemente und Variablen

Fangen wir mit 1. Grundkonfiguration an. Dies können wir wie bereits hier beschrieben 1:1 übernehmen.

Für die benötigten MQTT-Topics macht man sich am besten einen Plan, was alles auf dem Dashboard angezeigt werden soll. Dort können wir Platzierung und Bezeichnung der benötigten Variablen/Topics definieren. Unser erster Entwurf:

Skizze für Dashboard in ESPHome

Skizze für Dashboard in ESPHome

Das praktische an den MQTT-Topics in ESPHome ist die Tatsache, dass beim ersten Abonnement die Topics in den ioBroker-Objekten automatisch angelegt werden (um dann über ein Blockly-Script mit den entsprechenden Daten zu füllen). Hier ein Ausschnitt unserer abonnierten MQTT-Topics:

# MQTT Topics abonnieren
text_sensor:
  - platform: mqtt_subscribe
    id: h_g
    topic: esphome/RahmenDashboard/h_g
  - platform: mqtt_subscribe
    id: h_t
    topic: esphome/RahmenDashboard/h_t
  - platform: mqtt_subscribe
    id: h_l
    topic: esphome/RahmenDashboard/h_l
  - platform: mqtt_subscribe
    id: h_txt
    topic: esphome/RahmenDashboard/h_txt    
  - platform: mqtt_subscribe
    id: h_12_g
    topic: esphome/RahmenDashboard/h_12_g
  - platform: mqtt_subscribe
    id: h_12_t
    topic: esphome/RahmenDashboard/h_12_t
  - platform: mqtt_subscribe
    id: h_12_r
    topic: esphome/RahmenDashboard/h_12_r
  - platform: mqtt_subscribe
    id: h_12_w
    topic: esphome/RahmenDashboard/h_12_w

Auf Grund des deepsleep-Verhaltens und der Tatsache, dass der ESP32 möglichst batterieschonend schnell wieder in den Tiefschlaf versetzt werden soll, haben wir die Aktualisierung des Displays über ein Timeout geregelt. Nach dem Aufwachen des ESP32 muss dieser sich zunächst mit dem WLAN verbinden, den connect zum MQTT-Server herstellen und die Topics abrufen, danach erst kann das Display mit den aktualisierten Werten refreshed werden. Unsere Config sieht haben wir wie folgt definiert:

esphome:
  name: rahmendashboard
  friendly_name: RahmenDashboard
  on_boot:
      - delay: 20s
      - component.update: RDis
      - logger.log: "Update Screen"

20 Sekunden nach dem erfolgreichen Bootvorgang wird das Display aktualisiert, 30 Sekunden nach dem Bootvorgang der ESP32 für 30min in den Tiefschlaf versetzt:

# Deepsleep Konfiguration
deep_sleep:
  id: deep_sleep_rahmen
  run_duration: 25s
  sleep_duration: 30min

Wird der ESP32 mit Strom versorgt, geht das Device also unweigerlich nach 30 Sekunden in den Tiefschlaf und ist z.B. für ein OTA-Update der YAML-Konfiguration nicht erreichbar.

Um eine aktive Deepsleep-Konfiguration zu unterbrechen, gibt es glücklicherweise in ESPHome den Befehl deep_sleep.prevent. Die Idee: Wir setzen ein MQTT-Topic auf einen bestimmten Wert, fragen den Wert bei Start des ESP32 ab und stoppen den deepsleep. Exakt derselbe Weg soll genutzt werden, um nach einem erfolgreichen OTA-Update den deepsleep wieder zu aktiveren.

In unserem Fall lösen wir dies über ein Topic OTA. Ist das Topic leer, dann bootet und schläft das Device wie definiert, enthält das Topic „OTA“ wird der deepsleep unterbrochen und das Device bleibt online. Um das Device wieder schlafen zu legen, setzen wir das Topic OTA auf SLEEP. Unmittelbar nach Übertragung des MQTT-Topics, fällt das Device in den Tiefschlaf, um den nächsten Bootvorgang nicht frühzeitig mit dem nächsten Tiefschlaf vorzeitig zu beenden, müssen wir das Topic OTA wieder leeren. Der entsprechende Code im MQTT-Bereich:

# MQTT Konfiguration
mqtt:
  broker: ##IP-Adresse MQTT Server##
  username: !secret mqtt_user
  password: !secret mqtt_password
  client_id: RahmenDashboard
  topic_prefix: esphome
  on_message:
# OTA Steuerung
    - topic: esphome/RahmenDashboard/ota
      payload: 'OTA'
      then:
        - deep_sleep.prevent: deep_sleep_rahmen
        - logger.log: deepsleep off
    - topic: esphome/RahmenDashboard/ota
      payload: 'SLEEP'
      then:
        - deep_sleep.enter: deep_sleep_rahmen
        - logger.log: deepsleep on

Schön wäre es außerdem, wenn wir die Spannung der Batterie bzw. des Akkus monitoren könnten. Hierzu dient die Komponente ADC in ESPHome. Wir müssen lediglich die +-Leitung des Akkus mit einem geeigneten GPIO des ESP32 verbinden, z.B. GPIO33. Die ermittelte Spannung wird per MQTT an ioBroker übertragen und wir können den Wert dort auswerten. Z.B. um ein low-battery-Alert mit Pushover abzusetzen. Unsere YAML-Config:

sensor:
  # Spannung der Batterie an GPIO33 messen
  - platform: adc
    pin: GPIO33
    id: SpannungBatterie
    attenuation: auto
    update_interval: 20s
    accuracy_decimals: 2
    on_value:
      - mqtt.publish:
          topic: esphome/RahmenDashboard/Batterie
          payload: !lambda |-
            return to_string(id(SpannungBatterie).state);
LiPoFe4 für Waveshare driver board

LiPoFe4 für Waveshare driver board

Etwas umständlich ist die Definition der benötigten Schriftarten. Entgegen der üblichen Erfahrung in WORD und ähnlichen Programmen, können wir nicht am eigentlichen Text selbst die Formatierung vornehmen. Dies wird übergreifend in einer FONT-Definition geregelt. Ressourcenschonend können außerdem nur die Zeichen angegeben und in die Firmware kompiliert werden, die wir benötigen. Dies wird insbesondere für Schriftarten mit Grafiken interessant:

# Schriftarten definieren
font:
  - file: "Fonts/Verdana.ttf"
    id: Verdana25
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 25
  - file: "Fonts/Verdana.ttf"
    id: Verdana21
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 21
  - file: "Fonts/Verdana.ttf"
    id: Verdana35
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 32
  - file: "Fonts/Verdana.ttf"
    id: Verdana18
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 20


  - file: "Fonts/Verdana.ttf"
    id: Verdana12
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 12


  - file: "Fonts/Verdana.ttf"
    id: Verdana60
    glyphs:
      [';', '&', '@', '!', ',', '.', '?', '"', '%', '(', ')', '+', '-', '_', ':', '°', '0',
       '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
       'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
       'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
       'u', 'v', 'w', 'x', 'y', 'z','å', 'Ä', 'ä', 'Ö', 'ö', 'Ü', 'ü', '/','ß']    
    size: 40
# liste https://developer.accuweather.com/weather-icons
  - file: "Fonts/accuweathericons.ttf"
    id: Icon75
    size: 170
    glyphs:
    - "\ue900"
    - "\ue901"
    - "\ue90a"
    - "\ue911"
    - "\ue91a"
    - "\ue922"
    - "\ue927"
    - "\ue928"
    - "\ue929"
    - "\ue92a"
    - "\ue921"
    - "\ue92e"
    - "\ue936"
    - "\ue940"
    - "\ue942"
    - "\ue948"
    - "\ue950"
    - "\ue956"
    - "\ue958"
    - "\ue95e"
    - "\ue966"
    - "\ue96a"
    - "\ue972"
    - "\ue973"
    - "\ue977"
    - "\ue97d"
    - "\ue981"
    - "\ue983"
    - "\ue985"
    - "\ue986"
    - "\ue987"
    - "\ue98a"
    - "\ue98d"
    - "\ue990"
    - "\ue994"
    - "\ue996"
    - "\ue99c"
    - "\ue9a1"
    - "\ue9a5"
    - "\ue9a8"
    - "\ue9ab"


  - file: "Fonts/accuweathericons.ttf"
    id: Icon60
    size: 60
    glyphs:
    - "\ue900"
    - "\ue901"
    - "\ue90a"
    - "\ue911"
    - "\ue91a"
    - "\ue922"
    - "\ue927"
    - "\ue928"
    - "\ue929"
    - "\ue92a"
    - "\ue921"
    - "\ue92e"
    - "\ue936"
    - "\ue940"
    - "\ue942"
    - "\ue948"
    - "\ue950"
    - "\ue956"
    - "\ue958"
    - "\ue95e"
    - "\ue966"
    - "\ue96a"
    - "\ue972"
    - "\ue973"
    - "\ue977"
    - "\ue97d"
    - "\ue981"
    - "\ue983"
    - "\ue985"
    - "\ue986"
    - "\ue987"
    - "\ue98a"
    - "\ue98d"
    - "\ue990"
    - "\ue994"
    - "\ue996"
    - "\ue99c"
    - "\ue9a1"
    - "\ue9a5"
    - "\ue9a8"
    - "\ue9ab"




  - file: "Fonts/accuweathericons.ttf"
    id: Icon40
    size: 50
    glyphs:
    - "\ue900"
    - "\ue901"
    - "\ue90a"
    - "\ue911"
    - "\ue91a"
    - "\ue922"
    - "\ue927"
    - "\ue928"
    - "\ue929"
    - "\ue92a"
    - "\ue921"
    - "\ue92e"
    - "\ue936"
    - "\ue940"
    - "\ue942"
    - "\ue948"
    - "\ue950"
    - "\ue956"
    - "\ue958"
    - "\ue95e"
    - "\ue966"
    - "\ue96a"
    - "\ue972"
    - "\ue973"
    - "\ue977"
    - "\ue97d"
    - "\ue981"
    - "\ue983"
    - "\ue985"
    - "\ue986"
    - "\ue987"
    - "\ue98a"
    - "\ue98d"
    - "\ue990"
    - "\ue994"
    - "\ue996"
    - "\ue99c"
    - "\ue9a1"
    - "\ue9a5"
    - "\ue9a8"
    - "\ue9ab"


  - file: "Fonts/accuweathericons.ttf"
    id: Icon25
    size: 45
    glyphs:
    - "\ue900"
    - "\ue901"
    - "\ue90a"
    - "\ue911"
    - "\ue91a"
    - "\ue922"
    - "\ue927"
    - "\ue928"
    - "\ue929"
    - "\ue92a"
    - "\ue921"
    - "\ue92e"
    - "\ue936"
    - "\ue940"
    - "\ue942"
    - "\ue948"
    - "\ue950"
    - "\ue956"
    - "\ue958"
    - "\ue95e"
    - "\ue966"
    - "\ue96a"
    - "\ue972"
    - "\ue973"
    - "\ue977"
    - "\ue97d"
    - "\ue981"
    - "\ue983"
    - "\ue985"
    - "\ue986"
    - "\ue987"
    - "\ue98a"
    - "\ue98d"
    - "\ue990"
    - "\ue994"
    - "\ue996"
    - "\ue99c"
    - "\ue9a1"
    - "\ue9a5"
    - "\ue9a8"
    - "\ue9ab"


  - file: "Fonts/materialdesignicons.ttf"
    id: Icons_gross100
    size: 100
    glyphs:
    - "\U000F1A74" # Solar
    - "\U000F1904" # Haus
    - "\U000F1AAF" # Heizung
    - "\U000F058F" # WasserhahnF050F
    - "\U000F050F" # Thermometer    
    - "\U000F054B" # Regenschirm


  - file: "Fonts/materialdesignicons.ttf"
    id: Icons_gross
    size: 25
    glyphs:
    - "\U000F1A74" # Solar
    - "\U000F1904" # Haus
    - "\U000F1AAF" # Heizung
    - "\U000F058F" # WasserhahnF050F
    - "\U000F050F" # Thermometer    
    - "\U000F054B" # Regenschirm


  - file: "Fonts/materialdesignicons.ttf"
    id: Icons_mittel
    size: 23
    glyphs:
    - "\U000F1A74" # Solar
    - "\U000F1904" # Haus
    - "\U000F1AAF" # Heizung
    - "\U000F058F" # Wasserhahn
    - "\U000F050F" # Thermometer    
    - "\U000F054B" # Regenschirm
    - "\U000F15FA" # Wind


  - file: "Fonts/materialdesignicons.ttf"
    id: Icons_klein
    size: 22
    glyphs:
    - "\U000F1A74" # Solar
    - "\U000F1904" # Haus
    - "\U000F1AAF" # Heizung
    - "\U000F058F" # Wasserhahn
    - "\U000F050F" # Thermometer    
    - "\U000F054B" # Regenschirm
    - "\U000F15FA" # Wind
    - "\U000F1A45" # Heizung
    - "\U000F0EB8" # Gas

Ein spannender Bestandteil ist das Mapping der Wettergrafiken. In den ioBroker-Daten werden Grafiken mit einem numerischen Index bereitgestellt, die wir dann auf unsere Symbole in der Schriftart mappen müssen. Dies erfolgt in der Display-Definition:

display:
  - platform: waveshare_epaper
    cs_pin: GPIO15 #D2
    dc_pin: GPIO27 #D3
    busy_pin: GPIO25 #D4
    reset_pin: GPIO26 #D5
    model: 7.50inV2
    reset_duration: 2ms    
    update_interval: never
    rotation: 180
    id: RDis
    lambda: |-
      std::map<std::string, std::string> awi_map
        {
          {"1", "\ue900"},
          {"2", "\ue901"},
          {"3", "\ue90a"},
          {"4", "\ue911"},
          {"5", "\ue91a"},
          {"6", "\ue922"},
          {"7", "\ue927"},
          {"8", "\ue928"},
          {"11", "\ue929"},
          {"12", "\ue92a"},
          {"13", "\ue92e"},
          {"14", "\ue936"},
          {"15", "\ue940"},
          {"16", "\ue942"},
          {"17", "\ue948"},
          {"18", "\ue950"},
          {"19", "\ue956"},
          {"20", "\ue958"},
          {"21", "\ue95e"},
          {"22", "\ue966"},
          {"23", "\ue96a"},
          {"24", "\ue972"},
          {"25", "\ue973"},
          {"26", "\ue977"},
          {"29", "\ue97d"},
          {"30", "\ue981"},
          {"31", "\ue983"},          
          {"32", "\ue985"},
          {"33", "\ue986"},
          {"34", "\ue987"},
          {"35", "\ue98a"},
          {"36", "\ue98d"},
          {"37", "\ue990"},
          {"38", "\ue994"},
          {"39", "\ue996"},
          {"40", "\ue99c"},
          {"41", "\ue9a1"},
          {"42", "\ue9a5"},
          {"43", "\ue9a8"},
          {"44", "\ue9ab"}
        };

Hier werden alle numerischen Werte auf die Symbole der Schriftart gemapped. Aber welche Schriftart sollen wir nehmen? Ein Klassiker ist MaterialDesign-Webfont – der Font bietet aber bei weitem nicht so viele Wettersymbole, wie uns Accuweather dies in den numerischen Werten liefert, siehe in dieser Übersicht.

Accuweather Übersicht der Wetter-Icons

Accuweather Übersicht der Wetter-Icons

In den Objekten ist auch eine Verlinkung von SVG-Grafiken enthalten. Wir haben einen effizienten Weg für die Einbindung gefunden: Wir konvertieren auf https://icomoon.io/app/ alle SCG-Grafiken zu einem Font, binden diesen in ESPHome ein und mappen die numerischen Values auf die entsprechenden Symbole.

Accuweather SCGs Farbtheme auf eine Farbe reduzieren

Accuweather SCGs Farbtheme auf eine Farbe reduzieren

Auswahl der farbigen Accuweather Icons für Icomoon

Auswahl der farbigen Accuweather Icons für Icomoon

Codes für accuweather-Symbole in Webfont

Codes für accuweather-Symbole in Webfont

Wir downloaden den Font und definieren in den FONT-Deklarationen alle benötigten Symbole:

- file: "Fonts/accuweathericons.ttf"
  id: Icon25
  size: 45
  glyphs:
  - "\ue900"
  - "\ue901"
  - "\ue90a"
  - "\ue911"
  - "\ue91a"
  - "\ue922"
  - "\ue927"
  - "\ue928"
  - "\ue929"
  - "\ue92a"
  - "\ue921"
  - "\ue92e"
  - "\ue936"
  - "\ue940"
  - "\ue942"
  - "\ue948"
  - "\ue950"
  - "\ue956"
  - "\ue958"
  - "\ue95e"
  - "\ue966"
  - "\ue96a"
  - "\ue972"
  - "\ue973"
  - "\ue977"
  - "\ue97d"
  - "\ue981"
  - "\ue983"
  - "\ue985"
  - "\ue986"
  - "\ue987"
  - "\ue98a"
  - "\ue98d"
  - "\ue990"
  - "\ue994"
  - "\ue996"
  - "\ue99c"
  - "\ue9a1"
  - "\ue9a5"
  - "\ue9a8"
  - "\ue9ab"

Haben wir diese Vorarbeiten erledigt, kommen wir zum grafischen Teil der Umsetzung.

Der zeitlich aufwendigste Teil ist tatsächlich das Setzen der einzelnen grafischen Bestandteile auf dem Display. Jedes einzelne Element muss über die x- und y-Koordinaten auf dem Display platziert werden, im Fall des Waveshare E-Paper Display 7.5inch V2 stehen uns 800×480 Pixel zur Verfügung. Ein Auszug aus unserer YAML:

it.filled_rectangle(0, 326, 800, 55, COLOR_ON);
     it.strftime(0, 0, id(Verdana18), TextAlign::TOP_LEFT, "%H:%M", id(sntp_time).now());
     it.printf(25, 170, id(Icon75), TextAlign::BOTTOM_LEFT, "%s", awi_map[id(h_g).state.c_str()].c_str());
     it.printf(280, 30, id(Verdana60), TextAlign::TOP_CENTER, "%s", id(h_t).state.c_str());
     it.printf(280, 80, id(Verdana35), TextAlign::TOP_CENTER, "%s", id(h_l).state.c_str());
     it.printf(200, 160, id(Verdana18), TextAlign::TOP_CENTER, "%s", id(h_txt).state.c_str());

     it.line(400, 5, 400, 190, grey);
     it.line(5, 190, 795, 190, grey);

     it.printf(456, 23, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1A74");
     it.printf(456, 46, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1904");
     it.printf(456, 69, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F058F");  
     it.printf(456, 92, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1AAF");
     it.printf(430, 115, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1AAF");
     it.printf(430, 138, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1AAF");
     it.printf(430, 161, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1AAF");  
     it.printf(456, 115, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F058F");
     it.printf(456, 138, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F1A74");  
     it.printf(456, 161, id(Icons_klein), TextAlign::TOP_RIGHT, "\U000F0EB8");  

     it.filled_rectangle(400, 2, 400, 23, COLOR_ON);  

     it.printf(505, 0, id(Verdana18), COLOR_OFF, TextAlign::TOP_CENTER, "Heute");
     it.printf(505, 23, id(Verdana18), TextAlign::TOP_CENTER, "%s", id(pv_h_p).state.c_str());
     it.printf(505, 46, id(Verdana18), TextAlign::TOP_CENTER, "%skW", id(strom_h_p).state.c_str());
     it.printf(505, 69, id(Verdana18), TextAlign::TOP_CENTER, "%sl", id(w_w_h).state.c_str());
     it.printf(505, 92, id(Verdana18), TextAlign::TOP_CENTER, "%skW", id(hzg_h_h).state.c_str());
     it.printf(505, 115, id(Verdana18), TextAlign::TOP_CENTER, "%skW", id(hzg_ww_h).state.c_str());      
     it.printf(505, 138, id(Verdana18), TextAlign::TOP_CENTER, "%skW", id(hzg_y_h).state.c_str());
     it.printf(505, 161, id(Verdana18), TextAlign::TOP_CENTER, "%sqm", id(hzg_g_h).state.c_str());      


Neben dem Setzen der grafischen Bestandteile ist die Befüllung der MQTT-Topics mit einigem Aufwand verbunden. Einige Werte können 1:1 aus bestehenden Objekten übernommen werden, andere Werte müssen zunächst berechnet werden.

Wir unterscheiden zwischen zwei Typen von Werten:

  • Berechnung nur 1x pro Tag
    • Dies betrifft vor allem Verbrauchswerte, die in der Vergangenheit liegen.
  • Berechnung mehrfach über den Tag
    • Dies betrifft vor allem Verbrauchswerte oder Wetterinformationen, die wir über den Tag hinweg aktualisieren wollen.

Uns kam in der Umsetzung dieses Projekts ein neues Blockly-Element gerade recht, das die Auswertung von historischen Werten eine Datenpunkts ermöglicht. So können wir maximale oder durchschnittliche Werte von Objekten grafisch einfach bestimmen und in das MQTT-Topic schreiben, z.B. der durchschnittliche tägliche Stromverbrauch über die letzten 7 Tage.

Blockly für die Berechnung der Werte

Blockly für die Berechnung der Werte

Das Ergebnis sind einige Inhalte auf 800 x 480 Pixel, die bei uns im 30-Minuten-Abstand regelmäßig aktualisiert werden.

ioBroker Status Dashboard mit Waveshare E-Paper Display

ioBroker Status Dashboard mit Waveshare E-Paper Display