Skip to content

Conversation

@SW-Niko
Copy link

@SW-Niko SW-Niko commented Dec 16, 2024

Berechnet die "Batterie Leerlaufspannung" und verwendet sie als Vergleichswert für den „Start-Schwellwert“ und den „Stop-Schwellwert“.

Einschränkungen für die automatische Berechnung des Internen DC-Pulse-Widerstandes:

  • Die interne Widerstand wird aus Änderungen des Batteriestroms automatisch berechnet.
  • Um eine ausreichende Genauigkeit zu erzielen muss der Strom sich um mindestens 4A ändern
  • Es werden Durchschnittswerte gebildet
  • Erst wenn mindestens 5 Werte vorhanden sind wird der Wert als gültig angesehen

Beispiel: Kompensation beim Laden der Batterie ("Start-Schwellwert“)
Die Batterie wird mit 4.7A geladen. Deshalb ist die Batteriespannung höher als die Leerlaufspannung.

grafik

Update 07.06.25
Es gibt für die Dokumentation gibt es ein Update:
Whitepater-BatteryGuard.pdf

@SW-Niko
Copy link
Author

SW-Niko commented Dec 16, 2024

Noch eine Anmerkung zum "Internal Resistance". Man kann natürlich auch den Begriff "Load compensation factor" verwenden. Beides lässt sich in den jeweils anderen Wert einfach umrechnen.
Aber "Internal Resistance" hat einem großen Vorteil, weil man den Anfangs/Default Wert einfach vom Datenblatt der Batterie übernehmen kann.

@AndreasBoehm
Copy link
Member

Was noch fehlt ist ein Anfangs/Defaultwert der über die Web-UI konfiguriert werden kann.
An dieser Stelle benötige ich Unterstützung.

Dabei kann ich dir gerne helfen.
Was machen wir denn wenn ich "Internal Resistance" meines Akkus nicht kenne? Für meine Pytes V5 konnte ich diese Info bisher nicht finden.

@schlimmchen
Copy link
Member

Was noch fehlt ist ein Anfangs/Defaultwert der über die Web-UI konfiguriert werden kann.

Warum? IMHO sollte das nicht konfigurierbar sein. Insbesondere weil dieser Wert ja dann "automatisch" obsolet wird. Und selbst Andreas weiß nicht, was er da eintragen soll... Was macht dann der Standard-Benutzer?

Meinst du vielleicht, dass diese Werte persistiert werden sollten, sodass der Algorithmus nicht bei jedem Neustart der OpenDTU-OnBattery von vorne beginnen muss? Das fänd ich nachvollziehbar. Wenn man das gleich richtig macht, ist das aber ein handfestes Feature. Denn in der Konfig verstecken möchte ich solche Sachen nur ungerne, die gehören da eigentlich nicht rein. Das sind "Kalibrierwerte" und die würde ich gerne in eine separate JSON im LittleFS ablegen. Macht das Sinn? Ich hab für den Battery Watchdog beispielsweise auch schon Werte im Kopf, die persistiert werden sollten (Zeitpunkt der letzten vollständigen Aufladung der Batterie). Und auch der charge cycle des DPL sollte da persistiert werden, das wäre sehr sinnvoll.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 10, 2025

Was noch fehlt ist ein Anfangs/Defaultwert der über die Web-UI konfiguriert werden kann.
An dieser Stelle benötige ich Unterstützung.

Gut...das muss ich noch etwas genauer erklären. Ich benötige keinen Anfangswert aber er wäre nützlich.
Der "interne Batteriewiderstand" wird automatisch aus dem laufenden Betrieb berechnet und folgt auch automatisch wenn er sich ändert.
Damit ich ihn aber berechnen kann muss ausreichend Laständerung vorhanden sein. Das kann Minuten oder auch Stunden dauern.

"Kalibrierwerte" und die würde ich gerne in eine separate JSON im LittleFS ablegen. Macht das Sinn?

Klar, das geht im Prinzip genau so um das Start Problem zu umgehen.

Aber es gibt noch einen spezial Fall:
Immer dann wenn ein festes oder niedriges Power Limit eingestellt wurde dann kann ich keinen "internen Batteriewiderstand"
berechnen. (Die Grenze liegt so bei ca. 150W)
Die Alternative wäre beim Start-Up oder auf Knopfdruck eine Kalibrierung zu machen. Das war mir zu viel Aufwand.

Und aus all diesen Überlegungen bin ich dann auf die Idee gekommen:
Biete eine Konfiguration an und zeige den aktuellen Wert.

  1. Wer den Widerstandswert im Datenblatt seiner Batterie hat, der kann ihn sofort eintragen.
  2. Wer den Widerstandswert nicht hat, bei dem dauert es etwas bis der Wert berechnet worden ist.
  3. Wer den Widerstandswert nicht hat der kann auch nach einiger Zeit nachschauen wo er liegt und ihn dann als Startwert eintragen.

Bei meiner Batterie steht im Datenblatt Ri < 12mOhm und diesen Wert nehme ich auch als Startwert.
PS: Das ist normalerweise der Widerstand der mit einem Mischstrom bei 1kHz gemessen wird.
Und der passt gut zu den Werten die ich mit DC Lastwechseln ermittle.

Aber die Lösung mit einer Kalibrier-JSON finde ich auch gut.

@schlimmchen

Das sind "Kalibrierwerte" und die würde ich gerne in eine separate JSON im LittleFS ablegen. Macht das Sinn? Ich hab für den Battery Watchdog beispielsweise auch schon Werte im Kopf, die persistiert werden sollten (Zeitpunkt der letzten vollständigen Aufladung der Batterie). Und auch der charge cycle des DPL sollte da persistiert werden, das wäre sehr sinnvoll.

Das wäre ein super Feature. Könnte ich auch an der einen oder anderen Stelle brauchen. Ich habe ja schon eine einfache Routine die dafür sorgt das alle 14 Tage die Batterie auf 100% SoC aufgeladen wird. Aber diese Info geht leider bei jedem Neustart verloren.

Wichtig wäre das das ganze mal auf einen anderen System getestet wird. Momentan geht es ja nur in Verbindung mit einem Smart Shunt. Ich kann aber auch gerne die fehlenden Codezeilen für andere Batterieprovider einfügen.

@AndreasBoehm
Copy link
Member

Wichtig wäre das das ganze mal auf einen anderen System getestet wird. Momentan geht es ja nur in Verbindung mit einem Smart Shunt. Ich kann aber auch gerne die fehlenden Codezeilen für andere Batterieprovider einfügen.

Ich würde das Feature gerne testen, nutze allerdings eine Pytes Batterie.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 10, 2025

Ok, ich schau mir die Pytes von den technischen Daten mal an und mache die notwendigen Änderungen.
Mit welcher Auflösung bekommst du die Daten von der Pytes? 1mV? 100mA?

@AndreasBoehm
Copy link
Member

Auflösung: 10 mV und 100 mA

Genial wäre es wenn wir das so integriert bekommen das es direkt für alle Provider funktioniert.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 10, 2025

Genial wäre es wenn wir das so integriert bekommen das es direkt für alle Provider funktioniert.

Es gibt nur 2 Limitierungen:

  • Die Auflösung. Je schlechter desto höher muss die Laständerung sein.
  • Die Zeitabstände zwischen den Messungen

Beides lässt sich automatisch ermitteln. Und wenn die Werte zu schlecht sind dann gibt es keine automatische Berechnung des "internen Batteriewiderstands" und man muss mit dem Startwert leben.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 15, 2025

Hallo @AndreasBoehm,
Der Battery Guard arbeitet nun mit allen Battery Providern.
Genauer gesagt: Er untersucht die Daten und entscheidet, ob er daraus den Ri und die Leerlaufspannung berechnen kann.
Falls er das kann, dann nimmt der DPL die Leerlaufspannung als Vergleichswert für die Schwellenwerte.

Einfach eine Zeit lang laufen lassen und dann im Log nachschauen wie es funktioniert.
Ich bin echt gespannt wie es auf einen System mit Pytes funktioniert. 🤔

16:39:37.963 > [BatteryGuard]
16:39:38.010 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
16:39:38.061 > [BatteryGuard] Battery Guard: Enabled
16:39:38.182 > [BatteryGuard]
16:39:38.236 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
16:39:38.388 > [BatteryGuard] Open circuit voltage: 25.917V (Actual voltage: 25.907V, Average voltage: 25.907V)
16:39:38.440 > [BatteryGuard] Resistance in use: 13.2mOhm (Calculated: 13.2mOhm, Configured: 12.0mOhm)
16:39:38.487 > [BatteryGuard] Calculated resistance: 13.2mOhm (Min: 11.5, Max: 15.1, Last: 13.2, Amount: 12)
16:39:38.537 > [BatteryGuard] Voltage resolution: 1mV, Current resolution: 1mA, Period: 993ms
16:39:38.580 > [BatteryGuard] Open circuit voltage not available counter: 4
16:39:38.631 > [BatteryGuard] Battery voltage statistics: 25.907V (Min: 25.896, Max: 26.753, Last: 25.907, Amount: 10000)
16:39:38.676 > [BatteryGuard]
16:39:39.267 > [BatteryGuard] --------------------------------------------------------------------------------

@SW-Niko SW-Niko marked this pull request as ready for review February 15, 2025 15:48
@AndreasBoehm
Copy link
Member

Ich war so frei und hab den PR rebased.
Werde mir jetzt ein build von deinem PR installieren, ich bin gespannt :)

@AndreasBoehm
Copy link
Member

Natürlich war mein Akku beim installieren deiner Version schon leer und der WR aus.

Was mich irritiert ist diese Zeile, denn es wurde ja eigentlich noch gar nichts berechnet? Das sagt uns zumindest auch die Zeile darüber.

Calculated resistance: 33.3mOhm (Min: 33.3, Max: 33.3, Last: 33.3, Amount: 1)
22:15:02.876 > [BatteryGuard]
22:15:02.880 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
22:15:02.880 > [BatteryGuard] Battery Guard: Enabled
22:15:02.882 > [BatteryGuard]
22:15:02.885 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
22:15:02.888 > [BatteryGuard] Open circuit voltage: 0.000V (Actual voltage: 51.460V, Avarage voltage: 51.460V)
22:15:02.891 > [BatteryGuard] Resistance neither calculated (5 times) nor configured
22:15:02.895 > [BatteryGuard] Calculated resistance: 33.3mOhm (Min: 33.3, Max: 33.3, Last: 33.3, Amount: 1)
22:15:02.896 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1ms
22:15:02.899 > [BatteryGuard] Open circuit voltage not available counter: 38
22:15:02.902 > [BatteryGuard] Battery voltage statistics: 51.460V (Min: 50.870, Max: 51.570, Last: 51.460, Amount: 10000)
22:15:02.905 > [BatteryGuard] --------------------------------------------------------------------------------
22:15:02.908 > [BatteryGuard]

@AndreasBoehm
Copy link
Member

Ich sehe gerade das du die Werte nicht mehr für die LiveView ausspielst. Das sollte eigentlich ganz einfach für alle Battery Provider machbar sein.

in BatteryStats.cpp in der methode void BatteryStats::getLiveViewData(JsonVariant& root) const kannst du die Werte des BatteryGuard abfragen und mit addLiveViewValue(root,.....) hinzufügen. Ich würde mir nur wünschen das in den property titeln dann auch 'calculated' oder 'configured' oder so ähnlich steht, je nach dem ob wir den wert berechnet haben oder nur aus der config genommen haben.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 16, 2025

Was mich irritiert ist diese Zeile, denn es wurde ja eigentlich noch gar nichts berechnet? Das sagt uns zumindest auch die Zeile darüber.

Calculated resistance: 33.3mOhm (Min: 33.3, Max: 33.3, Last: 33.3, Amount: 1)

Das irritiert mich auch. Allerdings wird der Widerstand aus jeder ausreichenden Stromänderung berechnet. Egal in welche Richtung. Gibt es bei deinem System außer dem Inverter und dem Solar Charger noch weitere Geräte die den Strom um mindestens 3.5A ändern?

Und ich sehe noch einen weiteren Punkt der mir nicht gefällt.

Voltage resolution: 10mV, Current resolution: 100mA, Period: 1ms

Die Resolution passt zu deinen Angaben. 👍
Aber die Messperiode ist super schnell.

Ursache 1:
Entweder sie ist wirklich so schnell. Was nicht gut wäre weil ich im falschen Zeitbereich messe und damit einen anderen Ri berechne.

Ursache 2:
Oder wir haben ein ähnliches Problem wie mit dem Smart Shunt. Der gaukelt uns 500ms vor aber in Wirklichkeit sind es 1000ms. Siehe auch #1500

Für Ursache 1 muss ich auf jeden Fall noch was in die Berechnung einbauen.

PS: Ich hätte bei deiner Batterie grob über den Daumen so mit 20mOhm gerechnet.

Nachtrag: Ich denke ich habe das Problem gefunden. Sollte einfach zu fixen sein.

@AndreasBoehm
Copy link
Member

Sorry, mir ist gerade eingefallen das der WR nach dem installieren deiner Version kurz losgelegt hat, das erklärt warum wir einen Messwert haben. Lass uns das also erstmal ignorieren.

Zur Timing problematik:

Aktuell gehst du auf _lastUpdate der BatteryStats, wir haben aber auch

uint32_t _lastUpdateVoltage = 0;

und
uint32_t _lastUpdateCurrent = 0;

Bei CAN Batterien wird _lastUpdate durch jede empfangene CAN Nachricht neu gesetzt, ob wir etwas damit anfangen können oder nicht ist dabei egal.

@AndreasBoehm
Copy link
Member

Hier noch ein Log mit dem du ein gefühl dafür bekommst wie oft wir neue Werte der Pytes Batterie bekommen (falls das interessant ist für dich)

Log
Middle missing
10:34:25.287 > Request retransmit: 4
10:34:25.389 > Success
10:34:25.776 > Fetch inverter: 1164A00A6340
10:34:25.780 > Queue size - NRF: 0 CMT: 1
10:34:25.782 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:25.786 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:25.826 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:25.833 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:25.837 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:25.846 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:25.850 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:25.854 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:25.857 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:25.862 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:25.865 > [Pytes] soh: 100 cycles: 54
10:34:25.868 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:25.872 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:26.324 > Success
10:34:26.807 > Fetch inverter: 1164A00A6340
10:34:26.812 > Queue size - NRF: 0 CMT: 1
10:34:26.815 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:26.818 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:26.851 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:26.853 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:26.857 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:26.861 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:26.864 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:26.870 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:26.873 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:26.875 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:26.878 > [Pytes] soh: 100 cycles: 54
10:34:26.882 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 2E 01 00
10:34:26.886 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:27.352 > Success
10:34:27.911 > Fetch inverter: 1164A00A6340
10:34:27.914 > Queue size - NRF: 0 CMT: 1
10:34:27.915 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:27.915 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:27.916 > [Pytes] Received CAN message: 0x0401 - AE 0C A5 0C 04 00 0F 00
10:34:27.916 > [Pytes] lowestCellMilliVolt: 3237 highestCellMilliVolt: 3246 cellMinVoltageName: 1500 cellMaxVoltageName: 0400
10:34:27.918 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:27.920 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:27.924 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:27.927 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:27.930 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:27.935 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:27.948 > [Pytes] soh: 100 cycles: 54
10:34:28.413 > Success
10:34:28.752 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:28.757 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:28.761 > [Pytes] Received CAN message: 0x0401 - AE 0C A5 0C 04 00 0F 00
10:34:28.761 > [Pytes] lowestCellMilliVolt: 3237 highestCellMilliVolt: 3246 cellMinVoltageName: 1500 cellMaxVoltageName: 0400
10:34:28.764 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:28.767 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:28.771 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:28.776 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:28.778 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:28.781 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:28.794 > [Pytes] soh: 100 cycles: 54
10:34:28.813 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:28.817 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:28.820 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:28.824 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:28.827 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:28.831 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:28.836 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:28.838 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:28.843 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:28.846 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:28.851 > [Pytes] Manufacturer: PYTES
10:34:28.860 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 30 01 00
10:34:28.870 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:28.873 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:28.879 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:28.887 > [Pytes] balance: 0
10:34:28.901 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:28.917 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:28.977 > Fetch inverter: 1164A00A6340
10:34:28.986 > Queue size - NRF: 0 CMT: 1
10:34:29.528 > Success
10:34:29.750 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:29.756 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:29.758 > [Pytes] Received CAN message: 0x0401 - AE 0C A5 0C 04 00 0E 00
10:34:29.759 > [Pytes] lowestCellMilliVolt: 3237 highestCellMilliVolt: 3246 cellMinVoltageName: 1400 cellMaxVoltageName: 0400
10:34:29.762 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:29.767 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:29.769 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:29.771 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:29.778 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:29.778 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:29.781 > [Pytes] soh: 100 cycles: 54
10:34:29.789 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:29.789 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:29.795 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:29.796 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:29.798 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:29.821 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:29.824 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:29.828 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:29.831 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:29.835 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:29.838 > [Pytes] Manufacturer: PYTES
10:34:29.842 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 31 01 00
10:34:29.845 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:29.849 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:29.853 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:29.856 > [Pytes] balance: 0
10:34:29.859 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:29.864 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:30.112 > Fetch inverter: 1164A00A6340
10:34:30.126 > Queue size - NRF: 0 CMT: 1
10:34:30.659 > Success
10:34:30.816 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:30.822 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:30.824 > [Pytes] Received CAN message: 0x0401 - AE 0C A5 0C 04 00 0E 00
10:34:30.825 > [Pytes] lowestCellMilliVolt: 3237 highestCellMilliVolt: 3246 cellMinVoltageName: 1400 cellMaxVoltageName: 0400
10:34:30.828 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:30.831 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:30.842 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:30.845 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:30.849 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:30.852 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:30.855 > [Pytes] soh: 100 cycles: 54
10:34:30.859 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:30.862 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:30.865 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:31.183 > Fetch inverter: 1164A00A6340
10:34:31.194 > Queue size - NRF: 0 CMT: 1
10:34:31.736 > Success
10:34:31.907 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:31.919 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:31.922 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:31.927 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:31.931 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:31.934 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:31.948 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:31.948 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:31.949 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:31.951 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:31.953 > [Pytes] soh: 100 cycles: 54
10:34:32.247 > Fetch inverter: 1164A00A6340
10:34:32.254 > Queue size - NRF: 0 CMT: 1
10:34:32.752 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:32.759 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:32.761 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:32.762 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:32.766 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:32.769 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:32.772 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:32.777 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:32.801 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:32.820 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:32.823 > [Pytes] soh: 100 cycles: 54
10:34:32.829 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:32.836 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:32.841 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:32.847 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:32.852 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:32.856 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:32.862 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:32.865 > Success
10:34:32.872 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:32.877 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:32.977 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:32.980 > [Pytes] Manufacturer: PYTES
10:34:33.007 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 34 01 00
10:34:33.017 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:33.021 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:33.024 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:33.027 > [Pytes] balance: 0
10:34:33.030 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:33.035 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:33.362 > Fetch inverter: 1164A00A6340
10:34:33.369 > Queue size - NRF: 0 CMT: 1
10:34:33.752 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:33.759 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:33.762 > [DPL] the system is stable, the last power limit is still valid
10:34:33.763 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:33.767 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:33.768 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:33.771 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:33.775 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:33.778 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:33.781 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:33.785 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:33.788 > [Pytes] soh: 100 cycles: 54
10:34:33.793 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:33.796 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:33.799 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:33.821 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:33.826 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:33.829 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:33.833 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:33.836 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:33.839 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:33.843 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:33.847 > [Pytes] Manufacturer: PYTES
10:34:33.851 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 35 01 00
10:34:33.855 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:33.862 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:33.876 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:33.877 > [Pytes] balance: 0
10:34:33.882 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:33.887 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:33.893 > Success
10:34:34.357 > Fetch inverter: 1164A00A6340
10:34:34.363 > Queue size - NRF: 0 CMT: 1
10:34:34.750 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:34.754 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:34.758 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:34.762 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:34.765 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:34.767 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:34.772 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:34.774 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:34.777 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:34.781 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:34.785 > [Pytes] soh: 100 cycles: 54
10:34:34.788 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:34.792 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:34.797 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:34.799 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:34.804 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:34.805 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:34.819 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:34.822 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:34.825 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:34.837 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:34.842 > [Pytes] Manufacturer: PYTES
10:34:34.844 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 36 01 00
10:34:34.852 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:34.853 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:34.855 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:34.858 > [Pytes] balance: 0
10:34:34.861 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:34.864 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:34.906 > Success
10:34:35.454 > Fetch inverter: 1164A00A6340
10:34:35.462 > Queue size - NRF: 0 CMT: 1
10:34:35.782 > [Pytes] Received CAN message: 0x0400 - 38 02 2C 01 EE 02 C7 01
10:34:35.790 > [Pytes] chargeVoltageLimit: 56.799999 chargeCurrentLimit: 30.000000 dischargeCurrentLimit: 75.000000 dischargeVoltageLimit: 45.500000
10:34:35.790 > [Pytes] Received CAN message: 0x0401 - AE 0C A6 0C 04 00 08 00
10:34:35.790 > [Pytes] lowestCellMilliVolt: 3238 highestCellMilliVolt: 3246 cellMinVoltageName: 0800 cellMaxVoltageName: 0400
10:34:35.791 > [Pytes] Received CAN message: 0x0402 - 5A 00 5A 00 00 00 00 00
10:34:35.791 > [Pytes] minimumCellTemperature: 9.000000 maximumCellTemperature: 9.000000 cellMinTemperatureName: 0000 cellMaxTemperatureName: 0000
10:34:35.791 > [Pytes] Received CAN message: 0x0403 - 04 44 80 02 04 04 80 00
10:34:35.792 > [Pytes] Alarms: 0 0 0 0 0 0 0 0
10:34:35.792 > [Pytes] Warnings: 0 0 0 0 0 0 0 0
10:34:35.793 > [Pytes] Received CAN message: 0x0404 - 15 00 64 00 01 00 36 00
10:34:35.795 > [Pytes] soh: 100 cycles: 54
10:34:35.799 > [Pytes] Received CAN message: 0x0405 - 42 14 00 00 5A 00 10 00
10:34:35.806 > [Pytes] voltage: 51.860001 current: 0.000000 temperature: 9.000000
10:34:35.820 > [Pytes] Received CAN message: 0x0406 - 00 00 00 00 00 00 00 00
10:34:35.823 > [Pytes] internalFailure: 0 (bits: 00000000)
10:34:35.827 > [Pytes] Received CAN message: 0x0407 - 3B 1B 7F 21 3B 1B 00 00
10:34:35.829 > [Pytes] Received CAN message: 0x0408 - 01 01 00 00 00 00 00
10:34:35.833 > [Pytes] chargeEnabled: 1 dischargeEnabled: 1 chargeImmediately: 0 moduleCountBlockingDischarge: 0 moduleCountBlockingCharge: 0
10:34:35.837 > [Pytes] Received CAN message: 0x0409 - A0 86 01 00 CC 52 00 00
10:34:35.841 > [Pytes] soc: 21.20 totalCapacity: 100.00 Ah availableCapacity: 21.20 Ah 
10:34:35.844 > [Pytes] Received CAN message: 0x040A - 50 59 54 45 53
10:34:35.849 > [Pytes] Manufacturer: PYTES
10:34:35.851 > [Pytes] Received CAN message: 0x040B - 19 02 10 11 21 37 01 00
10:34:35.865 > [Pytes] moduleCountOnline: 1 moduleCountOffline: 0
10:34:35.866 > [Pytes] Received CAN message: 0x040C - 01 00 00 00 01 00 00 00
10:34:35.870 > [Pytes] Received CAN message: 0x040D - 00 00 00 00 00 00 00 00
10:34:35.873 > [Pytes] balance: 0
10:34:35.877 > [Pytes] Received CAN message: 0x041E - 44 0B 00 00 EB 0A 00 00
10:34:35.882 > [Pytes] chargedEnergy: 288.399994 dischargedEnergy: 279.500000
10:34:35.997 > Success

@SW-Niko
Copy link
Author

SW-Niko commented Feb 16, 2025

Sorry, mir ist gerade eingefallen das der WR nach dem installieren deiner Version kurz losgelegt hat, das erklärt warum wir einen Messwert haben. Lass uns das also erstmal ignorieren.

Ja, ist bei mir genauso. Das passt. 👍

Aktuell gehst du auf _lastUpdate der BatteryStats, wir haben aber auch

Das habe ich gefixt.
Und wenn die Daten doch schneller als 1 Sekunde kommen dann wird das bei der Widerstandsberechnung nun auch berücksichtigt.

Der Report ist gar nicht so schlecht. 2 Probleme identifiziert und gefixt. Ich kann den Fix leider nicht testen.

Bitte Fix installieren und nochmal den Report posten. Danke Andreas.

@AndreasBoehm
Copy link
Member

AndreasBoehm commented Feb 16, 2025

Hier der erste Report nach der Installation der neuen Version. Ich schau später nochmal drauf.

10:53:56.085 > [BatteryGuard]
10:53:56.087 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
10:53:56.090 > [BatteryGuard] Battery Guard: Enabled
10:53:56.094 > [BatteryGuard]
10:53:56.096 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data not sufficient
10:53:56.099 > [BatteryGuard] Open circuit voltage: 0.000V (Actual voltage: 51.920V, Avarage voltage: 51.922V)
10:53:56.103 > [BatteryGuard] Resistance neither calculated (5 times) nor configured
10:53:56.106 > [BatteryGuard] Calculated resistance: 0.0mOhm (Min: 0.0, Max: 0.0, Last: 0.0, Amount: 0)
10:53:56.109 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 400mA, Period: 1569ms
10:53:56.113 > [BatteryGuard] Open circuit voltage not available counter: 56
10:53:56.116 > [BatteryGuard] Battery voltage statistics: 51.922V (Min: 51.920, Max: 51.930, Last: 51.920, Amount: 48)
10:53:56.119 > [BatteryGuard] --------------------------------------------------------------------------------
10:53:56.123 > [BatteryGuard]

Hier nochmal nach einer Stunde, leider liegt Schnee auf den Modulen.

12:21:56.156 > [BatteryGuard]
12:21:56.159 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
12:21:56.162 > [BatteryGuard] Battery Guard: Enabled
12:21:56.165 > [BatteryGuard]
12:21:56.169 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
12:21:56.171 > [BatteryGuard] Open circuit voltage: 0.000V (Actual voltage: 52.140V, Avarage voltage: 52.140V)
12:21:56.174 > [BatteryGuard] Resistance neither calculated (5 times) nor configured
12:21:56.180 > [BatteryGuard] Calculated resistance: 0.0mOhm (Min: 0.0, Max: 0.0, Last: 0.0, Amount: 0)
12:21:56.184 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1533ms
12:21:56.185 > [BatteryGuard] Open circuit voltage not available counter: 4847
12:21:56.191 > [BatteryGuard] Battery voltage statistics: 52.140V (Min: 51.920, Max: 52.170, Last: 52.140, Amount: 3939)
12:21:56.195 > [BatteryGuard] --------------------------------------------------------------------------------
12:21:56.195 > [BatteryGuard]

@SW-Niko
Copy link
Author

SW-Niko commented Feb 16, 2025

12:21:56.184 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1533ms

Das schaut schon mal sehr gut aus. 👍

Jetzt brauchen wir nur noch genügend Lastwechsel und dann sollte es klappen.

Allerdings muss ich noch einen Schutz einbauen. Ich muss noch sicherstellen das der Spannungs- und der Stromwerte zeitlich zusammengehören. Beim Smart Shunt und bei Pytes ist das automatisch gegeben. Beide Werte haben den gleichen Zeitstempel und es ist nicht möglich das eine Berechnung mit den beiden Werten erfolgt wenn erst einer der beiden Werte angekommen ist.
Ist das bei allen bestehenden und zukünftigen Batterie Providern ebenso gegeben?

Das trifft uns bei anderen Berechnungen genauso P = U(t1) * I(t1) und nicht P = U(t2) * I(t1).
Diese Synchronisierung machen die Battery Provider nicht bewusst, oder?
Ich vermute nein, und deshalb werden wir eine Überprüfung an vielen Stellen benötigen wo die Werte verarbeitet werden.
Ich lass mir was einfallen. 🤔

@AndreasBoehm
Copy link
Member

Ist das bei allen bestehenden und zukünftigen Batterie Providern ebenso gegeben?

Grundsätzlich sieht es so aus, ich würde aber nicht meine Hand dafür ins Feuer legen.

Im Falle des JkBms werden die Timestamps der einzelnen Datenpunkte genutzt, also theoretisch können die Timestamps abweichen, wie es in der Praxis aussieht kann ich dir aber nicht sagen.. Hab das auch bei anderen Providern so gesehen.

auto oVoltage = dp.get<Label::BatteryVoltageMilliVolt>();
if (oVoltage.has_value()) {
auto oVoltageDataPoint = dp.getDataPointFor<Label::BatteryVoltageMilliVolt>();
BatteryStats::setVoltage(static_cast<float>(*oVoltage) / 1000,
oVoltageDataPoint->getTimestamp());
}
auto oCurrent = dp.get<Label::BatteryCurrentMilliAmps>();
if (oCurrent.has_value()) {
auto oCurrentDataPoint = dp.getDataPointFor<Label::BatteryCurrentMilliAmps>();
BatteryStats::setCurrent(static_cast<float>(*oCurrent) / 1000, 2/*precision*/,
oCurrentDataPoint->getTimestamp());
}

Wir müssen uns noch was für den MQTT Provider überlegen, der unterstützt Stromwerte nicht, also brauchen wir hier eine ausnahme, das wir nicht versuchen was zu berechnen wenns nie klappen wird.

@schlimmchen
Copy link
Member

Beim JK und JBD BMS werden DataPoints verarbeitet. Diesen Ansatz würde ich langfristig gerne auch bei anderen Softwarekomponenten sehen. Dort hat jeder Skalar einen eigenen Zeitstempel, der auch mal ein paar wenige Millisekunden von anderen abweichen kann, weil es eben auch Millisekunden dauern kann, einen Satz Daten von der Peripherie zu verarbeiten. Darüber hinaus ist es nicht vorgesehen garantieren zu müssen, dass alle Datenpunkte, wenn man den Container anschaut, immer aus dem gleichen Datensatz der Peripherie kommen.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 16, 2025

Dort hat jeder Skalar einen eigenen Zeitstempel, der auch mal ein paar wenige Millisekunden von anderen abweichen kann.

Die Millisekunden stören nicht. Was stört ... ist das an vielen Stellen wo die Daten verarbeitet werden erst mal überprüft werden muss ob der neue Spannungswert zu dem bereits vorhandenen Stromwert zeitlich passt oder ob der passende Stromwert erst in einigen Millisekunden eintreffen wird.

Aber das ist mit etwas Zusatzaufwand lösbar. Ich bin dran ...

@AndreasBoehm
Copy link
Member

Leider liegt immer noch Schnee auf meinen Modulen, der Widerstand konnte aber mittlerweile berechnet werden.

Der Amount bei Battery voltage statistics bleibt bei 10000 stehen.

17.02.

11:57:53.732 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
11:57:53.735 > [BatteryGuard] Battery Guard: Enabled
11:57:53.753 > [BatteryGuard]
11:57:53.756 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
11:57:53.758 > [BatteryGuard] Open circuit voltage: 0.000V (Actual voltage: 51.830V, Avarage voltage: 51.833V)
11:57:53.762 > [BatteryGuard] Resistance neither calculated (5 times) nor configured
11:57:53.765 > [BatteryGuard] Calculated resistance: 37.1mOhm (Min: 25.4, Max: 44.4, Last: 35.7, Amount: 4)
11:57:53.768 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1542ms
11:57:53.772 > [BatteryGuard] Open circuit voltage not available counter: 82163
11:57:53.787 > [BatteryGuard] Battery voltage statistics: 51.833V (Min: 50.440, Max: 52.280, Last: 51.830, Amount: 10000)
11:57:53.787 > [BatteryGuard] --------------------------------------------------------------------------------

18.02.

08:58:53.522 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
08:58:53.524 > [BatteryGuard] Battery Guard: Enabled
08:58:53.527 > [BatteryGuard]
08:58:53.530 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
08:58:53.535 > [BatteryGuard] Open circuit voltage: 51.448V (Actual voltage: 51.450V, Avarage voltage: 51.448V)
08:58:53.538 > [BatteryGuard] Resistance in use: 42.5mOhm (Calculated: 42.5mOhm, Configured: 0.0mOhm)
08:58:53.544 > [BatteryGuard] Calculated resistance: 42.5mOhm (Min: 25.4, Max: 60.0, Last: 54.1, Amount: 7)
08:58:53.546 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1632ms
08:58:53.548 > [BatteryGuard] Open circuit voltage not available counter: 90246
08:58:53.553 > [BatteryGuard] Battery voltage statistics: 51.448V (Min: 50.440, Max: 52.280, Last: 51.450, Amount: 10000)
08:58:53.555 > [BatteryGuard] --------------------------------------------------------------------------------

Hier noch der Verlauf des Stroms
Screenshot 2025-02-18 at 09 21 18

@SW-Niko
Copy link
Author

SW-Niko commented Feb 18, 2025

Der Amount bei Battery voltage statistics bleibt bei 10000 stehen.

Kein Grund zur Sorge. Es wird weiter gemittelt. Ich lass den Zähler nur nicht über 10000. Vielleicht sollte ich "Amount: > 10000" ausgeben?

08:58:53.544 > [BatteryGuard] Calculated resistance: 42.5mOhm (Min: 25.4, Max: 60.0, Last: 54.1, Amount: 7)

Der Unterschied zwischen Min und Max ist etwas zu groß für meinen Geschmack, Da kann ich aber noch was machen.
Die Pytes hat eine 10fach schlechtere Spannungs- und eine 100fach schlechtere Strom-Auflösung als der Smart Shunt.

08:58:53.535 > [BatteryGuard] Open circuit voltage: 51.448V (Actual voltage: 51.450V, Avarage voltage: 51.448V)

Der jetzt wirklich wichtige Punkt ist herauszufinden, ob der Wert von 40mOhm für deine Batterie ausreichend genau ist.
Hmm... Versuch doch mal folgendes:
Lass deinen Inverter mit 50% Limit so ca. für 1 Minute laufen und notiere dir die "Open Circuit Voltage".
Dann schalte den Inverter wieder ab und schau ob die Batteriespannung spätestens nach 1 Minute über dem notierten Wert liegt.
Am besten Abends, ansonsten kann der Solar Charger das Ergebnis verfälschen.

@SW-Niko
Copy link
Author

SW-Niko commented Feb 18, 2025

Hallo @schlimmchen ,
das war ein guter Hinweis. Danke.

Darüber hinaus ist es nicht vorgesehen garantieren zu müssen, dass alle Datenpunkte, wenn man den Container anschaut, immer aus dem gleichen Datensatz der Peripherie kommen.

Ich habe eine Lösung gefunden, die mit allen Varianten, wie die Daten daherkommen können, zurechtkommt.
Ich bin noch am Testen, aber sehr zuversichtlich, das für das Berechnen des Innenwiderstandes und der Leerlaufspannung keine Nachteile entstehen.

@AndreasBoehm
Copy link
Member

Lass deinen Inverter mit 50% Limit so ca. für 1 Minute laufen und notiere dir die "Open Circuit Voltage".
Dann schalte den Inverter wieder ab und schau ob die Batteriespannung spätestens nach 1 Minute über dem notierten Wert liegt.
Am besten Abends, ansonsten kann der Solar Charger das Ergebnis verfälschen.

Hab zwischenzeitlich andere builds auf meiner DTU ausprobiert.
Ich hoffe das ich morgen genug Messpunkte zusammen bekomme um die Open Circuit Voltage wieder berechnet zu bekommen, dann werde ich diesen testen mal machen.

@SW-Niko
Copy link
Author

SW-Niko commented Jul 23, 2025

Verstehe ... Auch das kann man Lösen wenn man zusätzlich noch Spannungsgrenzwerte einbaut. Ich bin mir nur nicht sicher wie viel Aufwand wir noch investieren sollen.
Der PR behebt einige Probleme rund um die Schwellenwerte und die automatische Berechnung des Innenwiderstandes gibt es noch als Sahnehäubchen obendrauf. (Für alle die einen Batterie Provider haben der SoC Werte liefert.)
Wenn der aktuelle Funktionsumfang gut funktioniert dann kann man über weitere Funktionen reden.
Ich habe ja noch den "Low Voltage Limiter" und die "Make Battery Full" Funktionen, die beide auf den Battery-Guard aufsetzen.

Einfach melden wenn ich noch was ändern soll. 👍

SW-Niko and others added 26 commits October 8, 2025 21:25
@github-actions
Copy link

github-actions bot commented Oct 8, 2025

Build Artifacts

Firmware built from this pull request's code:

Notice

  • These artifacts are ZIP files containing the factory update binary as well as the OTA update binary.
    Extract the binaries from the ZIP files first. Do not use the ZIP files themselves to perform an update.
  • These links point to artifacts of the latest successful build run.
  • The linked artifacts were built from d57ae0d.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants