Ich wollte etwas, das eigentlich trivial klingt: meinen AC·THOR 9s — den my-PV-Heizstab, der PV-Überschuss in Warmwasser verwandelt — aus Home Assistant heraus per Boost auf eine Zieltemperatur fahren, wenn abends nicht genug Sonne kam. Lesen über Modbus TCP lief längst: Boiler-Temperatur, Leistung, alles sauber als Sensor in HA. Also dachte ich, der Schreibzugriff sei nur noch eine Zeile YAML entfernt.
War er nicht. Jeder Modbus-Write an den AC·THOR endete in einem connection refused. Kein Timeout, kein leiser Fehlschlag — das Gerät weist Schreibversuche aktiv ab. Das steht so in keiner Doku, und es kostete mich einen Abend Fehlersuche, bis ich verstand: Am AC·THOR 9s ist Modbus-TCP read-only. Punkt.
Das eigentliche Problem: Modbus lesen ja, schreiben nein
Die Trennung ist hart und reproduzierbar. Monitoring funktioniert dauerhaft über Modbus, Steuerung gar nicht. Wer wie ich erst die Lese-Sensoren baut und sich dann freut, ist auf dem Holzweg, sobald der erste set-Befehl kommt. Hier die Bestandsaufnahme, die ich mir nach der Fehlersuche notiert habe:
BLOCKED: Modbus-TCP-Write-Operationen (Geräte-seitige Restriktion, 'connection refused' auf jeden Schreibversuch)
WORKING: Steuerung via Cloud-API PUT /setup
WORKING: Temperatur-Monitoring via Modbus-TCP weiterhin (read-only)
Getestete Parameter (PUT /setup, JSON-Body):
bstmode Sicherstellungs-/Boost-Modus 0=Off, 1=On
ww1boost Zieltemperatur 550 = 55,0°C (Zehntel °C)
ww1target Max-Temperatur Solarbetrieb 650 = 65,0°C (Zehntel °C)
bstton1 Boost-Zeitfenster 1 Start Stunde 0-23
bsttof1 Boost-Zeitfenster 1 Ende Stunde 0-23
Stolperfallen:
- Propagation-Delay: Änderung greift erst nach 4-6 s am Gerät.
- API antwortet sofort mit 'ok' (kein Beleg, dass der Wert schon gesetzt ist).
- Vor der GET /setup-Verifikation warten.Die Rettung ist die my-PV Cloud-API. Sie ist kaum dokumentiert, aber sie nimmt genau die Schreibbefehle entgegen, die das lokale Modbus verweigert. Der Weg führt also nicht über das LAN direkt aufs Gerät, sondern über den Umweg my-PV-Cloud — die das Gerät dann selbst nachzieht.
Die Lösung: my-PV Cloud-API per PUT /setup
Die API hat einen einzigen Steuer-Endpoint, der zählt: PUT /api/v1/device/<serial>/setup. Der JSON-Body enthält genau die Felder, die du ändern willst — alles andere bleibt unangetastet. Authentifiziert wird per Authorization-Header mit deinem Cloud-API-Token. Das ist der gesamte Transport-Mechanismus: ein PUT mit ein paar Schlüsseln im Body.
Wichtig zur Einordnung: Dieser Post behandelt nur die Transport-Schicht — also wie der Schreibbefehl überhaupt zum Gerät kommt. Die eigentliche Überschuss-Logik (wann boosten, Boost-Stop bei 55 °C) gehört in eine separate Automation und ist Thema des AC·THOR-Überschuss-Posts.
Die shell_command.yaml — Boost und Zieltemperatur setzen
Da es für die my-PV Cloud keine native HA-Integration gibt, baue ich die Schreibbefehle als shell_command mit curl. Jeder Eintrag ist ein einzelner PUT. Ersetze DEVICE_SERIAL durch deine my-PV-Seriennummer und YOUR_MYPV_API_TOKEN durch dein Cloud-API-Token (am besten als !secret auslagern, hier zur Lesbarkeit inline):
# AC·THOR 9s Cloud-API Commands (direkte REST-Calls)
# Nutzt die my-PV Cloud-API, da Modbus-TCP-Write geräteseitig blockiert ist.
# Platzhalter ersetzen:
# DEVICE_SERIAL = deine my-PV Geräte-Seriennummer
# YOUR_MYPV_API_TOKEN = dein my-PV Cloud-API Authorization-Token
acthor_enable_boost: 'curl -s -X PUT "https://api.my-pv.com/api/v1/device/DEVICE_SERIAL/setup" -H "Authorization: YOUR_MYPV_API_TOKEN" -H "Content-Type: application/json" -d "{\"bstmode\": 1}"'
acthor_disable_boost: 'curl -s -X PUT "https://api.my-pv.com/api/v1/device/DEVICE_SERIAL/setup" -H "Authorization: YOUR_MYPV_API_TOKEN" -H "Content-Type: application/json" -d "{\"bstmode\": 0}"'
# Zieltemperatur (in Zehntel °C: 550=55°C, 600=60°C, 650=65°C)
acthor_set_target_temp_55: 'curl -s -X PUT "https://api.my-pv.com/api/v1/device/DEVICE_SERIAL/setup" -H "Authorization: YOUR_MYPV_API_TOKEN" -H "Content-Type: application/json" -d "{\"ww1boost\": 550}"'
# Max-Solar-Temperatur
acthor_set_max_temp_65: 'curl -s -X PUT "https://api.my-pv.com/api/v1/device/DEVICE_SERIAL/setup" -H "Authorization: YOUR_MYPV_API_TOKEN" -H "Content-Type: application/json" -d "{\"ww1target\": 650}"'
# Boost-Zeitfenster (Start/Ende als Stunde 0-23)
acthor_enable_boost_with_time: 'curl -s -X PUT "https://api.my-pv.com/api/v1/device/DEVICE_SERIAL/setup" -H "Authorization: YOUR_MYPV_API_TOKEN" -H "Content-Type: application/json" -d "{\"bstmode\": 1, \"bstton1\": {{ start_hour }}, \"bsttof1\": {{ end_hour }}}"'Nach einem Reload der shell_commands stehen shell_command.acthor_enable_boost und die anderen als Service in HA bereit und lassen sich aus jeder Automation oder vom Developer-Tools-Service-Tab aus aufrufen. Damit ist der Schreibweg, den Modbus verweigert hat, wiederhergestellt.
Die Parameter, die wirklich funktionieren
Ich habe die Felder einzeln durchprobiert, weil die my-PV-Doku hier schweigt. Diese vier (plus die zwei Zeitfenster-Felder) reichen für die komplette Boost-Steuerung. bstmode ist der Schalter: 1 startet den Boost, 0 stoppt ihn. ww1boost ist die Zieltemperatur des Boosts, ww1target die Maximaltemperatur im normalen Solarbetrieb — beide in Zehntel Grad, also 550 für 55,0 °C. bstton1 und bsttof1 legen ein Boost-Zeitfenster als ganze Stunde (0–23) fest.
Der häufigste Anfängerfehler ist die Einheit: Wer 55 statt 550 schickt, fährt das Gerät auf 5,5 °C Ziel — also faktisch aus. Die Zehntel-Grad-Konvention ist nirgends sauber dokumentiert, sie ist aber konsistent über alle Temperatur-Felder.
Die Stolperfalle: der Propagation-Delay
Hier verlor ich am meisten Zeit. Die API antwortet auf jeden PUT sofort mit 'ok' — aber das bedeutet nur, dass die Cloud den Befehl entgegengenommen hat, nicht dass das Gerät den Wert schon übernommen hat. Bis die Änderung tatsächlich am AC·THOR ankommt, vergehen 4 bis 6 Sekunden.
Praktisch heißt das: Wenn du nach dem Schreiben sofort per GET /setup verifizierst, liest du noch den alten Wert und denkst, der Befehl sei fehlgeschlagen. Baue also nach dem PUT eine kleine Wartezeit ein, bevor du die Verifikation oder eine Folge-Aktion auslöst. In einer HA-Automation mache ich das mit einem delay von ein paar Sekunden zwischen dem shell_command und dem nächsten Schritt — das hat alle Phantom-Fehlschläge eliminiert.
Monitoring bleibt auf Modbus
Ein angenehmer Nebeneffekt: Du musst das funktionierende Modbus-Read nicht aufgeben. Bei mir liest HA weiter die Boiler-Temperatur und die Leistung lokal per Modbus TCP — schnell, ohne Cloud-Abhängigkeit und ohne Rate-Limit. Nur der Schreibweg läuft über die Cloud. Dieses hybride Setup (lokal lesen, Cloud schreiben) ist robust: Fällt das Internet aus, verlierst du nur die Steuerung, nicht die Anzeige. Wer den Wechselrichter dahinter ebenfalls per Modbus anbindet, findet die Grundlagen im Modbus-Cache-Post.
Häufige Fragen
Warum lässt der AC·THOR 9s keinen Modbus-Write zu?
Das ist eine geräteseitige Restriktion von my-PV: Der Modbus-TCP-Server am AC·THOR ist read-only ausgelegt, jeder Schreibversuch wird mit 'connection refused' abgewiesen. Steuerung ist ausschließlich über die offizielle App, das lokale Webinterface oder eben die Cloud-API vorgesehen. Es ist kein Fehler in deiner Konfiguration — es ist Absicht des Herstellers.
Brauche ich zwingend die Cloud, oder geht es auch lokal?
Für den Schreibzugriff per API führt der dokumentierte Weg über die my-PV Cloud (api.my-pv.com). Manche Firmware-Stände bieten zusätzlich lokale HTTP-Endpunkte, das ist aber versionsabhängig und nicht garantiert. Der hier gezeigte Cloud-Weg funktioniert geräteübergreifend zuverlässig — der Preis ist die Internet-Abhängigkeit für die Steuerung. Das Monitoring bleibt davon unberührt lokal.
Warum schlägt meine Verifikation direkt nach dem Schreiben fehl?
Mit hoher Wahrscheinlichkeit wegen des Propagation-Delays. Die API quittiert sofort mit 'ok', das Gerät übernimmt den Wert aber erst nach 4–6 Sekunden. Wenn du unmittelbar danach GET /setup abfragst, liest du noch den alten Stand. Warte ein paar Sekunden zwischen Schreiben und Lesen, dann stimmt das Ergebnis.
Wie verstecke ich Seriennummer und Token in der Konfiguration?
Lege beide in secrets.yaml ab und referenziere sie per !secret im shell_command. Damit landen weder die Geräte-Seriennummer noch das Cloud-API-Token im versionierten YAML. Achte besonders darauf, dass das Token nirgends in Logs, Screenshots oder einem Git-Repo auftaucht — es gewährt vollen Schreibzugriff auf dein Gerät.



