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
    11
    2
    202

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

  • 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.
  • 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
                              • H Offline
                                H Offline
                                harvey637
                                wrote on last edited by
                                #24

                                Hi, ich schaue mir das auch an und habe winzige Anpassungen (bzw. Vorschläge, dies in Post 1 in das Script einzubauen)

                                • alle Datenpunkte als const, also auch den Verbrauchszähler, z.B.
                                /** Datenpunkt für den aktuell gemessene Akku Ladungzustand in % */
                                const AKTUELLER_AKKULADEZUSTAND = 'alias.0.MSA-000000000000.q_soc'; // q = aus quick
                                
                                /** Datenpunkt für den aktuell gemessene Verbrauch plus=Überschuss/Einspeisung minus=Verbrauch/Kauf*/
                                const VERBRAUCHSZAEHLER = '0_userdata.0.Blockly.ShellyEmu.Power-Total-Raw';
                                
                                • neben "laden" und "entladen" gibt es noch "standby" als Status des Akku, wenn er voll ist. Dies könnte auch bei der Loganzeige verwendet werden, da ein Akku > SOC_Ladeschwelle nicht mehr geladen wird.
                                const akkuSOC = getState(AKTUELLER_AKKULADEZUSTAND).val;
                                const istAkkuVoll = akkuSOC > SOC_LADESTOPP; // grösser als Ladestopp bedeutet Akku voll
                                
                                • die internen Werte könnten auch optional als iobroker-Werte gespeichert werden, dann kann man sie auch in Grafen verwenden, eventuell in einstellbarem Zeitraster, um nicht zuviele Punkte in die DB zu schreiben

                                • eine Variable zum einfachen Pausieren der Regelung, etwa um Akkuswapping bei mehreren Akkus zu verhindern

                                Ansonsten vielen Dank für deine Mühe, läuft schon ganz gut, mal auf Erfahrungen warten
                                cu
                                Harvey

                                1 Reply Last reply
                                1
                                • I Offline
                                  I Offline
                                  isolator
                                  wrote on last edited by
                                  #25

                                  Hallo Bert,

                                  vielen dank für dein Script.
                                  Läuft ganz gut, bekomme aber ein paar Warnungen angezeigt. Da muss ich nochmal nachschauen an was das liegt, bin aber ein absoluter Neuling in Java 😉

                                  Also die Steuerung über Nacht und die Ladung mit Rest PV-Strom funktioniert prima.

                                  Einzig bei Lastwechsel (E-Herd) ist noch nicht so zufriedenstellend 😉
                                  Irgendwie ist der Speicher zu langsam. Habe überschuss, speicher lädt, Last vom E-Herd geht rein, Speicher speist noch ein, obwohl Fremdbezug ist.

                                  Könnte man die Interwalle kürzer setzen oder Zerschießt es dann das Script ?

                                  Oder gibt es eine andere Lösung, für das "kleine" Problem

                                  mfg

                                  BertDerKleineB 1 Reply Last reply
                                  0
                                  • I isolator

                                    Hallo Bert,

                                    vielen dank für dein Script.
                                    Läuft ganz gut, bekomme aber ein paar Warnungen angezeigt. Da muss ich nochmal nachschauen an was das liegt, bin aber ein absoluter Neuling in Java 😉

                                    Also die Steuerung über Nacht und die Ladung mit Rest PV-Strom funktioniert prima.

                                    Einzig bei Lastwechsel (E-Herd) ist noch nicht so zufriedenstellend 😉
                                    Irgendwie ist der Speicher zu langsam. Habe überschuss, speicher lädt, Last vom E-Herd geht rein, Speicher speist noch ein, obwohl Fremdbezug ist.

                                    Könnte man die Interwalle kürzer setzen oder Zerschießt es dann das Script ?

                                    Oder gibt es eine andere Lösung, für das "kleine" Problem

                                    mfg

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

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

                                    Einzig bei Lastwechsel (E-Herd) ist noch nicht so zufriedenstellend 😉
                                    Irgendwie ist der Speicher zu langsam. Habe überschuss, speicher lädt, Last vom E-Herd geht rein, Speicher speist noch ein, obwohl Fremdbezug ist.

                                    Lastwechsel sind so ein Ding, denn die Steuerung soll ja tatsächlich gedämpft reagieren und nicht wild oszillieren.
                                    Da musst Du Dein Optimum durch ausprobieren finden.
                                    Du kannst das Samplingintervall etwas runtersetzen um mehr daten schneller zu bekommen und den Integralfaktor raufsetzen.
                                    Außerdem kannst Du mit der Schrittweite spielen (Zeile 254). Das ist aktuell auf 30% begrenzt.

                                    Ich habe hier auch mal die hardware-integrierte Logik über Unimeter-Emulation laufen gelassen und die ist zwar schneller in der Anpassung als das Skript oben mit den vorgeschlagenen Parametern, aber z.B. Wasserkocher sind dem auch eher zu schnell da und wieder weg.

                                    Am Ende bleibt daher nur Ausprobieren für das persönliche Verbrauchsprofil.

                                    Wenn Du bessere Parameter findest, kannst Du sie ja hier teilen.

                                    O 1 Reply Last reply
                                    0
                                    • BertDerKleineB BertDerKleine

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

                                      Einzig bei Lastwechsel (E-Herd) ist noch nicht so zufriedenstellend 😉
                                      Irgendwie ist der Speicher zu langsam. Habe überschuss, speicher lädt, Last vom E-Herd geht rein, Speicher speist noch ein, obwohl Fremdbezug ist.

                                      Lastwechsel sind so ein Ding, denn die Steuerung soll ja tatsächlich gedämpft reagieren und nicht wild oszillieren.
                                      Da musst Du Dein Optimum durch ausprobieren finden.
                                      Du kannst das Samplingintervall etwas runtersetzen um mehr daten schneller zu bekommen und den Integralfaktor raufsetzen.
                                      Außerdem kannst Du mit der Schrittweite spielen (Zeile 254). Das ist aktuell auf 30% begrenzt.

                                      Ich habe hier auch mal die hardware-integrierte Logik über Unimeter-Emulation laufen gelassen und die ist zwar schneller in der Anpassung als das Skript oben mit den vorgeschlagenen Parametern, aber z.B. Wasserkocher sind dem auch eher zu schnell da und wieder weg.

                                      Am Ende bleibt daher nur Ausprobieren für das persönliche Verbrauchsprofil.

                                      Wenn Du bessere Parameter findest, kannst Du sie ja hier teilen.

                                      O Offline
                                      O Offline
                                      opöl
                                      wrote on last edited by
                                      #27

                                      @bertderkleine ,

                                      sehr interessanter Beitrag.
                                      Wenn ich Dich recht verstehe, betreibst Du den Speicher „stand alone“, also nur am Netz, ohne angeschlossene PV Anlage als „Powerbank“. Zur Verbrauchsmessung nutzt Du einen IR Sensor (Hichi IR Sensor?) am Zähler.

                                      Da kommt mir doch die Idee, meine Balkon PV so zu lassen, wie sie ist (ohne Speicher mit Deye WR direkt ans Netz angeschlossen) und den HM MS-A2 in der Wohnung ebenfalls nur ans Hausnetz anzuschließen.
                                      Dann könnte ich den Verbrauch am Zähler über meinen Hichi erfassen und via iobroker und Java Script die Ladung und Entladung (nur über das Hausnetz) steuern.
                                      Das ließe dann (theoretisch) auch den Betrieb mehrerer Speicher sowie eine Nulleinspeisung zu.
                                      Ist das so grob richtig oder bin ich irgendwo komplett falsch abgebogen?

                                      Gruß

                                      BertDerKleineB 1 Reply Last reply
                                      0
                                      • O opöl

                                        @bertderkleine ,

                                        sehr interessanter Beitrag.
                                        Wenn ich Dich recht verstehe, betreibst Du den Speicher „stand alone“, also nur am Netz, ohne angeschlossene PV Anlage als „Powerbank“. Zur Verbrauchsmessung nutzt Du einen IR Sensor (Hichi IR Sensor?) am Zähler.

                                        Da kommt mir doch die Idee, meine Balkon PV so zu lassen, wie sie ist (ohne Speicher mit Deye WR direkt ans Netz angeschlossen) und den HM MS-A2 in der Wohnung ebenfalls nur ans Hausnetz anzuschließen.
                                        Dann könnte ich den Verbrauch am Zähler über meinen Hichi erfassen und via iobroker und Java Script die Ladung und Entladung (nur über das Hausnetz) steuern.
                                        Das ließe dann (theoretisch) auch den Betrieb mehrerer Speicher sowie eine Nulleinspeisung zu.
                                        Ist das so grob richtig oder bin ich irgendwo komplett falsch abgebogen?

                                        Gruß

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

                                        @opöl sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                        @bertderkleine ,
                                        sehr interessanter Beitrag.
                                        Wenn ich Dich recht verstehe, betreibst Du den Speicher „stand alone“, also nur am Netz, ohne angeschlossene PV Anlage als „Powerbank“.

                                        Ohne kleines Balkopanel, ja. Den Strom erzeugen PV-Panels auf dem Dach ohne direkte Verkabelung zum Speicher.

                                        Zur Verbrauchsmessung nutzt Du einen IR Sensor (Hichi IR Sensor?) am Zähler.

                                        Ein Wattwächter, was quasi das gleiche ist, nur out-of-the Box benutzerfreundlich in Betrieb zu nehmen.

                                        Dann könnte ich den Verbrauch am Zähler über meinen Hichi erfassen und via iobroker und Java Script die Ladung und Entladung (nur über das Hausnetz) steuern.

                                        Korrekt.
                                        Wobei ich selbst aktuell in diesem Setup aktuell die aktive Steuerung (eher aus Bequemlichkeit) wieder der eingebauten Logik übertragen habe und MQTT nur zum Daten-Auslesen nutze.
                                        Die Wattwächter-Daten emulieren via Uni-Meter-Emulatorsoftware einen Shelly, den der Speicher dann erkennt und für Steuersignale nutzt.
                                        Für mein Setup reicht das aus.

                                        Das ließe dann (theoretisch) auch den Betrieb mehrerer Speicher sowie eine Nulleinspeisung zu.
                                        Ist das so grob richtig oder bin ich irgendwo komplett falsch abgebogen?
                                        Korrekt.

                                        Die "Nulleinspeisung" geht auf beide Wege.

                                        Der Betrieb komplexerer Logiken wie disjunkte Speicher oder das, was weiter oben diskutiert wurde hier im Thread, geht natürlich out of the box mit der eingebauten Steuerung nicht. Da spielt dann eine persönlich ausgestaltete Steuerung über iobroker ihre Stärken aus. Dafür ist das hier beschrieben: damit man es nach Gusto so formt, wie man es braucht.

                                        Zwei baugleiche 2kWh Speicher kann man natürlich auch mit der internen Steuerung einfach in Reihe schalten plug-and-play. Erst wenn man noch mehr will oder die unbedingt an unterschiedlichen Orten aufgestellt werden sollen, muss man zwingend selbst eine Steuerung schreiben in iobroker.

                                        O 1 Reply Last reply
                                        0
                                        • BertDerKleineB BertDerKleine

                                          @opöl sagte in Erfahrung: Hoymiles MS-A2 Akku via MQTT iobroker steuern:

                                          @bertderkleine ,
                                          sehr interessanter Beitrag.
                                          Wenn ich Dich recht verstehe, betreibst Du den Speicher „stand alone“, also nur am Netz, ohne angeschlossene PV Anlage als „Powerbank“.

                                          Ohne kleines Balkopanel, ja. Den Strom erzeugen PV-Panels auf dem Dach ohne direkte Verkabelung zum Speicher.

                                          Zur Verbrauchsmessung nutzt Du einen IR Sensor (Hichi IR Sensor?) am Zähler.

                                          Ein Wattwächter, was quasi das gleiche ist, nur out-of-the Box benutzerfreundlich in Betrieb zu nehmen.

                                          Dann könnte ich den Verbrauch am Zähler über meinen Hichi erfassen und via iobroker und Java Script die Ladung und Entladung (nur über das Hausnetz) steuern.

                                          Korrekt.
                                          Wobei ich selbst aktuell in diesem Setup aktuell die aktive Steuerung (eher aus Bequemlichkeit) wieder der eingebauten Logik übertragen habe und MQTT nur zum Daten-Auslesen nutze.
                                          Die Wattwächter-Daten emulieren via Uni-Meter-Emulatorsoftware einen Shelly, den der Speicher dann erkennt und für Steuersignale nutzt.
                                          Für mein Setup reicht das aus.

                                          Das ließe dann (theoretisch) auch den Betrieb mehrerer Speicher sowie eine Nulleinspeisung zu.
                                          Ist das so grob richtig oder bin ich irgendwo komplett falsch abgebogen?
                                          Korrekt.

                                          Die "Nulleinspeisung" geht auf beide Wege.

                                          Der Betrieb komplexerer Logiken wie disjunkte Speicher oder das, was weiter oben diskutiert wurde hier im Thread, geht natürlich out of the box mit der eingebauten Steuerung nicht. Da spielt dann eine persönlich ausgestaltete Steuerung über iobroker ihre Stärken aus. Dafür ist das hier beschrieben: damit man es nach Gusto so formt, wie man es braucht.

                                          Zwei baugleiche 2kWh Speicher kann man natürlich auch mit der internen Steuerung einfach in Reihe schalten plug-and-play. Erst wenn man noch mehr will oder die unbedingt an unterschiedlichen Orten aufgestellt werden sollen, muss man zwingend selbst eine Steuerung schreiben in iobroker.

                                          O Offline
                                          O Offline
                                          opöl
                                          wrote on last edited by opöl
                                          #29

                                          @bertderkleine ,

                                          vielen Dank für Deine Erklärungen. Eine Frage hätte ich noch. Du schriebst:

                                          „Die Wattwächter-Daten emulieren via Uni-Meter-Emulatorsoftware einen Shelly, den der Speicher dann erkennt und für Steuersignale nutzt.“

                                          Wo läuft die Uni-Meter Software und wird ein/mein Hichi WLAN IR Sensor genauso als Shelly erkannt wie Dein Wattwächter, also out of the box ohne zusätzliche HW/SW?

                                          Danke und Gruß

                                          BertDerKleineB 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

                                          135

                                          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