ESP8266 oder ESP32 als Home Assistant Schalter und Sensoren

In letzer Zeit experimentiere ich viel mit der Cloud-freien Heimautomatisierungssoftware Home Assistant. Bister habe ich viele Sensoren und Aktoren einzeln betrieben, quasi unabhängig von einem zentralen System. So loggte meine Wetterstation in eine Datenbank, ebenso mein Stromzähler in eine andere. Dafür gab es dann jeweils eine Visualisierung. Meine Bewässerungssteuerung wurde von einem Raspberry Pi mit einer selbst gebauten Oberfläche verwaltet. Nun jedoch möchte ich die Dinge zusammenführen und kosolidieren, um eine bessere Usability zu haben und den WAF zu verbessern.

Kürzlich habe ich daher bereits über meine Integration eines Stromzählers in Home Assistant geschrieben, nun stehen meine Bewässerungssteuerung bzw. meine Relaissteuerung auf dem Plan. Bisher habe ich dafür oben genannten Raspberry Pi verwendet – doch diesen mit einem Raspbian 99% des Tages nichts tun zu lassen halte ich für Verschwendung.

Deswegen kommt nun ein ESP8266-basierter Mikrocontroller (Wemos D1 mini) zum Einsatz, den ich mit der Arduino-IDE ein HTTP-Interface zum Setzen und Abrufen von Ausgängen und Eingängen ausgestattet habe. Beispielhaft für ein Wemos D1 mini mit dem offiziellen Relais-Schild werde ich den Code hier einmal zusammenfassen.

Arduino-Code

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#ifndef STASSID
#define STASSID "WLAN-NAME"
#define STAPSK  "WLAN-PASSWORT"
#endif

const char *ssid = STASSID;
const char *password = STAPSK;

ESP8266WebServer server(80);

void handleRoot() {
   server.send(200, "text/plain", String(analogRead(A0))); // Testweise den Analogwert ausgeben
}

void handleSet() {
  for (uint8_t i=0; i<server.args(); i++){
    if (server.argName(i)=="D1") { digitalWrite(D1, server.arg(i).toInt()); }
  }
  server.send(200, "text/plain","OK");
}

void handleGet() {
  for (uint8_t i=0; i<server.args(); i++){
    if (server.argName(i)=="D1") { server.send(200, "text/plain", String(digitalRead(D1))); }
    }
  server.send(200, "text/plain","OK");
}

void setup() {
  //IO
  pinMode(D1, OUTPUT);
  digitalWrite(D1, OFF);

  //WIFI
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  //HTTP
  server.on("/", handleRoot);
  server.on("/set", handleSet);
  server.on("/get", handleGet);
  server.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient();
  MDNS.update();
  ArduinoOTA.handle();
}

Home Assistant-Code

Hier wird Beispielhaft die IP des ESP als 192.168.178.77 angenommen – dies ist natürlich anzupassen.


#Aktor Wemos D1 mini mit Rückmeldung
switch:
  - platform: command_line 
    switches:
      esp_aktor_001_d1:
        friendly_name: "Aktor 001 D1"
        command_state: "/usr/bin/curl 192.168.178.77/get?D1"
        command_on: "/usr/bin/curl 192.168.178.77/set?D1=1"
        command_off: "/usr/bin/curl 192.168.178.77/set?D1=0"
        value_template: '{{ value == "1" }}'

#Sensor Wemos D1 mini
  - platform: command_line
    name: "Aktor 001 A0"
    command: "/usr/bin/curl 192.168.178.77/get?A0"

Auf diese Weise kann der Relais-Status geschrieben und gelesen werden. Auch den Analog-Eingang kann man auswerten.

Natürlich bleibt es einem überlassen, mehr Ein- oder Ausgänge zu implementieren. Ich beispielweise nutze den erwähnten Wemos mit einem 8-fach Relais-Board, was diesen beinahe auslastet. Mit einem D32 oder ähnlichem wäre da bei weitem mehr möglich.

EasyMeter Stromzähler in Home Assistant einbinden

Unser Messstellenbetreiber nutzt die “smarten” Stromzähler der Firma EasyMeter GmbH, speziell den Easy Meter Q3M. Dies ist ein Drehstromzähler, der dahingehend “smart” ist, dass man einige Daten auslesen kann. Je nach Konfiguration des Messstellenbetreibers können die aktuelle Gesamtleistung, die Leistung pro Phase in Watt und die “verbrauchte” sowie eingespeiste Energie in Wattstunden ausgelesen werden. Dazu wird eine optische Schnittstelle namens “Info-DSS” bereitgestellt, die nichts anderes ist als eine unidirektionale Implementierung des SML Protokolls.

Über das SML Protokoll werden mittels sogenannter OBIS-Codes die oben genannten Informationen sekündlich über die Schnittstelle gepusht. Diese Daten muss man “nur” noch abgreifen und bereitstellen. Dazu benötigt man – zusätzlich zum bestehenden Home Assistant System – ein Gerät direkt am Zähler, dass die Daten der Info-DSS-Schnittstelle entgegennimmt und lesbar umwandelt. Ich nutze dafür einen Raspberry Pi (Zero W), aber auch andere Geräte mit einem Linux funktionieren. Die Anbindung funktioniert bei mir über einen IR-Lesekopf, den man sich aber auch selber bauen kann.

Auf meinem Raspebrry Pi habe ich dann die Software vzlogger installiert – wohlgemerkt ohne die Volkszähler-Middleware, die sonst die Speicherung und Darstellung der Daten übernimmt. Der vzlogger kann die aktuellen Daten problemlos allein auswerten und als json bereitstellen. Dafür ist in /etc/vzlogger.conf folgende Konfiguration notwendig:

{
  "retry": 0,
  "daemon": true,
  "verbosity": 3,
  "local": {
    "enabled": true,
    "port": 8084,
    "index": true,
    "timeout": 0,
    "buffer": -1
  },
  "meters": [
    {
      "enabled": true,
      "allowskip": true,
      "interval": -1,
      "aggtime": -1,
      "aggfixedinterval": false,
      "channels": [
        {
          "api": "null",
          "uuid": "abcdefgh-ijkl-mnop-qrst-uvwxyz012345",
          "identifier": "1-0:1.8.0*255",
          "aggmode": "max",
          "duplicates": 3600
        }
	  ],
      "protocol": "sml",
      "device": "/dev/ttyUSB0",
      "pullseq": "",
      "baudrate": 9600,
      "parity": "8n1",
      "use_local_time": true
    }
  ]
}

Wobei ich die uuid hier unkenntlich gemacht habe und der Übersicht halber nur einen “channel”, nämlich die Energiemenge “Verbrauch” erfasse. Nachdem die Datei gespeichert ist wird der vzlogger-Daemon neu gestartet:

sudo systemctl restart vzlogger

Und somit kann man die aktuellen Daten unter der IP des Raspberry Pi abrufen: http://[ip_des_pi]:8084 . Das Ganze könnte dann so aussehen:

{
	"version": "0.8.0",
	"generator": "vzlogger",
	"data":[ {
		"uuid": "abcdefgh-ijkl-mnop-qrst-uvwxyz012345", 
		"last": 1634638205040,
		"interval": -1,
		"protocol": "sml",
		"tuples": [ [ 1634638205040, 7418885.2847000007 ] ] 
	} ]
}

In dem Tuple steht also der aktuelle Zählerstand in Wh. Diesen müssen wir nun über Home Assistant auslesen, dazu wird in der Datei /config/configuration.yaml zuerst folgender Bereich eingefügt:

#Zählerstand Verbrauch
sensor:
  - platform: rest
    resource: http://192.168.178.202:8084/
    value_template: >
      {% for i in value_json.data %}
        {% if i.uuid == "abcdefgh-ijkl-mnop-qrst-uvwxyz012345" %}
           {{ '%.2f'%(i.tuples[0][1]) | float }}
        {% endif %}
      {% endfor %}
    method: GET
    name: "Zählerstand Verbrauch"
    unit_of_measurement: Wh
    device_class: energy

Zu beachten an dieser Stelle: Der String, der aus dem Tuple extrahiert wird, bekommt mittels ‘%.2f’% eine Begrenzung der Kommastellen auf 2. Sonst wird der Float regelmäßig mit einer unterschiedlichen Anzahl Kommastellenangezeigt, was die Lesbarkeit beeinträchtigt. Mittels | float wandel ich den String direkt in einen Float um, damit kann ein PC immer besser umgehen als mit String-Zahlen.

Nun könnte man über sensor.zahlerstand_verbrauch schon den aktuellen Zählerstand in Homeassistandt nutzen, aber unglücklicherweise nicht im neuen Energy-Management. Denn dafür muss der Sensor eine Eigenschaft mit state_class haben – die es aber Stand heute nicht gibt (Featue-Request läuft). Daher müssen einige wenige weitere Anpassungen in der /config/configuration.yaml vorgenommen werden:

homeassistant:
  customize:
    #grid consumption
    sensor.zahlerstand_verbrauch:
      state_class: total_increasing

Mit diesen Zeilen teilen wir Home Assistant mit, dass unser Zählerstand eine Gesamtsumme ist, die immer weiter wächst. So kann dann sensor.zahlerstand_verbrauch auch endgültig ins neue Energy-Management eingefügt werden:

Abschließend sei angemerkt, dass diese Integration im Prinzip mit allen Daten funktioniert, die der vzLogger produziert und das ist eine ganze Menge. Implementiert sind unter anderem das OMS-Protokoll, mit dem man funkende Wasserzähler, elektronische Heizkostenverteile und Wärmemengenzähler empfangen kann, aber auch diverse andere sind auf der Info-Seite vermerkt. Von der verfügbaren volkszähler-Implementierung für Home Assistant kann ich leider nur abraten. Diese bietet weder die Performance wie der hier dargestellte Ansatz, noch können die Daten ins Energy-Management einfließen. Auch würde man sich damit eine doppelte Datenhaltung ins Haus holen.

Stromzähler mit S0-Impulsausgang an Raspberry Pi mit Volkszähler auswerten

Ich nutze seit geraumer Zeit das freies Smart Meter von Volkszähler, um meinen Stromverbrauch am Stromzähler grafisch zu erfassen. Ich habe als Stromzähler eine “moderne Messeinrichtung”, also einen Stromzähler mit SML Datenschnittstelle. Aber um diesen Zähler soll es heute gar nicht gehen. Interessieren soll uns heute ein einfach Wechselstromzähler mit einem Impulsausgang.

Der Impulsausgang wird in diesem Fall “S0”-Schnittstelle genannt und ist nicht mit der gleichnamigen S0-Schnittstelle von ISDN zu verwechseln. Im Prinzip handelt es sich um einen potentialfreien Schaltkontakt, der oft über einen Optokoppler ausgeführt ist, so auch in meinem Beispiel bei dem Wechselstromzähler Typ DDS5188. Dieser gibt wür jede “verbrauchte” Kilowattstunde 2000 Impulse aus, sprich einen Impuls pro 0,5 Wattstunden. Die Anbindung an Volkszähler, genauer gesagt den VZLogger hat mir einiges an grauen Haaren bereitet, denn ich wollte nicht die Impulse aufsummiert dargestellt haben, sondern live die verbrauchte Leistung darstellen.

Hardware-Setup

In den meisten Fällen haben die Zähler einen “S0+”- und einen “S0-“-Anschluss. Ich habe den “S0-“-Anschluss direkt auf Masse gelegt, wenn der Zähler einen Impuls ausgibt, wird der “S0+”-Anschluss also gegen Masse gezogen. Damit dieser sonst nicht in der Luft hängt, kann man am GPIO den Pullup-Widerstand aktivieren, oder man baut einen ein, wie im Schaltplan dargestellt. Wichtig: Die GPIO des Raspberry Pi sind nicht 5V-tolerant, man muss den Pullup also auf 3,3V legen!

Wechselstromzähler mit S0 Impulsausgang am Raspberry Pi Zero

Bei jedem Impuls des Zählers, also bei jeder “verbrauchten” halben Wattstunde bekommt der Raspberry Pi an GPIO 18 (Pin 12) nun also einen negativen Impuls von einigem Millisekunden. Nun gilt es, den vzlogger dafür zu konfigurieren.

Konfiguration des vzloggers

Die Konfiguration des vzloggers befindet sich in der Datei /etc/vzlogger.conf und muss mit root rechten bearbeitet werden. Es folgt eine erläuterte Beispiel-Konfiguration für den Zähler:

{
  "retry": 0,
  "verbosity": 3, //die SD-karte nicht zu sehr belasten...
  "log": "/var/log/vzlogger.log",
  "local": {  //Ich möchte auf lokal auf die Daten zugreifen, ohne push
    "enabled": true,
    "port": 8084,
    "index": true,
    "timeout": 0,
    "buffer": 0
  },
  "meters": [
  {
    "enabled": true,
    "allowskip": false,
    "aggtime": 0, //Die Daten werden nicht zusammengefasst
    "aggfixedinterval": false,
    "aggmode": "sum",
    "protocol": "s0", //S0-Impulse
    "gpio": 18, //Broadcom-Pin an dem der Impulsausgang hängt
    "mmap": "",
    "gpio_dir": -1,
    "configureGPIO": true, //vzlogger soll die GPIO für mich konfigurieren
    "resolution": 1, //hier könnte man die 2000 Impulse pro kWh eintragen
    "send_zero": false, //keine Nullen übertragen
    "channels": [
        {
          "uuid": "4307f540-dcb4-11eb-b124-5da08f82312d",
          "identifier": "Power", //DAS ist die wichtigste Stelle! Wer hier "Impulse" einträgt bekommt nicht die aktuelle Leistung
          "api": "volkszaehler",
          "middleware": "http://localhost/middleware.php",
          "timeout" : 10,
          "duplicates": 30
        }
    ]
  }
  ]
}

Das Ganze kann dann so aussehen:

Leistung dargestellt über die Zeit

Möchte man mehrere Zähler mit einem Raspberry Pi auslesen, so müssen mehrere “meters” in geschweiften Klammern angelegt werden. Leider auch dann, wenn man pro Phase einen S0-Ausgang hat.

Als kleinen Tipp am Ende kann ich noch die fertigen Images für den Raspberry Pi von Volkszähler empfehlen: https://wiki.volkszaehler.org/howto/raspberry_pi_image