TinyC family · read the electricity meter, chart it, hand it onTinyC-Familie · Stromzähler auslesen, aufzeichnen, weitergeben
An ESP32 with a reading head sits on your electricity meter and reads it over SML. Every program of this family shares the same meter setup; they differ in what they add on top: charts, a meter emulator for a PV battery, a Modbus slave.
Requirements: ESP32 (no ESP8266), Tasmota with TinyC and USE_SML, and a reading head (examples on my blog).
Everything is set up on the web page, no code editing. Language, meter, pins and options are stored on the device.
Buttons in Tasmota's main menu. A running program adds its own entries:
| ⚙️ SML | All settings. Programs with a battery emulator show ⚙️ SML /🔋 instead. |
|---|---|
| ☁️ Marstek | Only in the CT002 programs: account and CT registration. |
| 💻 TinyC | Tasmota's TinyC page — slots, upload, editor. |
The charts have a page of their own, reached by the 📈 link under the readings on the main page. They are no longer drawn into the main page, which used to make it slow.
Ein ESP32 mit Lesekopf sitzt am Stromzähler und liest ihn über SML aus. Alle Programme dieser Familie teilen sich die gleiche Zählereinrichtung; sie unterscheiden sich nur in dem, was oben drauf kommt: Diagramme, ein Zähler-Emulator für eine PV-Batterie, ein Modbus-Slave.
Voraussetzungen: ESP32 (kein ESP8266), Tasmota mit TinyC und USE_SML und ein Lesekopf (Beispiele auf meinem Blog).
Alles wird auf der Weboberfläche eingestellt, nichts im Code. Sprache, Zähler, Pins und Optionen liegen auf dem Gerät.
The current smoothed value is shown in this section on the settings page. It used to sit on the main page as Power (smoothed) and moved here, next to the switch that publishes it.
The publishes carry log level 3: the console stays quiet at weblog 2 and shows them from weblog 3, without recompiling. A failed publish is logged once with its return code — -2 means MQTT is switched off on the device (SetOption3).
Buttons in Tasmotas Hauptmenü. Ein laufendes Programm ergänzt eigene Einträge:
| ⚙️ SML | Alle Einstellungen. Programme mit Akku-Emulator zeigen stattdessen ⚙️ SML /🔋. |
|---|---|
| ☁️ Marstek | Nur in den CT002-Programmen: Konto und CT-Registrierung. |
| 💻 TinyC | Tasmotas TinyC-Seite — Slots, Upload, Editor. |
Die Diagramme haben eine eigene Seite, erreichbar über das 📈 unter den Messwerten auf der Hauptseite. Sie werden nicht mehr in die Hauptseite gezeichnet, was diese früher langsam gemacht hat.
Pick one, compile it, upload it into slot 0. Modbus is an option inside every one of them.
| sml_simple.tc | Meter only. Smallest program. |
|---|---|
| sml_chart.tc | + charts and tables, feed-in switchable. |
| sml_ct002.tc | + Marstek CT002/CT003 emulator (docs). |
| sml_chart_ct002.tc | Charts + CT002 emulator. |
| sml_eco_shelly.tc | + EcoTracker / Shelly Pro 3EM emulator (docs). |
| sml_chart_eco_shelly.tc | Charts + EcoTracker / Shelly emulator. |
TinyCIde, then open http://<ip>/tc..tc file, Compile, Upload into slot 0.TinyCRun /<name>.tcb.Slot 0 only for the emulator variants: their HTTP endpoints are webOn handlers, and Tasmota dispatches those to slot 0.
Each program keeps its own settings file. Switching programs means setting the meter up again.
Eines aussuchen, kompilieren, in Slot 0 hochladen. Modbus ist in jedem davon als Option enthalten.
| sml_simple.tc | Nur Zähler. Kleinstes Programm. |
|---|---|
| sml_chart.tc | + Diagramme und Tabellen, Einspeisung schaltbar. |
| sml_ct002.tc | + Marstek-CT002/CT003-Emulator (Doku). |
| sml_chart_ct002.tc | Diagramme + CT002-Emulator. |
| sml_eco_shelly.tc | + EcoTracker- / Shelly-Pro-3EM-Emulator (Doku). |
| sml_chart_eco_shelly.tc | Diagramme + EcoTracker- / Shelly-Emulator. |
TinyCIde, dann http://<ip>/tc öffnen..tc-Datei laden, Compile, Upload in Slot 0.TinyCRun /<name>.tcb starten.Nur Slot 0 bei den Emulator-Varianten: deren HTTP-Endpunkte sind webOn-Handler, und die reicht Tasmota an Slot 0 weiter.
Jedes Programm hat seine eigene Einstellungsdatei. Beim Wechsel muss der Zähler neu eingerichtet werden.
Tasmota lets the chip doze between loop passes — Sleep 50, fifty milliseconds, is the default. It saves current, and it costs response time: while the radio sleeps the access point holds packets back until the next wake window.
| OFF (default) | Sleep 50. Lower power draw, a cooler chip. |
|---|---|
| ON | Sleep 0. The loop runs without pause. The web UI, the emulator's UDP replies and the charts all answer sooner. |
Measured on an ESP32-C3 at −87 dBm, twenty-five renders of the settings page:
| Sleep 50 | Sleep 0 | |
| median | 389 ms | 141 ms |
| 90th percentile | 2253 ms | 186 ms |
| slowest | 3315 ms | 277 ms |
| over one second | 6 of 25 | none |
The second run was made on a link that had meanwhile got worse (−90 dBm), so the seconds-long outliers came from the dozing, not from the radio. The weaker your signal, the more this switch is worth: a sleeping station misses beacons, and the access point buffers for it.
It is not a dial with a sweet spot in between. Tasmota ties the Wi-Fi radio's power saving to the value being zero:
if (0 == TasmotaGlobal.sleep || wifi_no_sleep) {
setSleepMode(WIFI_NONE_SLEEP); // radio stays on
} else {
setSleepMode(WIFI_MODEM_SLEEP); // radio dozes between beacons
}
Sleep 10 therefore behaves on the air exactly like Sleep 50 — only the processor's pause per loop gets shorter. There is nothing to tune between the two states, which is why this is a checkbox and not a number field.
| Sleep 50 | Sleep 0 | |
| Power draw | 50–400 mW, fluctuating | 400 mW, constant |
| Wi-Fi radio | dozes, wakes for beacons | receiving continuously |
Measured on an ESP32-C3 reading head. Almost all of it is the radio: the core draws roughly 70–100 mW when busy, a continuously receiving Wi-Fi 260–330 mW. The low values are the dozing module, the peaks its wake windows. SetOption127 (wifi_no_sleep) does not help here either — it keeps the radio on without lifting the processor's pause, so you end up at the same 400 mW.
The difference of about 250 mW is some 2.2 kWh a year — well under a euro. For a device a battery polls once a second that is the right trade.
| Emulator in use | ON. The battery polls every second and a late answer costs regulation quality. |
|---|---|
| Weak Wi-Fi | ON. Below about −80 dBm power saving and a poor link make each other worse: the station misses beacons, the access point buffers, and what should be 100–300 ms of waiting became outliers of over three seconds here. |
| Meter reading only | OFF. MQTT every 60 s does not care about two seconds of delay, and the device runs cooler. |
The bigger lever is the aerial, not this switch. At −65 dBm Sleep 50 would most likely be unremarkable, and an access point near the meter fixes response time and power draw at once.
Turning it back off sets Sleep 50, Tasmota's default — not whatever value stood there before. If you run a custom value, set it again with the Sleep command. The switch acts only on a change you make here — nothing is sent at start-up, so a Sleep set from the console is left alone. It is also not read back: after setting one from the console, tick the box once so the two agree.
The cost is real: more current and a warmer chip. On a mains-powered reading head that is usually the right trade; on anything battery-fed it is not.
Tasmota lässt den Chip zwischen den Schleifendurchläufen dösen — Sleep 50, fünfzig Millisekunden, ist der Standard. Das spart Strom und kostet Reaktionszeit: während das Funkmodul schläft, hält der Access Point Pakete bis zum nächsten Aufwachfenster zurück.
| AUS (Standard) | Sleep 50. Weniger Stromaufnahme, kühlerer Chip. |
|---|---|
| EIN | Sleep 0. Die Schleife läuft ohne Pause. Oberfläche, UDP-Antworten des Emulators und Diagramme kommen schneller. |
Gemessen an einem ESP32-C3 bei −87 dBm, fünfundzwanzig Aufrufe der Einstellungsseite:
| Sleep 50 | Sleep 0 | |
| Median | 389 ms | 141 ms |
| 90. Perzentil | 2253 ms | 186 ms |
| langsamste | 3315 ms | 277 ms |
| über eine Sekunde | 6 von 25 | keine |
Der zweite Durchlauf entstand auf einer Verbindung, die inzwischen schlechter war (−90 dBm) — die Sekundenausreißer kamen also vom Dösen, nicht vom Funk. Je schwächer dein Signal, desto mehr bringt der Schalter: eine schlafende Station verpasst Beacons, und der Access Point puffert für sie.
Er ist kein Regler mit einem Optimum dazwischen. Tasmota koppelt den Energiesparmodus des Funkmoduls daran, dass der Wert null ist:
if (0 == TasmotaGlobal.sleep || wifi_no_sleep) {
setSleepMode(WIFI_NONE_SLEEP); // Funk bleibt an
} else {
setSleepMode(WIFI_MODEM_SLEEP); // Funk döst zwischen Beacons
}
Sleep 10 verhält sich funktechnisch also exakt wie Sleep 50 — nur die Pause des Prozessors je Schleifendurchlauf wird kürzer. Zwischen den beiden Zuständen gibt es nichts zu justieren, deshalb ist das hier ein Häkchen und kein Zahlenfeld.
| Sleep 50 | Sleep 0 | |
| Leistungsaufnahme | 50–400 mW, schwankend | 400 mW, konstant |
| WLAN-Modul | döst, wacht zu Beacons auf | empfängt durchgehend |
Gemessen an einem ESP32-C3-Lesekopf. Fast alles davon ist das Funkmodul: der Kern zieht aktiv grob 70–100 mW, ein dauerhaft empfangendes WLAN 260–330 mW. Die niedrigen Werte sind das dösende Modul, die Spitzen seine Aufwachfenster. SetOption127 (wifi_no_sleep) hilft hier ebenfalls nicht — es hält den Funk an, ohne die Prozessorpause aufzuheben, du landest also bei denselben 400 mW.
Die Differenz von rund 250 mW sind etwa 2,2 kWh im Jahr — deutlich unter einem Euro. Für ein Gerät, das ein Akku im Sekundentakt abfragt, ist das der richtige Tausch.
| Emulator im Einsatz | EIN. Der Akku fragt im Sekundentakt, und eine späte Antwort kostet Regelgüte. |
|---|---|
| Schwaches WLAN | EIN. Unterhalb von etwa −80 dBm verstärken sich Energiesparmodus und schlechte Verbindung gegenseitig: das Modul verpasst Beacons, der Access Point puffert, und aus 100–300 ms Wartezeit wurden hier Ausreißer von über drei Sekunden. |
| Nur Zähler auslesen | AUS. MQTT alle 60 s stören zwei Sekunden Verzögerung nicht, und das Gerät bleibt kühler. |
Der größere Hebel ist die Antenne, nicht dieser Schalter. Bei −65 dBm wäre Sleep 50 sehr wahrscheinlich unauffällig, und ein Access Point in Zählernähe behebt Reaktionszeit und Verbrauch auf einen Schlag.
Wieder ausschalten setzt Sleep 50, den Tasmota-Standard — nicht den Wert, der vorher dort stand. Wer einen eigenen Wert fährt, setzt ihn mit dem Befehl Sleep erneut. Der Schalter wirkt nur auf eine Änderung, die du hier machst — beim Start wird nichts gesendet, ein von der Konsole gesetzter Sleep bleibt also unangetastet. Gelesen wird er auch nicht: nach einem Konsolenbefehl das Häkchen einmal setzen, damit beide übereinstimmen.
Der Preis ist real: mehr Strom und ein wärmerer Chip. Bei einem netzgespeisten Lesekopf ist das meist der richtige Tausch, bei allem Batteriebetriebenen nicht.
The descriptor tells the SML driver how to read your meter: baud rate, protocol and which OBIS codes go into which value. It lives in /sml_meter.def.
| Meter active | Switches the SML driver on and off (Rule1). Off means no readings at all. |
|---|---|
| 3 phases | Default OFF. Switch it on only if two things are true: your meter really sends power per phase, and the three phases are entered in the descriptor (sml_meter.def). The main page then shows an L1 / L2 / L3 row and the emulators report real per-phase values instead of putting everything on L1. Publishing over MQTT does not depend on this option: if the phases are in the descriptor they are published either way — as zeros if the meter cannot supply them. If they are not in the descriptor, nothing is published, whatever this option says. |
| From repo | Pulldown with ready-made descriptors from my repository. Picking one downloads it and restarts the driver. |
| Edit descriptor | Opens the file editor for hand-tuning. Your meter not in the list? Start from the closest one. |
The first three values are fixed by convention and everything else builds on them: 1 power [W], 2 import [kWh], 3 export [kWh].
Der Descriptor sagt dem SML-Treiber, wie dein Zähler zu lesen ist: Baudrate, Protokoll und welcher OBIS-Code in welchen Wert geht. Er liegt in /sml_meter.def.
| Zähler aktiv | Schaltet den SML-Treiber ein und aus (Rule1). Aus heißt: gar keine Messwerte. |
|---|---|
| 3 Phasen | Standard AUS. Nur einschalten, wenn beides zutrifft: der Zähler sendet die Leistung je Phase wirklich, und die drei Phasen sind im Descriptor (sml_meter.def) eingetragen. Dann erscheint auf der Hauptseite eine Zeile L1 / L2 / L3, und die Emulatoren melden echte Phasenwerte statt alles auf L1. Vom Zustand dieser Option unabhängig ist die Veröffentlichung per MQTT: Stehen die Phasen im Descriptor, werden sie so oder so gesendet — kann der Zähler sie nicht liefern, als Nullen. Fehlen sie im Descriptor, wird gar nichts veröffentlicht, egal wie diese Option steht. |
| Aus Repo | Auswahlliste mit fertigen Descriptoren aus meinem Repository. Eine Auswahl lädt ihn herunter und startet den Treiber neu. |
| Descriptor bearbeiten | Öffnet den Dateieditor zum Anpassen. Zähler nicht in der Liste? Mit dem ähnlichsten anfangen. |
Die ersten drei Werte sind per Konvention festgelegt, alles andere baut darauf auf: 1 Leistung [W], 2 Bezug [kWh], 3 Einspeisung [kWh].
RX is the pin the reading head's data line goes to. TX is only needed for meters that have to be woken up or that expect a request.
| RX 3 · TX 1 | Hichi, Stromleser, LesekopfV32, Wattwächter |
|---|---|
| RX 5 · TX 4 | bitShake |
The pulldown only offers pins Tasmota has left free. A pin already assigned in the module configuration will not show up.
Changing a pin rewrites the descriptor and restarts the driver — no reboot needed.
RX ist der Pin, an dem die Datenleitung des Lesekopfs hängt. TX braucht man nur bei Zählern, die geweckt werden müssen oder eine Anforderung erwarten.
| RX 3 · TX 1 | Hichi, Stromleser, LesekopfV32, Wattwächter |
|---|---|
| RX 5 · TX 4 | bitShake |
Die Auswahlliste zeigt nur Pins, die Tasmota frei gelassen hat. Ein in der Modulkonfiguration belegter Pin taucht nicht auf.
Eine Pin-Änderung schreibt den Descriptor neu und startet den Treiber neu — ohne Neustart des Geräts.
A median filter over the incoming power values. It throws away single outliers — the spikes that make a chart unreadable and an emulator regulate against nothing.
Leave it on unless you need the raw value. It costs a little response time, which matters only for battery regulation.
Ein Median-Filter über die eingehenden Leistungswerte. Er wirft einzelne Ausreißer weg — die Spitzen, die ein Diagramm unlesbar machen und einen Emulator gegen nichts regeln lassen.
Ruhig anlassen, außer du brauchst den Rohwert. Er kostet etwas Reaktionszeit, was nur bei der Akkuregelung eine Rolle spielt.
The SML driver can print its own rows on the main page, with the meter name in front of every value. The script prints the same values itself, in your language and without the prefix.
| OFF (default) | Only the script's rows. Tidier. |
|---|---|
| ON | Driver rows as well — useful while setting up a descriptor, because you see every value it produces, not just the first three. |
The MQTT telemetry (SENSOR) always contains the driver's values, whatever this is set to. Home Assistant is unaffected.
Der SML-Treiber kann eigene Zeilen auf der Hauptseite ausgeben, mit dem Zählernamen vor jedem Wert. Das Script gibt dieselben Werte selbst aus — in deiner Sprache und ohne Präfix.
| AUS (Standard) | Nur die Zeilen des Scripts. Aufgeräumter. |
|---|---|
| EIN | Zusätzlich die Treiberzeilen — praktisch beim Einrichten eines Descriptors, weil du jeden erzeugten Wert siehst, nicht nur die ersten drei. |
Die MQTT-Telemetrie (SENSOR) enthält die Treiberwerte immer, unabhängig von dieser Einstellung. Home Assistant merkt davon nichts.
Only in the chart variants. OFF shows consumption alone, ON adds feed-in: day, month and year rows, a daily production chart and a month chart with both directions.
Switch it on if your meter has a feed-in register (1.8.0 and 2.8.0). Without solar the extra charts stay at zero.
Nur in den Diagramm-Varianten. AUS zeigt nur den Verbrauch, EIN nimmt die Einspeisung dazu: Tages-, Monats- und Jahreszeile, ein Tagesertragsdiagramm und ein Monatsdiagramm mit beiden Richtungen.
Einschalten, wenn dein Zähler ein Einspeiseregister hat (1.8.0 und 2.8.0). Ohne PV bleiben die zusätzlichen Diagramme auf null.
| Short-term chart | Time range of the first chart: 15 minutes, 30 minutes, 1 hour, 2 hours or 4 hours (the default). The shorter the range, the finer the resolution — the chart always holds 180 to 240 points, so 15 minutes stores one every 5 seconds where 4 hours stores one a minute. |
|---|---|
| Charts on the main page | Off: the charts live on their own page, reached by the 📈 link in the value list. On: they are drawn on Tasmota’s own main page instead — under the values and buttons, the way they used to be — and the link disappears. The separate page stays reachable at /tc_ui?p=2 either way. |
| Range | One point every | Points |
|---|---|---|
| 15 minutes | 5 s | 180 |
| 30 minutes | 10 s | 180 |
| 1 hour | 15 s | 240 |
| 2 hours | 30 s | 240 |
| 4 hours | 60 s | 240 |
Changing the range and saving clears this chart. It has to: the stored slots would otherwise be read as a span they were never recorded for. The 24 h chart and the bar charts are untouched.
Each point is the average over its whole slot, so a shorter range is not noisier — it is genuinely finer. Nothing else changes: the ring is the same one, and a 15-minute chart costs no more memory than a 4-hour one.
The ↻ Auto update button above the charts reloads the page every 10 seconds. Google Charts draws once when the page is built and Tasmota’s own refresh only touches the value list, so without it a 15-minute chart freezes on screen while the numbers above it keep moving. The setting is remembered by the browser, not by the device, and a reload is skipped while you have a field selected.
| Kurzzeit-Diagramm | Zeitspanne des ersten Diagramms: 15 Minuten, 30 Minuten, 1 Stunde, 2 Stunden oder 4 Stunden (Standard). Je kürzer die Spanne, desto feiner die Auflösung — das Diagramm fasst immer 180 bis 240 Punkte, bei 15 Minuten also alle 5 Sekunden einen, bei 4 Stunden einen je Minute. |
|---|---|
| Diagramme auf der Hauptseite | Aus: die Diagramme liegen auf einer eigenen Seite, erreichbar über den 📈-Link in der Werteliste. Ein: sie werden auf Tasmotas eigener Hauptseite gezeichnet — unter den Werten und Knöpfen, so wie früher — und der Link entfällt. Die eigene Seite bleibt in beiden Fällen unter /tc_ui?p=2 erreichbar. |
| Spanne | Ein Punkt alle | Punkte |
|---|---|---|
| 15 Minuten | 5 s | 180 |
| 30 Minuten | 10 s | 180 |
| 1 Stunde | 15 s | 240 |
| 2 Stunden | 30 s | 240 |
| 4 Stunden | 60 s | 240 |
Eine andere Spanne zu wählen und zu speichern leert dieses Diagramm. Das muss so sein: die gespeicherten Slots würden sonst als eine Zeitspanne gelesen, für die sie nie aufgezeichnet wurden. Das 24-h-Diagramm und die Balkendiagramme bleiben unberührt.
Jeder Punkt ist der Mittelwert über seinen ganzen Slot — eine kürzere Spanne ist also nicht unruhiger, sondern wirklich feiner. Sonst ändert sich nichts: es ist derselbe Ring, und ein 15-Minuten-Diagramm braucht keinen Speicher mehr als ein 4-Stunden-Diagramm.
Der Knopf ↻ Auto-Update über den Diagrammen lädt die Seite alle 10 Sekunden neu. Google Charts zeichnet einmal beim Seitenaufbau, und Tasmotas eigene Aktualisierung fasst nur die Werteliste an — ohne den Knopf steht ein 15-Minuten-Diagramm also fest, während die Zahlen darüber weiterlaufen. Die Einstellung merkt sich der Browser, nicht das Gerät, und solange ein Feld ausgewählt ist, wird nicht neu geladen.
| 🔢 Reset | Restarts the day, month and year values from the current meter reading. Do this once after installing, and whenever the counters show nonsense — a full meter reading instead of a daily figure means the baselines are missing. The charts keep their history. |
|---|---|
| 📈 Reset | Empties the short-term and 24 h power charts. The values above and the bar charts stay as they are. |
| 📊 Reset | Clears the day and month columns. The counters keep running. Asks first. |
The 💾 CSV button at the bottom of the settings page writes /sml_chart.csv, and /sml_chart_pv.csv as well when the feed-in side is on. It reads only, so it fires without asking. Download the files in Tasmota's file manager.
The CSV holds the baselines in line 1, then the short-term, 24 h, daily and monthly arrays — tab separated, one array per line. That is the format to keep a backup in or to open in a spreadsheet.
The live data lives in the slot's .pvs file, saved by name. A backup is that one file: copy it away, copy it back, restart the slot. /sml_chart.bin is only read once at startup, for importing data from an older version.
The export also works while the meter is silent — that is deliberate, since a meter that stopped is exactly when the stored data matters.
Charts need the clock. Before the device has NTP time (2020) nothing is recorded.
| 🔢 Reset | Lässt Tages-, Monats- und Jahreswert neu beim aktuellen Zählerstand beginnen. Einmal nach der Installation, und immer dann, wenn die Zähler Unsinn zeigen — ein voller Zählerstand statt eines Tageswerts heißt, die Nullpunkte fehlen. Die Diagramme behalten ihren Verlauf. |
|---|---|
| 📈 Reset | Leert das Kurzzeit- und das 24-h-Verlaufsdiagramm. Die Werte darüber und die Balkendiagramme bleiben unberührt. |
| 📊 Reset | Löscht die Tages- und Monatsspalten. Die Zähler laufen weiter. Fragt vorher nach. |
Der Knopf 💾 CSV ganz unten auf der Einstellungsseite schreibt /sml_chart.csv, bei eingeschalteter Einspeiseseite zusätzlich /sml_chart_pv.csv. Er liest nur und fragt deshalb nicht nach. Heruntergeladen werden die Dateien im Dateimanager von Tasmota.
Die CSV enthält in Zeile 1 die Nullpunkte, danach die Arrays für das Kurzzeit-Diagramm, 24 h, Tage und Monate — tabgetrennt, ein Array je Zeile. Das ist das Format für eine Sicherung oder zum Öffnen in der Tabellenkalkulation.
Die laufenden Daten liegen in der .pvs-Datei des Slots, namensbasiert gespeichert. Eine Sicherung ist genau diese eine Datei: wegkopieren, zurückkopieren, Slot neu starten. /sml_chart.bin wird nur einmal beim Start gelesen, zum Übernehmen von Daten aus einer älteren Version.
Der Export funktioniert auch, während der Zähler schweigt — das ist Absicht, denn ein ausgefallener Zähler ist genau der Moment, in dem die gespeicherten Daten zählen.
Diagramme brauchen die Uhr. Bevor das Gerät NTP-Zeit hat (2020), wird nichts aufgezeichnet.
Default OFF. Switched ON, the script publishes a heavily smoothed power value every 5 s and serves it over HTTP as well.
stat/<topic>/script/power2 | Smoothed power [W]. Exponential average, 10 % new value per step — slow on purpose. |
|---|---|
stat/<topic>/script/cpwr | Emulator variants only: the value handed to the battery, after offset and shaping. |
/pwr{"power2":-217,"cpwr":-180,"power":-440,"in":26714.950,"out":659.775}
For a second battery that polls over HTTP instead of listening for a meter — opendtu-onbattery's dynamic power limiter, for example. With telemetry off the endpoint answers {"enabled":0}.
Why smoothed: a battery that follows every spike swings. power is the raw value, power2 the calm one.
Standard AUS. Auf EIN veröffentlicht das Script alle 5 s einen stark gemittelten Leistungswert und liefert ihn zusätzlich über HTTP.
stat/<topic>/script/power2 | Gemittelte Leistung [W]. Exponentieller Mittelwert, 10 % neuer Wert pro Schritt — absichtlich träge. |
|---|---|
stat/<topic>/script/cpwr | Nur Emulator-Varianten: der Wert, den der Akku bekommt, nach Offset und Regleroptimierung. |
/pwr{"power2":-217,"cpwr":-180,"power":-440,"in":26714.950,"out":659.775}
Für einen zweiten Akku, der über HTTP pollt statt auf einen Zähler zu horchen — zum Beispiel der Dynamic Power Limiter von opendtu-onbattery. Bei ausgeschalteter Telemetrie antwortet der Endpunkt mit {"enabled":0}.
Warum gemittelt: ein Akku, der jeder Spitze folgt, schwingt. power ist der Rohwert, power2 der ruhige.
Der aktuelle gefilterte Wert steht in diesem Abschnitt auf der Einstellungsseite. Früher stand er als Leistung (gefiltert) auf der Hauptseite und ist hierher gewandert, neben den Schalter, der ihn versendet.
Die Publishes tragen Log-Stufe 3: bei weblog 2 bleibt die Konsole ruhig, ab weblog 3 werden sie sichtbar, ohne neu zu übersetzen. Ein fehlgeschlagener Publish wird einmal mit Rückgabewert protokolliert — -2 heißt, MQTT ist auf dem Gerät abgeschaltet (SetOption3).
Default OFF. Switched ON, the device is a Modbus-TCP slave (server) and any client can read the meter.
| Address | 4x reference | Value | Unit |
|---|---|---|---|
| 0 | 40001 | Power | W |
| 2 | 40003 | Import | kWh |
| 4 | 40005 | Export | kWh |
Two numbering conventions exist for the same registers, which is the usual source of an illegal data address. The left column is the address that goes on the wire; the right one is the 4x notation that counts from 1.
Modbus Poll counts from 0 unless PLC addresses (base 1) is ticked — then it shows the 4x references instead.
| Function | 03 Read Holding Registers |
|---|---|
| Address | 0 (or 40001 with PLC addresses) |
| Quantity | 2 for one value, 6 for all three |
The reply arrives as single 16-bit registers. To see a real number, select the two registers that belong to one value, then Format → 32-bit Float Big-Endian.
Two registers per value, 32-bit IEEE-754 float, big-endian. Holding registers, FC03 only. Reads must start on a value boundary and cover whole values.
Port 502 is standard. Change it if something else on the device already uses it. The change takes effect within a second, no reboot.
Anything outside the map is answered properly: a wrong function code gives exception 01, a bad address exception 02, and an odd or oversized quantity exception 03. A quantity of 1 is therefore refused — half a float is not a value.
Standard AUS. Auf EIN ist das Gerät ein Modbus-TCP-Slave (Server), und jeder Client kann den Zähler lesen.
| Adresse | 4x-Bezeichnung | Wert | Einheit |
|---|---|---|---|
| 0 | 40001 | Leistung | W |
| 2 | 40003 | Bezug | kWh |
| 4 | 40005 | Einspeisung | kWh |
Für dieselben Register gibt es zwei Zählweisen, und daher kommt fast jedes illegal data address. Links steht die Adresse, die auf die Leitung geht, rechts die 4x-Schreibweise, die ab 1 zählt.
Modbus Poll zählt ab 0, solange PLC addresses (base 1) nicht angehakt ist — mit Haken zeigt es die 4x-Bezeichnungen.
| Function | 03 Read Holding Registers |
|---|---|
| Address | 0 (mit PLC addresses 40001) |
| Quantity | 2 für einen Wert, 6 für alle drei |
Die Antwort kommt als einzelne 16-Bit-Register. Damit eine echte Zahl erscheint, die zwei zusammengehörenden Register markieren und dann Format → 32-Bit Float Big-Endian wählen.
Zwei Register je Wert, 32-Bit-IEEE-754-Float, big-endian. Holding-Register, nur FC03. Ein Lesezugriff muss auf einer Wertgrenze beginnen und ganze Werte umfassen.
Port 502 ist Standard. Nur ändern, wenn ihn auf dem Gerät schon etwas anderes benutzt. Die Änderung greift innerhalb einer Sekunde, ohne Neustart.
Alles außerhalb der Tabelle wird sauber beantwortet: falscher Funktionscode gibt Exception 01, falsche Adresse Exception 02, eine ungerade oder zu große Anzahl Exception 03. Quantity 1 wird deshalb abgelehnt — ein halber Float ist kein Wert.
Each program keeps its settings in its own .pvs — the name is derived from the .tcb, so switching programs used to start from scratch: no meter, no pins, no language, and the day/month/year totals back at zero. /tc_options.cfg sits beside them and is shared by all of them.
# tc_options - shared by all programs
@ui_de=1
@sml_meter_sel=89
@sml_rx_pin=3
@sml_tx_pin=1
@sml_ph3=1
@es_mode=2
@sml_da=3
@chart_short=240
@imp_day=26714.950
@exp_day=659.775
One @name=value per line. A program reads the keys it knows and carries the rest through untouched, so running sml_simple for a while does not throw away the emulator's settings — go back and they are still there.
ui_* | Language, power saving. |
|---|---|
sml_* | Meter, RX/TX pin, filter, phases, driver rows. |
es_* / ct_* / mb_* | Emulators and Modbus. |
chart_* | chart_short is the short-term chart's range in minutes (15, 30, 60, 120, 240) — minutes rather than a menu position, so the number says what it means. chart_onmain puts the charts on Tasmota's main page. |
imp_* / exp_* | The energy baselines in kWh: the zero points day, month and year totals are counted from. sml_da is the last-seen day of the month and belongs with them. |
Download the file, change it, upload it, then restart the script — in that order. It is read once at start; a running program holds the values in memory and would write yours back over at the next rollover.
The baselines are what you would correct: set imp_day to the meter reading at midnight and today's consumption is right again.
Do not delete the file to "reset" things — it is rebuilt from whatever the current program has in its own .pvs, which after a program change may be zeros.
The file is written when something actually changes: once when it is created, on a Save that changed a value, and when a baseline rolls over at midnight. Not on a timer — roughly one write a day.
Jedes Programm hält seine Einstellungen in einer eigenen .pvs — der Name wird aus der .tcb abgeleitet. Ein Programmwechsel fing deshalb bei null an: kein Zähler, keine Pins, keine Sprache, und die Tages-, Monats- und Jahreswerte zurück auf Anfang. /tc_options.cfg liegt daneben und gehört allen gemeinsam.
# tc_options - shared by all programs
@ui_de=1
@sml_meter_sel=89
@sml_rx_pin=3
@sml_tx_pin=1
@sml_ph3=1
@es_mode=2
@sml_da=3
@chart_short=240
@imp_day=26714.950
@exp_day=659.775
Eine Zeile @name=wert je Eintrag. Ein Programm liest die Schlüssel, die es kennt, und trägt alle anderen unverändert mit — läuft eine Weile sml_simple, überleben die Emulator-Einstellungen trotzdem und sind beim Zurückwechseln wieder da.
ui_* | Sprache, Energiesparmodus. |
|---|---|
sml_* | Zähler, RX-/TX-Pin, Filter, Phasen, Treiberzeilen. |
es_* / ct_* / mb_* | Emulatoren und Modbus. |
chart_* | chart_short ist die Zeitspanne des Kurzzeit-Diagramms in Minuten (15, 30, 60, 120, 240) — Minuten statt einer Menüposition, damit die Zahl sagt, was sie bedeutet. chart_onmain legt die Diagramme auf Tasmotas Hauptseite. |
imp_* / exp_* | Die Basiswerte in kWh: die Nullpunkte, von denen Tages-, Monats- und Jahressumme aus gezählt werden. sml_da ist der zuletzt gesehene Monatstag und gehört dazu. |
Datei herunterladen, ändern, hochladen, dann das Script neu starten — in dieser Reihenfolge. Gelesen wird sie einmal beim Start; ein laufendes Programm hält die Werte im Speicher und schriebe deine Korrektur beim nächsten Umbruch wieder weg.
Zu korrigieren sind vor allem die Basiswerte: imp_day auf den Zählerstand um Mitternacht gesetzt, und der Tagesverbrauch stimmt wieder.
Die Datei nicht löschen, um etwas „zurückzusetzen“ — sie wird aus dem neu aufgebaut, was das gerade laufende Programm in seiner eigenen .pvs stehen hat, und das können nach einem Programmwechsel Nullen sein.
Geschrieben wird nur, wenn sich wirklich etwas ändert: einmal beim Anlegen, bei einem Speichern mit geändertem Wert, und wenn um Mitternacht ein Basiswert umspringt. Nicht im Takt — also etwa einmal am Tag.
| All values 0 | Check Meter active, then the pins, then the descriptor. Show driver rows on tells you whether the driver is producing anything at all. |
|---|---|
| Power has the wrong sign | Import and export are swapped in the descriptor. Feed-in must be negative. |
| Values jump | Switch the filter on. If it stays wild, the reading head is sitting badly. |
| Charts stay empty | No NTP time yet, or the baselines were never initialised. See chart data. |
| Settings lost after reboot | Settings are written when they change and at program stop. A power cut in between can cost the last change. |
| Modbus does not answer | Check the port, and whether the network was up when the program started. weblog 4 shows the bind. |
| Alle Werte 0 | Erst Zähler aktiv prüfen, dann die Pins, dann den Descriptor. Treiberzeilen zeigen an verrät, ob der Treiber überhaupt etwas liefert. |
|---|---|
| Leistung mit falschem Vorzeichen | Bezug und Einspeisung sind im Descriptor vertauscht. Einspeisung muss negativ sein. |
| Werte springen | Filter einschalten. Bleibt es unruhig, sitzt der Lesekopf schlecht. |
| Diagramme bleiben leer | Noch keine NTP-Zeit, oder die Basiswerte wurden nie initialisiert. Siehe Diagrammdaten. |
| Einstellungen nach Neustart weg | Einstellungen werden bei Änderung und beim Programmende geschrieben. Ein Stromausfall dazwischen kann die letzte Änderung kosten. |
| Modbus antwortet nicht | Port prüfen und ob das Netzwerk beim Programmstart schon stand. weblog 4 zeigt das Binden. |