# Marstek Venus E Mini – Raspberry Pi als virtueller Shelly Pro 3EM

**EcoTracker → Raspberry Pi → Shelly-Pro-3EM-Emulation → Marstek Venus E Mini**

> **Praxis-Workaround:** Der Raspberry Pi liest die Messwerte eines EcoTrackers per HTTP aus und beantwortet die Shelly-RPC-Anfragen der Venus E Mini über UDP-Port 2220. Damit kann ein EcoTracker als Datenquelle für die Nulleinspeisungsregelung der Venus verwendet werden, obwohl der EcoTracker in der Marstek-App nicht direkt als CT auswählbar ist.

**Stand:** August 2026

---

## 1. Voraussetzungen

Benötigt werden:

- Marstek Venus E Mini
- Raspberry Pi (z. B. Raspberry Pi 3)
- Raspberry Pi OS / Debian mit Python 3
- EcoTracker mit HTTP-API
- Netzwerkverbindung für Raspberry Pi, EcoTracker und Venus
- Zugriff auf ein Terminal bzw. SSH

Der Volkszähler ist für diesen Aufbau **nicht erforderlich**.

### Beispiel-Netzwerk

| Gerät | Beispiel-IP | Funktion |
|---|---|---|
| EcoTracker | `192.168.178.75` | Quelle der Messwerte |
| Raspberry Pi | `192.168.178.58` | virtueller Shelly Pro 3EM |
| Venus E Mini | `192.168.178.110` | fragt den virtuellen Shelly ab |

Die IP-Adressen sind nur Beispiele und müssen an die jeweilige Installation angepasst werden.

Für einen dauerhaften Betrieb empfiehlt sich, dem Raspberry Pi und dem EcoTracker im Router feste DHCP-Leases zu geben.

---

## 2. Funktionsprinzip

Der Aufbau sieht so aus:

```text
              ┌───────────────────┐
              │     EcoTracker    │
              │                   │
              │ power             │
              │ powerPhase1       │
              │ powerPhase2       │
              │ powerPhase3       │
              └─────────┬─────────┘
                        │
                   HTTP / JSON
                        │
                        ▼
              ┌───────────────────┐
              │   Raspberry Pi    │
              │                   │
              │ Python Emulator   │
              │ UDP :2220         │
              └─────────┬─────────┘
                        │
                  Shelly RPC
                  EM.GetStatus
                        │
                        ▼
              ┌───────────────────┐
              │  Marstek Venus    │
              │     E Mini        │
              │                   │
              │ Nulleinspeisung   │
              └───────────────────┘
```

Der Raspberry Pi übernimmt **nicht** die Regelung der Batterie. Er stellt lediglich Messwerte in einer Form bereit, die die Venus wie einen Shelly Pro 3EM abfragen kann.

Shelly dokumentiert `EM.GetStatus` als Statusabfrage des Energy-Meter-Moduls und liefert dabei unter anderem die Leistungen der drei Phasen (`a_act_power`, `b_act_power`, `c_act_power`) sowie `total_act_power`. Shelly dokumentiert außerdem RPC über UDP.  
Quelle: https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/EM/  
Quelle: https://shelly-api-docs.shelly.cloud/gen2/General/RPCChannels/

---

## 3. EcoTracker-API prüfen

Auf dem Raspberry Pi zunächst testen:

```bash
curl -s http://192.168.178.75/v1/json
```

Bei dem im Praxistest verwendeten EcoTracker sieht die Antwort beispielsweise so aus:

```json
{
    "power": 363,
    "powerAvg": 330,
    "agePower": 39,
    "powerPhase1": 291,
    "powerPhase2": -131,
    "powerPhase3": 203,
    "energyCounterOut": 59918235.7,
    "energyCounterIn": 92259741,
    "energyCounterInT1": 92259741,
    "energyCounterInT2": 0
}
```

Wichtig sind:

```text
power
powerPhase1
powerPhase2
powerPhase3
```

Im getesteten System gilt:

- positiver Wert = Netzbezug
- negativer Wert = Einspeisung

Beispiel:

```text
L1 = +291 W
L2 = -131 W
L3 = +203 W
```

ergibt:

```text
291 - 131 + 203 = 363 W
```

und entspricht damit dem Wert `power`.

**Achtung:** Andere Stromzähler können eine andere Vorzeichenkonvention verwenden. Vor der Aktivierung der Nulleinspeisung muss die Zählrichtung unbedingt überprüft werden.

---

## 4. Warum UDP-Port 2220?

Bei unserem Praxistest sendete die Venus regelmäßig eine Anfrage wie:

```json
{
  "id": 0,
  "method": "EM.GetStatus",
  "params": {
    "id": 0
  }
}
```

Die Venus sendet diese Anfrage per UDP an Port **2220** des virtuellen Shelly.

Der Raspberry Pi lauscht deshalb auf:

```text
UDP 2220
```

und antwortet direkt an die Absenderadresse der Venus.

Die Shelly-Dokumentation beschreibt UDP-RPC als JSON-basierte Datagrammkommunikation. UDP bietet allerdings keine Zustellgarantie.  
Quelle: https://shelly-api-docs.shelly.cloud/gen2/General/RPCChannels/

Auch Community-Emulatoren für einen virtuellen Shelly Pro 3EM verwenden `EM.GetStatus` über UDP auf Port 2220. Beispiel: https://github.com/jonasneustock/virtual_shelly3empro

---

## 5. Python-Emulator installieren

Datei anlegen:

```bash
nano ~/shelly_emulator.py
```

Dann das folgende **vollständige Script** einfügen.

> **Wichtig:** Die Variable `ECOTRACKER_URL` muss an die IP-Adresse des eigenen EcoTrackers angepasst werden.

```python
#!/usr/bin/env python3

import socket
import json
import time
import threading
import urllib.request

# ============================================================
# Konfiguration
# ============================================================

ECOTRACKER_URL = "http://192.168.178.75/v1/json"

LISTEN_IP = "0.0.0.0"
LISTEN_PORT = 2220

# EcoTracker alle 1 Sekunde abfragen
UPDATE_INTERVAL = 1.0

# Ein Messwert gilt höchstens so lange als frisch
MAX_DATA_AGE = 5.0


# ============================================================
# Messwerte
# ============================================================

power = 0.0
power_phase1 = 0.0
power_phase2 = 0.0
power_phase3 = 0.0

last_update = 0.0

data_lock = threading.Lock()


# ============================================================
# EcoTracker auslesen
# ============================================================

def read_ecotracker():

    global power
    global power_phase1
    global power_phase2
    global power_phase3
    global last_update

    try:

        with urllib.request.urlopen(
            ECOTRACKER_URL,
            timeout=2
        ) as response:

            data = json.loads(
                response.read().decode("utf-8")
            )

        new_power = float(data["power"])
        new_p1 = float(data["powerPhase1"])
        new_p2 = float(data["powerPhase2"])
        new_p3 = float(data["powerPhase3"])

        with data_lock:

            power = new_power
            power_phase1 = new_p1
            power_phase2 = new_p2
            power_phase3 = new_p3
            last_update = time.monotonic()

        print(
            f"EcoTracker: "
            f"L1={new_p1:.0f} W, "
            f"L2={new_p2:.0f} W, "
            f"L3={new_p3:.0f} W, "
            f"Gesamt={new_power:.0f} W"
        )

    except Exception as e:

        print(
            "FEHLER EcoTracker:",
            e
        )


# ============================================================
# Hintergrund-Thread
# ============================================================

def ecotracker_loop():

    while True:

        read_ecotracker()

        time.sleep(UPDATE_INTERVAL)


# ============================================================
# UDP-Socket für Shelly
# ============================================================

sock = socket.socket(
    socket.AF_INET,
    socket.SOCK_DGRAM
)

sock.setsockopt(
    socket.SOL_SOCKET,
    socket.SO_BROADCAST,
    1
)

sock.bind(
    (LISTEN_IP, LISTEN_PORT)
)

print(
    f"Shelly-Emulator läuft auf "
    f"UDP Port {LISTEN_PORT}"
)

print(
    f"EcoTracker: {ECOTRACKER_URL}"
)

print(
    f"Maximales Messwertalter: "
    f"{MAX_DATA_AGE} Sekunden"
)


# ============================================================
# EcoTracker-Thread starten
# ============================================================

thread = threading.Thread(
    target=ecotracker_loop,
    daemon=True
)

thread.start()


# ============================================================
# Venus-Anfragen
# ============================================================

while True:

    data, addr = sock.recvfrom(4096)

    try:

        request = json.loads(
            data.decode("utf-8")
        )

    except Exception:

        continue

    print(
        f"Venus {addr}: {request}"
    )

    if request.get("method") != "EM.GetStatus":

        continue

    # --------------------------------------------------------
    # Aktuelle Daten holen
    # --------------------------------------------------------

    with data_lock:

        p1 = power_phase1
        p2 = power_phase2
        p3 = power_phase3
        total = power

        age = time.monotonic() - last_update

    # --------------------------------------------------------
    # Sicherheitsprüfung
    # --------------------------------------------------------

    if age > MAX_DATA_AGE:

        print(
            f"ACHTUNG: EcoTracker-Daten sind "
            f"{age:.1f} Sekunden alt."
        )

        print(
            "Keine Shelly-Antwort an Venus."
        )

        continue

    # --------------------------------------------------------
    # Shelly-Pro-3EM-Werte
    # --------------------------------------------------------

    voltage = 230.0

    current1 = abs(p1) / voltage
    current2 = abs(p2) / voltage
    current3 = abs(p3) / voltage

    response = {

        "id": request.get("id", 0),

        "src": "shellypro3em-pi",

        "dst": "reply",

        "result": {

            "id": 0,

            "a_current": current1,
            "a_voltage": voltage,
            "a_act_power": p1,
            "a_aprt_power": abs(p1),
            "a_pf": 1.0,
            "a_freq": 50.0,
            "a_errors": [],

            "b_current": current2,
            "b_voltage": voltage,
            "b_act_power": p2,
            "b_aprt_power": abs(p2),
            "b_pf": 1.0,
            "b_freq": 50.0,
            "b_errors": [],

            "c_current": current3,
            "c_voltage": voltage,
            "c_act_power": p3,
            "c_aprt_power": abs(p3),
            "c_pf": 1.0,
            "c_freq": 50.0,
            "c_errors": [],

            "total_current":
                current1 +
                current2 +
                current3,

            "total_act_power": total,

            "total_aprt_power":
                abs(p1) +
                abs(p2) +
                abs(p3),

            "errors": []
        }
    }

    response_data = json.dumps(
        response,
        separators=(",", ":")
    ).encode("utf-8")

    sock.sendto(
        response_data,
        addr
    )

    print(
        f"→ Venus: "
        f"L1={p1:.0f} W, "
        f"L2={p2:.0f} W, "
        f"L3={p3:.0f} W, "
        f"Gesamt={total:.0f} W "
        f"(Alter {age:.1f}s)"
    )
```

Datei speichern und schließen.

Danach:

```bash
chmod +x ~/shelly_emulator.py
```

---

## 6. Emulator manuell starten

```bash
python3 ~/shelly_emulator.py
```

Eine erfolgreiche Ausgabe sieht ungefähr so aus:

```text
Shelly-Emulator läuft auf UDP Port 2220
EcoTracker: http://192.168.178.75/v1/json
Maximales Messwertalter: 5.0 Sekunden

EcoTracker: L1=291 W, L2=-131 W, L3=203 W, Gesamt=363 W
```

Wenn die Venus den Emulator abfragt:

```text
Venus ('192.168.178.110', 22222):
{'id': 0, 'method': 'EM.GetStatus', 'params': {'id': 0}}

→ Venus: L1=291 W, L2=-131 W, L3=203 W,
Gesamt=363 W (Alter 0.3s)
```

Damit ist die Kommunikation grundsätzlich hergestellt:

```text
EcoTracker → Raspberry Pi → Venus
```

---

## 7. Venus in der Marstek-App konfigurieren

In der Marstek-App den externen Stromzähler bzw. CT als:

**Shelly Pro 3EM**

auswählen.

Die genaue Bezeichnung kann abhängig von App- und Firmware-Version variieren.

### Wichtig

Bei unserem Aufbau muss die Venus nicht die IP-Adresse eines echten Shelly kennen. Die Venus sendet die Shelly-RPC-Anfrage per UDP an Port 2220, und der Raspberry Pi beantwortet sie.

Deshalb ist entscheidend:

- Raspberry Pi und Venus befinden sich im selben LAN
- UDP-Port 2220 ist erreichbar
- der Emulator läuft
- der Pi besitzt eine stabile IP-Adresse

---

## 8. Kontrollierter Funktionstest

**Diesen Test sollte man unbedingt durchführen, bevor die Nulleinspeisung aktiviert wird.**

Im Python-Script können testweise feste Werte eingesetzt werden:

```python
p1 = 333.0
p2 = 334.0
p3 = 333.0

total = 1000.0
```

Die Venus sollte danach ungefähr:

```text
1000 W
```

Netzbezug anzeigen.

Damit lässt sich überprüfen, ob die Venus die simulierten Messwerte tatsächlich empfängt.

### Danach unbedingt wieder zurückstellen!

Die festen Testwerte müssen wieder entfernt werden. Anschließend muss wieder der EcoTracker als Datenquelle verwendet werden.

---

## 9. Vorzeichen überprüfen

Vor Aktivierung der Nulleinspeisung muss die Zählrichtung eindeutig bekannt sein.

Beispiel:

```text
L1 = +300 W
L2 = -150 W
L3 = +200 W
```

ergibt:

```text
+350 W
```

Der Gesamtwert muss mit dem vom EcoTracker gemeldeten `power` übereinstimmen.

Besonders sinnvoll ist ein Test mit einer bekannten Last, z. B. einem Heizlüfter oder Wasserkocher:

1. Verbraucher ausschalten
2. Leistung am EcoTracker beobachten
3. Verbraucher einschalten
4. prüfen, ob die Leistung erwartungsgemäß steigt
5. anschließend bei PV-Überschuss auch die Einspeiserichtung kontrollieren

---

## 10. Automatischer Start nach dem Raspberry-Pi-Neustart

Damit der Emulator nach einem Stromausfall bzw. Neustart automatisch startet:

```bash
sudo nano /etc/systemd/system/shelly-emulator.service
```

Inhalt:

```ini
[Unit]
Description=Shelly Pro 3EM Emulator for Marstek Venus E Mini
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=shellypi3
ExecStart=/usr/bin/python3 /home/shellypi3/shelly_emulator.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

**Wichtig:** Benutzername und Pfad müssen an die eigene Installation angepasst werden.

Danach:

```bash
sudo systemctl daemon-reload
```

```bash
sudo systemctl enable shelly-emulator.service
```

```bash
sudo systemctl start shelly-emulator.service
```

Status prüfen:

```bash
sudo systemctl status shelly-emulator.service
```

Wenn dort

```text
Active: active (running)
```

steht, läuft der Emulator.

Laufende Meldungen:

```bash
sudo journalctl -u shelly-emulator.service -f
```

---

## 11. Neustart testen

```bash
sudo reboot
```

Nach dem Neustart:

```bash
sudo systemctl status shelly-emulator.service
```

Der Emulator sollte automatisch wieder laufen.

---

# 12. Fehlerbehebung

## „Konfiguration fehlgeschlagen“ in der Marstek-App

Folgendes prüfen:

1. Läuft der Python-Emulator?
2. Ist der Raspberry Pi im gleichen Netzwerk wie die Venus?
3. Ist UDP-Port 2220 erreichbar?
4. Ist die IP-Adresse der Venus korrekt?
5. Ist die IP-Adresse des EcoTrackers im Script korrekt?
6. Liefert die EcoTracker-API tatsächlich Daten?

---

## Prüfen, ob die Venus Anfragen sendet

Auf dem Raspberry Pi:

```bash
sudo tcpdump -i wlan0 -n -X 'host 192.168.178.110 and udp port 2220'
```

Die IP-Adresse muss natürlich durch die tatsächliche IP der Venus ersetzt werden.

Eine erfolgreiche Anfrage sieht beispielsweise so aus:

```text
192.168.178.110.22222 > 192.168.178.255.2220:
UDP, length 50
```

Im Datenbereich sollte unter anderem stehen:

```text
{"id":0,"method":"EM.GetStatus","params":{"id":0}}
```

Das ist ein sehr wichtiger Diagnosepunkt: Wenn diese Anfrage sichtbar ist, hat die Venus den virtuellen Shelly bereits gefunden bzw. versucht, ihn anzusprechen.

---

## Keine EcoTracker-Werte

Direkt testen:

```bash
curl -s http://192.168.178.75/v1/json
```

Wenn keine Antwort kommt:

- IP-Adresse überprüfen
- EcoTracker einschalten
- Netzwerkverbindung prüfen
- gegebenenfalls EcoTracker neu starten

---

## Python meldet „Address already in use“

Das bedeutet normalerweise, dass bereits ein Emulator läuft.

Prüfen:

```bash
sudo ss -lunp | grep 2220
```

oder:

```bash
sudo lsof -i UDP:2220
```

Wenn der Emulator bereits als `systemd`-Dienst läuft, nicht zusätzlich noch einmal manuell starten.

---

## Vorzeichen falsch

Die Vorzeichen müssen zur tatsächlichen Zählrichtung passen.

**Vor Aktivierung der Nulleinspeisung unbedingt kontrollieren!**

Ein falsch interpretiertes Vorzeichen kann dazu führen, dass die Venus in die falsche Richtung regelt.

---

## Messwerte bleiben stehen

Das Script akzeptiert einen Messwert maximal fünf Sekunden:

```python
MAX_DATA_AGE = 5.0
```

Wenn der EcoTracker keine aktuellen Werte mehr liefert, antwortet der Emulator nicht mit einem alten Messwert.

Das ist absichtlich so implementiert.

---

## 13. Warum die einzelnen Phasen übertragen werden

Bei einem dreiphasigen Hausanschluss sollte nicht einfach nur ein Gesamtwert übertragen werden.

Beispiel:

```text
L1 = +300 W
L2 = -150 W
L3 = +200 W
```

Netto:

```text
+350 W
```

Die Venus erhält aber zusätzlich die Information über die einzelnen Phasen.

Der echte Shelly Pro 3EM liefert ebenfalls separate Werte für A, B und C sowie einen Gesamtwert. Shellys offizielle `EM.GetStatus`-Dokumentation zeigt genau diese Struktur.  
Quelle: https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/EM/

---

## 14. Grenzen und Sicherheit

Diese Lösung ist ein **Community-Workaround** und kein offizielles Marstek- oder Shelly-Produkt.

Der Raspberry Pi ist:

- kein geeichter Stromzähler
- kein offizieller Shelly
- nicht Teil der Marstek-Firmware
- nicht für sicherheitskritische Messaufgaben zertifiziert

Firmware- oder App-Änderungen von Marstek können dazu führen, dass der Emulator angepasst werden muss.

### Besonders wichtig

Vor dem Dauerbetrieb überprüfen:

- stimmen die Vorzeichen?
- stimmen L1/L2/L3?
- stimmt die Summe?
- reagiert die Venus plausibel auf Laständerungen?
- zeigt die Marstek-App die erwarteten Werte?
- funktioniert der Emulator nach einem Raspberry-Pi-Neustart?

Erst danach die Nulleinspeisung aktivieren.

---

## 15. Gesamtübersicht

```text
EcoTracker
    │
    │ HTTP / JSON
    ▼
Raspberry Pi
    │
    │ UDP 2220
    │ Shelly RPC
    │ EM.GetStatus
    ▼
Marstek Venus E Mini
    │
    ▼
Nulleinspeisungsregelung
```

Die Venus übernimmt die eigentliche Lade-/Entladeregelung.

Der Raspberry Pi stellt lediglich die aktuellen Messwerte des EcoTrackers als Shelly-Pro-3EM-kompatible Antwort bereit.

---

## 16. Weiterführende Quellen

### Shelly – Energy Meter / EM.GetStatus

https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/EM/

### Shelly – RPC Channels / UDP

https://shelly-api-docs.shelly.cloud/gen2/General/RPCChannels/

### Community-Projekt: Virtual Shelly 3EM Pro

https://github.com/jonasneustock/virtual_shelly3empro

### Hinweis

Diese Anleitung basiert auf einem praktisch getesteten Aufbau mit einer Marstek Venus E Mini, einem EcoTracker und einem Raspberry Pi 3. Die konkrete Kommunikation der Venus kann sich bei zukünftigen Firmware-/App-Versionen ändern.

