Ankündigung

Einklappen
Keine Ankündigung bisher.

Werte von Fronius Wechselrichter

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Werte von Fronius Wechselrichter

    Salü zusammen
    Hat schon jemand von euch, Werte von einem Fronius-Wechselrichter per http-Abfrage oder via ModBus ins Openhab bekommen?
    Falls über http-get nicht möglich, wie schliesse ich den ModBus an? Direkt an einen Raspery oder brauch ich dazu sonst was?

    Gruss Lukas

    #2
    Ich mache das bisher per http-Request. openhab.cfg:
    Code:
    # http-Binding #
    http:froniusrtd.url=http://[COLOR=#FF0000]<fronius-ip>[/COLOR]/solar_api/v1/GetInverterRealtimeData.cgi?Scope=System
    http:froniusrtd.updateInterval=30000
    .items:
    Code:
    Number PV_Current "Aktuelle Leistung [%0f W]" <inverter> (PV,PV_Graf) { http="<[froniusrtd:30000:JSONPATH($.Body.Data.PAC.Values.1)]" }
    Number PV_DaySum "Tagessumme [%0f Wh]" <inverter> (PV,PV_Graf) { http="<[froniusrtd:30000:JSONPATH($.Body.Data.DAY_ENERGY.Values.1)]" }
    Number PV_YearSum "Jahressumme [%0f Wh]" <inverter> (PV) { http="<[froniusrtd:30000:JSONPATH($.Body.Data.YEAR_ENERGY.Values.1)]" }
    Number PV_Total "Gesamtsumme [%0f Wh]" <inverter> (PV) { http="<[froniusrtd:30000:JSONPATH($.Body.Data.TOTAL_ENERGY.Values.1)]" }
    Number HZ_Watts "Aktueller Verbrauch [%.2f W]" <inverter> { http="<[http://[COLOR=#FF0000]<fronius-ip>[/COLOR]/solar_api/v1/GetMeterRealtimeData.cgi?Scope=System:5000:JSONPATH($.Body.Data.0.PowerReal_P_Sum)]" }
    String MyPV "PV-Anlage [%s]" <inverter> (PV)
    .rules:
    Code:
    rule "PV-Anlage Update"
    when
            Item PV_Current received update
    then
            MyPV.postUpdate(PV_Current.state.toString+"W "+PV_DaySum.state.toString+"Wh/d "+PV_YearSum.state.toString+"Wh/y "+PV_Total.state.toString+"Wh/t")
    end
    .sitemap
    Code:
    Text item=HZ_Watts
        Text item=MyPV
        {
            Chart item=PV_Graf period=12h refresh=10000
         }
    In der Übersicht sehe ich also aktuelle Leistung/Tages/Jahres/Total-Summe, im Chart sehe ich zwei Linien, die mir den Leistungsverlauf und die Tagesproduktion anzeigen - ich hab noch eine Auswahl, mit der ich den Zeitraum wählen kann, das hab ich jetzt weg gelassen, wie auch die Persistence (everyMinute für rrd4j, ich logge aber alle 30 Sekunden, weil noch andere Persistences dran hängen)
    HZ_Watts ist der Zähler, der die dynamische Leistungsbegrenzung steuert (ist über den S0-Eingang angeschlossen).
    Leider gibt es etliche Werte, die man nicht über RealtimeData bekommt. Ich hab noch ein cron-Script laufen, welches mir täglich alle verfügbaren Daten aus dem Speicher ausliest und in eine MySQL-DB kopiert (String- und Phasenspannung und -strom, 5-Minuten-Auflösung).

    Modbus ginge auch über TCP, wäre also nur eine reine Protokoll-Frage, leider hab ich so überhaupt keine Ahnung von Binding-Programmierung, ein eigenes Binding für die Fronius (mit Modbus-Zugriff) wäre wahrscheinlich wesentlich mächtiger.

    Kommentar


      #3
      udo1toni Warum verwendest du bei den Items als Pfad froniusrtd und beim Item HZ_Watts gibst du eine URL an. Die steckt doch in froniusrtd oder nicht?

      Edit:
      Bin gerade etwas am rumexperimentieren, habe noch nicht so viel Erfahrung mit den Rules. Ich will mir anhand der Werte vom Wechselrichter und vom Smart Meter den Ladezustand eine "virtuellen" Batterie berechnen. Jedesmal wenn das Item PV_SummeSmartmeter sich ändert will ich den Ladezustand neu berechnen. Folgendes hab ich programmiert:

      Items:
      Code:
      Number PV_TestBatterie "Batterieladestand [%.2f Wh]"
      Number PV_Current "Aktuelle Leistung PV [%.0f W]" (gPV) { http="<[froniusrtd:30000:JSONPATH($.Body.Data.PAC.Values.1)]" }
      Number PV_SummeSmartmeter "Summe Smartmeter [%.0f W]" <inverter> { http="<[http://192.168.0.5/solar_api/v1/GetMeterRealtimeData.cgi?Scope=System:5000:JSONPATH($.Body.Data.0.PowerReal_P_Sum)]" }
      Rule
      Code:
      rule "Batterieladestand Test"
          when
              Item PV_SummeSmartmeter changed
          then
              PV_TestBatterie.postUpdate((PV_TestBatterie.state as DecimalType)
                                      + ((PV_Current.state as DecimalType) / 720)
                                      + (((PV_SummeSmartmeter.state as DecimalType) / 720) * -1) )
              
              if  (PV_TestBatterie.state < 0.0) {
                      PV_TestBatterie.postUpdate(0.0)
              }
              if  (PV_TestBatterie.state > 5000.0) {
                      PV_TestBatterie.postUpdate(5000.0)
          }
          end
      In der Sitemap wird mir folgendes angezeigt. Hab ich hier noch einen Fehler in der Rule? Habe auch schon Item PV_SummeSmartmeter received update probiert, geht auch nicht.

      BatterieTest.JPG
      Zuletzt geändert von Donnerknall; 27.08.2018, 22:41.

      Kommentar


        #4
        Also, das mit der Adresse ist vermutlich nur historisch bedingt Ich könnte mich damit herausreden, dass der Cache ja keine Realtime Daten enthält... aber nein, das ist nicht der Grund. Eher schon, dass ich beim Anpassen eine Zeile vergessen habe...

        Was Deine Rule betrifft, solltest Du besser Number statt DecimalType verwenden, dafür aber auch überall, wo Du explizit auf eine Zahl zugreifst.
        Weiterhin schreibst Du einen Wert in ein Item und liest ihn unmittelbar danach aus, das kann schief gehen, das System ist asynchron designed, es gibt keine garantierten Antwortzeiten, openHAB erhält den Befehl, einen Status auf dem internen Bus zu setzen, danach wird die rule sofort weiter ausgeführt, ob openHAB nun den Status gesetzt hat oder nicht.

        Deine Rule geht stillschweigend davon aus, dass alle Items eine Zahl enthalten. Falls die Items per restoreOnStartup aus einer Persistence wiederhergestellt werden, wird das vermutlich auch so sein, aber zumindest ist das ein Kandidat für einen möglichen Fehler. Besser, das abzufangen:
        Code:
        rule "Batterieladestand Test"
        when
            Item PV_SummeSmartmeter changed
        then
            if(!(PV_TestBatterie.state instanceof Number)) {
                logError("batterie","PV_TestBatterie Status: {}",PV_TestBatterie.state)
                return;   //rule abbrechen
            }
            if(!(PV_Current.state instanceof Number)) {
                logError("batterie","PV_Current Status: {}",PV_Current.state)
                return;   //rule abbrechen
            }
            if(!(PV_SummeSmartmeter.state instanceof Number)) {
                logError("batterie","PV_SummeSmartmeter Status: {}",PV_SummeSmartmeter.state)
                return;   //rule abbrechen
            }
            val Number neuWert = (PV_TestBatterie.state as Number) +
                                 (PV_Current.state as Number)/720 -
                                 (PV_SummeSmartmeter.state as Number)/720
            logInfo("batterie","PV_TestBatterie berechneter Wert: {}",neuWert)
            PV_TestBatterie.postUpdate(if(neuWert < 0) 0 else if(neuWert > 5000) 5000 else neuWert)
        end
        Der erste Teil der Rule prüft also alle verwendeten Items auf Plausibilität. Für den Trigger könnte man sich das eventuell sparen, vorausgesetzt, das verwendete Addon liefert unter allen Umständen eine gültige Zahl, aber... "'s kost' ja nix". Im Fehlerfall gibt es eine passende Meldung, was hilfreich ist, falls sich die Rule mal merkwürdig verhält.
        Dann wird der neue Wert berechnet und in einer Konstanten abgespeichert. Zum Schluss wir abhängig vom Wert der Konstanten das Item mit einem neuen Status versehen. Der erweiterte ternäre Operator macht die Rule an dieser Stelle auch recht schlank.
        Wenn man Number verwendet, spielt es keine Rolle, ob es sich um Integer oder Float handelt, was der Rule ebenso gut tut
        Zuletzt geändert von udo1toni; 28.08.2018, 15:25.

        Kommentar


          #5
          Hey super, funktioniert einwandfrei Wieder sehr hilfreicher Code und Erläuterungen von dir, da kann man gut drauf aufbauen.

          Zitat von udo1toni Beitrag anzeigen
          Deine Rule geht stillschweigend davon aus, dass alle Items eine Zahl enthalten. Falls die Items per restoreOnStartup aus einer Persistence wiederhergestellt werden, wird das vermutlich auch so sein, aber zumindest ist das ein Kandidat für einen möglichen Fehler.
          Gibt es irgendeine Möglichkeit ein Item zu initialisieren außer mit einer Rule bei System Start? Ich möchte mein System nicht neu starten müssen. Eine Rule in der man
          Item.state instanceof Number abfrägt, wenn nicht auf 0 initialisiert und anschließen die Rule wieder löscht?

          Kommentar


            #6
            Es kommt auf das Item (bzw. das dahinter evtl. vorhandene Binding) an. für Items, die an knx gekoppelt sind, kann man openHAB anweisen, den Status vom Bus zu lesen. Das funktioniert natürlich nur, wenn der Status auch lesbar ist (also ein Device auf den Read Request antwortet). Dieses Verhalten gibt es natürlich auch bei anderen Bindings, aber da hab ich halt keine Ahnung
            Wenn diese Methode nicht zur Verfügung steht, und man also darauf angewiesen ist, dass openHAB "zufällig" einen Status mitgeteilt bekommt, kann man mit einer Persistence mit der Option restoreOnStartup dafür sorgen, dass openHAB beim Systemstart den letzten bekannten Status in das Item lädt, das ist oft allemal besser als gar kein Status.

            Wenn man nur verhindern will, dass eine Rule mit Fehlermeldung abbricht, kann man natürlich statt des return; auch ein meinItem.postUpdate(0) verwenden, allerdings sollte man dann dafür Sorge tragen, dass openHAB genug Zeit hatte, das postUpdate() auch auszuführen.

            Kommentar


              #7
              Also ein Problem habe ich noch. Ich habe die Rule wie von dir vorgeschlagen am Laufen. Allerdings funktioniert es nicht mehr, wenn der Speicher "leergelaufen" ist. Dann steht in der Sitemap " - Wh". Der Speicher wird dann auch nicht mehr geladen. Wenn ich den Wert auf irgendeinen Wert initialisiere dann funktioenirt es wieder.

              Ich habe dann die Rule angepasst vonr PV_TestBatterie.postUpdate(if(neuWert < 0) 0 auf PV_TestBatterie.postUpdate(if(neuWert < 1) 1.
              Da passiert aber das gleiche. Was könnte das sein?

              Kommentar


                #8
                Eigentlich sollte das so funktionieren. Wie gesagt, falls ein Item durch die null- Prüfung fällt, könnte man alternativ 0 hineinschreiben. Den ternären Operator könnten wir auch auflösen, falls die DSL mit der Verkettung Probleme haben sollte:
                Code:
                rule "Batterieladestand Test"
                when
                    Item PV_SummeSmartmeter changed
                then
                    var boolean bWait = false
                    if(!(PV_TestBatterie.state instanceof Number)) {
                        logWarn("batterie","PV_TestBatterie Status: {}, initialisiere mit 0!",PV_TestBatterie.state)
                        PV_TestBatterie.postUpdate(0)   //intialisieren
                        bWait = true
                    }
                    if(!(PV_Current.state instanceof Number)) {
                        logWarn("batterie","PV_Current Status: {}, initialisiere mit 0!",PV_Current.state)
                        PV_Current.postUpdate(0)   //intialisieren
                        bWait = true
                    }
                    if(!(PV_SummeSmartmeter.state instanceof Number)) {
                        logWarn("batterie","PV_SummeSmartmeter Status: {}, initialisiere mit 0!",PV_SummeSmartmeter.state)
                        PV_SummeSmartmeter.postUpdate(0)   //intialisieren
                        bWait = true
                    }
                    if (bWait) Thread::sleep(500)  // warte, falls mindestens ein postUpdate ausgelöst wurde
                    var Number neuWert = (PV_TestBatterie.state as Number) +  //var statt val
                                         (PV_Current.state as Number)/720 -
                                         (PV_SummeSmartmeter.state as Number)/720
                    logInfo("batterie","PV_TestBatterie berechneter Wert: {}",neuWert)
                    if(neuWert < 0) neuWert = 0
                    if(neuWert > 5000) neuWert = 5000
                    PV_TestBatterie.postUpdate(neuWert)
                end
                Die Rule ist großteils geändert!
                Da die Rule nun nicht mehr abbricht, ist der LogLevel auf Warn für die ersten drei Statements, denn die Rule setzt notfalls Initialwerte.
                Wenn eines der Items per postUpdate geändert wird, legt die Rule eine halbe Sekunde Pause ein, um sicher zu gehen, dass das postUpdate bereits durch ist.
                Durch die Auflösung des ternären Operators, wird nun das Ergebnis der Berechnung verändert. Damit muss der Wert nun auch in einer Variablen gespeichert werden, anstatt als Konstante.
                Die Rule schreibt ausschließlich Zahlenwerte zwischen 0 und 5000 in das Item PV_TestBatterie, entsprechend sollte auch kein Strich mehr auftauchen, außer bei Systemstart bis zur ersten Berechnung. Ich gehe davon aus, dass Du bei Systemstart den aktuellen Ladezustand z.B.
                per karaf Konsole smarthome send PV_TestBatterie <zahl> auf den aktuellen Zustand setzt.

                Kommentar


                  #9
                  Also läuft seit einigen Tagen stabil
                  Eine Frage noch zum Thread::Sleep. Ich gehe davon aus, während dieser Zeit laufen die anderen Rules normal weiter?

                  Kommentar


                    #10
                    Thread::sleep() legt für den Thread, in dem es aufgerufen wird eine Pause ein, also ja, die anderen Rules laufen normal weiter.

                    ABER: openHAB stellt per default lediglich 5 Threads zur Ausführung von Rules zur Verfügung, weitere 2 Threads stehen für Time cron Rules zur Verfügung, macht insgesamt 7. Werden mehr als zwei Rules mit dem gleichen Time cron Trigger gestartet, kommen nur zwei zum Zuge. werden zeitgleich mehr als 5 Rules durch etwas anderes getriggert, kommen nur fünf zum Zug. Wenn Du nun lange Thread::sleep()s in den Rules einbaust, steigt das Risiko, dass sich mehrere Rules im Schlummerzustand befinden und dann andere Rules das Nachsehen haben.

                    Die allgemeine Empfehlung lautet, Thread::sleep() nicht mit Zeiten über 500 Millisekunden aufzurufen. Wenn man längere Pausen im Code einlegen will, eignet sich createTimer() wesentlich besser.

                    Wenn man fixe Zeiten benötigt, z.B. um ein Item automatisch auf einen Wert zu setzen (Stichwort Treppenlichtsteuerung), kann man das sehr elegant über das Expire Binding erledigen. Sollen die Zeiten dynamisch gesteuert werden, ist createTimer() die einzige Möglichkeit.

                    Kommentar


                      #11
                      Wie immer sehr informative Antwort von dir! Da lernt man richtig was Vielen Dank!

                      Kommentar

                      Lädt...
                      X