Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First Support for VE-Direct Hex messages #479

Closed

Conversation

philippsandhaus
Copy link

This is some initial base work for both #470 and #436 to make further development of the two issues independent.

It does two things:

  1. Initial support for sending VE-Direct Hex commands (thanks to @JaMo523). Also received Hex messages are checked for a valid checksum, but not yet further handled.
  2. An additional class VeDirectChargerController is introduced which is the new base class for VeDirectMpptController. The idea is to include all code here which is shared between a MPPT charger and a Victron AC Charger. It did not yet add this new class to this PR yet as its is mostly empty for now.

@philippsandhaus philippsandhaus marked this pull request as ready for review October 3, 2023 22:25
@JaMo523
Copy link

JaMo523 commented Oct 4, 2023

Vielen Dank für das Programmieren. Hast du dir schon Gedanken gemacht wie das Auslesen von Werten funktionieren soll? Eventuell Variablen für alle Werte anlegen und dann alle Werte zyklisch auslesen?

@philippsandhaus
Copy link
Author

philippsandhaus commented Oct 4, 2023

Generell wird das Auslesen von vielen Werten ja schon über das Textprotokoll unterstützt und hierfür gibt es z.B. für den MPPTController auch die entsprechende Variable veFrame die entsprechend ausgelesen werden kann. Dies sind alles Werte, die vom MPPT-Controller geschickt, ohne dass hierfür eine Anfrage gesendet werden muss. Dazu kommen die "asynchronous Hex-Messages", die im Moment nicht ausgewertet werden. Ich habe gerade keinen Überblick, ob hier andere oder mehr Werte als über das Text-Protokoll gesendet werden. Hast Du für dich interessante Werte im Kopf, die nicht über das Text-Protokoll abgebildet werden?

Interessant sind denke ich die Werte, für die eine Anfrage (GET-Kommando) gestellt werden muss über das Hex-Protokoll. Da die Antworten hier mit einer Zeitverzögerung kommen wäre vielleicht eine Umsetzung über einen Callback-Mechanismus sinnvoll um den Kontrollfluss nicht zu blockieren. D.h. beim Anfragen eines Wertes wird eine Referenz zu einer Funktion mit Übergeben die aufgerufen wird, wenn z.B. vom MPPT-Controller eine Antwort gekommen ist.

@schlimmchen
Copy link
Member

Da die Antworten hier mit einer Zeitverzögerung kommen wäre vielleicht eine Umsetzung über einen Callback-Mechanismus sinnvoll um den Kontrollfluss nicht zu blockieren.

Das klingt sehr vernünftig, allerdings wäre das mehr als genug für diesen Anwendungsfall. In der loop() schickst du regelmäßig GET Kommandos (fire and forget), und wenn du eine Antwort erhälst, sammelst du sie ein.

Der JK BMS Controller macht es ähnlich.

@JaMo523
Copy link

JaMo523 commented Oct 4, 2023

Für mich ist nur das auslesen des battery maximum current (0xEDF0). interessant.

Für jemande der den Akku maximal ausnutzen möchte, wäre der "BMS Controlled" Modus + Remote sensor data (voltage and/or temperature) interessant. Da könnte man die Werte von der Pylontech oder einem anderen BMS and den Victron senden.

image

Man könnte ein Array anlegen, in dem die zyklischen GET + SET Befehle und die dazu passenden empfangenen Werte eingetragen werden.

Die Befehle aus dem Array würden dann zyklisch abgefragt werden.

Dann könnte später je nach eingestellten Optionen dem Array Befehle hinzugefügt oder entfernt werden.

@helgeerbe helgeerbe marked this pull request as draft October 4, 2023 11:24
@philippsandhaus
Copy link
Author

Ok, ich bin bei ein paar Tests auf 2 Probleme gestossen:

  1. Sobald man ein Hex-Kommando sendet, dauert es etwa 2-3 Sekunden, bis wieder Nachrichten über das Text-Protokoll gesendet werden. Asynchrone Hex-Nachrichten werden aber weiterhin parallel gesendet.
  2. Wenn ich direkt mehrere Hex-Kommandos hintereinander sende, sind die Antworten sehr unzuverlässig. Manchmal kommt eine Antwort auf das erste Kommando, manchmal auf das erste und dritte. Es wäre also nötig, Pausen zwischen dem Absenden von Hex-Kommandos einzubauen.

Zum Thema zyklisches Abfragen von Werten wie z.B.Maximum Battery Current: Das ist eigentlich nur möglich, wenn man eine Anfrage nur alle paar Sekunden sendet, ansonsten gibt es keine Daten mehr über das Textprotokoll. Vor allen Dingen wenn mehrere Werte abgefragt werden kann es dann länger dauern. Ausserdem muss man irgendwie die kurzen Pausen zwischen den einzelnen Kommandos sicherstellen. Könnte man das z.B. in einen separaten Thread auslagern? Da habe ich keine Erfahrung mit dem ESP32.

Alternativ könnte man auch komplett auf das Textprotokoll verzichten und nur die asynchronen Hex-Nachrichten auswerten. Soweit ich das sehe werde hier mindestens die gleichen Werte gesendet. Das könnte das gesamte Handling sogar einfacher machen, wäre aber eine große Umstellung.

Man könnte auch komplett auf das zyklische Anfragen der Werte verzichten und es so umsetzen, der "Consumer" aktiv den gewünschten Wert anfragen muss und dieser dann wie beim JK BMS Controller abgespeichert wird, wenn die Antwort kommt.

Viele Möglichkeiten, was meint ihr? Klar, wenn es nur um den einen Wert für maximum Battery geht kein Problem, aber es soll ja auch erweiterbar sein.

@JaMo523
Copy link

JaMo523 commented Oct 7, 2023

Ok, ich bin bei ein paar Tests auf 2 Probleme gestossen:

  1. Sobald man ein Hex-Kommando sendet, dauert es etwa 2-3 Sekunden, bis wieder Nachrichten über das Text-Protokoll gesendet werden. Asynchrone Hex-Nachrichten werden aber weiterhin parallel gesendet.
  2. Wenn ich direkt mehrere Hex-Kommandos hintereinander sende, sind die Antworten sehr unzuverlässig. Manchmal kommt eine Antwort auf das erste Kommando, manchmal auf das erste und dritte. Es wäre also nötig, Pausen zwischen dem Absenden von Hex-Kommandos einzubauen.

Zum Thema zyklisches Abfragen von Werten wie z.B.Maximum Battery Current: Das ist eigentlich nur möglich, wenn man eine Anfrage nur alle paar Sekunden sendet, ansonsten gibt es keine Daten mehr über das Textprotokoll. Vor allen Dingen wenn mehrere Werte abgefragt werden kann es dann länger dauern. Ausserdem muss man irgendwie die kurzen Pausen zwischen den einzelnen Kommandos sicherstellen. Könnte man das z.B. in einen separaten Thread auslagern? Da habe ich keine Erfahrung mit dem ESP32.

Alternativ könnte man auch komplett auf das Textprotokoll verzichten und nur die asynchronen Hex-Nachrichten auswerten. Soweit ich das sehe werde hier mindestens die gleichen Werte gesendet. Das könnte das gesamte Handling sogar einfacher machen, wäre aber eine große Umstellung.

Man könnte auch komplett auf das zyklische Anfragen der Werte verzichten und es so umsetzen, der "Consumer" aktiv den gewünschten Wert anfragen muss und dieser dann wie beim JK BMS Controller abgespeichert wird, wenn die Antwort kommt.

Viele Möglichkeiten, was meint ihr? Klar, wenn es nur um den einen Wert für maximum Battery geht kein Problem, aber es soll ja auch erweiterbar sein.

Also ich habe es noch nicht getestet. Kannst du bitte kurz schreiben auf welchem Gerät mit welcher Firmware du getestet hast?

In dem Dokument steht ja, dass wenn das HEX-Protokoll benutzt wird, das Text-Protokoll unterbunden wird.

image

Eigentlich kann das HEX-Protokoll gar nicht so langsam sein, Victron nutzt es ja selber um MPPTs zu synchronisieren bzw. BMS / Battery Sense usw.

Da es eine Serielle Schnittstelle ist, ist der Ablauf eigentlich klar. Befehl senden, auf Antwort warten, Befehl senden, auf Antwort warten.... Dauerfeuer raussenden und hoffen, dass alles in der richtigen Reihenfolge abgearbeitet wird, wird nicht funktionieren. Die Geräte brauchen in der Regel immer ein paar ms um zu Antworten.

Ich denke auch der Teil welcher momentan das Textprotokoll verwendet müsste auf HEX-Protokoll umgeändert werden und durch eine loop zyklisch abgefragt werden.

@philippsandhaus
Copy link
Author

Ich teste das gerade mit meinem AC Lader Blue Smart IP22 24/16 FW 3.42, passt also nicht ganz zu de Dokumentation für die MPPTs, es gibt aber anscheinend viele Überschneidungen.

Eigentlich kann das HEX-Protokoll gar nicht so langsam sein, Victron nutzt es ja selber um MPPTs zu synchronisieren bzw. BMS / Battery Sense usw.

Langsam ist es auch nicht, bzw. auf jeden Fall ausreichend. Zum Synchronisieren von mehreren MPPTs untereinander reicht es auf jeden Fall, da muss ja nicht kontinuierlich gesendet werden.

Da es eine Serielle Schnittstelle ist, ist der Ablauf eigentlich klar. Befehl senden, auf Antwort warten, Befehl senden, auf Antwort warten.... Dauerfeuer raussenden und hoffen, dass alles in der richtigen Reihenfolge abgearbeitet wird, wird nicht funktionieren. Die Geräte brauchen in der Regel immer ein paar ms um zu Antworten.

Je nachdem, wie es auf der Gegenstelle implementiert ist. Da könnte auch eine Art FiFO-Buffer sein, der erst einmal alle Befehle entgegennimmt und der Reihe nach abarbeitet, je nach dem wann Zeit ist. Das Abarbeiten in der richtigen Reihenfolge wäre nebenbei ja auch gar nicht nötig. Schwierig ist eben nur die Strategie immer erst auf eine Antwort zu warten bevor der nächste Befehl gesendet wird. Was passiert, wenn es zu Übertragungsfehlern kommt? Wie lange warten man? Ich habe mich gerade mal testweise angetastet: Wenn ich immer 50ms Pause zwischen den Befehlen lasse, wird auch kein Befehl verschluckt, d.h. es kommt relativ zuverlässig zu jedem Befehl eine Antwort. Wäre vielleicht eine Strategie, oder einfach pro loop-Durchlauf jeweils nur einen Befehl absenden. Dann hat man implizit ein delay was gross genug sein sollte und muss kein delay(50) einbauen wie ich es gerade testweise gemacht habe.

Generell: Ich glaube trotzdem immer noch dass da Victron-Protokoll schon implizit so designed ist dass die Werte, die sich oft ändern ohnehin schon automatisch per Text-Protokoll und asynchrone Nachricht geschickt wird. Der Wert für Max Battery Current ist ja so ein typischer Wert, der eigentlich gerade nicht kontinuierlich abgefragt werden müsste.

@schlimmchen
Copy link
Member

Da es eine Serielle Schnittstelle ist, ist der Ablauf eigentlich klar. Befehl senden, auf Antwort warten, Befehl senden, auf Antwort warten...

Da stimme ich zu. So sollte es sein.

Was passiert, wenn es zu Übertragungsfehlern kommt? Wie lange warten man?

Du stellst definitiv die richtigen Fragen, sehr gut. Bei Übertragungsfehlern bekommst du vermutlich keine Antwort. Dir bleibt nur, ein Timeout abzuwarten und deine Nachricht zu wiederholen. Oder die nächste zu schicken, weil sich die Schicht drüber kümmern wird/muss, dass es nochmal versucht wird.

Im JK BMS Controller ist so eine "state machine" mit einem Timeout implementiert.

Warum schickst du mehrere Nachrichten kurz hintereinander? Willst du mehrere Werte "gleichzeitig" abfragen? Hast du geprüft, ob man nicht mehrere Werte pro Nachricht anfragen kann?

@philippsandhaus
Copy link
Author

Warum schickst du mehrere Nachrichten kurz hintereinander?

Das war eigentlich eher als Test ob man die Implementierung z.B. ohne eine State-Machine hinbekommt. Meine Überlegung: Ich schicke einfach Regelmässig Anfragen (GET Befehle) für alle Werte raus, für die ich gerne eine Antwort hätte und die nicht ohnehin schon regelmässig automatisch unaufgefordert kommen. Die Antworten sammeln ich dann einfach wie sie kommen ein und kann da das gleiche Handling machen wie auch jetzt schon. Nur das zusätzlich auch Hex-Nachrichten geparsed werden. So muss ich mich auch nicht Übertragungsfehler beim Empfangen oder Senden der Nachrichten zu kümmern und mir merken, ob eine Anfrage erfolgreich gesendet wurde.

Anders sieht es beim Setzen von Werten aus, wie z.B. dem Battery Current Limit. Hier braucht man denke ich eine State-Machine die Überprüft, ob ein entsprechendes ACK zum gesendeten Befehl empfangen wurde.

Im JK BMS Controller ist es in dem Sinne etwas anders, weil hier die Werte immer erst angefragt werden müssen.

Willst du mehrere Werte "gleichzeitig" abfragen? Hast du geprüft, ob man nicht mehrere Werte pro Nachricht anfragen kann?

Nein, ich wollte wie gesagt nur das regelmässige Abfragen von mehreren Werten einfacher machen (siehe oben). Mehrere Werte gleichzeitig anfragen geht nicht laut VE.Direct Protokoll.

Danke erst einmal für den Input. Ich probiere mal, was bei mir funktioniert und teste auch mal mit meinem MPPT Lader.

@JaMo523
Copy link

JaMo523 commented Oct 9, 2023

Meine Überlegung: Ich schicke einfach Regelmässig Anfragen (GET Befehle) für alle Werte raus, für die ich gerne eine Antwort hätte und die nicht ohnehin schon regelmässig automatisch unaufgefordert kommen. Die Antworten sammeln ich dann einfach wie sie kommen ein und kann da das gleiche Handling machen wie auch jetzt schon. Nur das zusätzlich auch Hex-Nachrichten geparsed werden. So muss ich mich auch nicht Übertragungsfehler beim Empfangen oder Senden der Nachrichten zu kümmern und mir merken, ob eine Anfrage erfolgreich gesendet wurde.

Anders sieht es beim Setzen von Werten aus, wie z.B. dem Battery Current Limit. Hier braucht man denke ich eine State-Machine die Überprüft, ob ein entsprechendes ACK zum gesendeten Befehl empfangen wurde.

Es ist vermutlich Sinnvoller die GET-Befehle genauso zu behandeln wie die SET-Befehle. Damit du Fehlermeldungen zu ordnen kannst.

Wie bereits oben geschrieben macht der Ablauf Befehl senden, Antwort abwarten und auswerten, Befehl senden, Antwort abwarten und auswerten am meisten Sinn bei so einer Schnittstelle. Das ist ein sequentieller Ablauf der für alle Befehle gilt.

Befehle raus senden und Antworten einsammeln wird nicht funktionieren.

@philippsandhaus
Copy link
Author

philippsandhaus commented Oct 9, 2023

Wie bereits oben geschrieben macht der Ablauf Befehl senden, Antwort abwarten und auswerten, Befehl senden, Antwort abwarten und auswerten am meisten Sinn bei so einer Schnittstelle. Das ist ein sequentieller Ablauf der für alle Befehle gilt.

Befehle raus senden und Antworten einsammeln wird nicht funktionieren.

Sehe ich grundsätzlich nicht so und das Bestätigen meine Tests auch nicht. Hier mal ein Ausschnitt aus den Logs:

21:13:49.991 > [VE.Direct] send hex command: :7501000EE
21:13:50.006 > [VE.Direct] send hex command: :70202004A
21:13:50.021 > [VE.Direct] hex frame received: :75010000000000000000000001B0A190A00000000000000000000000000000000002A00340048
21:13:50.027 > [VE.Direct] hex frame received: :70202000200000048
21:13:50.034 > [VE.Direct] send hex command: :7F0ED0071
21:13:50.055 > [VE.Direct] hex frame received: :7F0ED00C800A9
21:13:50.064 > [VE.Direct] send hex command: :7501000EE
21:13:50.078 > [VE.Direct] send hex command: :70202004A
21:13:50.092 > [VE.Direct] hex frame received: :75010000000000000000000001B0A190A00000000000000000000000000000000002A00340048
21:13:50.101 > [VE.Direct] hex frame received: :70202000200000048
21:13:50.108 > [VE.Direct] send hex command: :7F0ED0071
21:13:50.123 > [VE.Direct] hex frame received: :7F0ED00C800A9
21:13:50.132 > [VE.Direct] send hex command: :7501000EE
21:13:50.159 > [VE.Direct] hex frame received: :75010000000000000000000001B0A190A00000000000000000000000000000000002A00340048

Man sieht am Anfang schön, dass zeitlich erst einmal 2 Kommandos gesendet werden und die Antworten auf beide Kommandos danach reinkommen

@JaMo523
Copy link

JaMo523 commented Oct 9, 2023

Man sieht am Anfang schön, dass zeitlich erst einmal 2 Kommandos gesendet werden und die Antworten auf beide Kommandos danach reinkommen

Daraus darf man aber nicht herleiten, dass x-beliebige Befehle, Anzahl auch >2 senden direkt hintereinander funktioniert.

Du weißt nicht wie viele Befehle der Victron zwischenspeichern kann, bzw. Bytes und du weißt auch nicht ob es sich von Modell zu Modell oder von Firmware zu Firmware oder von Typ zu Typ unterscheidet. Und selbst wenn man es wüsste, dann müsste man selber mit rechnen wie viel Bytes die gesendeten Befehle haben um den Buffer gegenüber nicht zum Überlauf zu bringen.

@philippsandhaus
Copy link
Author

Ich glaube, wir reden gerade auch ein bisschen aneinander vorbei. Mir geht es gar nicht darum, den Input-Buffer mit Befehlen zu fluten und evtl. zum Überlaufen zu bringen. Das würde ich einfach dadurch lösen, dass ich genug Zeit zwischen den einzelnen Kommandos lasse (obwohl der Victron da auch sehr robust zu sein scheint). Ich glaube eben nur einfach, dass man für das reine regelmässige Abfragen von Werten, die nicht als automatisch als :A Nachrichten kommen, es erst einmal einfach halten kann. Wenn zwischendurch mal eine Fehlermeldung wegen eines fehlerhaft empfangenen Kommandos kommt, dann kann man die auch einfach ignorieren. Dann kommt das Update eben mit der nächsten Abfrage. Dadurch kann man sich Geschichten wie Warten auf Antworten, die nie kommen, Errorhandling und Timeouts sparen.

Noch mal ein anderer Punkt der mir eher Sorgen macht. In der Doku steht:

Battery settings registers
WARNING: stored in non-volatile memory. Continuous writing, for example from a control loop, will lead to early failure.

Das wäre ja bei Nutzung im DPL schon der Fall. Hast Du dir dazu Gedanken gemacht? Es hört sich eher nicht danach an, als ob man den Wert für Battery Maximum Current oft verändern sollte.

@JaMo523
Copy link

JaMo523 commented Oct 9, 2023

Dadurch kann man sich Geschichten wie Warten auf Antworten, die nie kommen, Errorhandling und Timeouts sparen.

Unabhängig davon wie viele Befehle, man weiß nicht wann man den Input Buffer gegenüber überflutet und wie groß der ist. Ich habe da auch schon so meine Erfahrungen gemacht und würde es direkt mit Errorhandling und Timeouts machen da Probleme früher oder später auftreten werden und man sich dann ein kompliziertes debuggen sparen kann.

Noch mal ein anderer Punkt der mir eher Sorgen macht. In der Doku steht:

Battery settings registers
WARNING: stored in non-volatile memory. Continuous writing, for example from a control loop, will lead to early failure.

Das wäre ja bei Nutzung im DPL schon der Fall. Hast Du dir dazu Gedanken gemacht? Es hört sich eher nicht danach an, als ob man den Wert für Battery Maximum Current oft verändern sollte.

Das wird in einen nicht flüchtigen Speicher geschrieben. Solche Schreibvorgänge dauern immer etwas länger, deshalb soll man es nicht in einer loop machen. Wenn es ein EEPROM ist, dann verträgt der > 100.000 Schreibzyklen. Ich schreibe das Limit nur wenn der Full Solar Passtrough erreicht ist und wenn er wieder ausgeschaltet wird. Das sind maximal 2 Schreibzyklen an einem Tag an dem die Sonne scheint. Man könnte auch das Remote Register benutzen, dann müsste man aber spätestens alle 60 Sekunden den Wert erneut geschrieben haben.

Der Charger Maximum Current ist übrigens Load + Batterycurrent.

image

@philippsandhaus
Copy link
Author

Unabhängig davon wie viele Befehle, man weiß nicht wann man den Input Buffer gegenüber überflutet und wie groß der ist. Ich habe da auch schon so meine Erfahrungen gemacht und würde es direkt mit Errorhandling und Timeouts machen da Probleme früher oder später auftreten werden und man sich dann ein kompliziertes debuggen sparen kann.

Ganz ehrlich, ich würde wahrscheinlich nach aktuellem Stand ohnehin erst einmal gar keine Werte so kontinuierlich abfragen. Alle relevanten sich oft ändernden Werte kommen ohnehin schon jetzt automatisch und werden abgespeichert. Du sagst ja selber, dass Du das Battery Limit Current maximal 2 Mal am Tag anpassen würdest. Dafür muss der aktuelle Wert nicht alle paar Sekunden gezogen werden. Ein anderer Anwendungsfall wären statistische Werte der letzen Tage (jeweils größere Brocken). Die können auch bei Bedarf angefragt werden in dem Moment wo sie gebraucht werden (z.B. zur Anzeige im Webinterface).

Vorschlag: Für die relevanten Werte gibt es jeweils Variablen in z.B. VeDirectMppt, evtl. noch mit einem Timestamp vom letzten Update. Diese Werte können entweder explizit von aussen neu angefragt werden z.B.

int VeDirectMpptController::requestMeasurementUpdate(VeDirectMeasurement measurement);

oder werden upgedatet, wenn ein entsprechendes positives ACK auf eine SET-Anfrage an das Victron-Gerät empfangen wurde.

'requestMeasurementUpdate' stösst dann den Tanz mit einer State-Machine, Error-Handling, Timeout etc. an und returned dann auch mit entprechendem Zustand als Fehler-Rückgabewert, wenn gerade schon eine Abfrage am Laufen ist, bzw. auf eine Antwort gewartet wird.

Das sind maximal 2 Schreibzyklen an einem Tag an dem die Sonne scheint.

Das stimmt. Ich merke auch gerade, dass ich da eher an meinen Anwendungsfall gedacht habe, also das kontinuierliche Anpassen für Überschusseinspeisung mit einem AC Lader.

Man könnte auch das Remote Register benutzen, dann müsste man aber spätestens alle 60 Sekunden den Wert erneut geschrieben haben.

Das wäre dann vielleicht eher etwas für meinen Anwendungsfall. Danke für den Hinweis.

Der Charger Maximum Current ist übrigens Load + Batterycurrent.

Jupp, hab ich auch schon gefunden und getestet. Der Wert ist leider Read-only.

@JaMo523
Copy link

JaMo523 commented Oct 10, 2023

Ganz ehrlich, ich würde wahrscheinlich nach aktuellem Stand ohnehin erst einmal gar keine Werte so kontinuierlich abfragen. Alle relevanten sich oft ändernden Werte kommen ohnehin schon jetzt automatisch und werden abgespeichert. Du sagst ja selber, dass Du das Battery Limit Current maximal 2 Mal am Tag anpassen würdest. Dafür muss der aktuelle Wert nicht alle paar Sekunden gezogen werden.

Ich würde das Limit gerne auf der Webseite anzeigen und da man es auch per APP ändern kann würde ich es wiederholt abfragen.

Ein anderer Anwendungsfall wären statistische Werte der letzen Tage (jeweils größere Brocken). Die können auch bei Bedarf angefragt werden in dem Moment wo sie gebraucht werden (z.B. zur Anzeige im Webinterface).

Da reicht eine Abfrage am Tag, weil die Daten sich innerhalb eines Tages ja nicht ändern können.

Vorschlag: Für die relevanten Werte gibt es jeweils Variablen in z.B. VeDirectMppt, evtl. noch mit einem Timestamp vom letzten Update.
Diese Werte können entweder explizit von aussen neu angefragt werden z.B.

int VeDirectMpptController::requestMeasurementUpdate(VeDirectMeasurement measurement);

oder werden upgedatet, wenn ein entsprechendes positives ACK auf eine SET-Anfrage an das Victron-Gerät empfangen wurde.

'requestMeasurementUpdate' stösst dann den Tanz mit einer State-Machine, Error-Handling, Timeout etc. an und returned dann auch mit entprechendem Zustand als Fehler-Rückgabewert, wenn gerade schon eine Abfrage am Laufen ist, bzw. auf eine Antwort gewartet wird.

Ich würde das erweitern um:

  • ein Array/Queue welches Daten enthält welche zyklisch abgefagt oder gesetzt werden sollen.

  • ein Array/Queue welches Daten enthält die explizit abgefragt oder gesetzt werden sollen.

Das Array verwendet einen eigenen Datentyp bestehend aus z.B. command, response, fault, responseTimestamp, Intervall

eine State-Machine welche eine innere Loop hat:

  1. send Command (Befehl an Mppt senden)
  2. wait for response (auf Antwort warten)
    • check faults (prüfen ob kein Fehler zurückgemeldet wurde)
  3. Timeout (keine Antwort erhalten, Debug Information, nächster Befehl)

und eine äußere Loop:

  1. Array zyklische abfrage/setzen abarbeiten
    • responseTimestamp und intervall prüfen (falls :A bereits die Daten bereitgestellt hat oder Intervall noch nicht erreicht wurde, kann der Befehl übersprungen werden.)
  2. Array explizite abfrage/setzen abarbeiten.

Dann kann man eine Funktion schreiben welche die daten entsprechend hinzufügt und auswertet:

VeDirectMpptController::addCommand(VeDirectCommand command, int request, int intervall);

Eine Funktion welche Werte im Array setzt oder abfragt
VeDirectMpptController::setValue(VeDirectCommand command, int value);
int VeDirectMpptController::getValue(VeDirectCommand command);

Beispiel zyklische abfrage BatteyMaximumCurrent
VeDirectMpptController::addCommand(BATTERY_MAXIMUM_CURRENT_0xEDF0, CYCLIC_GET, 1000MS);

Beispiel zyklisches setzen ChargeCurrentLimit
VeDirectMpptController::addCommand(CHARGE_CURRENT_LIMIT_0x2015, CYCLIC_SET, 10000MS);

Beispiel explizite abfrage BatteyMaximumCurrent
VeDirectMpptController::addCommand(BATTERY_MAXIMUM_CURRENT_0xEDF0, SINGLE_GET,0);

Der Vorteil:

  • Wenn das Protokoll erweitert wird, dann muss man nicht neue Variablen erzeugen sondern kann einfach die Befehlsliste erweitern. Abhängig von Einstellungen könnten Werte beliebig zyklisch oder explizit abgefragt oder gesetzt werden.

  • Man kann in Zukunft auch die Remoteregister nutzten und z.B. Daten von der BMS zyklisch an den MPPT weiter zu leiten.

Ich denke so viel mehr Arbeit ist das auch nicht. Ich kann da gerne auch mithelfen...

@JaMo523
Copy link

JaMo523 commented Oct 16, 2023

@philippsandhaus Ich kann auch was vorbereiten und bei mir testen.

@philippsandhaus
Copy link
Author

@JaMo523 Ja, mach das gerne. Ich komme leider im Moment nicht zu viel. Nimm also gerne meinen aktuellen Stand und erweitern entsprechend.

@philippsandhaus philippsandhaus force-pushed the victron-hex branch 3 times, most recently from b771e5e to 0f062a9 Compare October 20, 2023 18:33
@bonzai-wurst
Copy link

Servus, ich habe das hex Protokoll bei mir schon seit einigen Monaten laufen. Ich kann Werte aktiv Abfragen, die Antworten verarbeiten und Werte setzen. Umgesetzt habe ich damit zum Beispiel ein soclimit. Wenn der Forecast am nächsten Tag einen gewissen Wert überschreitet, dann limitiere ich den soc auf 80%, das reicht dann für die Nacht. Für die Limitierung habe ich zwei Mechanismen implementiert:
Limit über I: Der Maximale Ladestrom wird auf den aktuellen Invertercurrent limitiert VEDirect_ID_RC_ChargeCurrentLimit (0x2015)
Limit über U: Die Ladespannung wird so eingestellt, dass der Ladestrom 0 ist. Das war meine erste Umsetzung, funktioniert grundsätzlich auch aber bei wechselhaftem Wetter ist die I Variante deutlich besser.
Beides geht über den external control Modus vom Victron. Die Werte müssen dazu zyklisch gesendet werden, sonst fällt der Victron zurück in seinen normalen Modus. Nebenbei übergebe ich noch die aktuelle Batteriespannung und Temperatur.

Ich kann euch dazu gerne Erfahrungswerte liefern falls irgendwelche Fragen aufkommen :) Programmiertechnisch ist es sicher alles andere als gut umgesetzt aber es funktioniert für mich stabil :)

Ich würde den Ladestrom nicht über die Batterysettings dynamisch anpassen. Falls der esp mal aussteigt, dann verbleibt evtl ein ungünstiger Wert. Lieber über external control zyklisch senden, dann gibts bei Ausfall einen Fallback.

@philippsandhaus
Copy link
Author

Hallo @bonzai-wurst , danke für die Infos. Aus meiner Sicht macht es sehr viel den external control Modus zu nutzen, des Aspekt definierter Fallback, falls OpenDTU mal ausfällt, hatte ich noch gar nicht im Sinn. Ausserdem wird dadurch auch das Problem umgangen, dass der Flash des MPPT zu oft geschrieben würde. Dadurch könnte man es super ganz normal mit in die Controlloop vom vom DPL mit einbinden. Ich hoffe, ich finde nächstens etwas mehr Zeit, dann würde ich das mal so umsetzen.

Vielleicht schon einmal zwei Frage:

  1. Muss Batteriespannung und Temperatur auch übergeben werden, wenn wie bei mir z.B. Shunt und MPPT per Bluetooth gekoppelt sind?
  2. Die Werte müssen ja wie du sagst zyklisch gesendet werden. Hast Du Erfahrungswerte, wie groß die Abstände höchstens sein sollten?

@bonzai-wurst
Copy link

Hi Philipp,

1. Muss Batteriespannung und Temperatur auch übergeben werden, wenn wie bei mir z.B. Shunt und MPPT per Bluetooth gekoppelt sind?

Ich weiß nicht was der shunt alles übergibt aber für external control sind Batteriespannung und Temp nicht relevant. Also wenn die Werte über den shunt reinkommen, dann werden sie das auch während external control weiter tun.

2. Die Werte müssen ja wie du sagst zyklisch gesendet werden. Hast Du Erfahrungswerte, wie groß die Abstände höchstens sein sollten?

Laut Victrons hex Protocol documentation Seite 23 muss das mindestens einmal pro Minute gesendet werden.

Ich habe den Empfang von hex Werten übrigens mit einem array von struct mit hex id, timestamp und value gelöst. Das Array enthält von jeder id immer den neuesten Wert, wenn das Array voll ist, wird der älteste Wert überschrieben. Das ist sicher nicht elegant aber es funktioniert für mich :-) Ich lese eigentlich nur den voltage setpoint falls sich der mppt im state absorption oder float befindet. Alles andere hat mich bisher nicht interessiert. Den voltage setpoint brauche ich, weil ich ein "overfeed" implementiert habe. Wenn der Speicher voll ist und ich die überschüssige Energie nicht selbst brauchen kann, wird eingespeist und an die Allgemeinheit verschenkt.

@hoschiking
Copy link

Dieser Thread ist für mich sehr interessant, da ich nach einer Möglichkeit suche, den Ladestrom eines MPPT von extern dynamisch zu steuern, da ich bisher einen zum AC- Überschußladen missbrauche. Eigentlich genau das,
was @bonzai-wurst schon implementiert hat. Bisher schalte ich den MPPT einfach nur EIN/AUS. Ist es angedacht, so was mal in die Firmware zu implementieren? Falls nein, wie könnte ich, als Elektrotechniker ohne Programmierkenntnisse , sowas am einfachsten implementieren? Einen ESP flashen und ein weniger an Textfiles herumspielen bekomme auch ich hin :-)
Danke euch

@schlimmchen
Copy link
Member

Wenn ich direkt mehrere Hex-Kommandos hintereinander sende, sind die Antworten sehr unzuverlässig.

Das kann ich bestätigen. Manchmal kommen einfach gar keine Antworten, dann eine Weile wieder alle. Pausen machen hat nicht geholfen. Was aber sehr gut zu funktionieren scheint: HEX-Kommandos direkt nach einer ungefragten TEXT-Nachricht verschicken. Mein MPPT antwortet dann sehr zuverlässig, auch wenn die Kommandos direkt aneinandergereiht sind. Meine beste Vermutung dazu: Der MPPT mag keinen Input verarbeiten, während er TEXT-Nachrichten verschickt.

@schlimmchen
Copy link
Member

@philippsandhaus Basierend auf #833, was sollte als nächstes passieren? Können wir diesen PR schließen und du formulierst deine Anforderungen in einem neuen Issue, oder machst basierend auf #833 weiter am Code in einem neuem PR?

@philippsandhaus
Copy link
Author

Hallo @schlimmchen, ja, ich denke es ist am besten diesen PR zu schliessen. Die angedachten Arbeiten sind ja erledigt. Ich würde auf Basis des jetzigen und #436 dann einen neuen PR aufbauen.

Copy link

github-actions bot commented May 3, 2024

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new discussion or issue for related concerns.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants