Zum Inhalt springen
Smart laden

Plugins

Plugins lesen und schreiben einzelne Werte an einem Gerät, z. B. eine Leistungsmessung, einen Zielstrom oder einen Freigabebefehl. Sie stecken hinter den mitgelieferten Geräte-Templates und werden direkt referenziert, wenn du ein benutzerdefiniertes Gerät vom Typ type: custom aufbaust.

Plugins können für folgende Kategorien verwendet werden:

Auch Benachrichtigungen nutzen Plugins, um Lebenszyklus-Ereignisse zu versenden.

  • GPIO-Plugin: Plugin für den direkten Zugriff auf GPIO-Pins (nur Linux).
  • Go-Plugin: Plugin, das Werte über ein Go-Skript bereitstellt oder entgegennimmt.
  • HTTP-Plugin: Plugin, das über eine HTTP-API mit Endgeräten kommuniziert.
  • JavaScript-Plugin: Plugin, das Werte über ein JavaScript-Skript bereitstellt oder entgegennimmt.
  • Modbus-Plugin: Plugin zum Auslesen eines Modbus-fähigen Geräts.
  • MQTT-Plugin: Plugin, um indirekt über MQTT mit MQTT-fähigen Geräten zu kommunizieren.
  • Prometheus-Plugin: Plugin zum Lesen von Metriken aus Prometheus über PromQL.
  • Shell-Plugin: Plugin, das ein Shell-Skript ausführt, um Daten zu extrahieren oder zu schreibende Daten entgegenzunehmen.
  • SMA/Speedwire-Plugin: Plugin speziell für SMA-Geräte, die über das Speedwire-Protokoll kommunizieren.
  • Websocket-Plugin: Plugin zum Empfangen von Gerätedaten über einen eigenen Webserver. Kann nur zum Lesen von Daten genutzt werden.
  • Calc-Plugin: Meta-Plugin, um Ausgaben anderer Plugins arithmetisch zu verknüpfen.
  • Combined-Plugin: Meta-Plugin speziell für charger, um die booleschen Statuswerte für den angeschlossenen (plugged) und ladenden (charging) Zustand zu einem einzigen Ladestatus zu kombinieren.
  • Const-Plugin: Spezielles Plugin, das einfach einen konstanten Wert zurückgibt.
  • Error-Plugin: Spezielles Plugin, das einen bekannten Fehlerwert zurückgibt.
  • Convert-Plugin: Meta-Plugin zur Datentyp-Konvertierung beim Schreiben (z. B. float zu int).
  • Delta-Plugin: Meta-Plugin zur Umwandlung absoluter Werte in Änderungswerte (Deltas) beim Schreiben.
  • Ignore-Plugin: Meta-Plugin zum Unterdrücken bestimmter Fehlermeldungen.
  • IfElse-Plugin: Meta-Plugin für bedingte Schreibvorgänge mit zwei Zweigen (if/else).
  • Map-Plugin: Meta-Plugin zur Übersetzung von Integer-Werten (z. B. gerätespezifische Modi in evcc-Modi).
  • Meter-Plugin: Plugin, um einen anderen Zähler als Datenquelle zu verwenden.
  • Sequence-Plugin: Meta-Plugin zur sequenziellen Ausführung mehrerer Schreibvorgänge.
  • Sleep-Plugin: Hilfsplugin zum Verzögern von Aktionen (wird meist mit Sequence verwendet).
  • Switch-Plugin: Meta-Plugin für bedingte Schreibvorgänge abhängig von Eingabewerten (wie switch/case).
  • Valid-Plugin: Meta-Plugin, um Plugin-Werte anhand einer booleschen Validierung bereitzustellen.
  • Watchdog-Plugin: Meta-Plugin zur automatischen Wiederholung von Schreibvorgängen in regelmäßigen Abständen.

Ein Plugin wird an ein Attribut eines Geräts gehängt. Der Attributname (z. B. power, enable, soc) bestimmt die Rolle, source wählt den Plugin-Typ. Die übrigen Schlüssel sind Parameter des jeweiligen Plugins.

<attribut>:
source: <plugin>
<p-attr1>: ...
<p-attr2>: ...

Jedes Plugin wird entweder in einem lesenden oder einem schreibenden Kontext verwendet. Einige Parameter sind nur in einem der beiden Modi sinnvoll. Die vollständigen Attributlisten für Zähler, Wallboxen, Fahrzeuge und Tarife findest du auf der Seite Benutzerdefinierte Geräte.

Beim Lesen von Daten mithilfe eines Plugins können sogenannte Pipelines verwendet werden. Damit lassen sich gezielt einzelne Werte aus der Ausgabe des Plugins extrahieren. Dies ermöglicht es, komplexe Datenstrukturen wie JSON oder XML zu verarbeiten und die benötigten Informationen herauszufiltern. Mögliche Parameter für die Datenextraktion sind:

  • regex: Ein regulärer Ausdruck, um Werte aus dem empfangenen Text zu extrahieren.
  • jq: Ein jq-Ausdruck, um Werte aus JSON-Strukturen zu extrahieren. Die vollständige Syntax und alle Möglichkeiten findest du in der jq-Dokumentation.
  • quote: Boolescher Wert. Wenn er gesetzt ist, werden die Eingabedaten in Anführungszeichen gesetzt, bevor sie an jq weitergegeben werden. Dadurch kann jq Strings ohne Anführungszeichen (z. B. von MQTT) verarbeiten. Bei einem MQTT-Wert wie Charging kannst du quote: true und jq: '. == "Charging"' verwenden.
  • unpack: Konvertiert Werte aus anderen Zahlenrepräsentationen, z. B. hex.
  • decode: Dekodiert Binärformate wie uint32, float32 usw.

HTTP-, MQTT- und Websocket-Plugins können spezielle Fehlerwerte als String zurückgeben. evcc erkennt diese und wandelt sie in interne Fehlercodes um, anstatt sie als Daten zu behandeln. Das ist z. B. nützlich für benutzerdefinierte Fahrzeugintegrationen, bei denen die Datenquelle den Zustand des Fahrzeugs kennt.

  • ErrAsleep: Fahrzeug schläft. evcc kann das Fahrzeug dann wecken und es erneut versuchen.
  • ErrMustRetry: Vorgang soll erneut versucht werden (z. B. bei Rate-Limiting).
  • ErrNotAvailable: Wert ist nicht verfügbar. evcc behandelt dies als permanenten Fehler bis zum nächsten Neustart.

Wenn ein Plugin den String ErrAsleep als Antwort liefert, erzeugt evcc intern den entsprechenden Fehler. Das Error-Plugin nutzt denselben Mechanismus, um einen festen Fehlerwert als Konstante zurückzugeben.

Beim Schreiben können Parameter in der Konfiguration Platzhalter enthalten. Die Daten werden in Form von ${var[:format]} zur Verfügung gestellt. Wenn kein Format angegeben ist, werden die Daten im Go-Standardformat %v bereitgestellt. Die Variablen werden durch den entsprechenden Wert ersetzt, bevor das Plugin ausgeführt wird. Zusätzlich können sämtliche Funktionen der Go-Template-Bibliothek verwendet werden, um komplexere Datentransformationen durchzuführen.

GPIO lesen schreiben

Abschnitt betitelt „GPIO “

Das gpio-Plugin ermöglicht den direkten Zugriff auf GPIO-Pins (General Purpose Input/Output) unter Linux. Es eignet sich besonders für den Raspberry Pi und ähnliche Einplatinencomputer.

Parameter:

ParameterTypErforderlichBeschreibung
functionstringjaModus: read (Eingang) oder write (Ausgang)
pinintjaPin-Nummer (BCM-Nummerierung, z. B. GPIO 17)

Funktionsweise:

  • Lesen (function: read): Liest den Zustand eines GPIO-Pins als booleschen Wert (true = HIGH, false = LOW)
  • Schreiben (function: write): Setzt einen GPIO-Pin auf HIGH (true) oder LOW (false)

Eingänge nutzen immer den internen Pull-up-Widerstand, daher wird ein Schaltkontakt zwischen Pin und Masse (GND) angeschlossen. Ein offener Kontakt ergibt true (HIGH), ein geschlossener false (LOW). Für ein Begrenzungssignal nutze den Öffnerkontakt (NC) des Relais. Im Normalbetrieb ist der Kontakt geschlossen und der Pin liefert false. Wird die Begrenzung aktiviert, öffnet der Kontakt und der Pin liefert true. Auch ein Kabelbruch ergibt true, sodass die Begrenzung ausfallsicher greift.

Die Pin-Nummerierung folgt dem BCM-Schema (Broadcom-Nummern, nicht die physische Pin-Position). Eine Pinbelegung des Raspberry Pi findest du z. B. auf pinout.xyz.

Beispiel Lesen:

source: gpio
function: read
pin: 17 # BCM-Pin-Nummer

Beispiel Schreiben:

source: gpio
function: write
pin: 27 # BCM-Pin-Nummer

Das go-Plugin verwendet den Interpreter Yaegi, um Go-Code zur Laufzeit auszuführen. Es ist besonders nützlich für typsichere Berechnungen und komplexe Datenverarbeitungslogik.

Folgende Go-Pakete stehen automatisch zur Verfügung und müssen nicht importiert werden:

  • fmt: Formatierte Ein-/Ausgabe
  • math: Mathematische Funktionen
  • strings: String-Manipulation
  • time: Zeit- und Datumsfunktionen

Beispiel Lesen:

source: go
script: |
res := 500.0
res * 2 // liefert 1000.0

Beispiel mit Zeitfunktionen:

source: go
script: |
hour := time.Now().Hour()
price := 50.0 // Nachttarif
if hour >= 9 && hour < 17 {
price = 100.0 // Tarifpreis während der Geschäftszeiten
}
price // liefert 50.0 oder 100.0 je nach Tageszeit

Beispiel mit String-Verarbeitung:

source: go
script: |
text := "hello world"
strings.ToUpper(text) // liefert "HELLO WORLD"

Wenn das go-Plugin zum Schreiben verwendet wird, wird der zu schreibende Wert dem Skript als Variable übergeben:

Beispiel Schreiben:

maxcurrent:
source: go
script: |
fmt.Printf("Setze Ladestrom: %d A\n", maxcurrent)
// Variable maxcurrent ist automatisch verfügbar

Die Plugins go und js unterstützen die Parameter in und out, um Werte aus anderen Quellen als Variablen im Skript zu verwenden oder das Skriptergebnis an andere Plugins weiterzuleiten.

Mit dem Parameter in kannst du Werte aus anderen Quellen als Variablen in deinem Skript verwenden. Jeder Eintrag benötigt name (Variablenname im Skript), type (bool, int, float, string) und config (Plugin-Konfiguration).

Dieses Beispiel zeigt eine bedingte Logik, die mit den einfachen Calc-Operationen nicht möglich ist:

power:
source: go
script: |
// Leistung abhängig von Ladestand und Standby
power := 5000.0 // normal
if standby {
power = 0.0 // im Standby keine Last
} else if soc < 20.0 {
power = 1000.0 // niedrig
}
power // liefert 5000.0 (standby=false, soc>=20)
in:
- name: soc
type: float
config:
source: const
value: 85.0
- name: standby
type: bool
config:
source: const
value: false

Der Parameter out leitet das Skriptergebnis an andere Plugins weiter. Das ist besonders im Schreibkontext nützlich, z. B. wenn das Skriptergebnis per MQTT oder HTTP weiterverarbeitet werden soll. Jeder Eintrag benötigt name, type und config, analog zu in.

maxcurrent:
source: go
script: |
watts := maxcurrent * 230
watts
out:
- name: watts
type: float
config:
source: mqtt
topic: heater/target_power

HTTP lesen schreiben

Abschnitt betitelt „HTTP “

Das http-Plugin führt HTTP-Aufrufe aus, um Daten zu lesen oder zu aktualisieren. Außerdem kann es JSON-Datenstrukturen (z. B. von REST-APIs) per jq-Abfrage auslesen und einfach umformen. Der volle Funktionsumfang ist in der offiziellen jq-Dokumentation beschrieben.

Als Authentifizierungsmethoden stehen basic, bearer und digest zur Verfügung. Die Namen der jeweiligen Parameter finden sich hier.

Für HTTP-Anfragen stehen verschiedene Authentifizierungsmethoden zur Verfügung:

Basic-Authentifizierung:

auth:
type: basic
user: <benutzername>
password: <passwort>

Bearer-Token (z. B. für JWT):

auth:
type: bearer
token: <token>

Digest-Authentifizierung:

auth:
type: digest
user: <benutzername>
password: <passwort>

Benutzerdefinierte Authentifizierung:

Für komplexere Authentifizierungsszenarien können benutzerdefinierte Authentifizierungs-Plugins entwickelt werden. Diese werden über den Parameter source eingebunden:

auth:
source: <plugin-name>
user: <benutzername>
password: <passwort>
# weitere plugin-spezifische Parameter

Dies ermöglicht die Integration von Geräten mit speziellen Authentifizierungsanforderungen, ohne den gesamten HTTP-Plugin-Code anpassen zu müssen.

Beispiel Lesen:

source: http
uri: https://volkszaehler/api/data/<uuid>.json?from=now
method: GET # Standard-HTTP-Methode
headers:
- content-type: application/json
auth: # Basic-Authentifizierung
type: basic
user: foo
password: bar
insecure: false # auf true setzen, um selbstsignierten Zertifikaten zu vertrauen
jq: .data.tuples[0][1] # JSON-Antwort auswerten
scale: 0.001 # Faktor für das Ergebnis, z. B. zur Umrechnung von W in kW
cache: 60s # Cache-Dauer der Antwort
timeout: 10s # Timeout im Go-Duration-Format, siehe https://golang.org/pkg/time/#ParseDuration
source: http
uri: http://charger/status
jq: .total_power > 10 # wandelt eine JSON-Ganzzahl in einen booleschen Wert um

Beispiel Schreiben:

body: %v # nur bei PUT- oder POST-Anfragen
enable:
source: http
uri: "http://charger/relay/0?turn={{if .enable}}on{{else}}off{{end}}"

Dynamische URIs:

uri und body sind Go-Templates, die bei jeder Anfrage neu ausgewertet werden. Neben den sprig-Funktionen stehen addDate und timeRound zur Verfügung. Damit lässt sich z. B. eine Vorhersage-API immer für einen gleitenden Zeitraum abfragen:

forecast:
source: http
uri: https://api.example.org/forecast?from={{ now | date "2006-01-02" }}&to={{ addDate now 0 0 2 | date "2006-01-02" }}

JavaScript lesen schreiben

Abschnitt betitelt „JavaScript “

evcc integriert einen JavaScript-Interpreter mit der Bibliothek Underscore.js, die direkt über _. erreichbar ist, z. B. _.random(0,5). Das js-Plugin kann JavaScript-Code über den Parameter script ausführen. Das ist besonders für schnelles Prototyping hilfreich:

Beispiel Lesen:

source: js
script: |
var res = 500;
2 * res; // liefert 1000

Wenn das js-Plugin zum Schreiben verwendet wird, wird der zu schreibende Wert dem Skript als Variable übergeben:

Beispiel Schreiben:

maxcurrent:
source: js
script: |
console.log(maxcurrent);

Das js-Plugin unterstützt dieselben Input- und Output-Transformationen (in/out) wie das go-Plugin.

Modbus lesen schreiben

Abschnitt betitelt „Modbus “

Das modbus-Plugin kann Daten von jedem Modbus-fähigen Gerät oder SunSpec-kompatiblen Wechselrichter lesen. Viele Zähler sind bereits vorkonfiguriert (siehe MBMD Supported Devices). Außerdem lassen sich Modbus-Register schreiben, um weitere Wallboxen einzubinden.

Beispiel:

source: modbus
id: 1
uri: 192.168.1.10:502
register:
address: 300
type: holding
decode: uint16

Weitere Details findest du in der Modbus-Dokumentation.

MQTT lesen schreiben

Abschnitt betitelt „MQTT “

Das mqtt-Plugin ermöglicht das Lesen von Werten über MQTT-Topics. Das ist besonders für Zähler nützlich, z. B. wenn diese ihre Daten bereits über MQTT bereitstellen. Ein Beispiel, wie Modbus-Messdaten nach MQTT gelangen, findest du in der MBMD-Dokumentation.

Parameter (Lesen):

ParameterTypErforderlichBeschreibung
topicstringjaMQTT-Topic zum Lesen
timeoutdurationneinMaximales Alter empfangener Werte
scalefloatneinSkalierungsfaktor für das Ergebnis (z. B. 0,001 zur Umrechnung von Wh in kWh)

Das Plugin gibt einen Fehler zurück, wenn innerhalb der mit timeout festgelegten Zeit kein neuer Wert empfangen wurde. Wenn timeout nicht gesetzt ist, werden Werte beliebigen Alters akzeptiert, sobald die erste Nachricht empfangen wurde. Es wird empfohlen, einen Timeout zu setzen, um zu erkennen, wenn die Quelle keine aktuellen Daten mehr liefert.

Für die Datenextraktion stehen die unter Lesen beschriebenen Pipeline-Parameter zur Verfügung (regex, jq, quote usw.).

Beispiel Lesen:

source: mqtt
topic: mbmd/sdm1-1/Power
timeout: 30s # Werte älter als timeout nicht akzeptieren
scale: 0.001 # Faktor für das Ergebnis, z. B. zur Umrechnung von Wh in kWh

Parameter (Schreiben):

ParameterTypErforderlichBeschreibung
topicstringjaMQTT-Topic zum Schreiben
payloadstringneinPayload-Template (verwendet Wert im Standardformat, wenn nicht gesetzt)

Für den Schreibzugriff werden die Daten mit dem Attribut payload bereitgestellt. Falls dieser Parameter in der Konfiguration fehlt, wird der Wert im Standardformat geschrieben.

Beispiel Schreiben:

source: mqtt
topic: mbmd/charger/maxcurrent
payload: ${var:%d}

Das prometheus-Plugin liest Metriken aus einer Prometheus-Instanz über PromQL-Abfragen. Dies ist nützlich, wenn bereits Monitoring-Daten in Prometheus vorliegen, die in evcc verwendet werden sollen.

Parameter:

ParameterTypErforderlichBeschreibung
uristringjaURL des Prometheus-Servers
querystringjaPromQL-Abfrage
timeoutdurationneinTimeout (Standard: 2 Minuten)

Unterstützte Abfrageergebnisse:

  • Scalar: Ein einzelner Zahlenwert
  • Vector: Ein Vektor mit genau einem Metrik-Eintrag

Beispiel:

power:
source: prometheus
uri: http://prometheus.local:9090
query: "sum(household_power_watts)"
timeout: 30s

Beispiel mit Zeitbereich:

energy:
source: prometheus
uri: http://prometheus.local:9090
query: "increase(energy_total_kwh[1h])"

Die Abfrage muss einen einzelnen numerischen Wert zurückgeben. Bei Vektor-Ergebnissen muss genau eine Metrik enthalten sein.

Shell-Skript lesen schreiben

Abschnitt betitelt „Shell-Skript “

Das script-Plugin führt externe Skripte aus, um Daten zu lesen oder zu aktualisieren. Damit lassen sich beliebige externe Funktionen einbinden.

Beispiel Lesen:

source: script
cmd: /bin/bash -c "cat /dev/urandom"
timeout: 5s

Beispiel Schreiben:

source: script
cmd: /home/user/my-script.sh ${enable:%b} # booleschen Wert enable als 0/1 formatieren
timeout: 5s

Das sma-Plugin bietet eine Schnittstelle zu SMA-Geräten, die das Speedwire-Protokoll unterstützen.

Beispiel Lesen:

source: sma
uri: 192.168.4.51 # Alternative zu serial
serial: 123456 # Alternative zu uri
value: ActivePowerPlus # ID des zu lesenden Werts
password: "0000" # optional (Standard: 0000)
interface: eth0 # optional
scale: 1 # optionaler Skalierungsfaktor für den Wert

Unterstützte Werte für value findest du in der Diagnoseausgabe des Befehls evcc meter (bei konfigurierten SMA-Geräten vom Typ meter).

Alle möglichen Werte sind hier als Konstanten aufgeführt (verwende den Namen der Konstante für value).

Das websocket-Plugin bietet einen WebSocket-Listener. Außerdem kann es JSON-Datenstrukturen über jq-ähnliche Abfragen auslesen. Damit lassen sich z. B. Daten vom Volkszähler-Push-Server empfangen.

Für die Datenextraktion stehen die unter Lesen beschriebenen Pipeline-Parameter zur Verfügung (regex, jq, quote usw.).

Beispiel Lesen:

source: http
uri: ws://<volkszaehler host:port>/socket
jq: .data | select(.uuid=="<uuid>") .tuples[0][1] # JSON-Nachricht auswerten
scale: 0.001 # Faktor für das Ergebnis, z. B. zur Umrechnung von Wh in kWh
timeout: 30s # Fehler, wenn 30 Sekunden lang kein Update empfangen wird

Das calc-Plugin erlaubt es, mehrere Einzelwerte mathematisch weiterzuverarbeiten:

Beispiel Lesen:

source: calc
add:
- source: ...
...
- source: ...
...
source: calc
mul:
- source: calc
sign:
source: ... (power)
...
- source: ... (current)
...

Unterstützt werden die Operationen Addition (add), Multiplikation (mul), Division (div), Vorzeichenumkehr (sign), Absolutwert (abs), Minimum (min) und Maximum (max).

Mit scale: -1 bei einem der Werte kann eine einfache Subtraktion durchgeführt werden, mit scale: 0.001 eine Division, z. B. zur Umrechnung von Wh in kWh.

Mit sign: wird jede positive Zahl zu +1, jede negative zu -1, und 0 bleibt 0. In Verbindung mit mul lassen sich so Vorzeichen auf andere Werte übertragen. So lässt sich z. B. bei Zählern die Richtung der Leistung (Einspeisung oder Netzbezug) auf die gemessenen Ströme übertragen.

Mit abs: wird der Absolutwert einer Zahl berechnet.

Mit min: und max: wird der Minimalwert bzw. der Maximalwert berechnet.

Das calc-Plugin ist hilfreich, um z. B.

  • Leistungswerte einzelner PV-Strings zu summieren (addieren)
  • die Scheinleistung aus Spannung und Strom zu berechnen (multiplizieren)
  • getrennte Leistungswerte für Netzbezug und Einspeisung zu einem vorzeichenbehafteten Einzelwert zu kombinieren (subtrahieren)
  • prozentuale Füllstände zu berechnen (dividieren)
  • die richtige Richtung des Stromflusses zu bestimmen (sign)
  • bekannte Offsets zu eliminieren (addieren mit dem const-Plugin)

Das combined-Plugin fasst die booleschen Statuswerte Plugged (angeschlossen) und Charging (lädt) zu einem evcc-kompatiblen Ladestatus A bis F zusammen. Es wird z. B. zusammen mit einer OpenWB-MQTT-Integration verwendet.

Beispiel Lesen:

source: combined
plugged:
source: mqtt
topic: openWB/lp/1/boolPlugStat
charging:
source: mqtt
topic: openWB/lp/1/boolChargeStat

Das const-Plugin gibt einen konstanten Wert zurück. Es eignet sich z. B. dazu, in Verbindung mit dem calc-Plugin feste Korrekturwerte (Offset) auf einen variablen Wert anzuwenden oder Mess- und Statuswerte zu Testzwecken zu simulieren.

Beispiel Lesen:

source: const
value: -16247

Das error-Plugin gibt immer einen bekannten Fehlerwert zurück. Es ist nützlich, um ein nicht implementiertes Attribut explizit als nicht verfügbar zu kennzeichnen.

Parameter:

ParameterTypErforderlichBeschreibung
errorstringjaFehlerwert (ErrAsleep, ErrMustRetry oder ErrNotAvailable)

Beispiel:

soc:
source: error
error: ErrNotAvailable

Das convert-Plugin konvertiert Datentypen beim Schreiben. Es wird verwendet, wenn ein Plugin einen anderen Datentyp erwartet, als evcc liefert.

Parameter:

ParameterTypErforderlichBeschreibung
convertstringjaKonvertierungstyp
setconfigjaPlugin zum Schreiben nach Konvertierung

Unterstützte Konvertierungen:

KonvertierungBeschreibung
float2intFloat64 → Int64 (Nachkommastellen werden abgeschnitten)
int2floatInt64 → Float64
int2bytesInt64 → Byte-Array (Big Endian, 8 Bytes)
bool2intBool → Int64 (true=1, false=0)

Beispiel (evcc liefert float, Gerät erwartet int):

limitsoc:
source: convert
convert: float2int
set:
source: modbus
uri: 192.168.1.10:502
id: 1
register:
address: 41009
type: writesingle
encoding: uint16

In diesem Beispiel konvertiert evcc einen Float-Wert wie 85.5 in 85, bevor er in das Modbus-Register geschrieben wird.

Das delta-Plugin wandelt absolute Werte in Änderungswerte (Deltas) um. Es wird für Geräte verwendet, die geschriebene Werte zu einem internen Summenwert addieren, anstatt sie direkt zu setzen.

Parameter:

ParameterTypErforderlichBeschreibung
getconfigneinPlugin zum Lesen des aktuellen Gesamtwerts vom Gerät
setconfigjaPlugin zum Schreiben des berechneten Deltas

Funktionsweise:

  1. Der Eingabewert wird empfangen (z. B. 1000)
  2. Falls get konfiguriert ist, wird der aktuelle Gesamtwert vom Gerät gelesen
  3. Das Delta wird berechnet: delta = new_value - current_total
  4. Das Delta wird über das set-Plugin geschrieben
  5. Der interne Zustand wird aktualisiert

Ohne den Parameter get führt das Plugin den Gesamtwert intern (beginnend bei 0). Bei einem Neustart von evcc geht die Synchronisation mit dem Gerät verloren. Daher wird empfohlen, get zu konfigurieren, wenn das Gerät ein lesbares Summenregister bereitstellt.

Unterstützte Datentypen: int64, float64

Anwendungsfall:

Einige Wärmepumpen (z. B. Ochsner) haben Register, die Änderungswerte statt absolute Werte erwarten. Beim Schreiben von 500 addiert das Gerät 500 W zum internen Wert, anstatt ihn auf 500 W zu setzen. Um von 1000 W auf 1500 W zu erhöhen, muss +500 geschrieben werden. Um zu reduzieren, werden negative Werte geschrieben (z. B. -300).

Beispiel Schreiben:

setmaxpower:
source: delta
get: # Aktuellen Gesamtwert vom Gerät lesen
source: modbus
uri: 192.168.1.50:502
id: 50
register:
address: 2012 # Internes Summenregister des Geräts
type: input
decode: uint16
set: # Berechnetes Delta schreiben
source: modbus
uri: 192.168.1.50:502
id: 50
register:
address: 2201 # Delta-Register
type: writeholding
decode: uint16

Beispiel mit Watchdog:

Das Delta-Plugin wird häufig mit dem Watchdog-Plugin kombiniert, wenn das Gerät regelmäßige Updates benötigt:

setmaxpower:
source: watchdog
timeout: 60s # Erneutes Senden alle 30 Sekunden
set:
source: delta # Absolute Werte in Deltas umwandeln
get: # Aktuellen Gesamtwert lesen
source: modbus
uri: 192.168.1.50:502
id: 50
register:
address: 2012 # Summenwert-Register
type: input
decode: uint16
set: # Delta schreiben
source: modbus
uri: 192.168.1.50:502
id: 50
register:
address: 2201 # Delta-Register
type: writeholding
decode: uint16

Das ignore-Plugin unterdrückt bestimmte Fehlermeldungen beim Schreiben. Es wird verwendet, wenn ein Gerät harmlose Fehler zurückgibt, die ignoriert werden können.

Parameter:

ParameterTypErforderlichBeschreibung
errorstringjaPräfix der Fehlermeldung, das ignoriert werden soll
setconfigjaPlugin zum Schreiben

Funktionsweise:

  1. Das verschachtelte set-Plugin wird ausgeführt
  2. Falls ein Fehler auftritt, wird geprüft, ob die Fehlermeldung mit dem error-String beginnt
  3. Wenn ja, wird der Fehler ignoriert und der Schreibvorgang gilt als erfolgreich
  4. Wenn nein, wird der Fehler normal weitergegeben

Unterstützte Datentypen: int64, float64, bool, []byte

Beispiel:

batterymode:
source: switch
switch:
- case: 1 # normal
set:
source: const
value: 2
set:
source: ignore
error: "modbus: response data size '18' does not match count '4'"
set:
source: modbus
uri: 192.168.1.10:502
id: 1
register:
address: 0x1110
type: writemultiple
encoding: int16

In diesem Beispiel gibt das Gerät einen harmlosen Modbus-Fehler zurück, der ignoriert wird.

Das ifelse-Plugin führt bedingte Schreibvorgänge mit zwei Zweigen aus. Je nach Eingabewert wird entweder das if- oder das else-Plugin ausgeführt.

Parameter:

ParameterTypErforderlichBeschreibung
ifconfigjaPlugin, das bei erfüllter Bedingung ausgeführt wird
elseconfigjaPlugin, das bei nicht erfüllter Bedingung ausgeführt wird

Funktionsweise:

  • Bei bool-Werten: true führt if aus, false führt else aus
  • Bei int64-Werten: > 0 führt if aus, sonst else

Unterstützte Datentypen: int64, bool

Beispiel (unterschiedliche Endpunkte für Ein- und Ausschalten):

enable:
source: ifelse
if:
source: http
uri: http://device.local/api/on
method: POST
else:
source: http
uri: http://device.local/api/off
method: POST

Das map-Plugin übersetzt Integer-Werte in andere Integer-Werte mithilfe einer Lookup-Tabelle. Es wird häufig verwendet, um gerätespezifische Werte in evcc-Standardwerte zu konvertieren und umgekehrt.

Parameter:

ParameterTypErforderlichBeschreibung
valuesmap[int64]int64jaLookup-Tabelle, die Eingabewerte Ausgabewerten zuordnet
getconfigneinPlugin zum Lesen (nur beim Lesen erforderlich)
setconfigneinPlugin zum Schreiben (nur beim Schreiben erforderlich)

Funktionsweise:

Beim Lesen:

  1. Das get-Plugin liefert einen Wert (z. B. 0)
  2. Der Wert wird in der values-Tabelle nachgeschlagen
  3. Der zugeordnete Wert wird zurückgegeben (z. B. 0 → 2)

Beim Schreiben:

  1. Der Eingabewert wird empfangen (z. B. 3)
  2. Der Wert wird in der values-Tabelle nachgeschlagen
  3. Der zugeordnete Wert wird an das set-Plugin übergeben (z. B. 3 → 6)

Findet sich kein passender Wert in der Tabelle, meldet das Plugin einen Fehler.

Unterstützte Datentypen: int64 (nur Integer-Werte)

Beispiel Lesen (Gerätewert → evcc):

getmode:
source: map
values:
0: 2 # Gerät "Free" → evcc "normal"
1: 1 # Gerät "Forced off" → evcc "reduced"
2: 3 # Gerät "Recommended on" → evcc "boost"
3: 3 # Gerät "Forced on" → evcc "boost"
get:
source: modbus
uri: 192.168.1.10:502
id: 1
register:
address: 55
type: holding
encoding: int16

Beispiel Schreiben (evcc → Gerätewert):

setmode:
source: map
values:
1: 1 # evcc "reduced" → Gerät "Forced off"
2: 0 # evcc "normal" → Gerät "Free"
3: 3 # evcc "boost" → Gerät "Forced on"
set:
source: modbus
uri: 192.168.1.10:502
id: 1
register:
address: 55
type: writeholding
encoding: int16

Das meter-Plugin ermöglicht es, einen anderen Zähler als Datenquelle zu verwenden. Das ist nützlich, wenn du ein bestehendes Gerät für mehrere Messwerte verwenden möchtest oder für unterschiedliche Attribute verschiedene Methoden eines Geräts brauchst.

Der Abschnitt config enthält die vollständige Template-Konfiguration des einzubettenden Zählers. Der Parameter method bestimmt, welcher Wert gelesen wird: power, energy, returnenergy oder soc.

Beispiel Lesen:

meters:
- name: battery
type: custom
power:
source: meter
config:
type: template
template: shelly-1pm
host: 192.168.178.21
channel: 0
method: power
scale: -1
energy:
source: meter
config:
type: template
template: shelly-1pm
host: 192.168.178.21
channel: 0
method: energy
soc:
source: mqtt
topic: Haus/Batterie
jq: .soc
timeout: 60s

In diesem Beispiel dient ein Shelly 1PM als Datenquelle für Leistung und Energie einer Hausbatterie, während der Ladestand über MQTT abgerufen wird.

Das sequence-Plugin führt mehrere Schreibvorgänge nacheinander aus. Alle verschachtelten Plugins erhalten denselben Eingabewert und werden in der definierten Reihenfolge ausgeführt. Bei einem Fehler stoppt die Ausführung sofort.

Parameter:

ParameterTypErforderlichBeschreibung
set[config]jaArray von verschachtelten Plugin-Konfigurationen

Funktionsweise:

  1. Der Eingabewert wird empfangen
  2. Jedes Plugin in der set-Liste wird nacheinander mit diesem Wert aufgerufen
  3. Bei einem Fehler wird die Sequenz abgebrochen und der Fehler zurückgegeben
  4. Die Sequenz gilt nur dann als erfolgreich, wenn alle Plugins fehlerfrei durchgelaufen sind

Unterstützte Datentypen: int64, float64, bool

Anwendungsfälle:

  • Mehrere HTTP-Aufrufe nacheinander ausführen
  • Mit dem sleep-Plugin für zeitlich verzögerte Aktionen kombinieren
  • Mehrere Modbus-Register in einem Schritt schreiben
  • Werte an mehrere Ziele weitergeben

Beispiel 1: Mehrere HTTP-Aufrufe

setmode:
source: sequence
set:
- source: http
uri: http://device.local/api/pin1
method: POST
body: '{"value": "on"}'
- source: http
uri: http://device.local/api/pin4
method: POST
body: '{"value": "off"}'

Beispiel 2: Kombination mit switch

batterymode:
source: sequence
set:
- source: switch
switch:
- case: 1 # normal
set:
source: http
uri: http://battery.local/api/mode
body: "automatic"
- case: 3 # charge
set:
source: sequence
set:
- source: sleep
duration: 1s
- source: http
uri: http://battery.local/api/charge
body: "5000" # 5 kW
- source: mqtt
topic: home/battery/status
payload: "mode_${batterymode}"

Ablauf bei batterymode: 1 (normal):

  1. Äußere sequence empfängt Wert 1
  2. Erster Schritt: switch prüft den Wert 1
    • Fall 1 trifft zu → HTTP-Aufruf an /api/mode mit Body automatic
  3. Zweiter Schritt: mqtt sendet eine Nachricht an home/battery/status mit Payload mode_1
  4. Fertig

Ablauf bei batterymode: 3 (charge):

  1. Äußere sequence empfängt Wert 3
  2. Erster Schritt: switch prüft den Wert 3
    • Fall 3 trifft zu → Innere sequence wird ausgeführt:
      • 1 Sekunde warten (sleep)
      • HTTP-Aufruf an /api/charge mit Body 5000
  3. Zweiter Schritt: mqtt sendet eine Nachricht an home/battery/status mit Payload mode_3
  4. Fertig

Der Wert fließt durch alle Plugins, wobei switch abhängig vom Wert unterschiedliche Aktionen ausführt und mqtt am Ende immer eine Nachricht sendet.

Das sleep-Plugin fügt eine Verzögerung ein. Es wird typischerweise innerhalb eines sequence-Plugins verwendet, um zeitliche Abstände zwischen Aktionen zu schaffen.

Parameter:

ParameterTypErforderlichBeschreibung
durationdurationjaWartezeit (z. B. 1s, 500ms, 0s für keine Verzögerung)

Beispiel:

setmode:
source: sequence
set:
- source: http
uri: http://device.local/api/prepare
method: POST
- source: sleep
duration: 500ms
- source: http
uri: http://device.local/api/activate
method: POST

Das switch-Plugin führt bedingte Schreibvorgänge durch, ähnlich einer switch/case-Anweisung in Programmiersprachen. Je nach Eingabewert wird die entsprechende Aktion ausgeführt.

Parameter:

ParameterTypErforderlichBeschreibung
switch[case]jaListe von Fällen mit case- und set-Konfiguration
defaultconfigneinFallback-Plugin, wenn kein Fall zutrifft

Funktionsweise:

  1. Der Eingabewert wird mit den case-Werten verglichen
  2. Bei Übereinstimmung wird das entsprechende set-Plugin ausgeführt
  3. Falls kein Fall zutrifft und default definiert ist, wird dieses ausgeführt
  4. Falls kein Fall zutrifft und kein default definiert ist, meldet das Plugin einen Fehler

Unterstützte Datentypen: int64 (nur Integer-Werte)

Beispiel:

setmode:
source: switch
switch:
- case: 1 # reduced
set:
source: http
uri: http://device.local/api/mode
body: "eco"
- case: 2 # normal
set:
source: http
uri: http://device.local/api/mode
body: "normal"
- case: 3 # boost
set:
source: http
uri: http://device.local/api/mode
body: "boost"

Das valid-Plugin ermöglicht es, Plugin-Werte anhand einer booleschen Validierung bereitzustellen. Es trennt die Gültigkeit eines Werts von seinem eigentlichen Inhalt. Wenn die Validierung false zurückgibt, wird der Wert als nicht verfügbar betrachtet.

Dies ist besonders nützlich für Integrationen wie ioBroker, die Gültigkeit und Wert getrennt bereitstellen.

Beispiel Lesen:

source: valid
valid:
source: mqtt
topic: iobroker/wallbox/power/valid
value:
source: mqtt
topic: iobroker/wallbox/power/value

In diesem Beispiel wird der Wert nur verwendet, wenn das valid-Topic true zurückgibt. Wenn es false zurückgibt, wird der Wert als nicht verfügbar markiert.

Das watchdog-Plugin ist ein Wrapper-Plugin, das Schreibvorgänge automatisch in regelmäßigen Abständen wiederholt. Manche Geräte (z. B. Hausbatterien, Wechselrichter) erwarten, dass Steuerbefehle regelmäßig wiederholt werden, um aktiv zu bleiben. Das Watchdog-Plugin überwacht Schreibvorgänge und wiederholt sie automatisch jeweils nach Ablauf des halben Timeouts.

Parameter:

ParameterTypErforderlichBeschreibung
timeoutdurationjaZeitintervall für Wiederholungen (Wert wird alle timeout/2 erneut geschrieben)
resetstring | [string]neinWert(e), bei denen Wiederholungen gestoppt werden
initialstringneinWert, der beim Start einmalig geschrieben wird
deferboolneinVerzögert Updates, statt sie sofort auszuführen (Standard: false)
setconfigjaVerschachteltes Plugin für den eigentlichen Schreibvorgang

Funktionsweise:

  1. Start: Falls initial konfiguriert ist, wird dieser Wert beim Start einmalig geschrieben
  2. Schreiben: Wenn ein Wert geschrieben wird, prüft das Plugin, ob dieser in der reset-Liste steht
  3. Watchdog aktiv: Falls der Wert nicht in reset steht, startet der Watchdog und schreibt den Wert automatisch im halben timeout-Intervall erneut
  4. Watchdog stoppt: Falls der Wert in reset steht, werden keine Wiederholungen durchgeführt

reset-Parameter:

  • Definiert Werte, bei denen der Watchdog gestoppt wird
  • Kann ein einzelner Wert (reset: 0) oder mehrere Werte (reset: [0, 1]) sein
  • Typischerweise für sichere Zustände oder Standardzustände verwendet, die keine kontinuierliche Wiederholung benötigen

initial-Parameter:

  • Optionaler Wert, der beim Start des Plugins einmalig geschrieben wird
  • Nützlich, um einen definierten Startzustand zu setzen
  • Wird vor allen anderen Schreibvorgängen ausgeführt

defer-Parameter:

  • Stellt sicher, dass zwischen zwei Updates ein Mindestabstand eingehalten wird
  • Der Watchdog wird während der Verzögerung gestoppt und nach Ablauf mit dem neuen Wert neu gestartet
  • Sinnvoll, wenn Geräte eine Mindestwartezeit zwischen Modusänderungen benötigen
  • Die Verzögerung wird anhand der Zeit seit dem letzten Update berechnet
  • Reset-Werte werden immer sofort (ohne Verzögerung) geschrieben

Unterstützte Datentypen: int64, float64, bool

Beispiel Schreiben:

source: watchdog
timeout: 60s
reset: 0
set:
source: modbus
uri: 192.168.1.10:502
id: 1
register:
address: 100
type: writemultiple
encoding: uint16

In diesem Beispiel werden Werte automatisch alle 30 s wiederholt, außer wenn der Wert 0 geschrieben wird.

Ablaufbeispiel mit timeout: 60s, reset: 0:

  • Plugin startet
  • Wert 100 schreiben → Watchdog läuft, Wert wird alle 30 s wiederholt
  • Nach 2 Minuten: Wert 100 wurde 5-mal geschrieben (bei 0, 30, 60, 90 und 120 s)
  • Wert 200 schreiben → Watchdog läuft weiter, jetzt mit dem neuen Wert 200 alle 30 s
  • Wert 0 schreiben → Watchdog stoppt (da 0 in reset definiert ist)
  • Keine weiteren Wiederholungen, bis ein neuer Wert ungleich 0 geschrieben wird

Beispiel mit Batteriesteuerung (batterymode verwendet Werte 1=normal, 2=hold, 3=charge, 4=holdcharge, 5=discharge):

batterymode:
source: watchdog
timeout: 60s
reset: 1 # Wiederholungen im Normalbetrieb stoppen
set:
source: switch
switch:
- case: 1 # normal
set:
source: modbus
# ... Modbus-Konfiguration für Normalbetrieb
- case: 2 # hold
set:
source: modbus
# ... Modbus-Konfiguration für Haltemodus
- case: 3 # charge
set:
source: modbus
# ... Modbus-Konfiguration für Lademodus