2xS0 mit ESP32 und Tasmota
Volkszähler auf RaspberryPi kaputt – also bauen wir etwas Neues
Im Ferienhaus erfasse ich schon seit 7 Jahren verschiedene Energieflüsse. Unter anderem möchte ich wissen, wie viel Strom das Gartenstudio verbraucht und was die Pelletheizung elektrisch benötigt.
Bisher liefen die beiden S0-Zähler über einen Volkszähler. Die Werte wurden von dessen Middleware abgefragt und anschließend per Python in meine InfluxDB geschrieben.
Das funktionierte lange gut. Nun ist der Volkszähler ausgefallen weil nach 7 Jahren die 8Gb SD-Karte aufgegeben hat.

Da ich Tasmota bereits bei verschiedenen anderen Projekten einsetze und damit gute Erfahrungen gemacht habe, lag es nahe, die beiden S0-Zähler mit einem ESP32 auszulesen.
Ziel war:
-
zwei S0-Zähler an einem ESP32
-
aktuelle Leistung in Watt
-
Verbrauch heute
-
Verbrauch gestern
-
Gesamtverbrauch
-
Werte sollen einen Neustart überleben
-
JSON-Ausgabe über HTTP
-
minütliche Übernahme per Python in meine bestehende InfluxDB 1.x
-
möglichst keine Cloud
-
möglichst wenig Spezialhardware
Also eigentlich genau das, was ich mag.
Das Ergebnis hier mal vorab in einem stylischen Holzgehäuse. Gehäuse sind nur Berührungsschutz, zumindest wenn sie im Stahlschrank unsichtbar untergebracht sind:

Die vorhandenen Stromzähler
Im Ferienhaus sind zwei Eltako-Zähler verbaut.
Gartenstudio

Ein dreiphasiger Eltako DSZ12D.
Pelletheizung

Ein Eltako WSZ12DE.
Beide besitzen einen S0-Ausgang mit:
-
S0+
-
S0-
Der S0-Ausgang liefert keine fertige Leistungsmessung, sondern Impulse. Aus Anzahl und zeitlichem Abstand der Impulse lässt sich Energie und Leistung berechnen.
Beim Gartenstudio stellte sich nach einigen Messungen heraus:
1000 Impulse/kWh
Damit gilt:
1 Impuls = 1 Wh
Für die Pelletheizung verwende ich:
100 Impulse/kWh
also:
1 Impuls = 10 Wh
Die beiden Zähler können im Script unabhängig voneinander parametriert werden.
Hardware
Zum Einsatz kommt ein:
ESP32-WROOM-32
mit einer Tasmota-Scripting-Firmware, der Development-Version mit Scripting.
Verwendete GPIOs:
| Funktion | GPIO | Tasmota |
|---|---|---|
| Gartenstudio | GPIO27 | Counter1 |
| Pelletheizung | GPIO26 | Counter2 |
Diese Pins sind beim normalen ESP32-WROOM-32 für diesen Zweck angenehm unkritisch.
Die Tasmota-Konfiguration lautet:
GPIO27 = Counter1
GPIO26 = Counter2
Zusätzlich:
SetOption159 0
CounterDebounce 20
CounterDebounceLow 10
CounterDebounceHigh 10
Damit wird bei einem Impuls nur eine Flanke gezählt.
S0-Eingang
Die Eltako-S0-Ausgänge werden nicht direkt mit 5 V auf den ESP32 gelegt, das hält der nicht aus, die Eltakos brauchen aber mindestens 5V.

Pro Kanal verwende ich:
-
2,2 kΩ im S0-Kreis
-
10 kΩ zum GPIO
-
15 kΩ vom GPIO nach GND
-
optional 100 nF vom GPIO nach GND
Der ESP32 erhält damit einen sauberen 3,3-V-kompatiblen Pegel.


Der ursprünglich ausprobierte bidirektionale Logic-Level-Converter flog wieder raus. Für so einen langsamen S0-Eingang ist eine einfache definierte Widerstandsschaltung übersichtlicher und weniger fehleranfällig.
Erst einmal nur Pulse zählen
Bevor die echten Zähler angeschlossen wurden, habe ich beide Eingänge einfach gegen GND geschaltet.
Damit ließ sich prüfen:
Counter1
Counter2
Ein Impuls auf GPIO27 musste exakt Counter1 erhöhen.
Ein Impuls auf GPIO26 musste exakt Counter2 erhöhen.
Das war wichtig, denn bei den ersten Breadboard-Versuchen hatte ich Mehrfachzählungen und sogar Impulse auf dem unbenutzten zweiten Eingang.
Mit sauberer Verdrahtung und sinnvoller Entprellung funktionierten beide Counter anschließend zuverlässig. Ich konnte sogar 2-5s brücken und erst beim loslassen wurde der Impuls, besser die Flanke gezählt.
Tasmota Scripting
Ich verwende:
Tasmota 16.0.0.1 scripting
Die beiden wichtigsten Faktoren stehen im Script ganz oben:
gwh=1
pwh=10
Dabei bedeutet:
gwh = Wh pro Impuls Gartenstudio
pwh = Wh pro Impuls Pelletheizung
Dadurch können die beiden Zähler vollkommen unabhängig voneinander angepasst werden.
Beispiele:
100 Imp/kWh = 10 Wh/Impuls
500 Imp/kWh = 2 Wh/Impuls
1000 Imp/kWh = 1 Wh/Impuls
2000 Imp/kWh = 0.5 Wh/Impuls
Energie berechnen
Für das Gartenstudio:
gday+=gd*gwh
gtot+=gd*gwh
Für die Pelletheizung:
pday+=pd*pwh
ptot+=pd*pwh
Damit wird jeder neue S0-Impuls direkt in Wh umgesetzt.
Momentanleistung aus dem Impulsabstand
Zwischen zwei S0-Impulsen wird die Zeit gemessen.
Die Berechnung lautet:
P = 3600000 * Wh_pro_Impuls / Impulsabstand_ms
Im Script:
gpwr=(3600000*gwh)/gdt
und:
ppwr=(3600000*pwh)/pdt
Damit funktioniert die Leistungsberechnung unabhängig von der Impulsrate des jeweiligen Zählers.
Wenn längere Zeit kein Impuls kommt, wird die Leistung nach zehn Minuten wieder auf 0 gesetzt.
if millis-gtm>600000
then
gpwr=0
endif
Dasselbe gibt es für die Pelletheizung.
Kleine Fehlersuche mit dem Heizlüfter
Beim ersten Versuch passte die angezeigte Leistung des Gartenstudios überhaupt nicht.
Backofen, Toaster und Wasserkocher ergaben Werte, die deutlich zu hoch waren.
Also nicht weiter am Faktor herumraten, sondern einen möglichst konstanten Verbraucher nehmen.
Ein kleiner Heizlüfter nahm gemessen ungefähr:
581 W
Bei praktisch keiner weiteren Grundlast ergab sich:
Start:
Counter1 = 1678
gday = 1254
nach 10 Minuten:
Counter1 = 1789
gday = 1476
nach 15 Minuten:
Counter1 = 1842
gday = 1582
Nach 10 Minuten waren also:
111 Impulse
gezählt worden.
Bei 1000 Imp/kWh entsprechen diese 111 Impulse:
111 Wh
Auf 10 Minuten gerechnet ergibt das ungefähr:
666 W
Das ist für 581 W Heizlüfter plus kleine Restverbraucher absolut plausibel.
Damit war klar:
Der DSZ12D arbeitet hier mit 1000 Imp/kWh.
Also:
gwh=1
Danach passte auch die Leistungsanzeige.
Die Pelletheizung habe ich über ihre bekannten Verbraucher geprüft. Pumpenleistung, Pellet-Sauger und elektrischer Heizstab beim Zünden liefern plausible Werte. Dort bleibt deshalb:
pwh=10
Tageswerte und Neustart
Ich wollte nicht nur die Momentanleistung erfassen.
Das Script führt deshalb pro Zähler:
Power
Today_Wh
Yesterday_Wh
Total_Wh
Die dafür verwendeten Variablen sind zum Teil persistent abgelegt:
p:gtot=0
p:gday=0
p:gyest=0
p:ptot=0
p:pday=0
p:pyest=0
p:date=0
Damit überleben die Werte einen ESP-Neustart.
Das war zunächst etwas knifflig.
Der erste Ansatz setzte beim Neustart Today_Wh wieder auf Null.
Der Grund war nicht die Persistenz, sondern die Tageswechsel-Logik. Das Script auf dem Tasmota-ESP lief bereits, bevor nach dem Boot eine gültige Uhrzeit vorhanden war.
Die Lösung war:
-
beim Boot keine Tageswerte löschen
-
erst nach plausibler Zeitinitialisierung das Datum bewerten
-
einen echten Datumswechsel von einer Erstinitialisierung unterscheiden
Seitdem bleiben Today, Yesterday und Total auch nach Neustarts erhalten.
JSON direkt aus Tasmota
Das Script erzeugt über die >J-Sektion zusätzliche JSON-Werte:
>J
,"Gartenstudio":{"Power":%0gpwr%,"Today_Wh":%0gday%,"Yesterday_Wh":%0gyest%,"Total_Wh":%0gtot%}
,"Pelletheizung":{"Power":%0ppwr%,"Today_Wh":%0pday%,"Yesterday_Wh":%0pyest%,"Total_Wh":%0ptot%}

Der ESP bekommt im WLan den Hostnamen:
energie-airbnb

Die Daten lassen sich mit einem einzigen HTTP-Aufruf abfragen:
http://energie-airbnb.local/cm?cmnd=Status%2010
oder über seine feste IP.
Beispiel:
{
"StatusSNS": {
"COUNTER": {
"C1": 973,
"C2": 1972
},
"Gartenstudio": {
"Power": 72,
"Today_Wh": 606,
"Yesterday_Wh": 3820,
"Total_Wh": 606
},
"Pelletheizung": {
"Power": 0,
"Today_Wh": 3047,
"Yesterday_Wh": 4910,
"Total_Wh": 3047
}
}
}
Damit brauche ich keinen Volkszähler und keine Middleware mehr zwischen S0-Zähler und Datenbank.
Anzeige direkt im Tasmota-Webinterface
Mit einer >W-Sektion lassen sich die wichtigsten Werte zusätzlich auf der Tasmota-Hauptseite anzeigen.
Zum Beispiel:
>W
<b>Gartenstudio</b><br>
Leistung: %0gpwr% W<br>
Heute: %0gday% Wh<br><br>
<b>Pelletheizung</b><br>
Leistung: %0ppwr% W<br>
Heute: %0pday% Wh<br>
Damit sehe ich schon beim Öffnen des ESP:
-
aktuelle Leistung Gartenstudio
-
Tagesverbrauch Gartenstudio
-
aktuelle Leistung Pelletheizung
-
Tagesverbrauch Pelletheizung
Die normalen Counter1- und Counter2-Werte bleiben zusätzlich sichtbar, diese konnte ich nicht ausblenden.

Python und InfluxDB 1.6
Meine bestehende InfluxDB läuft weiterhin mit:
Database:
strom
Measurement:
chaletmessung
Das wollte ich beibehalten, damit bestehende Grafana-Auswertungen weiter funktionieren.
Die Feldnamen bleiben deshalb ebenfalls möglichst kompatibel:
gartenstudio_power
gartenstudio_total
gartenstudio_today
gartenstudio_yesterday
chalet_hzg_power
chalet_hzg_total
chalet_hzg_today
chalet_hzg_yesterday
Die Tasmota-Werte werden in Wh geliefert.
Für die Datenbank rechne ich Energie in kWh um:
gartenstudio_total = float(garten["Total_Wh"]) / 1000.0
gartenstudio_today = float(garten["Today_Wh"]) / 1000.0
Die Leistung bleibt in Watt.
Python-Abfrage
Das Prinzip ist wegen der JSON Datenhaltung inzwischen erfreulich einfach:
import requests
from influxdb import InfluxDBClient
TASMOTA_URL = "http://energie-airbnb.local/cm?cmnd=Status%2010"
r = requests.get(TASMOTA_URL, timeout=5)
r.raise_for_status()
data = r.json()["StatusSNS"]
garten = data["Gartenstudio"]
heizung = data["Pelletheizung"]
Aus einem einzigen HTTP-Aufruf bekomme ich beide Zähler.
Anschließend werden alle Werte gemeinsam als ein Punkt nach InfluxDB geschrieben.
In den bestehenden Grafana Dashboards tauchen sie sofort wieder auf:


Das hat gegenüber meiner alten Volkszähler-Lösung sogar einen Vorteil:
Alle acht Werte erhalten exakt denselben Timestamp.
Gesamtwerte ab einem definierten Stichtag
Für meine eigentliche Auswertung möchte ich ab dem 1. November neu beginnen.
Die historischen Gesamtstände interessieren mich dabei nicht als Abrechnungsdaten.
Es geht mir darum zu sehen:
Wo geht die Energie hin?
Deshalb kann ich zu diesem Zeitpunkt die persistenten Summen einmal zurücksetzen:
script >gtot=0;ptot=0;gday=0;pday=0;gyest=0;pyest=0;svars
Diese Zeile wird einfach in der Console des Tasmota-ESP eingegeben. Danach bedeuten die Total-Werte:
Verbrauch seit Beginn meiner neuen Messreihe.
Das reicht für diesen Zweck vollkommen.
Warum das Ganze?
Im Ferienhaus gibt es mehrere größere Verbraucher bzw. Nutzungseinheiten.
Unter anderem:
-
das Chalet selbst
-
Gartenstudio
-
Pelletheizung
Die Gesamtenergiedaten bekomme ich schon aus dem Fronius-Wechselrichter, der auch die Daten für den Batteriespeicher und die Wallbox hergibt.
Wenn ich Gartenstudio und Pelletheizung separat messe, kann ich die Energieflüsse deutlich besser auseinanderhalten.
Es geht dabei ausdrücklich nicht um abrechnungsrelevante Messung.
Mich interessiert vielmehr:
-
Wo wird wie viel Energie verbraucht?
-
Wie verändert sich der Verbrauch?
-
Was benötigt die Heizung elektrisch?
-
Wie viel entfällt auf das Gartenstudio?
-
Wie passt das zur PV-Erzeugung?
-
Wie entwickeln sich Tages- und Jahreswerte?
Also Monitoring.
Und genau dafür reicht diese Lösung.
Fazit
Aus einem defekten Volkszähler wurde am Ende eine etwas einfachere Lösung:
Kein Cloud-Dienst.
Keine zusätzliche Middleware.
Keine proprietäre App.
Genau so mag ich solche Projekte: vorhandene Technik weiterverwenden, offene Schnittstellen nutzen und die Daten dort speichern, wo sie auch in einigen Jahren noch mir gehören.
Alles super einfach, oder?
Ok, davor lief ein RaspberryPi und hat die Daten von einem Wiesemann&Theis Interface bekommen. Beide hingen im LAN, per Kabel. Damit auch in meinem Zuständigkeitsbereich.
Der ESP-Tasmota verbindet sich mit WLAN. Mehr oder weniger, denn erstens ist er im Uponor Metallschrank untergebracht und zwietens ist das WLAN für die Gäste gedacht und es gibt keinen Weg vom Gästesnetz in mein Netzwerk.

Da hängt der ESP jetzt in der stylischen Holzschachtel und funkt ins Gästenetz während ich gerne die JSON auswerten würde. Ok, dann geh ich mit Powerline in den Uponor-Schrank und spanne dort ein WLAN nur für den ESP auf. Gute Idee, dafür brauche ich nur in der unzugänglichen Garage einen Powerline-Einspeiser. Der muss nur an den 5-fach-Switch von Netgear ran. Oh, der ist komplett belegt. –> Also ein neuer 8-fach-Switch installiert, den ich noch im Lager irgendwo hatte. Die beiden pairen und nach mehreren Versuchen endlich den Schreibfehler in der SSID finden. Der ESP wollte einfach nicht auftauchen.
Das Ferienhaus ist zwar mit dem Fahrrad erreichbar aber ich musste x-mal hin- und herfahren. Erst als der ESP eine IP-Adresse hatte, konnte ich den Rest unter Linux dann von Zuhause aus machen. Es gibt eine Richtfunkstrecke ins Ferienhaus für Monitoring der PV-Anlage, der Pelletheizung und jetzt auch der detaillierteren Stromnutzung.
Links
Das Skript das in die spezielle Scripting-Version von Tasmota als Skript, nicht als Berry-Skript eingefügt wird: das Skript
Das Python-Skript das die JSON-Ausgabe des Tasmota-ESP abfragt: Python-Skript
Hier zur Installation von vor 7 Jahren mit viel mehr Hardware-Aufwand
