
Als ich die PV-Anlage installiert habe, habe ich zwei Shelly Pro 3 EM installieren lassen. Jeweils dreiphasig misst einer den PV-Ertrag, der andere den Hausverbrauch. Das saldieren übernimmt openHAB.
Für Nachrüstspeicher ist das keine optimale Situation. Diese können oft mit einem Shelly interagieren – allerdings muss der Shelly direkt am Hausanschluss sitzen und für sich bereits Ertrag und Verbrauch saldieren. Physikalisch lässt sich das leider nicht einfach ändern, die Strommess-Klemmen umzusetzen klappt aus Platzgründen in der Verteilung nicht. Da müsste der Elektriker ran und etwas mehr umbauen.
Auch die vorhandenen Speicher konnten mich nicht restlos überzeugen. Die PV-Anlage besteht ausschließlich aus mehreren Microwechselrichtern und vom Dach geht daher eine AC-Leitung in den Keller. DC-Speicher zwischen PV-Paneel und Microwechselrichter erscheinen mir bisher arg als Bastellösung. Am liebsten hätte ich den Speicher im Keller und das auch als reinen AC-Speicher. Somit war das Thema „kleiner Heimspeicher“ erst einmal gestorben.
Im Photovoltaikforum wurde ich dann auf einen neuen Speicher von Marstek aufmerksam, den Venus C und Venus E. Er hat eine Backup/Notstromsteckdose und viele Einstellmöglichkeiten, unterstützt auch Shelly und weitere Smart Meter. Laden ist bis 2,5kW möglich, entladen mit Blick auf die Einspeiseregularien für BKWs mit 800W oder wer es einstellen möchte auch bis 2,5kW. Ebenso wurde ich auf Emulatoren aufmerksam, die Shelly Devices emulieren. Und das scheint beim Marstek Venus gut zu funktionieren.
Links und Details zum Marstek Venus C/E:
Am Ende entstand dann folgendes Setup:
Der Speicher Marstek Venus E mit 5,12kWh Speicherkapazität ist mit einem Virtuellen Shelly verbunden. Die Software hierzu läuft als Container auf einer Synology Diskstation. Werte werden per MQTT gelesen und geschrieben, so dass der saldierte Stromwert einfach aus openHAB heraus übergeben werden kann. Das Ganze ist mit der Wallbox gekoppelt, so dass der Speicher während des eAuto-Ladens die Füße still hält und ein Überschussladen auch weiterhin möglich ist.
Nachfolgend mein Vorgehen – vielleicht für den ein oder anderen hilfreich.
Schritt 1 – virtuellen Shelly emulieren auf Synology Container Manager
Das uni-meter Projekt ist unter https://github.com/sdeigm/uni-meter verfügbar und auch schon für Docker vorbereitet. Es ist allerdings nicht über Repos direkt im Container Manager herunterladbar, daher muss es im Rahmen eines neuen Projektes erst erstellt werden.
Zuerst das git-Reporitory in ein beliebiges Verzeichnis auf der Synology Diskstation klonen. Dann im Container-Manager ein neues Projekt erstellen. Bei Pfad auf das Verzeichnis „docker“ verweisen, welches im git-Repo enthalten ist. Anschließend die vorgeschlagene, vorhandene docker-compose.yml verwenden.
Diese passen wir dann aber an. Gerade wenn der Container im HOST-Modus läuft macht der durch Synology selbst bereits belegte Port 80 Probleme. Für den Marstek-Speicher ist allerdings nur der Port 1010 relevant. Ich habe aus der docker-compose.yml lediglich zwei Dateien als separate Konfigurationsdateien in einen separaten Konfigurationsordner kopiert und eingebunden (uni-meter.conf und logback.xml, falls man am loglevel drehen möchte).
Hier die angepasste docker-compose.yml:
services:
uni-meter:
image: sdeigm/uni-meter:latest
container_name: uni-meter
network_mode: host
restart: unless-stopped
ports:
- 1010:1010/udp
expose:
- 1010
volumes:
- /volume1/docker/uni-meter_shelly/conf/uni-meter.conf:/etc/uni-meter.conf
- /volume1/docker/uni-meter_shelly/conf/logback.xml:/opt/uni-meter/config/logback.xml
Das expose des Ports wäre nicht nötig (da HOST-Modus), ich habe es der Vollständigkeit halber aber im Configfile belassen.
Die uni-meter.conf ist so eingestellt, dass der Port 80 für die HTTP-API erst einmal umgebogen wird auf einen freien Postfreien Port (bei mir Port 4711), so dass das Ganze auch mit der Diskstation im Host-Modus kompatibel ist. Ebenso ist der mqtt-Server sowie das Topic, welches für den Strommesswert genutzt werden soll, konfiguriert:
uni-meter {
output = "uni-meter.output-devices.shelly-pro3em"
input = "uni-meter.input-devices.mqtt"
http-server {
port:4711
}
output-devices {
shelly-pro3em {
mac = "B827EB364242"
hostname = "shellypro3em-unimeter"
port = 4711
udp-port = 1010
udp-interface = "0.0.0.0"
}
}
input-devices {
mqtt {
type = "MQTT"
url = "tcp://192.168.1.10:1883"
power-phase-mode = "tri-phase"
energy-phase-mode = "tri-phase"
channels = [{
type = "json"
topic = "shellypro3em-virtual/SENSOR"
channel = "power-l1"
json-path = "$..power"
},{
type = "json"
topic = "shellypro3em-virtual/SENSOR"
channel = "energy-consumption-total"
json-path = "$..counter_pos"
},{
type = "json"
topic = "shellypro3em-virtual/SENSOR"
channel = "energy-production-total"
json-path = "$..counter_neg"
}]
}
}
}
Die power-total legen wir nur auf Phase 1 denn aktuell scheint es im Marstek nämlich noch einen Bug zu geben, dass er bei Übergabe von 3 Werten je Phase diese nicht richtig addiert. und nicht steuert. Im Marstek-Speicher stellen wir dann auf Phase A. Dies aber später nochmal.
Anschließend kann der Container (neu) gestartet werden und holt sich künftig seine Werte aus dem MQTT-Topic.
Schritt 2 – Saldierten Stromwert aus openHAB zur Verfügung stellen.
Der saldierte Stromwert wird bereits bei einer Rule berechnet und steht als Zahl (Number) zur Verfügung. Positiver Stromwert = Bezug, negativer Stromwert = Einspeisung.
Eine kleine Rule ist dafür verantwortlich, bei Veränderung des Wertes den aktuellen Wert in das MQTT-Topic zu publishen, der dann automatisch vom virtuellen Shelly übernommen wird:
rule "Publish Strom saldierend bei Änderung zu virtuellem Shelly-Device"
when
Item strom_saldierend changed
then
val powerValue = (strom_saldierend.state as QuantityType<Power>).doubleValue
val json = '{"power": ' + powerValue + '}'
val mqttActions = getActions("mqtt","mqtt:broker:c73084e70c")
mqttActions.publishMQTT("shellypro3em-virtual/SENSOR", json, false)
end
Ein Test des virtuellen Shellys ist über den Browser einfach möglich:
Ein Aufruf von (bei mir) http://192.168.1.10:4711/rpc/EM.GetStatus?id=0 zeigt entsprechend den Rückgabewert und den MQTT-Wert als Power bei Phase A (bei angenommenen 230V Netzspannung):
{
"id": 0,
"a_current": 0.06,
"a_voltage": 230,
"a_act_power": 14.15,
"a_aprt_power": 14.15,
"a_pf": 1,
"a_freq": 50,
"b_current": 0,
"b_voltage": 230,
"b_act_power": 0,
"b_aprt_power": 0,
"b_pf": 1,
"b_freq": 50,
"c_current": 0,
"c_voltage": 230,
"c_act_power": 0,
"c_aprt_power": 0,
"c_pf": 1,
"c_freq": 50,
"total_current": 0.06,
"total_act_power": 14.15,
"total_aprt_power": 14.15
}
Schritt 3 – virtuellen Shelly in Speicher konfigurieren
In der Marstek App einfach auf den CT-Button klicken, Shelly auswählen und den gefundenen emulierten Shelly damit einbinden.


Durch den virtuellen Shelly entstehen nun auch weitere Vorteile. Es ist nun einfach möglich, z.B. während des Ladens des e-Autos den Speicher aus dem Spiel zu nehmen usw. Ansonsten würde er auch beim e-Auto laden ständig mitregeln.
Schritt 4 – Kombination mit Überschussladen
Beim laden des Speichers kann es nun vorkommen, dass Überschuss übrig ist, weil die PV mehr liefert, als gespeichert werden kann. In dem Fall wird dem Shelly dauerhaft vorgegaukelt, es bestünde Einspeisung, so dass er weiter maximal versucht zu laden. Da er als regulärer Verbraucher auftritt regelt das Überschussladen entsprechend.
Findet kein Überschussladen statt und wird regulär geladen, dann wird versucht dem Speicher immer den Wert vorzugaukeln, der von ihm gerade geleistet wird, so dass sich dann der Speicher auf 0W Leistung einpendelt.
rule "Publish Strom saldierend bei Änderung zu virtuellem Shelly-Device"
when
Item strom_saldierend changed
then
var powerValue = 0.0
if ((GoeCharger_Power_All.state as Number) < 1) { // Auto lädt nicht
powerValue = (strom_saldierend.state as QuantityType<Power>).doubleValue
} else { // Auto lädt gerade
if (config_pv_laden_aktivieren.state == ON) {
// wenn Überschussladen aktiv ist, dann -100 vorgaugeln - Speicher geht damit vor Auto weil er immer mehr in den Speicher laden möchte, als geht
powerValue = -100
} else {
// Logik: Wir setzen den aktuellen per Shelly erhaltenen Wert der Einspeisung als angeblich saldierten Wert des Hausanschlusses
// in der Folge regelt der Speicher das (ggf. in ein paar Durchkläufen) aus
powerValue = (strom_pvspeicher.state as Number).doubleValue
}
}
val json = '{"power": ' + powerValue + '}'
val mqttActions = getActions("mqtt","mqtt:broker:c73084e70c")
mqttActions.publishMQTT("shellypro3em-virtual/SENSOR", json, false)
end
Fazit
Der Marstek Venus E ist eine gute Ergänzung egal für welche Größe der PV-Anlage. Wer lediglich ein „BKW“ mit 800kWp Leistung besitzt, ist mit der 2,56kWh-Version (Venus C) sicherlich besser bedient. Größere Anlagen sollten mit der 5,12kWh-Speicher-Version besser fahren.
Die Regelung mit dem Shelly bzw. dem Shelly-Emulator wirkt sehr zuverlässig und schnell, so dass man sehr nahe an eine Nulleinspeisung kommt.
Auch mit Überschussladen lässt sich das gut kombinieren. Sobald die PV-Anlage mehr als 2.500W Überschuss liefert, was die maximal aufnehmbare Leistung des Speicher ist, greift das Überschussladen von selbst und beim normalen Laden des Autos wird der Speicher aus dem Spiel genommen… So bekommt man beide Bedürfnisse (Speicher laden und auch Auto laden) gut zusammen.
Anbei noch die grafische Darstellung der Regelleistung des Speichers:

Hallo, vielen dank für die Anleitung.
Nachdem die docker compose ausgeführt wird, änderst du noch die config. Wo findest du denn die config um diese zu bearbeiten?
Die Volumes die du nennst, werden die automatisch erstellt nach dem ausführen?
Grüße
Hallo Benno,
die ursprünglichen Konfigurationsdateien bringt uni-meter mit: https://github.com/sdeigm/uni-meter/tree/main/docker
Die angepassten Dateien lege ich in einem anderen Pfad ab und binde sie ein. Die docker Composer verweist dann auf die neuen angepassten Dateien.
Die Volume-Pfade, die ich verwende sind die am meinen NAS (Synology Diskstation) angepassten, hier müssten die Pfade sicherlich angepasst werden.
Gruß
Florian
Coole Anleitung, danke für den Blogpost!
Ich bin auch openHAB Nutzer und überlege mir einen Solarspeicher zuzulegen. Neben dem warten auf einen „angemessehen Preis den ich zahlen möchte“, schaue ich derzeit nach den Steuermöglichkeiten.
2. Punkte die mich noch „stören“:
1. Hast du eine Möglichkeit gefunden den SOC (state of charge) aus dem Speicher auslesen zu können um ihn im openHAB zur Verfügung zu haben?
2. Den Speicher mit einem virtuellen Shelly zu verknüpfen ist zwar eine coole idee, aber man ist immernoch von der App des Herstellers Marstek abhängig, oder? Gibt es ein webinterface im Speicher wo man die Url des Shellys eintragen kann und fertig? Ich mache mir eben Gedanken was ist wenn die App des Herstellers eingestellt wird, oder auf neuren Android/iOS Versionen nicht mehr läuft, oder die App gar die Cloud braucht und dei weg ist, etc…
Hallo, SOC habe ich noch nicht in openhab. Ginge über Modbus-Anbindung, die bin ich aber noch nicht angegangen. Angeblich kommt laut Support noch eine API,da warte ich aktuell noch etwas ab, vielleicht passt das dann später. Soc ist eh nur informativ, da schaue ich aktuell in die App.
Abhängigkeiten sehe ich aber wegen des shellies keine, das Setup funktioniert ohne Cloud, wenn es eingerichtet ist. Notfalls bliebe ja noch die rs485-Schnittstelle. Das Problem,dass Software nicht mehr gepflegt wird, wenn ein Hersteller Pleite geht, ist aber herstellerunabhängig…Da sehe ich bei marstek kein erhöhtes Risiko.
Hallo Florian,
danke für dein Update.
ich habe mir das mit dem Modbus mal angeschaut. Weil wenn die App nicht mehr geht, kannst du auch keinen shelly mehr verknüpfen… (auch wenn der Speicher bloß die lokale URL davon bräuchte).
So wie ich Modbus verstehe gibt es folgende Register:
42010 – forcible charge/discharge
42020 – forcible charge power
42021 – forcible discharge power
Mit denen man völlig unabhängig von Marstek ist. Man benötigt nur einen TCP -> Modbus Adapter und der Rest sind ein paar oenHAB rules um das Verhalten des Shellys zu emulieren.
Dort kann man dann auch deine extra Logik einfließen lassen für das Vorzugsladen vom E-Auto.
Jetzt muss nur der Preis noch etwas fallen (und der Speicher wieder lieferbar werden) und dann ist er gekauft 😉