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

Feature: "Open circuit voltage" and "Battery internal resistance" #1466

Open
wants to merge 5 commits into
base: development
Choose a base branch
from

Conversation

SW-Niko
Copy link

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

Berechnet den "Internen Batteriewiderstand" und daraus die "Batterie Leerlaufspannung"

Einschränkungen:

  • Beim starten gibt es noch keinen Wert für den internen Widerstand
  • Die interne Widerstand wird aus Änderungen des Batteriestroms automatisch berechnet.
  • Um eine ausreichende Genauigkeit zu erzielen muss der Strom sich um mindestens 4A ändern
  • Die Leerlaufspannung und der Widerstand werden aktuell nur angezeigt
  • Es werden Durchschnittswerte gebildet
  • Erst wenn mindestens 5 Werte vorhanden sind wird der Wert als gültig angesehen und angezeigt
  • Aktuell nur für den Batterie Provider "SmartShunt"

grafik

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

@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 Feb 19, 2025

Hallo @AndreasBoehm ,
du kannst auch den Startwert in UpdateSettings() auf 40mOhm setzen _resistanceFromConfig = 0.040f;
Dann must du nicht warten bis 5 Widerstandsmessungen gemacht wurden.
Die Funktion verwendet dann solange den Startwert bis 5 Widerstandsberechnungen gemacht wurden.

@AndreasBoehm
Copy link
Member

AndreasBoehm commented Feb 21, 2025

Endlich hab ich dran gedacht.

Innenwiderstand ist mittlerweile auf 24,9 mOhm gesunken.

Vor dem Test (WR aus)

18:56:27.360 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
18:56:27.379 > [BatteryGuard] Battery Guard: Enabled
18:56:27.381 > [BatteryGuard]
18:56:27.388 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
18:56:27.388 > [BatteryGuard] Open circuit voltage: 52.355V (Actual voltage: 52.210V, Avarage voltage: 52.212V)
18:56:27.391 > [BatteryGuard] Resistance in use: 24.9mOhm (Calculated: 24.9mOhm, Configured: 0.0mOhm)
18:56:27.393 > [BatteryGuard] Calculated resistance: 24.9mOhm (Min: 16.7, Max: 43.4, Last: 23.3, Amount: 94)
18:56:27.397 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1672ms
18:56:27.400 > [BatteryGuard] Open circuit voltage not available counter: 47
18:56:27.404 > [BatteryGuard] Battery voltage statistics: 52.212V (Min: 52.040, Max: 54.200, Last: 52.210, Amount: 10000)
18:56:27.406 > [BatteryGuard] --------------------------------------------------------------------------------

Während dem Test (WR an, 1000 W)

18:58:27.393 > [BatteryGuard] --------------------- Battery Guard Report (every minute) ----------------------
18:58:27.394 > [BatteryGuard] Battery Guard: Enabled
18:58:27.397 > [BatteryGuard]
18:58:27.400 > [BatteryGuard] 1) Battery open circuit voltage: Enabled / Battery data sufficient
18:58:27.403 > [BatteryGuard] Open circuit voltage: 52.247V (Actual voltage: 51.720V, Avarage voltage: 51.735V)
18:58:27.405 > [BatteryGuard] Resistance in use: 24.8mOhm (Calculated: 24.8mOhm, Configured: 0.0mOhm)
18:58:27.409 > [BatteryGuard] Calculated resistance: 24.8mOhm (Min: 16.7, Max: 43.4, Last: 23.2, Amount: 95)
18:58:27.413 > [BatteryGuard] Voltage resolution: 10mV, Current resolution: 100mA, Period: 1544ms
18:58:27.416 > [BatteryGuard] Open circuit voltage not available counter: 47
18:58:27.418 > [BatteryGuard] Battery voltage statistics: 51.735V (Min: 51.720, Max: 54.200, Last: 51.720, Amount: 10000)
18:58:27.423 > [BatteryGuard] --------------------------------------------------------------------------------

Spannung ist nach dem die Last weg war auf ~52,1 V gesprungen, anschließend ist sie weiter gestiegen bis auf 52,48V.

Screenshot 2025-02-21 at 19 00 36

@SW-Niko
Copy link
Author

SW-Niko commented Feb 23, 2025

Cool, das passt. 👍
(52.2-51.7)V / 21A = 23.8mOhm.

Du müsstest jetzt auch schon feststellen, das für den Vergleich mit den Schwellenwerten, die Leerlaufspannung verwendet wird.

Jetzt stellt sich der Frage ob und wie wir weitermachen?
Wenn du willst, dann kann ich den "Low voltage battery limiter" gleich noch dazu packen? Siehe #1111

@AndreasBoehm
Copy link
Member

AndreasBoehm commented Feb 23, 2025

Jetzt stellt sich der Frage ob und wie wir weitermachen?

Ich würde gerne die Werte in der Batterie Live-View sehen, wie ursprünglich von dir implementiert. MQTT und HA auto-discovery wären traumhaft 🙈 Und dann brauchen wir noch "Battery Guard Settings" um das Feature-Set zu aktivieren, Default-Werte setzen (falls diese dem User bekannt sind) (EDIT: quatsch, das wollten wir ja gar nicht konfigurierbar machen) und um logging zu konfigurieren.

Sonst fällt mir gerade noch ein das wir noch schauen müssen was aktuell passiert wenn man MQTT als Provider konfiguriert hat, kommt es zu sinnlosen versuchen was zu kalkulieren das wir nie kalkulieren werden? Das löst sich dann eventuell über Default-Werte, die in dem Fall dann zwingend erforderlich sind oder über das hinzufügen eines Strom Topics?

Wenn du willst, dann kann ich den "Low voltage battery limiter" gleich noch dazu packen? Siehe #1111

Ich finde es besser wenn wir jedes feature in einem einzelnen PR haben, das macht das code review und auch das testing einfacher. Zusätzlich musst du nicht alles permanent rebasen und die einzelnen Features kommen dann schneller nach development und somit auch in ein release :)

@AndreasBoehm
Copy link
Member

Das sind "Kalibrierwerte" und die würde ich gerne in eine separate JSON im LittleFS ablegen.

Ich hab einen Issue angelegt um das nicht zu vergessen, dann wird dieser PR auch nicht zu groß.
#1676

Nur wenn du einverstanden bist das wir das nicht direkt implementieren @schlimmchen ?

@schlimmchen
Copy link
Member

Ja, passt. Wenn das Feature fliegt, soll es rein. Es ist natürlich echt ein Problem, wissentlich Baustellen übrig zu lassen, aber dieses Thema (open circuit voltage, das entsorgen des load correction factors) ist total gut und wichtig, dann müssen wir das halt schrittweise angehen.

@SW-Niko
Copy link
Author

SW-Niko commented Mar 7, 2025

Ok, Das Feature sollte nun mit allen Battery-Providern laufen, die folgende Bedingungen erfüllen:

  • Messauflösung der Spannung: <= 20mV
  • Messauflösung der Strom: <= 100mA
  • Messperiode: <= 4 sec
  • Strom und Spannung können unterschiedliche Zeitstempel haben
  • Anzeige der Werte für alle Provider

grafik

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