sphings-dev.de

Marstek Offline Endpoint auf dem Mac mit Docker Desktop einrichten

Den Marstek Offline Endpoint auf einem Mac mit Docker Desktop betreiben und per DNS dafür sorgen, dass die Batterie ihn statt der Cloud anspricht. Der Mac muss dafür dauerhaft eingeschaltet und wach bleiben.

Der Marstek Offline Endpoint ist ein kleiner Container, der den Telemetrie-Upload eines Marstek Venus (E, D, E v3) im Heimnetz beantwortet. Ohne Antwort aus der Cloud setzt die Batterie auf der Control-Firmware v150 alle 30 Minuten ihren Netzwerkchip zurück; Modbus-Verbindungen brechen dabei ab. Firmware v151 startet stattdessen die Steuerung neu, wenn vier Stunden lang mindestens fünf Uploads unversendet bleiben, und schaltet dabei den Wechselrichterausgang ab. Der Container bestätigt jeden Upload, damit beides gar nicht erst eintritt.

Ein Mac eignet sich weniger als Dauerbetrieb als ein Server oder NAS. Der Container muss dauerhaft laufen, und ein schlafender oder ausgeschalteter Mac beantwortet nichts. Diese Anleitung funktioniert, setzt aber voraus, dass der Mac eingeschaltet und wach bleibt.

So funktioniert die Umleitung

Die Batterie spricht zwei Server an: api-eu.marstekcloud.com für den Upload (HTTPS, Port 443) und eu.hamedata.com für die Uhrzeit (HTTP, Port 80). Du änderst nichts an der Batterie. Stattdessen sorgst du im Heimnetz dafür, dass beide Namen auf den Rechner zeigen, auf dem der Container läuft. Dazu legst du zwei DNS-Einträge für die ganzen Domains marstekcloud.com und hamedata.com an, damit auch eine andere Region als eu im Namen funktioniert. Die Ports 80 und 443 lassen sich nicht ändern, die Batterie verbindet sich fest dorthin.

Zwei Dinge gehören ausdrücklich nicht dazu: Den MQTT-Broker der Batterie leitest du nicht um (er prüft Zertifikate und lässt sich nicht nachbilden), und der Container gehört nicht ins Internet. Öffne also keine Ports im Router dorthin.

Vorbereitung

Mac dauerhaft wach halten

Docker Desktop läuft in deiner Benutzersitzung. Der Mac muss also angemeldet bleiben und darf nicht in den Ruhezustand gehen. Auf einem MacBook gehört dazu, dass es am Netzteil hängt. Gehe in den Einstellungen deines Macs in den Bereich Energie beziehungsweise Batterie und verhindere dort den automatischen Ruhezustand bei ausgeschaltetem Bildschirm. Je nach macOS-Version heißt die Einstellung etwas anders. Alternativ hält der Befehl caffeinate -s den Mac wach, solange das Terminalfenster offen bleibt und der Mac am Netzteil hängt.

Feste Adresse für den Mac

Die DNS-Einträge zeigen später auf den Mac. Seine Adresse darf sich deshalb nicht ändern. Lege im Router eine feste Zuordnung an (DHCP-Reservierung): Suche den Mac in der Geräteliste des Routers und aktiviere eine Option wie „immer dieselbe Adresse zuweisen“. Die genaue Bezeichnung hängt vom Router ab. Ein Kabel statt WLAN ist stabiler. Im Folgenden steht für die Adresse das Beispiel 192.168.1.60.

Docker Desktop installieren

Docker Desktop ist für Privatpersonen kostenlos, für Firmen mit weniger als 250 Mitarbeitenden und weniger als 10 Millionen US-Dollar Jahresumsatz ebenfalls. Das Image des Containers läuft auf Apple-Silicon-Macs nativ, es gibt eine arm64-Variante.

  1. Öffne die Seite docs.docker.com/desktop/setup/install/mac-install im Browser.
  2. Lade „Docker Desktop for Mac with Apple silicon“ herunter (bei einem Intel-Mac: „with Intel chip“).
  3. Öffne die heruntergeladene Datei Docker.dmg mit einem Doppelklick.
  4. Ziehe das Docker-Symbol in den Ordner „Programme“.
  5. Starte „Docker“ aus dem Ordner „Programme“ mit einem Doppelklick.
  6. Akzeptiere die Lizenzvereinbarung, wenn sie erscheint.

Nach dem Start erscheint ein Wal-Symbol in der Menüleiste. Ein Passwort fragt Docker Desktop in aktuellen Versionen nicht ab. Docker Desktop startet bei dir erst, wenn du dich angemeldet hast. Dafür schaltest du jetzt den Autostart ein.

  1. Klicke auf das Wal-Symbol in der Menüleiste und wähle „Settings“.
  2. Öffne den Bereich „General“.
  3. Setze den Haken bei „Start Docker Desktop when you sign in to your computer“.
  4. Klicke auf „Apply & restart“, falls die Schaltfläche erscheint.

Terminal öffnen und Docker prüfen

  1. Öffne mit Befehl-Leertaste die Spotlight-Suche, tippe „Terminal“ und drücke die Eingabetaste.
  1. Prüfe, dass Docker und Compose antworten.
docker compose version

Die Ausgabe nennt eine Versionsnummer. Kommt „command not found“, ist Docker Desktop noch nicht gestartet; warte, bis das Wal-Symbol ruhig steht, und versuche es erneut.

Container einrichten

  1. Lege einen Ordner für das Projekt an und wechsle hinein.
mkdir -p ~/marstek-offline-endpoint && cd ~/marstek-offline-endpoint
  1. Öffne einen Editor für die Compose-Datei.
nano compose.yaml
  1. Füge den folgenden Inhalt ein. Ändere TZ auf deine Zeitzone, falls du nicht in Deutschland bist.
# Marstek Offline Endpoint: beantwortet die Cloud-Anfragen deiner Marstek Venus im Heimnetz
services:
  marstek-offline-endpoint:
    image: ghcr.io/sphings79/marstek-offline-endpoint:latest   # fertiges Image für PC, NAS und Raspberry Pi
    container_name: marstek-offline-endpoint
    restart: unless-stopped        # startet nach einem Neustart automatisch wieder, das ist wichtig
    ports:
      - "443:443"                  # HTTPS: Telemetrie-Upload der Batterie (Port nicht ändern)
      - "80:80"                    # HTTP: Zeitabfrage der Batterie (Port nicht ändern)
    volumes:
      - ./data:/data               # empfangene Messdaten, eine Datei pro Tag
      - ./certs:/certs             # selbst erzeugtes Zertifikat, wird beim ersten Start angelegt
    environment:
      - TZ=Europe/Berlin           # deine Zeitzone, sonst stellt der Container die Uhr der Batterie auf UTC
  1. Speichere mit Control-O und der Eingabetaste und beende den Editor mit Control-X.

Die Zeitzone TZ ist wichtig: Der Container stellt die Uhr der Batterie, und der echte Server antwortet in Ortszeit. Ohne TZ bekommt die Batterie UTC.

  1. Starte den Container im Hintergrund.
docker compose up -d

Docker lädt das Image und startet den Container; zum Schluss steht „Started“. Gibt es einen Fehler wegen der Ports 80 oder 443, steht darin ein Hinweis auf das Binden der Ports; siehe unten bei „Wenn etwas nicht klappt“.

  1. Sieh dir die Startmeldungen an.
docker compose logs

Du willst drei „listening“-Zeilen sehen und keine Fehler:

https listening on :443
http  listening on :80
mqtt probe listening on :8883

Prüfen, ob die Ports 80 und 443 am Mac ankommen

Die Batterie verbindet sich fest auf 80 und 443. Ob Docker Desktop diese Ports auf deinem Mac bindet, hängt von Version und Einstellungen ab. Prüfe es deshalb jetzt am Mac selbst.

  1. Frage den Container über Port 80 ab.
curl -i http://127.0.0.1/

Egal welche Antwort kommt (auch ein Fehler 404 ist gut), der Container antwortet. Kommt „Connection refused“, erreicht Port 80 den Container nicht. Prüfe dann, ob ein anderes Programm den Port belegt (sudo lsof -iTCP:80 -sTCP:LISTEN), und starte Docker Desktop neu. Mach denselben Test für Port 443 mit curl -k -i https://127.0.0.1/; -k ist nötig, weil das Zertifikat selbstsigniert ist.

Hast du die Firewall von macOS eingeschaltet, erscheint bei der ersten Verbindung eventuell die Frage, ob Docker eingehende Verbindungen annehmen darf. Erlaube es, sonst erreicht die Batterie den Container nicht.

DNS-Einträge anlegen

Jetzt kommt der Schritt, der die Batterie tatsächlich zu deinem Container umleitet. Du brauchst Zugriff auf den DNS-Server, den dein Heimnetz benutzt. Das ist meist ein Pi-hole oder AdGuard Home, manchmal der Router selbst, wenn er lokale DNS-Einträge für ganze Domains erlaubt. Als Ziel trägst du die feste Adresse deines Macs ein; in dieser Anleitung ist das als Beispiel 192.168.1.60. Setze deine eigene Adresse ein.

So findest du heraus, wo du die Einträge anlegen musst: Schau in die DHCP-Einstellungen deines Routers. Der dort verteilte DNS-Server ist der, den auch die Batterie bekommt, und genau dort musst du die Einträge anlegen.

AdGuard Home

  1. Öffne die Weboberfläche von AdGuard Home.
  2. Wechsle zu „Filter › DNS-Umschreibungen“.
  3. Klicke auf „DNS-Umschreibung hinzufügen“.
  4. Trage als Domain marstekcloud.com und als IP-Adresse 192.168.1.60 ein und speichere.
  5. Lege ebenso *.marstekcloud.com mit 192.168.1.60 an.
  6. Lege hamedata.com mit 192.168.1.60 an.
  7. Lege *.hamedata.com mit 192.168.1.60 an.

AdGuard Home übernimmt Umschreibungen sofort. Es sind vier Einträge, jeweils die Domain ohne und mit Platzhalter.

Pi-hole

Die Maske für lokale DNS-Einträge in Pi-hole nimmt nur ganze Hostnamen. Einfacher ist eine kleine Konfigurationsdatei für den eingebauten dnsmasq-Dienst. Du legst sie auf dem Gerät an, auf dem Pi-hole läuft.

  1. Öffne ein Terminal auf dem Pi-hole-Rechner und gib den folgenden Befehl ein. Ersetze zuvor die Adresse durch deine eigene.
sudo tee /etc/dnsmasq.d/99-marstek.conf >/dev/null <<'EOF'
address=/marstekcloud.com/192.168.1.60
address=/hamedata.com/192.168.1.60
EOF
  1. Starte den DNS-Dienst von Pi-hole neu.
pihole restartdns

Wenn du statt der Domains nur die beiden genauen Namen eintragen willst, geht das in der Pi-hole-Oberfläche als lokaler DNS-Eintrag für api-eu.marstekcloud.com und für eu.hamedata.com. Das gilt dann nur für die Region eu, die bei der Batterie im Test beobachtet wurde. Die Domain-Variante ist die sicherere.

Router oder anderer DNS-Server

Wenn dein Router oder Firewall-System einen lokalen DNS-Eintrag oder „Host Override“ für eine ganze Domain anbietet, gelten dieselben zwei Domains mit derselben Zieladresse. Bei OPNsense liegt das unter „Services › Unbound DNS › Overrides › Domain Overrides“. Ob dein Router das kann, steht in dessen Handbuch; nicht jeder Router erlaubt Einträge für ganze Domains. Wenn nicht, brauchst du einen eigenen DNS-Server wie Pi-hole oder AdGuard Home.

Prüfen, ob die Einträge greifen

  1. Öffne auf einem PC oder Mac ein Terminal (unter Windows die Eingabeaufforderung oder PowerShell) und frage den ersten Namen ab.
nslookup api-eu.marstekcloud.com
  1. Frage auch den zweiten Namen ab.
nslookup eu.hamedata.com

In beiden Antworten muss unter „Name“ der jeweilige Hostname stehen und unter „Address“ die Adresse 192.168.1.60, also deine Container-Adresse, keine öffentliche. Steht dort eine fremde Adresse, benutzt dein PC einen anderen DNS-Server. Frage dann den richtigen direkt ab, indem du dessen Adresse anhängst: nslookup api-eu.marstekcloud.com DNS-SERVER-IP.

Die Batterie muss denselben DNS-Server benutzen wie dieser Test. Manche Geräte ignorieren den per DHCP verteilten DNS-Server und benutzen einen fest eingebauten. Dann hilft statt DNS eine Firewall-Regel (DNAT) im Router: Verkehr von der IP der Batterie auf die Ports 443 und 80 wird auf den Container umgebogen. Wenn die Batterie in einem eigenen VLAN hängt, muss sie den Container außerdem erreichen dürfen.

Kontrolle

  1. Verfolge die Meldungen des Containers live. Beenden kannst du die Anzeige mit Control-C.
cd ~/marstek-offline-endpoint && docker compose logs -f

Innerhalb von etwa fünf Minuten erscheinen Zeilen wie diese (Uhrzeit und Anhänge sind bei dir anders):

2026-08-26 08:17:38 TIME   http GET eu.hamedata.com/app/neng/getDateInfoeu.php?uid=… (0 B)
2026-08-26 08:19:07 ACCEPT https POST api-eu.marstekcloud.com/data-upload/v1/venus/… (1204 B)

TIME ist die Batterie, die nach der Uhrzeit fragt. ACCEPT ist der Telemetrie-Upload, den der Container bestätigt. Beides zusammen heißt: Die Umleitung funktioniert. Die Zeitabfrage kommt etwa alle zehn Minuten, der Upload etwa alle fünf Minuten.

Kommen vier TIME-Zeilen im Abstand von 20 Sekunden hintereinander, lehnt die Batterie die Antwort ab; dann läuft ein veraltetes Image, lade es neu. Kommen Uploads exakt alle 86 Sekunden, ist noch ein Rückstau in der Batterie abzubauen. Das ist für ein bis zwei Stunden normal.

  1. Prüfe, dass der Container die Messdaten mitschreibt.
ls ~/marstek-offline-endpoint/data

Dort liegt eine Datei requests-JJJJ-MM-TT.jsonl mit allem, was die Batterie gesendet hat. Die Daten bleiben bei dir zu Hause.

Um zu sehen, dass die Abbrüche weg sind, kannst du von einem Mac oder Linux-Rechner, der durchläuft, die Batterie anpingen. Das folgende Skript meldet sich nur, wenn ein Ping ausfällt; so sieht ein Netzwerk-Reset der Batterie von außen aus. Ersetze 192.168.1.50 durch die IP deiner Batterie (in der Geräteliste deines Routers, meist als „Marstek“, „VenusE“ oder ähnlich geführt).

IP=192.168.1.50; F=0
while true; do
  if ping -c1 -W1 "$IP" >/dev/null 2>&1; then
    [ $F -gt 0 ] && echo "$(date '+%F %T')  WIEDER DA nach ${F}s"; F=0
  else
    [ $F -eq 0 ] && echo "$(date '+%F %T')  WEG"; F=$((F+1))
  fi
  sleep 1
done

Bleibt die Ausgabe über zwei halbe Stunden leer, ist es geschafft. Vorher stand dort alle 30 Minuten eine Meldung. Beim gemessenen Gerät dauerte es nach dem ersten bestätigten Upload etwa 45 Minuten, bis der Rückstau abgebaut war und die Abbrüche aufhörten.

Ein Rest bleibt, den der Container nicht beheben kann: Bei jedem Upload rechnet die Batterie etwa vier bis fünf Sekunden am TLS-Schlüsselaustausch und beantwortet in der Zeit kein Modbus. Stelle deshalb in deinem Modbus-Client ein Antwort-Timeout von mindestens 6 Sekunden ein.

Später aktualisieren

  1. Wechsle in den Ordner mit der Compose-Datei und lade das neue Image.
cd ~/marstek-offline-endpoint && docker compose pull
  1. Ersetze den laufenden Container durch den neuen.
docker compose up -d

Daten und Zertifikat liegen in den Ordnern data und certs und bleiben erhalten.

Wenn etwas nicht klappt

Nach 15 Minuten steht nichts im Log.

Die Batterie landet nicht beim Container. Wiederhole die nslookup-Prüfung. Sieht sie richtig aus, hat die Batterie womöglich eine alte Antwort zwischengespeichert: Trenne sie kurz vom Strom, schalte sie wieder ein und warte fünf Minuten. Kommt immer noch nichts, benutzt sie einen fest eingebauten DNS-Server, dann hilft die DNAT-Regel im Router.

TIME-Zeilen kommen, aber kein ACCEPT.

Nur hamedata.com ist umgeleitet, marstekcloud.com nicht. Prüfe den zweiten DNS-Eintrag samt Platzhalter-Variante.

Es steht nichts im Log, obwohl nslookup die richtige Adresse zeigt.

Dann erreicht die Batterie den Mac nicht. Prüfe die Firewall von macOS, ob Docker eingehende Verbindungen annehmen darf, und ob der Mac wach ist. Ein Mac im Ruhezustand beantwortet nichts; dann kommen die Resets zurück.

Docker Desktop meldet einen Fehler beim Binden von Port 80 oder 443.

Entweder belegt ein anderes Programm den Port, oder Docker Desktop darf Ports unter 1024 nicht binden. Starte Docker Desktop neu und achte auf Rückfragen, ob es Zugriff auf Netzwerkfunktionen braucht. In älteren Versionen (bis 4.88) gab es dafür beim Installieren die Auswahl „Use recommended settings (requires password)“. Wenn alles nichts hilft, nimm einen Linux-Server oder ein NAS.

Nach einem Neustart oder Ruhezustand ist der Container weg.

Docker Desktop startet erst nach deiner Anmeldung. Prüfe den Autostart in „Settings › General“ und melde dich nach einem Neustart an. Länger als etwa 30 Minuten sollte der Container nicht fehlen.

Die Uhr der Batterie geht um Stunden falsch.

TZ fehlt oder ist falsch geschrieben. Trage in der Compose-Datei zum Beispiel Europe/Berlin ein und führe docker compose up -d erneut aus.

Voraussetzungen

  • Ein Mac, der dauerhaft läuft und wach bleibt (Apple Silicon oder Intel)
  • Docker Desktop (kostenlos für Privatpersonen; wird in der Anleitung installiert)
  • Die Ports 80 und 443 sind am Mac frei
  • Eine feste IP-Adresse für den Mac (DHCP-Reservierung im Router)
  • Zugriff auf den DNS-Server im Heimnetz (z. B. Pi-hole oder AdGuard Home)
  • Ein Marstek Venus (E, D oder E v3) im selben Netz

Andere Systeme

Unterstützen

Diese Tools entstehen in meiner Freizeit und bleiben kostenlos, offen und cloud-frei. Wenn dir eins davon einen Nachmittag gespart hat, freue ich mich über einen Kaffee oder ein Stück Pizza.

Kaffee oder Pizza