Skip to content
  • Recent
  • Tags
  • 0 Unread 0
  • Categories
  • Unreplied
  • Popular
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Logo
  1. ioBroker Community Home
  2. Deutsch
  3. Einsteigerfragen
  4. Einbindung von Geräten
  5. Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern

NEWS

  • Wartung am 15.11. – Forum ab 22:00 Uhr nicht erreichbar
    BluefoxB
    Bluefox
    12
    2
    259

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.0k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    1.7k

Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern

Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern

Scheduled Pinned Locked Moved Einbindung von Geräten
akkuhoymilesmqtt
37 Posts 10 Posters 5.2k Views 10 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    besimo
    wrote on last edited by
    #4

    @bertderkleine
    Danke für die schnelle Antwort. Also eine schleichende Reduzierung des SOC, wenn set power einige Stunden auf 0 stand, ist dir nicht aufgefallen ?

    Zum Vergleich beim EZHI von APsystems hat ein Nutzer von einer Reduzierung des SOC von 14% auf 8% in der Nacht, nachdem abends der eingestellte min SOC erreicht war, berichtet.

    BertDerKleineB 1 Reply Last reply
    0
    • B besimo

      @bertderkleine
      Danke für die schnelle Antwort. Also eine schleichende Reduzierung des SOC, wenn set power einige Stunden auf 0 stand, ist dir nicht aufgefallen ?

      Zum Vergleich beim EZHI von APsystems hat ein Nutzer von einer Reduzierung des SOC von 14% auf 8% in der Nacht, nachdem abends der eingestellte min SOC erreicht war, berichtet.

      BertDerKleineB Offline
      BertDerKleineB Offline
      BertDerKleine
      wrote on last edited by
      #5

      @besimo
      Ich kann zumindest sagen, dass der Akku wirklich nicht unter die eingestellte "Entladeschlussstufe" fällt, wenn er die mal erreicht hat.
      Darum kümmert sich die fest eingebaute Logik anscheinend.

      Was er da an Energie reinsteckt, weiss ich nicht. Ich gehe davon aus, dass die Geräte hier einen klar messbaren Eigenverbrauch haben.

      Siehe: https://www.photovoltaik.eu/solarspeicher/wie-viel-schluckt-der-speicher

      Also auch bei den teureren und größeren Gerätschaften sind 15 W nichts überraschendes.

      Je nachdem wo man den Hoymiles hinstellt, gibt es im Winter auch noch die Stromkosten für die eingebaute "Heizung", die an sich ein sinnvolles Feature ist.

      B 1 Reply Last reply
      0
      • BertDerKleineB BertDerKleine

        @besimo
        Ich kann zumindest sagen, dass der Akku wirklich nicht unter die eingestellte "Entladeschlussstufe" fällt, wenn er die mal erreicht hat.
        Darum kümmert sich die fest eingebaute Logik anscheinend.

        Was er da an Energie reinsteckt, weiss ich nicht. Ich gehe davon aus, dass die Geräte hier einen klar messbaren Eigenverbrauch haben.

        Siehe: https://www.photovoltaik.eu/solarspeicher/wie-viel-schluckt-der-speicher

        Also auch bei den teureren und größeren Gerätschaften sind 15 W nichts überraschendes.

        Je nachdem wo man den Hoymiles hinstellt, gibt es im Winter auch noch die Stromkosten für die eingebaute "Heizung", die an sich ein sinnvolles Feature ist.

        B Offline
        B Offline
        besimo
        wrote on last edited by besimo
        #6

        @bertderkleine
        Angeblich kann man in der App Langzeitspeicherung unterer SOC z.B. 10% einstellen, dann macht er keine Erhaltungsladung, wenn der SOC unter 10% fällt. Ist Langzeitspeicherung nicht eingestellt, macht er dann eine Erhaltungsladung.
        Hast du die Langzeitspeicherung aktiviert ?

        Grundsätzlich ist der MS-A2 ja sehr sparsam (3W im Standby) im Vergleich zu den grossen Speichern. Aber erreicht er das auch bei aktiviertem Mqtt ?

        Und Heizung ist kein Thema, die Temperatur kann man überwachen. Fällt sie unter 1°, muss man nur den Aufstellort ins Haus verlegen.

        Mein Ziel ist ja, im Winter auch noch einen bestmöglichen Autarkiegrad zu erreichen. Einen Fehlkauf habe ich ja schon mit der Huawei Luna2000-S1-10kWh. Da gehen jeden Tag von den 10kWh Nettokapazität 2kWh für den Eigenverbrauch drauf, also effektiv bleiben 8kWh echte Nettokapazität.

        BertDerKleineB 1 Reply Last reply
        0
        • B besimo

          @bertderkleine
          Angeblich kann man in der App Langzeitspeicherung unterer SOC z.B. 10% einstellen, dann macht er keine Erhaltungsladung, wenn der SOC unter 10% fällt. Ist Langzeitspeicherung nicht eingestellt, macht er dann eine Erhaltungsladung.
          Hast du die Langzeitspeicherung aktiviert ?

          Grundsätzlich ist der MS-A2 ja sehr sparsam (3W im Standby) im Vergleich zu den grossen Speichern. Aber erreicht er das auch bei aktiviertem Mqtt ?

          Und Heizung ist kein Thema, die Temperatur kann man überwachen. Fällt sie unter 1°, muss man nur den Aufstellort ins Haus verlegen.

          Mein Ziel ist ja, im Winter auch noch einen bestmöglichen Autarkiegrad zu erreichen. Einen Fehlkauf habe ich ja schon mit der Huawei Luna2000-S1-10kWh. Da gehen jeden Tag von den 10kWh Nettokapazität 2kWh für den Eigenverbrauch drauf, also effektiv bleiben 8kWh echte Nettokapazität.

          BertDerKleineB Offline
          BertDerKleineB Offline
          BertDerKleine
          wrote on last edited by
          #7

          @besimo sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

          Hast du die Langzeitspeicherung aktiviert ?

          Was meinst Du damit? Es gibt in der App nichts mit dem Namen.

          Ich habe (wie oben beschrieben) Zahnrad / Betriebsmodus / Eigenverbrauch / Entladeschlussstufe auf 10% gesetzt bzw. dieses Default so stehengelassen.

          B 1 Reply Last reply
          0
          • BertDerKleineB BertDerKleine

            @besimo sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

            Hast du die Langzeitspeicherung aktiviert ?

            Was meinst Du damit? Es gibt in der App nichts mit dem Namen.

            Ich habe (wie oben beschrieben) Zahnrad / Betriebsmodus / Eigenverbrauch / Entladeschlussstufe auf 10% gesetzt bzw. dieses Default so stehengelassen.

            B Offline
            B Offline
            besimo
            wrote on last edited by
            #8

            @bertderkleine
            Ich glaube, da hat chatgpt wieder Unwahrheiten geschrieben. Die Option Langzeitspeicherung scheint es wohl doch nicht zu geben. Die Erhaltungsladung kann bei Erreichen min SOC nur Manuell durch Ziehen des Schukostecker vermieden werden.
            Evtl. gäbe es noch die Option über den Zeitplan in der App auf kein Betrieb zu stellen und in iobroker den Ems-mode auf "General". Der SOC sollte bei dem Test deutlich grösser, als der min SOC sein, um eine Erhaltungsladung zu vermeiden.

            BertDerKleineB 1 Reply Last reply
            0
            • B besimo

              @bertderkleine
              Ich glaube, da hat chatgpt wieder Unwahrheiten geschrieben. Die Option Langzeitspeicherung scheint es wohl doch nicht zu geben. Die Erhaltungsladung kann bei Erreichen min SOC nur Manuell durch Ziehen des Schukostecker vermieden werden.
              Evtl. gäbe es noch die Option über den Zeitplan in der App auf kein Betrieb zu stellen und in iobroker den Ems-mode auf "General". Der SOC sollte bei dem Test deutlich grösser, als der min SOC sein, um eine Erhaltungsladung zu vermeiden.

              BertDerKleineB Offline
              BertDerKleineB Offline
              BertDerKleine
              wrote on last edited by
              #9

              @besimo
              Ich verstehe noch nicht, was Du erreichen willst.
              Wenn Du den Speicher nutzen willst, muss er voll im betrieb sein. Ob er jetzt über die App/Cloud gesteuert wird oder per MQTT dürfte keinen fundamentalen Unterscheid machen. Er muss ganz normal am Netz hängen und dann kostet die Erhaltungsladung Strom.

              Wenn ihn abklemmst gibts natürlich keine Erhaltungsladung, aber das Ding bringt Dir natürlich so nix.

              Statt Abklemmen kannst Du auch den Kopf 8 Sekunden drücken und den Speicher in den Inselmodus (off grid) versetzen. Dann ist auch Ruhe.

              Ich kann mir aber keinen vernünftigen Fall vorstellen, wo tägliches oder gar stündliches An/Abklemmen irgendeinen wirtschaftlichen Sinn macht.

              Ich schau die Tage mal, was ich über Stromverbrauch zur Erhaltung finden kann. Dazu brauche ich wieder Sonne und einen vollen Speicher.

              Hoymiles schreibt in der BDA übrigens:

              "• Die optimale Lebensdauer des Akkus wird durch regelmäßiges Aufladen erreicht. Laden Sie den Akku
              stets alle paar Monate auf, selbst wenn er nicht verwendet wird.

              • Wenn Sie den Akku über einen längeren Zeitraum einlagern, laden Sie das MS-A2 vor der Lagerung bei Raumtemperatur auf 40 % bis 50 % auf. "

              S B 2 Replies Last reply
              0
              • BertDerKleineB BertDerKleine

                @besimo
                Ich verstehe noch nicht, was Du erreichen willst.
                Wenn Du den Speicher nutzen willst, muss er voll im betrieb sein. Ob er jetzt über die App/Cloud gesteuert wird oder per MQTT dürfte keinen fundamentalen Unterscheid machen. Er muss ganz normal am Netz hängen und dann kostet die Erhaltungsladung Strom.

                Wenn ihn abklemmst gibts natürlich keine Erhaltungsladung, aber das Ding bringt Dir natürlich so nix.

                Statt Abklemmen kannst Du auch den Kopf 8 Sekunden drücken und den Speicher in den Inselmodus (off grid) versetzen. Dann ist auch Ruhe.

                Ich kann mir aber keinen vernünftigen Fall vorstellen, wo tägliches oder gar stündliches An/Abklemmen irgendeinen wirtschaftlichen Sinn macht.

                Ich schau die Tage mal, was ich über Stromverbrauch zur Erhaltung finden kann. Dazu brauche ich wieder Sonne und einen vollen Speicher.

                Hoymiles schreibt in der BDA übrigens:

                "• Die optimale Lebensdauer des Akkus wird durch regelmäßiges Aufladen erreicht. Laden Sie den Akku
                stets alle paar Monate auf, selbst wenn er nicht verwendet wird.

                • Wenn Sie den Akku über einen längeren Zeitraum einlagern, laden Sie das MS-A2 vor der Lagerung bei Raumtemperatur auf 40 % bis 50 % auf. "

                S Offline
                S Offline
                spiffel1234
                wrote on last edited by spiffel1234
                #10

                Hi ich finde es jetzt schon mal super das das Hoymiles MSA 2 dann jetzt auch mqtt kann. Was kann es alles für Werte liefern auch wenn evtl. nur Read Only. Evtl gibt es ja dann mal einen Adapter wo man Einstellungen vornehmen kann... so hat man halt die Datenpunkte einzeln.

                BertDerKleineB 1 Reply Last reply
                0
                • BertDerKleineB BertDerKleine

                  @besimo
                  Ich verstehe noch nicht, was Du erreichen willst.
                  Wenn Du den Speicher nutzen willst, muss er voll im betrieb sein. Ob er jetzt über die App/Cloud gesteuert wird oder per MQTT dürfte keinen fundamentalen Unterscheid machen. Er muss ganz normal am Netz hängen und dann kostet die Erhaltungsladung Strom.

                  Wenn ihn abklemmst gibts natürlich keine Erhaltungsladung, aber das Ding bringt Dir natürlich so nix.

                  Statt Abklemmen kannst Du auch den Kopf 8 Sekunden drücken und den Speicher in den Inselmodus (off grid) versetzen. Dann ist auch Ruhe.

                  Ich kann mir aber keinen vernünftigen Fall vorstellen, wo tägliches oder gar stündliches An/Abklemmen irgendeinen wirtschaftlichen Sinn macht.

                  Ich schau die Tage mal, was ich über Stromverbrauch zur Erhaltung finden kann. Dazu brauche ich wieder Sonne und einen vollen Speicher.

                  Hoymiles schreibt in der BDA übrigens:

                  "• Die optimale Lebensdauer des Akkus wird durch regelmäßiges Aufladen erreicht. Laden Sie den Akku
                  stets alle paar Monate auf, selbst wenn er nicht verwendet wird.

                  • Wenn Sie den Akku über einen längeren Zeitraum einlagern, laden Sie das MS-A2 vor der Lagerung bei Raumtemperatur auf 40 % bis 50 % auf. "

                  B Offline
                  B Offline
                  besimo
                  wrote on last edited by
                  #11

                  @bertderkleine
                  Da der Akku sehr klein ist, würde bei mir die tägliche Nutzungszeit sehr kurz sein, etwa 2 Stunden Laden am Tag und 6-8 Stunden Entladen in der Nacht, also i.M. 15 Stunden möglicher Standby pro Tag. Wäre blöd, wenn er in dieser Zeit wegen dem MQtt-Modus im vollen Betrieb bleibt. Wenn er da z.B. 33 W brauchen würde, also 30 W mehr, als im echten Standby, wären das 30x15x365=164kWh Jahres-Mehrverbrauch, mehr als mein Gefrierschrank.

                  Und generell will ich am Ende alles in ioBroker automatisiert steuern, am besten per javascript, so dass ich die Abfrageintervalle über den Tagesverkauf variabel gestalten kann.
                  Die manuelle Geschichte war ja nur zu Testzwecken gedacht, um rauszubekommen, wie hoch der Eigenverbrauch im "Mqtt-Standby" ist.

                  BertDerKleineB 1 Reply Last reply
                  0
                  • S spiffel1234

                    Hi ich finde es jetzt schon mal super das das Hoymiles MSA 2 dann jetzt auch mqtt kann. Was kann es alles für Werte liefern auch wenn evtl. nur Read Only. Evtl gibt es ja dann mal einen Adapter wo man Einstellungen vornehmen kann... so hat man halt die Datenpunkte einzeln.

                    BertDerKleineB Offline
                    BertDerKleineB Offline
                    BertDerKleine
                    wrote on last edited by
                    #12

                    @spiffel1234 sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                    Was kann es alles für Werte liefern auch wenn evtl. nur Read Only.

                    Schau oben in den ersten Link in die Entwicklerdoku. Da sind Kapitel 10 und 11 mit allen ausgegebenen Werten drin. Die landen in zwei JSONs.

                    1 Reply Last reply
                    0
                    • B besimo

                      @bertderkleine
                      Da der Akku sehr klein ist, würde bei mir die tägliche Nutzungszeit sehr kurz sein, etwa 2 Stunden Laden am Tag und 6-8 Stunden Entladen in der Nacht, also i.M. 15 Stunden möglicher Standby pro Tag. Wäre blöd, wenn er in dieser Zeit wegen dem MQtt-Modus im vollen Betrieb bleibt. Wenn er da z.B. 33 W brauchen würde, also 30 W mehr, als im echten Standby, wären das 30x15x365=164kWh Jahres-Mehrverbrauch, mehr als mein Gefrierschrank.

                      Und generell will ich am Ende alles in ioBroker automatisiert steuern, am besten per javascript, so dass ich die Abfrageintervalle über den Tagesverkauf variabel gestalten kann.
                      Die manuelle Geschichte war ja nur zu Testzwecken gedacht, um rauszubekommen, wie hoch der Eigenverbrauch im "Mqtt-Standby" ist.

                      BertDerKleineB Offline
                      BertDerKleineB Offline
                      BertDerKleine
                      wrote on last edited by
                      #13

                      @besimo sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                      Wäre blöd, wenn er in dieser Zeit wegen dem MQtt-Modus im vollen Betrieb bleibt.

                      Erstens verstehe ich nicht, warum die annimmst, dass ein "MQTT-Modus" anders Strom verbraucht als ein anderer, wo Cloud und App steuern. Ich denke, die Nutzung des Protokolls hat keine grosse Bedeutung.

                      Zweitens wirst Du im Schnitt (!) länger Aufladen und öfters, wiederholend. Das deutsche Wetter bietet ja üblicherweise was anderes als digital blauen Himmel oder gar keine Sonne. D.h. beim Laden/Entladen wird es oft hin- und hergehen.

                      1 Reply Last reply
                      0
                      • B besimo

                        @bertderkleine
                        Kann man den MS-A2 im Mqtt-Mode in den Standby zwingen z.B. durch Set Power = 0 W ?
                        Hat jemand den Eigenverbrauch gemessen bei Power = 0 W ?

                        BertDerKleineB Offline
                        BertDerKleineB Offline
                        BertDerKleine
                        wrote on last edited by BertDerKleine
                        #14

                        @besimo sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                        Hat jemand den Eigenverbrauch gemessen bei Power = 0 W ?

                        Ich habe MQTT aktuell lesend verbunden (d.h. der Akku sendet alle paar Sekunden den Status) und jetzt gerade ist er voll.
                        Der Eigenverbrauch des Akkus in der Gammelphase, den ein zwischengestecktes Strommessgerät anzeigt liegt bei 6,5 W (in dem Fall bei zwei in Reihe geschalteten Akkus).

                        Das sagt natürlich nicht automatisch etwas aus darüber, ob er irgendwann mal etwas nachlädt.

                        PS:
                        Hier https://www.smartzone.de/hoymiles-ms-a2-speicher-test/ ganz unten gibt es auch Angaben zur Effizienz und Eigenverbrauch

                        S 1 Reply Last reply
                        1
                        • BertDerKleineB BertDerKleine

                          @besimo sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                          Hat jemand den Eigenverbrauch gemessen bei Power = 0 W ?

                          Ich habe MQTT aktuell lesend verbunden (d.h. der Akku sendet alle paar Sekunden den Status) und jetzt gerade ist er voll.
                          Der Eigenverbrauch des Akkus in der Gammelphase, den ein zwischengestecktes Strommessgerät anzeigt liegt bei 6,5 W (in dem Fall bei zwei in Reihe geschalteten Akkus).

                          Das sagt natürlich nicht automatisch etwas aus darüber, ob er irgendwann mal etwas nachlädt.

                          PS:
                          Hier https://www.smartzone.de/hoymiles-ms-a2-speicher-test/ ganz unten gibt es auch Angaben zur Effizienz und Eigenverbrauch

                          S Offline
                          S Offline
                          spiffel1234
                          wrote on last edited by spiffel1234
                          #15

                          Hi ich muss nochmal einhaken weis jemand ob der MS-A2 Akku auch im "OpenDTU on Battery" supported wird? Hier kann man ja angeblich eine Nulleinspeisung machen. Evtl. Ich stelle jetzt erst mal von OPENDTU auf OPENDTU on Battery um.

                          @BertDerKleine vielen Dank für den Hinweis.

                          1 Reply Last reply
                          0
                          • BertDerKleineB BertDerKleine

                            Ich schildere hier mal, wie ich den Hoymiles MS-A2 standalone (kein WR, keine Balkonstrom-Panels, kein Shelly, kein Uni-Meter) per MQTT zum laufen bringe - als Nachrüstlösung für eine PV-Anlage.

                            Vielleicht kann das ja jemand gebrauchen als Idee. Kann man bestimmt alles noch besser machen, aber als Basis kann ich sagen, dass es funktioniert. 😃

                            Eventuell

                            Hintergrund:
                            Speziell für das Szenario, dass der MS-A2 standalone "als große Powerbank" betrieben werden soll, also ohne eingestöpselte Balkonstrom-Panels, braucht es eine Lade/Entladesteuerung, die auf Überschuß und Mangel reagiert.
                            Seit Anfang Juni 2025 beherrscht der MS-A2 nativ MQTT, was nun eine noch einfachere Lösung ermöglicht, nämlich die direkte Steuerung über iobroker.

                            Die offizielle Doku zum MQTT Feature findet man hier :

                            • https://www.photovoltaikforum.com/core/file-download/507290/
                            • https://www.photovoltaikforum.com/core/file-download/507291/
                            • Der User "Rong" in dem Thread ist übrigens anscheinend ein Mitarbeiter des Herstelllers Hoymiles.

                            Was braucht man also an Zutaten?

                            • eine laufende iobroker Installation und einen eingestöpselten und mit dem WLAN verbundenen MS-A2, dessen Firmware über die Handy-App aktualisiert wurde.
                            • einen MQTT Broker Adapter im iobroker
                            • in der S-Miles App unter Zahnrad / MQTT-Service die Daten konfigurieren (Server IP Adresse des iobrokers, den Port (meist 1883) und Benutzernamen / Passwort.

                            Dann tauscht der Akku mit iobroker Daten aus und im iobroker Objekt-Baum findet man unter mqtt / 0 / homeassistant nun die Datenpunkte.

                            Standardmäßig lassen sich die Datenpunkte nur auslesen, aber nichts steuern. Um den Akku steuern zu können, muss man in mqtt.0.homeassistant.select.MSA-123456789.ems_mode.command manuell den Befehl mqtt_ctrl einmalig absetzen (der bleibt dann da).

                            Die Steuerbefehle (Angaben in Watt) zum Laden/Entladen setzt man später in mqtt.0.homeassistant.number.MSA-123456789.power_ctrl.set ab. Dort stehen positive Werte für Entladen und negative für Laden des Akkus.

                            Genutzte Aliase:

                            Mein Steuerungsskript basiert auf ein paar Alias-Datenpunkten:

                            • alias.0.Akku_befohlene_Entladeleistung --> mqtt.0.homeassistant.number.MSA-123456789.power_ctrl.set
                            • alias.0.Akku_Ladezustand --> mqtt.0.homeassistant.sensor.MSA-123456789.quick.state mit Alias-Konverter beim Lesen JSON.parse(val).soc
                            • alias.0.Akku_grid_on_power --> mqtt.0.homeassistant.sensor.MSA-123456789.quick.state mit Alias-Konverter beim Lesen JSON.parse(val).grid_on_p

                            Mehr braucht es nicht. Man kann deutlich mehr Infos auslesen, aber zur Steuerung reicht das.

                            Benötigte Datenquelle:

                            Natürlich braucht es zusätzlich einen Datenpunkt im iobroker, der den aktuell vorliegenden Stromüberschuss im Haus liefert.

                            In meinem Skript wird aktuell alias.0.Stromüberschuss_IR-Lesekopf verwendet, was den Überschuss direkt vom offiziellen Stromzähler ausliest (mittels eines Tasmota-basierten Infrarot Lesekopfs, den man sich leicht für kleines Geld beschaffen kann und der ebenfalls seine daten via  MQTT zu iobroker sendet). Diese Daten können aber auch von einem PV-Wechselrichter oder Stromzähler kommen, Hauptsache es ist der Stromüberschuss (positive Watt-Werte für einen Überschuss, d.h. Strom der sonst ins öffentliche Netz eingespeist wird und negative Werte für Netzbezug).

                            Begrenzungen der Leistung und Entladung via App:

                            Egal, was Ihr per MQTT an Befehlen sendet, die Lade- und Entladeleistung des Akkus hält sich an die Vorgaben, die Ihr via der S-Miles App eingegeben habt unter

                            • Zahnrad / Einstellung der Ausgangsleistung (meist 800 W)
                            • Zahnrad / Netzgebundene Eingangseinstellung (meist 800 W)
                            • Zahnrad / Betriebsmodus / Eigenverbrauch / Entladeschlussstufe (meist 10%)

                            Das ist im Skript alles auch mit abgefangen, aber m.W. passt der Akku da auch drauf auf.

                            Besonderheit: Vergesslichkeit nach 59 Sekunden & Ignoranz bei immer gleichen Zahlen

                            Es gibt eine Besonderheit, die zu beachten ist, nämlich vergisst der Akku nach 59 Sekunden den per MQTT vorgegebenen Befehl zum Laden/Entladen wieder. Und außerdem ignoriert er auch simple Wiederholungen einer Vorgabe der exakt selben Wattzahl.

                            Sobald er diese Eure Vorgabe vergessen hat, führt der Akku das aus, was unter Zahnrad / Hauslasteinstellungen / Lastleistungskurve / Kurve 1 / (alle Tage und Uhrzeiten) in der App hinterlegt ist. Falls da also z.B. 100 W steht, wird der Akku dann mit 100 W entladen. Man kann in der App hier auch einfach "0 W" hinterlegen, so dass der Akku dann nix macht.

                            Aus diesem Grund sendet mein Skript alle 30 Sekunden eine neue Wattvorgabe und zusätzlich alterniert diese immer um 0,1 Watt. So wird die Steuerung aufrechterhalten.

                            Skript:

                            Und hier findet Ihr mein Javascript als Denkanstoß.
                            Ein großer Teil des Skripts ist Doku, Logging und Fehlerfindung gewidmet, man kann es also auch kürzen.

                            /**
                             * AKKU-MANAGEMENT-SKRIPT FÜR IO BROKER
                             * 
                             * Dieses Skript steuert einen Batteriespeicher basierend auf dem aktuellen Stromüberschuss.
                             * Es lädt den Akku bei PV-Überschuss und entlädt ihn bei Strombedarf.
                             * Entwurf von BertDerKleine
                             * 
                             * Merkmale:
                             * - Kontinuierliche Regelung unabhängig von Tageszeit
                             * - Getrennte Zielfaktoren für Lade- und Entladevorgänge
                             * - PI-Regler für stabile Regelung
                             * - SOC-Schutz gegen Überladung und Tiefentladung
                             * - Alternierende Steuerbefehle für zuverlässige Akku-Kommunikation
                             * - Ausführliche Diagnosefunktionen
                             * - Konfigurierbares Logging
                             */
                            
                            // ========== KONFIGURATION ==========
                            const AUSFUEHRLICHES_LOGGING = false;  // Auf TRUE setzen für detaillierte Regel-Logs (nur für Debugging)
                            const MAX_LOG_LAENGE = 100;             // Maximale Anzahl gespeicherter Log-Einträge für Diagnose
                            
                            // ========== GLOBALE VARIABLEN ==========
                            /**
                             * Intervall für das Senden von Steuerbefehlen (in Millisekunden)
                             * Der Akku benötigt regelmäßige Aktualisierungen, da er Befehle nach 60-90 Sekunden "vergisst"
                             * 30000 = 30 Sekunden ist ein bewährter Wert für zuverlässige Kommunikation
                             */
                            const alternierIntervall = 30000;
                            
                            /**
                             * Datenpunkt für Akku-Steuerbefehle
                             * - Positive Werte: Entladen (Leistungsabgabe)
                             * - Negative Werte: Laden (Leistungsaufnahme)
                             */
                            const AKTIONS_DATENPUNKT = 'alias.0.Akku_befohlene_Entladeleistung';
                            
                            /** Datenpunkt für die aktuell gemessene Akku-Leistung */
                            const AKTUELLE_AKKULEISTUNG = 'alias.0.Akku_grid_on_power';
                            
                            // Betriebsstatus
                            let regelungAktiv = false;  // Gibt an, ob die Regelung aktuell läuft
                            
                            // Intervalle
                            let messIntervall = null;    // Intervall für Leistungsmessungen
                            let regelIntervall = null;   // Intervall für Regelberechnungen
                            let sendeIntervall = null;   // Intervall für Steuerbefehle
                            
                            // Regelvariablen
                            let mittelungArray = [];     // Speichert die letzten Messwerte für die Mittelwertbildung
                            let aktuellerSollwert = 0;   // Aktuell berechneter Sollwert für Akku-Leistung
                            let toggleFlag = true;       // Steuert die Alternierung der Steuerbefehle (+0.1W Wechsel)
                            let integral = 0;            // Integralanteil des PI-Reglers
                            
                            // ========== PARAMETER ==========
                            /**
                             * Maximale Ladeleistung in Watt
                             * Sollte unterhalb der technischen Grenzen des Akkus liegen.
                             */
                            const maxLadeleistung = 800;
                            
                            /**
                             * Maximale Entladeleistung in Watt
                             * Abhängig von Akku-Kapazität und Wechselrichter.
                             */
                            const maxEntladeleistung = 800;
                            
                            /**
                             * Intervall für Leistungsmessungen in Millisekunden
                             * 10000 = 10 Sekunden ist ein guter Kompromiss zwischen Aktualität und Stabilität
                             */
                            const samplingIntervall = 10000;
                            
                            /**
                             * Faktor für den Integralanteil des PI-Reglers
                             * Ein höherer Wert reagiert stärker auf anhaltende Abweichungen
                             * 0.2 ist ein moderater Wert für stabile Regelung ohne zu starkes Überschwingen
                             */
                            const integralFaktor = 0.2;
                            
                            /** Ladezustand bei dem das Laden gestoppt wird (Vermeidung von Überladung) */
                            const SOC_LADESTOPP = 98;
                            
                            /** Ladezustand bei dem das Entladen gestoppt wird (Vermeidung von Tiefentladung) */
                            const SOC_ENTLADESTOPP = 10;
                            
                            /**
                             * Zielfaktoren für Regelung
                             * 
                             * zielFaktorLaden: Anteil des Überschusses der fürs Laden genutzt wird (0-1)
                             *   - 0.8 = 80% des Überschusses werden zum Laden genutzt (konservativ)
                             *   - Höhere Werte nutzen mehr Überschuss, können aber zu Netzinstabilität führen
                             * 
                             * zielFaktorEntladen: Anteil des Bedarfs der durch Entladen gedeckt wird (0-1)
                             *   - 1.0 = 100% des Bedarfs werden durch Entladen gedeckt (maximale Autarkie)
                             *   - Niedrigere Werte schonen den Akku, erhöhen aber Netzbezug
                             */
                            const zielFaktorLaden = 0.8;
                            const zielFaktorEntladen = 1.0;
                            
                            // ========== LOGGING SYSTEM ==========
                            let logHistorie = [];  // Speichert die letzten Log-Einträge für Diagnosezwecke
                            
                            /**
                             * Verbesserte Log-Funktion mit Historie-Speicherung und Level-Steuerung
                             * 
                             * @param {string} nachricht - Die zu loggende Nachricht
                             * @param {string} level - Log-Level ('debug', 'info', 'warn', 'error')
                             */
                            function log(nachricht, level = 'info') {
                                // Erstelle formatierten Log-Eintrag
                                const timestamp = new Date().toISOString();
                                const logEintrag = `[${timestamp}] [${level.toUpperCase()}] ${nachricht}`;
                                
                                // Füge zur Historie hinzu (begrenzt auf MAX_LOG_LAENGE)
                                logHistorie.push(logEintrag);
                                if (logHistorie.length > MAX_LOG_LAENGE) {
                                    logHistorie.shift();
                                }
                                
                                // Ausgabe basierend auf Level und Konfiguration
                                switch(level) {
                                    case 'error':
                                        console.error(logEintrag);
                                        break;
                                    case 'warn':
                                        console.warn(logEintrag);
                                        break;
                                    case 'info':
                                        console.log(logEintrag);
                                        break;
                                    case 'debug':
                                        // Debug-Logs nur bei aktiviertem ausführlichen Logging
                                        if (AUSFUEHRLICHES_LOGGING) {
                                            console.log(logEintrag);
                                        }
                                        break;
                                    default:
                                        console.log(logEintrag);
                                }
                            }
                            
                            // ========== HELFERFUNKTIONEN ==========
                            /**
                             * Setzt den Steuerungsdatenpunkt mit Fehlerbehandlung
                             * 
                             * @param {number} wert - Der zu setzende Wert
                             * @returns {boolean} True bei Erfolg, False bei Fehler
                             */
                            function sicherSetState(wert) {
                                try {
                                    setState(AKTIONS_DATENPUNKT, wert, false);
                                    return true;
                                } catch (e) {
                                    log(`Fehler beim Setzen des Datenpunkts: ${e.message}`, 'error');
                                    return false;
                                }
                            }
                            
                            /**
                             * Bereinigt den gemessenen Überschuss um den aktuellen Akku-Beitrag
                             * 
                             * @param {number} ueberschussGemessen - Gemessener Stromüberschuss
                             * @param {number} akkuLeistung - Aktuelle Akku-Leistung (positiv = Entladen, negativ = Laden)
                             * @returns {number} Bereinigter Überschuss
                             */
                            function bereinigeLeistung(ueberschussGemessen, akkuLeistung) {
                                return ueberschussGemessen - akkuLeistung;
                            }
                            
                            // ========== FLEXIBLE REGELUNG ==========
                            /**
                             * Startet die kontinuierliche Akku-Regelung
                             */
                            function starteFlexibleRegelung() {
                                if (regelungAktiv) {
                                    log("Regelung bereits aktiv - Start abgebrochen", 'debug');
                                    return;
                                }
                                
                                stoppeRegelung();
                                log("Starte flexible Regelung...");
                                
                                regelungAktiv = true;
                                mittelungArray = [];
                                aktuellerSollwert = 0;
                                integral = 0;
                                toggleFlag = true;
                            
                                // Initialer Status-Log mit Konfiguration
                                log(`Regelung gestartet mit:
                              Max Laden: ${maxLadeleistung}W
                              Max Entladen: ${maxEntladeleistung}W
                              Laden-Zielfaktor: ${zielFaktorLaden}
                              Entladen-Zielfaktor: ${zielFaktorEntladen}
                              SOC-Limits: Ladestopp >${SOC_LADESTOPP}%, Entladestopp <${SOC_ENTLADESTOPP}%`, 'info');
                            
                                // Messintervall - Sammelt regelmäßig Leistungsdaten
                                messIntervall = setInterval(() => {
                                    try {
                                        const ueberschussGemessen = getState('alias.0.Stromüberschuss_IR-Lesekopf').val;
                                        const akkuLeistung = getState(AKTUELLE_AKKULEISTUNG).val;
                                        const bereinigteLeistung = bereinigeLeistung(ueberschussGemessen, akkuLeistung);
                                        
                                        mittelungArray.push(bereinigteLeistung);
                                        if (mittelungArray.length > 6) mittelungArray.shift();
                                    } catch (e) {
                                        log("Messfehler: " + e.message, 'error');
                                    }
                                }, samplingIntervall);
                            
                                // Regelintervall - Berechnet alle 20 Sekunden neue Sollwerte
                                regelIntervall = setInterval(() => {
                                    try {
                                        if (mittelungArray.length < 3) {
                                            log("Nicht genug Messwerte für Regelung", 'debug');
                                            return;
                                        }
                                        
                                        // Berechne gleitenden Mittelwert der letzten Messungen
                                        const summe = mittelungArray.reduce((a, b) => a + b, 0);
                                        const mittelwert = summe / mittelungArray.length;
                                        
                                        // Bestimmung des Betriebsmodus
                                        const istLadebetrieb = mittelwert > 0; // Positiver Wert = Überschuss = Laden
                                        const zielFaktor = istLadebetrieb ? zielFaktorLaden : zielFaktorEntladen;
                                        
                                        // Berechnung der benötigten Akku-Leistung
                                        const zielLeistung = Math.abs(mittelwert) * zielFaktor;
                                        const zielwert = istLadebetrieb ? -zielLeistung : zielLeistung;
                                        
                                        // PI-Regler berechnet Anpassung
                                        const differenz = zielwert - aktuellerSollwert;
                                        integral += differenz * integralFaktor;
                                        
                                        // Integrator-Begrenzung
                                        const integratorLimit = istLadebetrieb ? maxLadeleistung : maxEntladeleistung;
                                        integral = Math.min(Math.max(integral, -integratorLimit), integratorLimit);
                                        
                                        // Neuen Sollwert berechnen
                                        let neuerSollwert = aktuellerSollwert + differenz + integral;
                                        
                                        // Physikalische Grenzen einhalten
                                        if (istLadebetrieb) {
                                            neuerSollwert = Math.min(neuerSollwert, 0); // Max 0 = keine Entladung
                                            neuerSollwert = Math.max(neuerSollwert, -maxLadeleistung); // Min = -maxLadeleistung
                                        } else {
                                            neuerSollwert = Math.max(neuerSollwert, 0); // Min 0 = kein Laden
                                            neuerSollwert = Math.min(neuerSollwert, maxEntladeleistung); // Max = maxEntladeleistung
                                        }
                                        
                                        // Sanfte Anpassung (30% pro Schritt)
                                        const aenderung = neuerSollwert - aktuellerSollwert;
                                        if (Math.abs(aenderung) > 10) {
                                            aktuellerSollwert += aenderung * 0.3;
                                        } else {
                                            aktuellerSollwert = neuerSollwert;
                                        }
                                        
                                        // Ausführliches Logging nur bei Bedarf
                                        if (AUSFUEHRLICHES_LOGGING) {
                                            log(`Regelberechnung:
                              Überschuss (gemittelt): ${mittelwert.toFixed(1)}W
                              Ziel-Leistung: ${zielLeistung.toFixed(1)}W
                              Zielwert (Akku): ${zielwert.toFixed(1)}W
                              Neuer Sollwert: ${neuerSollwert.toFixed(1)}W
                              Aktueller Sollwert: ${aktuellerSollwert.toFixed(1)}W
                              Differenz: ${differenz.toFixed(1)}W
                              Integral: ${integral.toFixed(1)}
                              Faktor: ${zielFaktor}
                              Modus: ${istLadebetrieb ? 'Laden' : 'Entladen'}`, 'debug');
                                        }
                                    } catch (e) {
                                        log("Regelfehler: " + e.message, 'error');
                                    }
                                }, 20000);
                            
                                // Sendeintervall - Sendet alle 30 Sekunden Steuerbefehle
                                sendeIntervall = setInterval(() => {
                                    if (!regelungAktiv) return;
                                    
                                    // SOC-Schutz - Verhindert Überladung und Tiefentladung
                                    const akkuSOC = getState('alias.0.Akku_Ladezustand').val;
                                    let effektiverSollwert = aktuellerSollwert;
                                    
                                    if (effektiverSollwert < 0 && akkuSOC > SOC_LADESTOPP) {
                                        effektiverSollwert = 0;
                                        log(`LADESTOPP: Akku > ${SOC_LADESTOPP}% (SOC: ${akkuSOC.toFixed(1)}%)`, 'warn');
                                    }
                                    
                                    if (effektiverSollwert > 0 && akkuSOC < SOC_ENTLADESTOPP) {
                                        effektiverSollwert = 0;
                                        log(`ENTLADESTOPP: Akku < ${SOC_ENTLADESTOPP}% (SOC: ${akkuSOC.toFixed(1)}%)`, 'warn');
                                    }
                                    
                                    // Alternierende Werte senden (jeder 2. Befehl +0.1W)
                                    const wert = toggleFlag ? effektiverSollwert : effektiverSollwert + 0.1;
                                    sicherSetState(wert);
                                    toggleFlag = !toggleFlag;
                                    
                                    // Protokolliere nur die ersten 20 Minuten oder bei Moduswechsel
                                    log(`Steuerbefehl gesendet: ${wert.toFixed(1)}W (${toggleFlag ? 'nächstes Mal Basiswert' : 'nächstes Mal +0.1W'})`, 'debug');
                                }, alternierIntervall);
                            
                                log("Flexible Regelung erfolgreich gestartet", 'info');
                            }
                            
                            /**
                             * Stoppt die laufende Regelung
                             */
                            function stoppeRegelung() {
                                if (!regelungAktiv) return;
                                
                                clearInterval(messIntervall);
                                clearInterval(regelIntervall);
                                clearInterval(sendeIntervall);
                                regelungAktiv = false;
                                
                                sicherSetState(0);
                                log("Regelung gestoppt", 'info');
                            }
                            
                            // ========== HAUPTPROGRAMM ==========
                            /**
                             * Initialisiert das Skript
                             */
                            function initSkript() {
                                try {
                                    starteFlexibleRegelung();
                                    log("Skript initialisierung abgeschlossen");
                                    
                                    // Aktiviere temporäres ausführliches Logging für die ersten 10 Minuten
                                    setTimeout(() => {
                                        if (!AUSFUEHRLICHES_LOGGING) {
                                            log("Initiale Debug-Periode beendet - Detaillogs deaktiviert");
                                        }
                                    }, 600000); // 10 Minuten
                                } catch (e) {
                                    log("Initialisierungsfehler: " + e.message, 'error');
                                }
                            }
                            
                            // Startverzögerung für Systeminitialisierung
                            setTimeout(initSkript, 5000);
                            
                            // ========== EVENT-HANDLER ==========
                            // Überwacht Ladezustandsänderungen
                            on({ id: 'alias.0.Akku_Ladezustand', change: 'ne' }, (state) => {
                                const soc = state.val;
                                
                                // Protokolliere nur bei relevanten Änderungen
                                if (soc > SOC_LADESTOPP && aktuellerSollwert < 0) {
                                    log(`AKTION: Ladung pausiert (SOC: ${soc}% > ${SOC_LADESTOPP}%)`, 'warn');
                                } else if (soc < SOC_ENTLADESTOPP && aktuellerSollwert > 0) {
                                    log(`AKTION: Entladung pausiert (SOC: ${soc}% < ${SOC_ENTLADESTOPP}%)`, 'warn');
                                } else if (soc <= SOC_LADESTOPP && soc >= SOC_ENTLADESTOPP) {
                                    log(`SOC im normalen Bereich: ${soc}%`, 'debug');
                                }
                            });
                            
                            // ========== DIAGNOSE & MONITORING ==========
                            // Regelmäßige Systemdiagnose
                            const diagIntervall = setInterval(() => {
                                const ueberschuss = getState('alias.0.Stromüberschuss_IR-Lesekopf').val || 0;
                                const akkuLeistung = getState(AKTUELLE_AKKULEISTUNG).val || 0;
                                const akkuSOC = getState('alias.0.Akku_Ladezustand').val || 0;
                                const istLadebetrieb = aktuellerSollwert < 0;
                                
                                log(`Systemdiagnose:
                              Regelstatus: ${regelungAktiv ? "AKTIV" : "INAKTIV"}
                              Betriebsmodus: ${istLadebetrieb ? 'LADEN' : 'ENTLADEN'}
                              Sollleistung: ${aktuellerSollwert.toFixed(1)}W
                              Istleistung: ${akkuLeistung}W
                              Überschuss: ${ueberschuss}W
                              SOC: ${akkuSOC.toFixed(1)}%
                              Messwerte: ${mittelungArray.length} gespeichert
                              Letzte Logs: ${logHistorie.slice(-3).join('\n  ')}`, 
                              'info');
                            }, 300000); // Alle 5 Minuten
                            
                            // Datenpunkt-Prüfung
                            function pruefeDatenpunkte() {
                                const datenpunkte = [
                                    'alias.0.Stromüberschuss_IR-Lesekopf',
                                    'alias.0.Akku_Ladezustand',
                                    AKTUELLE_AKKULEISTUNG,
                                    AKTIONS_DATENPUNKT
                                ];
                                
                                let fehler = false;
                                datenpunkte.forEach(id => {
                                    if (getState(id) === undefined) {
                                        fehler = true;
                                        log(`KRITISCH: Datenpunkt ${id} nicht gefunden!`, 'error');
                                    }
                                });
                                
                                if (fehler) {
                                    log("Fehlende Datenpunkte - Skriptfunktionalität eingeschränkt", 'error');
                                } else {
                                    log("Alle benötigten Datenpunkte verfügbar", 'debug');
                                }
                            }
                            
                            // Verzögerte Datenpunktprüfung
                            setTimeout(pruefeDatenpunkte, 15000);
                            
                            // ========== NOTFALL-SYSTEM ==========
                            // Automatischer Neustart bei Inaktivität
                            const watchdogIntervall = setInterval(() => {
                                if (!regelungAktiv) {
                                    log("Watchdog: Regelung inaktiv - Neustart wird versucht", 'warn');
                                    initSkript();
                                }
                            }, 600000); // Prüft alle 10 Minuten
                            
                            H Offline
                            H Offline
                            hschief
                            wrote on last edited by
                            #16

                            @bertderkleine danke für dein tolles Script, ich werde dies mal ausprobieren und im nächsten Schritt erweitern. Ich bin zwar weit nicht so gut in der Programmierung, aber wird schon klappen.
                            Da ich einen dynamischen Tarif habe, würde ich folgende Funktion noch reinbringen.

                            1. Entladung zu einem Zeitpunk wo der Bezugspreis am maximal ist (meist Abends & Morgens)
                            2. Netzladung bei niedrigen Preisen

                            Ich kann ja berichten, wird aber ein paar Tage dauern.
                            Liebe Grüße
                            Helmut

                            BertDerKleineB 1 Reply Last reply
                            0
                            • H hschief

                              @bertderkleine danke für dein tolles Script, ich werde dies mal ausprobieren und im nächsten Schritt erweitern. Ich bin zwar weit nicht so gut in der Programmierung, aber wird schon klappen.
                              Da ich einen dynamischen Tarif habe, würde ich folgende Funktion noch reinbringen.

                              1. Entladung zu einem Zeitpunk wo der Bezugspreis am maximal ist (meist Abends & Morgens)
                              2. Netzladung bei niedrigen Preisen

                              Ich kann ja berichten, wird aber ein paar Tage dauern.
                              Liebe Grüße
                              Helmut

                              BertDerKleineB Offline
                              BertDerKleineB Offline
                              BertDerKleine
                              wrote on last edited by
                              #17

                              @hschief sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                              Da ich einen dynamischen Tarif habe, würde ich folgende Funktion noch reinbringen

                              Wenn Du das zusätzlich zur bisherigen Steuerung nach Überschüssen einbringen willst, bin ich mal gespannt auf die Logik.
                              Ich denke nämlich, dass eine Programmierung hier der leichtere Teil ist im Vergleich dazu, eine wünschenswerte Logik zu ersinnen.
                              Einzeln eine Überschusssteuerung geht und einzeln eine Steuerung nach Preisen auch, aber das miteinander zu vermengen - schwierig.

                              Beispiel: Willst Du wirklich den Rest im Akku morgens entladen, wegen hoher Preise, obwohl vielleicht (!) nachmittags dicke Wolken aufziehen werden und Du dann den Strom selber brauchst?
                              Natürlich kann man hier centgenaue Arbitragen machen auf Basis von statistischer Erwartung der Sonneneinstrahlung, aber das wird dann schon sehr wissenschaftlich und umfangreich.

                              H 1 Reply Last reply
                              0
                              • BertDerKleineB BertDerKleine

                                @hschief sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                Da ich einen dynamischen Tarif habe, würde ich folgende Funktion noch reinbringen

                                Wenn Du das zusätzlich zur bisherigen Steuerung nach Überschüssen einbringen willst, bin ich mal gespannt auf die Logik.
                                Ich denke nämlich, dass eine Programmierung hier der leichtere Teil ist im Vergleich dazu, eine wünschenswerte Logik zu ersinnen.
                                Einzeln eine Überschusssteuerung geht und einzeln eine Steuerung nach Preisen auch, aber das miteinander zu vermengen - schwierig.

                                Beispiel: Willst Du wirklich den Rest im Akku morgens entladen, wegen hoher Preise, obwohl vielleicht (!) nachmittags dicke Wolken aufziehen werden und Du dann den Strom selber brauchst?
                                Natürlich kann man hier centgenaue Arbitragen machen auf Basis von statistischer Erwartung der Sonneneinstrahlung, aber das wird dann schon sehr wissenschaftlich und umfangreich.

                                H Offline
                                H Offline
                                hschief
                                wrote on last edited by hschief
                                #18

                                @bertderkleine
                                Ja, stimmt, ich tast mich mal langsam ran und vielleicht hilft auch der Mittelweg. Erstmal habe ich dein Script heute zum laufen gebracht. Ich habe die Logik zwar noch nicht ganz verstande, aber ich taste mich mal ran.
                                Folgende Änderungen habe ich mal reingebracht:

                                1. Zwei weitere Datenpunkte:
                                  const NetzLaden = '0_userdata.0.Technik.Strom.Speicher.MSA-280024340941.NetzLadung';
                                  const Entladen = '0_userdata.0.Technik.Strom.Speicher.MSA-280024340941.Entladung';

                                Wenn der erste auf True ist, dann wird zwangsweise vom Netz geladen
                                Wenn der zweite auf True ist, dann wird der Akku entladen. Mit diesem kann ich in einem ersten Schritt das Entladen am Tage blockieren und die Entladung zu einem späteren Zeitpunkt starten (Wenn der Preis oben ist)

                                In einem anderen Script habe ich nun zB. die Idee, die Tibberpreiskurve auszuwerten und zB. 2h vor dem max Preis && nach 18:00Uhr die Entladung zu starten. In der Regel ist der Akku dann durch den Verbrauch am Abend bis 24:00 Uhr leer.

                                Den Code habe ich wie folgt angepasst. Wenn du magst, kannst du das natürlich übernehmen oder an eine bessere Stelle überführen.

                                Zusätzlich habe ich was eingebaut, dass der Ladestrom reduziert wird, wenn die obere Ladegrenze erreicht ist. Ich meine, dies beobachtet zu haben, dass Hoymiles selber reduziert wenn es an die obere Grenze geht.

                                Ich berichte von meinen weiteren Versuchen 🙂

                                1 Reply Last reply
                                1
                                • BertDerKleineB BertDerKleine

                                  Ich schildere hier mal, wie ich den Hoymiles MS-A2 standalone (kein WR, keine Balkonstrom-Panels, kein Shelly, kein Uni-Meter) per MQTT zum laufen bringe - als Nachrüstlösung für eine PV-Anlage.

                                  Vielleicht kann das ja jemand gebrauchen als Idee. Kann man bestimmt alles noch besser machen, aber als Basis kann ich sagen, dass es funktioniert. 😃

                                  Eventuell

                                  Hintergrund:
                                  Speziell für das Szenario, dass der MS-A2 standalone "als große Powerbank" betrieben werden soll, also ohne eingestöpselte Balkonstrom-Panels, braucht es eine Lade/Entladesteuerung, die auf Überschuß und Mangel reagiert.
                                  Seit Anfang Juni 2025 beherrscht der MS-A2 nativ MQTT, was nun eine noch einfachere Lösung ermöglicht, nämlich die direkte Steuerung über iobroker.

                                  Die offizielle Doku zum MQTT Feature findet man hier :

                                  • https://www.photovoltaikforum.com/core/file-download/507290/
                                  • https://www.photovoltaikforum.com/core/file-download/507291/
                                  • Der User "Rong" in dem Thread ist übrigens anscheinend ein Mitarbeiter des Herstelllers Hoymiles.

                                  Was braucht man also an Zutaten?

                                  • eine laufende iobroker Installation und einen eingestöpselten und mit dem WLAN verbundenen MS-A2, dessen Firmware über die Handy-App aktualisiert wurde.
                                  • einen MQTT Broker Adapter im iobroker
                                  • in der S-Miles App unter Zahnrad / MQTT-Service die Daten konfigurieren (Server IP Adresse des iobrokers, den Port (meist 1883) und Benutzernamen / Passwort.

                                  Dann tauscht der Akku mit iobroker Daten aus und im iobroker Objekt-Baum findet man unter mqtt / 0 / homeassistant nun die Datenpunkte.

                                  Standardmäßig lassen sich die Datenpunkte nur auslesen, aber nichts steuern. Um den Akku steuern zu können, muss man in mqtt.0.homeassistant.select.MSA-123456789.ems_mode.command manuell den Befehl mqtt_ctrl einmalig absetzen (der bleibt dann da).

                                  Die Steuerbefehle (Angaben in Watt) zum Laden/Entladen setzt man später in mqtt.0.homeassistant.number.MSA-123456789.power_ctrl.set ab. Dort stehen positive Werte für Entladen und negative für Laden des Akkus.

                                  Genutzte Aliase:

                                  Mein Steuerungsskript basiert auf ein paar Alias-Datenpunkten:

                                  • alias.0.Akku_befohlene_Entladeleistung --> mqtt.0.homeassistant.number.MSA-123456789.power_ctrl.set
                                  • alias.0.Akku_Ladezustand --> mqtt.0.homeassistant.sensor.MSA-123456789.quick.state mit Alias-Konverter beim Lesen JSON.parse(val).soc
                                  • alias.0.Akku_grid_on_power --> mqtt.0.homeassistant.sensor.MSA-123456789.quick.state mit Alias-Konverter beim Lesen JSON.parse(val).grid_on_p

                                  Mehr braucht es nicht. Man kann deutlich mehr Infos auslesen, aber zur Steuerung reicht das.

                                  Benötigte Datenquelle:

                                  Natürlich braucht es zusätzlich einen Datenpunkt im iobroker, der den aktuell vorliegenden Stromüberschuss im Haus liefert.

                                  In meinem Skript wird aktuell alias.0.Stromüberschuss_IR-Lesekopf verwendet, was den Überschuss direkt vom offiziellen Stromzähler ausliest (mittels eines Tasmota-basierten Infrarot Lesekopfs, den man sich leicht für kleines Geld beschaffen kann und der ebenfalls seine daten via  MQTT zu iobroker sendet). Diese Daten können aber auch von einem PV-Wechselrichter oder Stromzähler kommen, Hauptsache es ist der Stromüberschuss (positive Watt-Werte für einen Überschuss, d.h. Strom der sonst ins öffentliche Netz eingespeist wird und negative Werte für Netzbezug).

                                  Begrenzungen der Leistung und Entladung via App:

                                  Egal, was Ihr per MQTT an Befehlen sendet, die Lade- und Entladeleistung des Akkus hält sich an die Vorgaben, die Ihr via der S-Miles App eingegeben habt unter

                                  • Zahnrad / Einstellung der Ausgangsleistung (meist 800 W)
                                  • Zahnrad / Netzgebundene Eingangseinstellung (meist 800 W)
                                  • Zahnrad / Betriebsmodus / Eigenverbrauch / Entladeschlussstufe (meist 10%)

                                  Das ist im Skript alles auch mit abgefangen, aber m.W. passt der Akku da auch drauf auf.

                                  Besonderheit: Vergesslichkeit nach 59 Sekunden & Ignoranz bei immer gleichen Zahlen

                                  Es gibt eine Besonderheit, die zu beachten ist, nämlich vergisst der Akku nach 59 Sekunden den per MQTT vorgegebenen Befehl zum Laden/Entladen wieder. Und außerdem ignoriert er auch simple Wiederholungen einer Vorgabe der exakt selben Wattzahl.

                                  Sobald er diese Eure Vorgabe vergessen hat, führt der Akku das aus, was unter Zahnrad / Hauslasteinstellungen / Lastleistungskurve / Kurve 1 / (alle Tage und Uhrzeiten) in der App hinterlegt ist. Falls da also z.B. 100 W steht, wird der Akku dann mit 100 W entladen. Man kann in der App hier auch einfach "0 W" hinterlegen, so dass der Akku dann nix macht.

                                  Aus diesem Grund sendet mein Skript alle 30 Sekunden eine neue Wattvorgabe und zusätzlich alterniert diese immer um 0,1 Watt. So wird die Steuerung aufrechterhalten.

                                  Skript:

                                  Und hier findet Ihr mein Javascript als Denkanstoß.
                                  Ein großer Teil des Skripts ist Doku, Logging und Fehlerfindung gewidmet, man kann es also auch kürzen.

                                  /**
                                   * AKKU-MANAGEMENT-SKRIPT FÜR IO BROKER
                                   * 
                                   * Dieses Skript steuert einen Batteriespeicher basierend auf dem aktuellen Stromüberschuss.
                                   * Es lädt den Akku bei PV-Überschuss und entlädt ihn bei Strombedarf.
                                   * Entwurf von BertDerKleine
                                   * 
                                   * Merkmale:
                                   * - Kontinuierliche Regelung unabhängig von Tageszeit
                                   * - Getrennte Zielfaktoren für Lade- und Entladevorgänge
                                   * - PI-Regler für stabile Regelung
                                   * - SOC-Schutz gegen Überladung und Tiefentladung
                                   * - Alternierende Steuerbefehle für zuverlässige Akku-Kommunikation
                                   * - Ausführliche Diagnosefunktionen
                                   * - Konfigurierbares Logging
                                   */
                                  
                                  // ========== KONFIGURATION ==========
                                  const AUSFUEHRLICHES_LOGGING = false;  // Auf TRUE setzen für detaillierte Regel-Logs (nur für Debugging)
                                  const MAX_LOG_LAENGE = 100;             // Maximale Anzahl gespeicherter Log-Einträge für Diagnose
                                  
                                  // ========== GLOBALE VARIABLEN ==========
                                  /**
                                   * Intervall für das Senden von Steuerbefehlen (in Millisekunden)
                                   * Der Akku benötigt regelmäßige Aktualisierungen, da er Befehle nach 60-90 Sekunden "vergisst"
                                   * 30000 = 30 Sekunden ist ein bewährter Wert für zuverlässige Kommunikation
                                   */
                                  const alternierIntervall = 30000;
                                  
                                  /**
                                   * Datenpunkt für Akku-Steuerbefehle
                                   * - Positive Werte: Entladen (Leistungsabgabe)
                                   * - Negative Werte: Laden (Leistungsaufnahme)
                                   */
                                  const AKTIONS_DATENPUNKT = 'alias.0.Akku_befohlene_Entladeleistung';
                                  
                                  /** Datenpunkt für die aktuell gemessene Akku-Leistung */
                                  const AKTUELLE_AKKULEISTUNG = 'alias.0.Akku_grid_on_power';
                                  
                                  // Betriebsstatus
                                  let regelungAktiv = false;  // Gibt an, ob die Regelung aktuell läuft
                                  
                                  // Intervalle
                                  let messIntervall = null;    // Intervall für Leistungsmessungen
                                  let regelIntervall = null;   // Intervall für Regelberechnungen
                                  let sendeIntervall = null;   // Intervall für Steuerbefehle
                                  
                                  // Regelvariablen
                                  let mittelungArray = [];     // Speichert die letzten Messwerte für die Mittelwertbildung
                                  let aktuellerSollwert = 0;   // Aktuell berechneter Sollwert für Akku-Leistung
                                  let toggleFlag = true;       // Steuert die Alternierung der Steuerbefehle (+0.1W Wechsel)
                                  let integral = 0;            // Integralanteil des PI-Reglers
                                  
                                  // ========== PARAMETER ==========
                                  /**
                                   * Maximale Ladeleistung in Watt
                                   * Sollte unterhalb der technischen Grenzen des Akkus liegen.
                                   */
                                  const maxLadeleistung = 800;
                                  
                                  /**
                                   * Maximale Entladeleistung in Watt
                                   * Abhängig von Akku-Kapazität und Wechselrichter.
                                   */
                                  const maxEntladeleistung = 800;
                                  
                                  /**
                                   * Intervall für Leistungsmessungen in Millisekunden
                                   * 10000 = 10 Sekunden ist ein guter Kompromiss zwischen Aktualität und Stabilität
                                   */
                                  const samplingIntervall = 10000;
                                  
                                  /**
                                   * Faktor für den Integralanteil des PI-Reglers
                                   * Ein höherer Wert reagiert stärker auf anhaltende Abweichungen
                                   * 0.2 ist ein moderater Wert für stabile Regelung ohne zu starkes Überschwingen
                                   */
                                  const integralFaktor = 0.2;
                                  
                                  /** Ladezustand bei dem das Laden gestoppt wird (Vermeidung von Überladung) */
                                  const SOC_LADESTOPP = 98;
                                  
                                  /** Ladezustand bei dem das Entladen gestoppt wird (Vermeidung von Tiefentladung) */
                                  const SOC_ENTLADESTOPP = 10;
                                  
                                  /**
                                   * Zielfaktoren für Regelung
                                   * 
                                   * zielFaktorLaden: Anteil des Überschusses der fürs Laden genutzt wird (0-1)
                                   *   - 0.8 = 80% des Überschusses werden zum Laden genutzt (konservativ)
                                   *   - Höhere Werte nutzen mehr Überschuss, können aber zu Netzinstabilität führen
                                   * 
                                   * zielFaktorEntladen: Anteil des Bedarfs der durch Entladen gedeckt wird (0-1)
                                   *   - 1.0 = 100% des Bedarfs werden durch Entladen gedeckt (maximale Autarkie)
                                   *   - Niedrigere Werte schonen den Akku, erhöhen aber Netzbezug
                                   */
                                  const zielFaktorLaden = 0.8;
                                  const zielFaktorEntladen = 1.0;
                                  
                                  // ========== LOGGING SYSTEM ==========
                                  let logHistorie = [];  // Speichert die letzten Log-Einträge für Diagnosezwecke
                                  
                                  /**
                                   * Verbesserte Log-Funktion mit Historie-Speicherung und Level-Steuerung
                                   * 
                                   * @param {string} nachricht - Die zu loggende Nachricht
                                   * @param {string} level - Log-Level ('debug', 'info', 'warn', 'error')
                                   */
                                  function log(nachricht, level = 'info') {
                                      // Erstelle formatierten Log-Eintrag
                                      const timestamp = new Date().toISOString();
                                      const logEintrag = `[${timestamp}] [${level.toUpperCase()}] ${nachricht}`;
                                      
                                      // Füge zur Historie hinzu (begrenzt auf MAX_LOG_LAENGE)
                                      logHistorie.push(logEintrag);
                                      if (logHistorie.length > MAX_LOG_LAENGE) {
                                          logHistorie.shift();
                                      }
                                      
                                      // Ausgabe basierend auf Level und Konfiguration
                                      switch(level) {
                                          case 'error':
                                              console.error(logEintrag);
                                              break;
                                          case 'warn':
                                              console.warn(logEintrag);
                                              break;
                                          case 'info':
                                              console.log(logEintrag);
                                              break;
                                          case 'debug':
                                              // Debug-Logs nur bei aktiviertem ausführlichen Logging
                                              if (AUSFUEHRLICHES_LOGGING) {
                                                  console.log(logEintrag);
                                              }
                                              break;
                                          default:
                                              console.log(logEintrag);
                                      }
                                  }
                                  
                                  // ========== HELFERFUNKTIONEN ==========
                                  /**
                                   * Setzt den Steuerungsdatenpunkt mit Fehlerbehandlung
                                   * 
                                   * @param {number} wert - Der zu setzende Wert
                                   * @returns {boolean} True bei Erfolg, False bei Fehler
                                   */
                                  function sicherSetState(wert) {
                                      try {
                                          setState(AKTIONS_DATENPUNKT, wert, false);
                                          return true;
                                      } catch (e) {
                                          log(`Fehler beim Setzen des Datenpunkts: ${e.message}`, 'error');
                                          return false;
                                      }
                                  }
                                  
                                  /**
                                   * Bereinigt den gemessenen Überschuss um den aktuellen Akku-Beitrag
                                   * 
                                   * @param {number} ueberschussGemessen - Gemessener Stromüberschuss
                                   * @param {number} akkuLeistung - Aktuelle Akku-Leistung (positiv = Entladen, negativ = Laden)
                                   * @returns {number} Bereinigter Überschuss
                                   */
                                  function bereinigeLeistung(ueberschussGemessen, akkuLeistung) {
                                      return ueberschussGemessen - akkuLeistung;
                                  }
                                  
                                  // ========== FLEXIBLE REGELUNG ==========
                                  /**
                                   * Startet die kontinuierliche Akku-Regelung
                                   */
                                  function starteFlexibleRegelung() {
                                      if (regelungAktiv) {
                                          log("Regelung bereits aktiv - Start abgebrochen", 'debug');
                                          return;
                                      }
                                      
                                      stoppeRegelung();
                                      log("Starte flexible Regelung...");
                                      
                                      regelungAktiv = true;
                                      mittelungArray = [];
                                      aktuellerSollwert = 0;
                                      integral = 0;
                                      toggleFlag = true;
                                  
                                      // Initialer Status-Log mit Konfiguration
                                      log(`Regelung gestartet mit:
                                    Max Laden: ${maxLadeleistung}W
                                    Max Entladen: ${maxEntladeleistung}W
                                    Laden-Zielfaktor: ${zielFaktorLaden}
                                    Entladen-Zielfaktor: ${zielFaktorEntladen}
                                    SOC-Limits: Ladestopp >${SOC_LADESTOPP}%, Entladestopp <${SOC_ENTLADESTOPP}%`, 'info');
                                  
                                      // Messintervall - Sammelt regelmäßig Leistungsdaten
                                      messIntervall = setInterval(() => {
                                          try {
                                              const ueberschussGemessen = getState('alias.0.Stromüberschuss_IR-Lesekopf').val;
                                              const akkuLeistung = getState(AKTUELLE_AKKULEISTUNG).val;
                                              const bereinigteLeistung = bereinigeLeistung(ueberschussGemessen, akkuLeistung);
                                              
                                              mittelungArray.push(bereinigteLeistung);
                                              if (mittelungArray.length > 6) mittelungArray.shift();
                                          } catch (e) {
                                              log("Messfehler: " + e.message, 'error');
                                          }
                                      }, samplingIntervall);
                                  
                                      // Regelintervall - Berechnet alle 20 Sekunden neue Sollwerte
                                      regelIntervall = setInterval(() => {
                                          try {
                                              if (mittelungArray.length < 3) {
                                                  log("Nicht genug Messwerte für Regelung", 'debug');
                                                  return;
                                              }
                                              
                                              // Berechne gleitenden Mittelwert der letzten Messungen
                                              const summe = mittelungArray.reduce((a, b) => a + b, 0);
                                              const mittelwert = summe / mittelungArray.length;
                                              
                                              // Bestimmung des Betriebsmodus
                                              const istLadebetrieb = mittelwert > 0; // Positiver Wert = Überschuss = Laden
                                              const zielFaktor = istLadebetrieb ? zielFaktorLaden : zielFaktorEntladen;
                                              
                                              // Berechnung der benötigten Akku-Leistung
                                              const zielLeistung = Math.abs(mittelwert) * zielFaktor;
                                              const zielwert = istLadebetrieb ? -zielLeistung : zielLeistung;
                                              
                                              // PI-Regler berechnet Anpassung
                                              const differenz = zielwert - aktuellerSollwert;
                                              integral += differenz * integralFaktor;
                                              
                                              // Integrator-Begrenzung
                                              const integratorLimit = istLadebetrieb ? maxLadeleistung : maxEntladeleistung;
                                              integral = Math.min(Math.max(integral, -integratorLimit), integratorLimit);
                                              
                                              // Neuen Sollwert berechnen
                                              let neuerSollwert = aktuellerSollwert + differenz + integral;
                                              
                                              // Physikalische Grenzen einhalten
                                              if (istLadebetrieb) {
                                                  neuerSollwert = Math.min(neuerSollwert, 0); // Max 0 = keine Entladung
                                                  neuerSollwert = Math.max(neuerSollwert, -maxLadeleistung); // Min = -maxLadeleistung
                                              } else {
                                                  neuerSollwert = Math.max(neuerSollwert, 0); // Min 0 = kein Laden
                                                  neuerSollwert = Math.min(neuerSollwert, maxEntladeleistung); // Max = maxEntladeleistung
                                              }
                                              
                                              // Sanfte Anpassung (30% pro Schritt)
                                              const aenderung = neuerSollwert - aktuellerSollwert;
                                              if (Math.abs(aenderung) > 10) {
                                                  aktuellerSollwert += aenderung * 0.3;
                                              } else {
                                                  aktuellerSollwert = neuerSollwert;
                                              }
                                              
                                              // Ausführliches Logging nur bei Bedarf
                                              if (AUSFUEHRLICHES_LOGGING) {
                                                  log(`Regelberechnung:
                                    Überschuss (gemittelt): ${mittelwert.toFixed(1)}W
                                    Ziel-Leistung: ${zielLeistung.toFixed(1)}W
                                    Zielwert (Akku): ${zielwert.toFixed(1)}W
                                    Neuer Sollwert: ${neuerSollwert.toFixed(1)}W
                                    Aktueller Sollwert: ${aktuellerSollwert.toFixed(1)}W
                                    Differenz: ${differenz.toFixed(1)}W
                                    Integral: ${integral.toFixed(1)}
                                    Faktor: ${zielFaktor}
                                    Modus: ${istLadebetrieb ? 'Laden' : 'Entladen'}`, 'debug');
                                              }
                                          } catch (e) {
                                              log("Regelfehler: " + e.message, 'error');
                                          }
                                      }, 20000);
                                  
                                      // Sendeintervall - Sendet alle 30 Sekunden Steuerbefehle
                                      sendeIntervall = setInterval(() => {
                                          if (!regelungAktiv) return;
                                          
                                          // SOC-Schutz - Verhindert Überladung und Tiefentladung
                                          const akkuSOC = getState('alias.0.Akku_Ladezustand').val;
                                          let effektiverSollwert = aktuellerSollwert;
                                          
                                          if (effektiverSollwert < 0 && akkuSOC > SOC_LADESTOPP) {
                                              effektiverSollwert = 0;
                                              log(`LADESTOPP: Akku > ${SOC_LADESTOPP}% (SOC: ${akkuSOC.toFixed(1)}%)`, 'warn');
                                          }
                                          
                                          if (effektiverSollwert > 0 && akkuSOC < SOC_ENTLADESTOPP) {
                                              effektiverSollwert = 0;
                                              log(`ENTLADESTOPP: Akku < ${SOC_ENTLADESTOPP}% (SOC: ${akkuSOC.toFixed(1)}%)`, 'warn');
                                          }
                                          
                                          // Alternierende Werte senden (jeder 2. Befehl +0.1W)
                                          const wert = toggleFlag ? effektiverSollwert : effektiverSollwert + 0.1;
                                          sicherSetState(wert);
                                          toggleFlag = !toggleFlag;
                                          
                                          // Protokolliere nur die ersten 20 Minuten oder bei Moduswechsel
                                          log(`Steuerbefehl gesendet: ${wert.toFixed(1)}W (${toggleFlag ? 'nächstes Mal Basiswert' : 'nächstes Mal +0.1W'})`, 'debug');
                                      }, alternierIntervall);
                                  
                                      log("Flexible Regelung erfolgreich gestartet", 'info');
                                  }
                                  
                                  /**
                                   * Stoppt die laufende Regelung
                                   */
                                  function stoppeRegelung() {
                                      if (!regelungAktiv) return;
                                      
                                      clearInterval(messIntervall);
                                      clearInterval(regelIntervall);
                                      clearInterval(sendeIntervall);
                                      regelungAktiv = false;
                                      
                                      sicherSetState(0);
                                      log("Regelung gestoppt", 'info');
                                  }
                                  
                                  // ========== HAUPTPROGRAMM ==========
                                  /**
                                   * Initialisiert das Skript
                                   */
                                  function initSkript() {
                                      try {
                                          starteFlexibleRegelung();
                                          log("Skript initialisierung abgeschlossen");
                                          
                                          // Aktiviere temporäres ausführliches Logging für die ersten 10 Minuten
                                          setTimeout(() => {
                                              if (!AUSFUEHRLICHES_LOGGING) {
                                                  log("Initiale Debug-Periode beendet - Detaillogs deaktiviert");
                                              }
                                          }, 600000); // 10 Minuten
                                      } catch (e) {
                                          log("Initialisierungsfehler: " + e.message, 'error');
                                      }
                                  }
                                  
                                  // Startverzögerung für Systeminitialisierung
                                  setTimeout(initSkript, 5000);
                                  
                                  // ========== EVENT-HANDLER ==========
                                  // Überwacht Ladezustandsänderungen
                                  on({ id: 'alias.0.Akku_Ladezustand', change: 'ne' }, (state) => {
                                      const soc = state.val;
                                      
                                      // Protokolliere nur bei relevanten Änderungen
                                      if (soc > SOC_LADESTOPP && aktuellerSollwert < 0) {
                                          log(`AKTION: Ladung pausiert (SOC: ${soc}% > ${SOC_LADESTOPP}%)`, 'warn');
                                      } else if (soc < SOC_ENTLADESTOPP && aktuellerSollwert > 0) {
                                          log(`AKTION: Entladung pausiert (SOC: ${soc}% < ${SOC_ENTLADESTOPP}%)`, 'warn');
                                      } else if (soc <= SOC_LADESTOPP && soc >= SOC_ENTLADESTOPP) {
                                          log(`SOC im normalen Bereich: ${soc}%`, 'debug');
                                      }
                                  });
                                  
                                  // ========== DIAGNOSE & MONITORING ==========
                                  // Regelmäßige Systemdiagnose
                                  const diagIntervall = setInterval(() => {
                                      const ueberschuss = getState('alias.0.Stromüberschuss_IR-Lesekopf').val || 0;
                                      const akkuLeistung = getState(AKTUELLE_AKKULEISTUNG).val || 0;
                                      const akkuSOC = getState('alias.0.Akku_Ladezustand').val || 0;
                                      const istLadebetrieb = aktuellerSollwert < 0;
                                      
                                      log(`Systemdiagnose:
                                    Regelstatus: ${regelungAktiv ? "AKTIV" : "INAKTIV"}
                                    Betriebsmodus: ${istLadebetrieb ? 'LADEN' : 'ENTLADEN'}
                                    Sollleistung: ${aktuellerSollwert.toFixed(1)}W
                                    Istleistung: ${akkuLeistung}W
                                    Überschuss: ${ueberschuss}W
                                    SOC: ${akkuSOC.toFixed(1)}%
                                    Messwerte: ${mittelungArray.length} gespeichert
                                    Letzte Logs: ${logHistorie.slice(-3).join('\n  ')}`, 
                                    'info');
                                  }, 300000); // Alle 5 Minuten
                                  
                                  // Datenpunkt-Prüfung
                                  function pruefeDatenpunkte() {
                                      const datenpunkte = [
                                          'alias.0.Stromüberschuss_IR-Lesekopf',
                                          'alias.0.Akku_Ladezustand',
                                          AKTUELLE_AKKULEISTUNG,
                                          AKTIONS_DATENPUNKT
                                      ];
                                      
                                      let fehler = false;
                                      datenpunkte.forEach(id => {
                                          if (getState(id) === undefined) {
                                              fehler = true;
                                              log(`KRITISCH: Datenpunkt ${id} nicht gefunden!`, 'error');
                                          }
                                      });
                                      
                                      if (fehler) {
                                          log("Fehlende Datenpunkte - Skriptfunktionalität eingeschränkt", 'error');
                                      } else {
                                          log("Alle benötigten Datenpunkte verfügbar", 'debug');
                                      }
                                  }
                                  
                                  // Verzögerte Datenpunktprüfung
                                  setTimeout(pruefeDatenpunkte, 15000);
                                  
                                  // ========== NOTFALL-SYSTEM ==========
                                  // Automatischer Neustart bei Inaktivität
                                  const watchdogIntervall = setInterval(() => {
                                      if (!regelungAktiv) {
                                          log("Watchdog: Regelung inaktiv - Neustart wird versucht", 'warn');
                                          initSkript();
                                      }
                                  }, 600000); // Prüft alle 10 Minuten
                                  
                                  A Offline
                                  A Offline
                                  assz
                                  wrote on last edited by assz
                                  #19

                                  Hallo,

                                  ich möchte mich hier mal mit einklinken, um meine Erfahrungen von parallel betriebenen Batteriesystemen zu teilen,
                                  da ich selbst zwei MS-A2 (4,48kwh) als STAND ALLONE parallel zur Bestandsanlage E3DC mit 13kwh Batteriespeicher BETREIBEN MÖCHTE 😉

                                  Grundidee:
                                  Dem MS-A2 nur erlauben UNTERHALB der maximalen Grundlast in der Nacht zu vordefinierten Zeiten den E3DC Hauptsystemspeicher zu entlasten.
                                  Also nur im General tätig sein, wenn genug PV Energie für alles vorhanden ist jedoch auch am Tag im mqtt mode in die Schranken weisen was er darf und nicht.
                                  Dazu aber weiter unten im Text...

                                  Punkt 1: Die deutsche Bürokratie und der NETZBETREIBER
                                  Erstmal... Anfrage beim Netzbetreiber da !Meldepflichtig wegen Anschluss am Niederspannungsnetz!
                                  Hier habe ich aufgrund der nicht wirklichen aufwändigen Installation (Salopp gesagt: Stecker rein...fertig) mal als gewissenhafter Bürger beim Netzbetreiber nach einer vereinfachten Anmeldung via Markstammregister
                                  --- telefonisch, --- per Mail, --- nochmals telefonisch, --- nochmals Mail... mit allen Datenblättern und Fakten 800W Begrenzung und so... angefragt.
                                  Es hieß.... Fachabteilung Einspeisung leitet an Fachabteilung XY weiter... wir melden uns.

                                  Nochmals telefonische Nachfrage auf Bearbeitungsstand da keine Antwort nach 4 Wochen...
                                  Antwort: Ich teile der Fachabteilung mit, dass sie nochmals angerufen haben.

                                  2 Monate später.... ich warte noch immer.
                                  Hier scheint fachlich keiner in der Lage zu sein eine Aussage machen zu können außer evtl. das was ich aus der Vergangenheit schon kenne:
                                  "Bitte wenden sie sich an einen eingetragenen Elektroinstallateur! Bitte senden sie uns eine E8 Inbetriebnahme Erklärung!"

                                  skip this chapter 😉

                                  Punkt 2: Hardware

                                  • 2x MS-A2,
                                    • Shelly 3EM Pro an der Hauptleitung
                                    • Shelly Plug an einer separaten 16A abgesicherten Schuko Steckdose für die beiden in Reihe geschalteten MS-A2
                                  • ioBroker Skript für mqtt Ansteuerung MS-A2 und Signalaustausch E3DC via Modbus
                                    (*by the way... bin EFK)

                                  Punkt 3: Probleme
                                  Wer den MS-A2 einfach "STAND ALLONE" zu seinem bestehenden PV Systemspeicher parallel betreiben möchte um seinen Batteriespeicher kostengünstig zu erweitern
                                  wird feststellen, dass sich die beiden Systeme im GENERAL MODE nicht vertragen.

                                  Was man also in solch einem Vorhaben unbedingt berücksichtigen muss sind Lastwechsel bzw. Zeiten von unzureichender PV Ertrag im General Mode des MS-A2!
                                  Der eine versucht den anderen zu Laden bzw. zu entladen da sie ja nichts voneinander wissen!
                                  Hier muss man schon einiges im Skript einbauen damit das nicht passiert!

                                  Lösungsansätze:

                                  • Bei unzureichendem PV Ertrag oder Lastwechsel von General in mqtt Mode wechseln um ein Eingenleben hart zu unterbinden.
                                  • Nur feste Entladezeiten im mqtt Mode in der Nacht über Astro oder Zeit z.B. 22:00 - 05:00 Uhr = 500W (unterhalb der min Grundlast)
                                  • Trotz Shelly 3EM Pro feste Freigaben definieren wann MS-A2 im General Überschuss laden darf. [PV Überschuss ausreichend?; Hauptspeicher geladen?; Brauchwassererwärmung ausreichen?; E-Fahrzeug wird geladen?; usw... ]
                                  • Entladen grundsätzlich am Tag unterbinden! (Energie ist nur für die Nacht!)
                                    Hier wird schnell klar das auch am Tage der General Mode zwischendurch weichen muss!

                                  Ergo: Man könnte sich theoretisch einen Shelly 3EM Pro an der Hauptleitung sparen und alles komplett über den ioBroker realisieren.

                                  BertDerKleineB H 2 Replies Last reply
                                  1
                                  • A assz

                                    Hallo,

                                    ich möchte mich hier mal mit einklinken, um meine Erfahrungen von parallel betriebenen Batteriesystemen zu teilen,
                                    da ich selbst zwei MS-A2 (4,48kwh) als STAND ALLONE parallel zur Bestandsanlage E3DC mit 13kwh Batteriespeicher BETREIBEN MÖCHTE 😉

                                    Grundidee:
                                    Dem MS-A2 nur erlauben UNTERHALB der maximalen Grundlast in der Nacht zu vordefinierten Zeiten den E3DC Hauptsystemspeicher zu entlasten.
                                    Also nur im General tätig sein, wenn genug PV Energie für alles vorhanden ist jedoch auch am Tag im mqtt mode in die Schranken weisen was er darf und nicht.
                                    Dazu aber weiter unten im Text...

                                    Punkt 1: Die deutsche Bürokratie und der NETZBETREIBER
                                    Erstmal... Anfrage beim Netzbetreiber da !Meldepflichtig wegen Anschluss am Niederspannungsnetz!
                                    Hier habe ich aufgrund der nicht wirklichen aufwändigen Installation (Salopp gesagt: Stecker rein...fertig) mal als gewissenhafter Bürger beim Netzbetreiber nach einer vereinfachten Anmeldung via Markstammregister
                                    --- telefonisch, --- per Mail, --- nochmals telefonisch, --- nochmals Mail... mit allen Datenblättern und Fakten 800W Begrenzung und so... angefragt.
                                    Es hieß.... Fachabteilung Einspeisung leitet an Fachabteilung XY weiter... wir melden uns.

                                    Nochmals telefonische Nachfrage auf Bearbeitungsstand da keine Antwort nach 4 Wochen...
                                    Antwort: Ich teile der Fachabteilung mit, dass sie nochmals angerufen haben.

                                    2 Monate später.... ich warte noch immer.
                                    Hier scheint fachlich keiner in der Lage zu sein eine Aussage machen zu können außer evtl. das was ich aus der Vergangenheit schon kenne:
                                    "Bitte wenden sie sich an einen eingetragenen Elektroinstallateur! Bitte senden sie uns eine E8 Inbetriebnahme Erklärung!"

                                    skip this chapter 😉

                                    Punkt 2: Hardware

                                    • 2x MS-A2,
                                      • Shelly 3EM Pro an der Hauptleitung
                                      • Shelly Plug an einer separaten 16A abgesicherten Schuko Steckdose für die beiden in Reihe geschalteten MS-A2
                                    • ioBroker Skript für mqtt Ansteuerung MS-A2 und Signalaustausch E3DC via Modbus
                                      (*by the way... bin EFK)

                                    Punkt 3: Probleme
                                    Wer den MS-A2 einfach "STAND ALLONE" zu seinem bestehenden PV Systemspeicher parallel betreiben möchte um seinen Batteriespeicher kostengünstig zu erweitern
                                    wird feststellen, dass sich die beiden Systeme im GENERAL MODE nicht vertragen.

                                    Was man also in solch einem Vorhaben unbedingt berücksichtigen muss sind Lastwechsel bzw. Zeiten von unzureichender PV Ertrag im General Mode des MS-A2!
                                    Der eine versucht den anderen zu Laden bzw. zu entladen da sie ja nichts voneinander wissen!
                                    Hier muss man schon einiges im Skript einbauen damit das nicht passiert!

                                    Lösungsansätze:

                                    • Bei unzureichendem PV Ertrag oder Lastwechsel von General in mqtt Mode wechseln um ein Eingenleben hart zu unterbinden.
                                    • Nur feste Entladezeiten im mqtt Mode in der Nacht über Astro oder Zeit z.B. 22:00 - 05:00 Uhr = 500W (unterhalb der min Grundlast)
                                    • Trotz Shelly 3EM Pro feste Freigaben definieren wann MS-A2 im General Überschuss laden darf. [PV Überschuss ausreichend?; Hauptspeicher geladen?; Brauchwassererwärmung ausreichen?; E-Fahrzeug wird geladen?; usw... ]
                                    • Entladen grundsätzlich am Tag unterbinden! (Energie ist nur für die Nacht!)
                                      Hier wird schnell klar das auch am Tage der General Mode zwischendurch weichen muss!

                                    Ergo: Man könnte sich theoretisch einen Shelly 3EM Pro an der Hauptleitung sparen und alles komplett über den ioBroker realisieren.

                                    BertDerKleineB Offline
                                    BertDerKleineB Offline
                                    BertDerKleine
                                    wrote on last edited by
                                    #20

                                    @assz sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                    Ergo: Man könnte sich theoretisch einen Shelly 3EM Pro an der Hauptleitung sparen und alles komplett über den ioBroker realisieren.

                                    Absolut. Mein Skript oben tut ja im Prinzip genau das per MQTT über iobroker, was die herstellereigene Logik im "general mode" macht.
                                    Ich habe auch gar keinen Shelly 3EM Pro an der Hauptleitung, sondern benutze einen Wattwächter direkt auf dem offiziellen Zähler, der sich über MQTT und die Software Uni-Meter als Shelly 3EM ausgibt.

                                    Das Skript oben habe ich dann direkt an den MQTT Datenpunkt des Wattwächters angebunden.

                                    Statt sowas wie Wattwächter kann man natürlich jede iobroker Datenquelle für bezogene oder eingespeiste Leistung benutzen, die man hat (z.B. aus der PV Anlage), daher schreibe ich oben ja einfach von einem Alias.

                                    Du kannst das obige MQTT Skript so erweitern, wie es für Dein Szenario passt. Du brauchst dazu halt zusätzliche Datenpunkte direkt aus Deinem Systemspeicher.

                                    Wie bei @hschief hast Du auch ein ganz spezifisches, anderes Szenario, das eigene Logik benötigt. Wenn Du die Logik für Dich mal klar hast, dürfte das Skripten der einfachere Teil werden.

                                    A 1 Reply Last reply
                                    0
                                    • BertDerKleineB BertDerKleine

                                      @assz sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                      Ergo: Man könnte sich theoretisch einen Shelly 3EM Pro an der Hauptleitung sparen und alles komplett über den ioBroker realisieren.

                                      Absolut. Mein Skript oben tut ja im Prinzip genau das per MQTT über iobroker, was die herstellereigene Logik im "general mode" macht.
                                      Ich habe auch gar keinen Shelly 3EM Pro an der Hauptleitung, sondern benutze einen Wattwächter direkt auf dem offiziellen Zähler, der sich über MQTT und die Software Uni-Meter als Shelly 3EM ausgibt.

                                      Das Skript oben habe ich dann direkt an den MQTT Datenpunkt des Wattwächters angebunden.

                                      Statt sowas wie Wattwächter kann man natürlich jede iobroker Datenquelle für bezogene oder eingespeiste Leistung benutzen, die man hat (z.B. aus der PV Anlage), daher schreibe ich oben ja einfach von einem Alias.

                                      Du kannst das obige MQTT Skript so erweitern, wie es für Dein Szenario passt. Du brauchst dazu halt zusätzliche Datenpunkte direkt aus Deinem Systemspeicher.

                                      Wie bei @hschief hast Du auch ein ganz spezifisches, anderes Szenario, das eigene Logik benötigt. Wenn Du die Logik für Dich mal klar hast, dürfte das Skripten der einfachere Teil werden.

                                      A Offline
                                      A Offline
                                      assz
                                      wrote on last edited by assz
                                      #21

                                      @bertderkleine
                                      Wollte nur andere User mit solch einem Vorhaben über das gegenseitige Speichergeschaukel im Vorfeld informieren.
                                      system runs bug-free 😉

                                      Hat denn jemand Info`s bezüglich Markstammregister für n MS-A2 als Stand Allone?

                                      BertDerKleineB 1 Reply Last reply
                                      0
                                      • A assz

                                        @bertderkleine
                                        Wollte nur andere User mit solch einem Vorhaben über das gegenseitige Speichergeschaukel im Vorfeld informieren.
                                        system runs bug-free 😉

                                        Hat denn jemand Info`s bezüglich Markstammregister für n MS-A2 als Stand Allone?

                                        BertDerKleineB Offline
                                        BertDerKleineB Offline
                                        BertDerKleine
                                        wrote on last edited by
                                        #22

                                        @assz sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                        @bertderkleine
                                        Wollte nur andere User mit solch einem Vorhaben über das gegenseitige Speichergeschaukel im Vorfeld informieren.
                                        system runs bug-free 😉

                                        Wenn's gut läuft, magst Du das Skript hier als Anregung für andere posten?

                                        1 Reply Last reply
                                        0
                                        • A Offline
                                          A Offline
                                          assz
                                          wrote on last edited by
                                          #23

                                          @bertderkleine
                                          Sorry,
                                          dafür ist es zu speziell,
                                          da ich 4 Skripte parallel laufen habe, die ineinander greifen und Schrittketten sowie Datenpunkte für meine Visualisierung mit eingebaut habe.

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          137

                                          Online

                                          32.4k

                                          Users

                                          81.3k

                                          Topics

                                          1.3m

                                          Posts
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Recent
                                          • Tags
                                          • Unread 0
                                          • Categories
                                          • Unreplied
                                          • Popular
                                          • GitHub
                                          • Docu
                                          • Hilfe