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

DPL Voltage Features #679

Merged
merged 6 commits into from
Feb 19, 2024

Conversation

schlimmchen
Copy link
Collaborator

Features added

DPL: use best available voltage value

the DPL is interested in the battery's voltage to make decisions about draining the battery or letting it charge (if the user opts to use voltage thresholds rather than SoC thresholds). using the DC input voltage reported by the inverter under control has disadvantages:

  • the data might be quite old due to the communication protocol implementation. more inverters being polled means even more lag. the connection being wireless makes this even worse, due to the need to retry the occasional lost packet, etc.
  • the data is not very accurate, since the DC input of the inverter is actually some cabling and a couple of junctions away from the actual battery. this voltage drop can mostly only be estimated and is worse with higher load. the load correction factor is there to mitigate this, but it has its own problems and is cumbersome to calibrate.

instead, this change aims to use more accurate battery voltage readings, if possible. the DPL now prefers the voltage as reported by the BMS, since it is for sure the closest to the battery of all measuring points and measures its voltage accurately regardless of the load (the voltage reading will still drop with higher loads, but this will be only due to the battery's internal resistance, not that of cabling or junctions). if no BMS voltage reading is available, the DPL will instead use the charge controller's voltage reading, as it is available with much higher frequency and is assumed to be more accurate as it offers a resolution of 10mV. only if none of these two sources can be used, the inverter DC input voltage is assumed as the battery voltage.

closes #655.

know and use SoC precision

the ictron SmartShunt communicates the SoC value in permille. this should be displayed in the web UI accordingly. this is a good excuse to fully move ownership of the SoC value to the BatteryStats base class and add a precision indicator variable. this is required to be set each time a derived class (a battery provider) wants to update the SoC value. the precision is then used when populating the JSON data for the web UI (live view).

related to #573.

implement subscription to battery voltage MQTT topic

this extends the MqttBattery implementation by an additional topic which allows to subscribe to receive battery voltage readings through the MQTT broker. similar to the battery SoC topic, this allows to import a critical battery data point for the DPL, in case the user chooses to use voltage thresholds rather than SoC thresholds to control the DPL. if an otherwise incompatible BMS is available which publishes the battery pack voltage through MQTT, this can now be used to feed accurate voltage readings to the DPL.

DPL: add switch allowing to ignore SoC

unfortunately, the battery SoC values reported by battery BMSs are unreliable, at least for some users, or at least without regular (manual) full charge cycles to calibrate the BMS. it offers great advantages to connect OpenDTU-OnBattery to a BMS (MQTT publishing of values, Home Assistent integration, etc.), but previously the users were then forced to configure the DPL by SoC values.

this change allows to configure the DPL such that SoC values are ignored. instead, the voltage limits are used to make DPL decisions, as if no SoC was available in the first place.

the SoC related setting are hidden from the DPL settings view if SoC values are configured to be ignored.

closes #654. supersedes #668. this is actually the same changeset as in #668, but since the other changes need this, it was included here and hence supersedes the previous PR.

Supporting Changes

replace BatteryStats::isValid() method

in the respective context, the DPL only needs to be sure that the SoC value is not outdated. it should not even care about other values reported by the battery interface. hence, the isValid() method shall be concerned with the SoC value timestamp only. the method is renamed for clarity.

BatteryStats: manage battery pack voltage in base class

the BatteryStats base class shall be able to tell the total battery pack voltage. for that reason, and to avoid code duplication, the voltage is now handled in the base class and treated as a datum that is common to all battery providers.

unfortunately, the battery SoC values reported by battery BMSs are
unreliable, at least for some users, or at least without regular
(manual) full charge cycles to calibrate the BMS. it offers great
advantages to connect OpenDTU-OnBattery to a BMS (MQTT publishing of
values, Home Assistent integration, etc.), but previously the users
were then forced to configure the DPL by SoC values.

this change allows to configure the DPL such that SoC values are
ignored. instead, the voltage limits are used to make DPL decisions, as
if no SoC was available in the first place.

the SoC related setting are hidden from the DPL settings view if SoC
values are configured to be ignored.

closes helgeerbe#654.
the BatteryStats base class shall be able to tell the total battery pack
voltage. for that reason, and to avoid code duplication, the voltage is
now handled in the base class and treated as a datum that is common to
all battery providers.
this extends the MqttBattery implementation by an additional topic which
allows to subscribe to receive battery voltage readings through the MQTT
broker. similar to the battery SoC topic, this allows to import a
critical battery data point for the DPL, in case the user chooses to use
voltage thresholds rather than SoC thresholds to control the DPL. if an
otherwise incompatible BMS is available which publishes the battery pack
voltage through MQTT, this can now be used to feed accurate voltage
readings to the DPL.
in the respective context, the DPL only needs to be sure that the SoC
value is not outdated. it should not even care about other values
reported by the battery interface. hence, the isValid() method shall be
concerned with the SoC value timestamp only. the method is renamed for
clarity.
the Victron SmartShunt communicates the SoC value in permille. this
should be displayed in the web UI accordingly. this is a good excuse to
fully move ownership of the SoC value to the BatteryStats base class and
add a precision indicator variable. this is required to be set each time
a derived class (a battery provider) wants to update the SoC value. the
precision is then used when populating the JSON data for the web UI
(live view).

related to helgeerbe#573.
the DPL is interested in the battery's voltage to make decisions about
draining the battery or letting it charge (if the user opts to use
voltage thresholds rather than SoC thresholds). using the DC input
voltage reported by the inverter under control has disadvantages:

* the data might be quite old due to the communication protocol
  implementation. more inverters being polled means even more lag. the
  connection being wireless makes this even worse, due to the need
  to retry the occasional lost packet, etc.
* the data is not very accurate, since the DC input of the inverter is
  actually some cabling and a couple of junctions away from the actual
  battery. this voltage drop can mostly only be estimated and is worse
  with higher load. the load correction factor is there to mitigate
  this, but it has its own problems and is cumbersome to calibrate.

instead, this change aims to use more accurate battery voltage readings,
if possible. the DPL now prefers the voltage as reported by the BMS,
since it is for sure the closest to the battery of all measuring points
and measures its voltage accurately regardless of the load (the voltage
reading will still drop with higher loads, but this will be only due to
the battery's internal resistance, not that of cabling or junctions). if
no BMS voltage reading is available, the DPL will instead use the charge
controller's voltage reading, as it is available with much higher
frequency and is assumed to be more accurate as it offers a resolution
of 10mV. only if none of these two sources can be used, the inverter DC
input voltage is assumed as the battery voltage.

closes helgeerbe#655.
@schlimmchen
Copy link
Collaborator Author

@helgeerbe Please do NOT squash the commits. I hope you find them sufficiently clean, and it would be nice to preserve the commit titles so they create a respective entry in the changelog. Thanks in advance!

@hoschiking Magst du das testen? Unten im Abschnitt "Artifacts" gibt es passende Dateien.

Regarding the feature to use BMS voltage over MPPT voltage over inverter voltage, here are respective logs to show the behavior:

BMS available:

21:13:41.359 > [DPL::loop] ******************* ENTER **********************
21:13:41.365 > [DPL::loop] battery interface enabled, SoC: 69 %, StartTH: 45 %, StopTH: 40 %, SoC age: 1 s, ignore: yes
21:13:41.368 > [DPL::getBatteryVoltage] BMS: 52.18 V, MPPT: 52.33 V, inverter: 52.30 V, returning: 52.18V
21:13:41.375 > [DPL::loop] dcVoltage: 52.18 V, loadCorrectedVoltage: 52.32 V, StartTH: 52.00 V, StopTH: 51.00 V
21:13:41.379 > [DPL::loop] StartTH reached: yes, StopTH reached: no, inverter is producing
21:13:41.383 > [DPL::loop] SolarPT enabled, Drain Strategy: 0, canUseDirectSolarPower: no
21:13:41.384 > [DPL::loop] battery discharging allowed, PowerMeter: 14 W, target consumption: 10 W
21:13:41.388 > [DPL::setNewPowerLimit] requested: 275 W, (re-)sending limit: 275 W
21:13:41.392 > [DPL::loop] ******************* Leaving PL, calculated limit: 275 W, requested limit: 275 W (updated from calculated)

BMS not available:

21:41:17.078 > [DPL::loop] ******************* ENTER **********************
21:41:17.082 > [DPL::loop] battery interface disabled, SoC: 0 %, StartTH: 45 %, StopTH: 40 %, SoC age: 1681 s, ignore: yes
21:41:17.084 > [DPL::getBatteryVoltage] BMS: -1.00 V, MPPT: 52.38 V, inverter: 52.30 V, returning: 52.38V
21:41:17.087 > [DPL::loop] dcVoltage: 52.38 V, loadCorrectedVoltage: 52.52 V, StartTH: 52.00 V, StopTH: 51.00 V
21:41:17.091 > [DPL::loop] StartTH reached: yes, StopTH reached: no, inverter is producing
21:41:17.094 > [DPL::loop] SolarPT enabled, Drain Strategy: 0, canUseDirectSolarPower: no
21:41:17.096 > [DPL::loop] battery discharging allowed, PowerMeter: 29 W, target consumption: 10 W
21:41:17.099 > [DPL::setNewPowerLimit] requested: 296 W, last limit: 289 W, diff: 7 W, hysteresis: 20 W, age: 12047 ms
21:41:17.101 > [DPL::loop] ******************* Leaving PL, calculated limit: 296 W, requested limit: 289 W (kept last requested)

Neither BMS nor MPPT available:

21:41:41.982 > [DPL::loop] ******************* ENTER **********************
21:41:41.988 > [DPL::loop] battery interface disabled, SoC: 0 %, StartTH: 45 %, StopTH: 40 %, SoC age: 1706 s, ignore: yes
21:41:41.992 > [DPL::getBatteryVoltage] BMS: -1.00 V, MPPT: -1.00 V, inverter: 52.20 V, returning: 52.20V
21:41:41.994 > [DPL::loop] dcVoltage: 52.20 V, loadCorrectedVoltage: 52.39 V, StartTH: 52.00 V, StopTH: 51.00 V
21:41:41.996 > [DPL::loop] StartTH reached: yes, StopTH reached: no, inverter is producing
21:41:42.000 > [DPL::loop] SolarPT enabled, Drain Strategy: 0, canUseDirectSolarPower: no
21:41:42.002 > [DPL::loop] battery discharging allowed, PowerMeter: -61 W, target consumption: 10 W
21:41:42.004 > [DPL::setNewPowerLimit] requested: 303 W, (re-)sending limit: 303 W
21:41:42.007 > [DPL::loop] ******************* Leaving PL, calculated limit: 303 W, requested limit: 303 W (updated from calculated)

@spcqike
Copy link

spcqike commented Feb 19, 2024

hello @schlimmchen

i really like the progress and idea, of having the ability to use different "voltage sources"

how will this automatic decission and fallback to the next lower device handle the load correction factor? wouldn't it be good, to either only define one specific "voltage source", that should be used, because right now we only can define one load correction factor? or else define multiple factors?

what i mean:
every source (BMS/Shunt, charge controller or inverter input) will have another resistance and therefore needs another factor.
the BMS or shunt will have the lowest resistance, as its as close as possible to the battery terminals (or allready inside the battery)

for the mppt and inverter, the resistance strongly depends on your setup and the loads.

grafik

in this scenario, if we dont charge the battery, the red connection is without load. so if the mppt is the voltage source, we don't need a factor. if we use one, we mustn't compensate the inverter load, but the mppt charge current.

if the inverter itself measures the voltage, we need the load correction, as it is implemented now.

grafik

if we use a busbar, it gets more complex and complicated.

here, we have several possibilities:
mppt measures voltage:

  • no charge, only discharge -> compensate orange + yellow only based on inverter DC current
  • charge, discharge -> compensate red based on chargecurrent and orange based on dischared, and somehow yellow
  • charge, no discharge -> red, based on "chargecurrent" (mppt output), orange based on real charge current (mppt output - inverter input currents) + yellow

inverter measures:

  • no charge, only discharge -> green + yellow + orange, based on inverter DC current (like now)
  • charge, discharge ...

i think you get what i mean.

imo the best and easiest solution is the BMS or a shunt, as they are as close as possible to the battery and have a well-defineable resistance. but one single factor, as we have it now, won't fit all use cases, that can occur with this automatic fallback, will it?

@helgeerbe helgeerbe merged commit 1eb75c3 into helgeerbe:development Feb 19, 2024
8 checks passed
@hoschiking
Copy link

hoschiking commented Feb 19, 2024

@schlimmchen
Ja mache ich. Es kommt zum passenden Zeitpunkt, da der Speicher mangels Sonne täglich leer ist.
Firmware ist drauf. Einzige sichtbare Änderung ist der Schalter "Batterie SOC" ignorieren.
Ich habe folgende Einstellungen vorgenommen:

Screenshot_2

Bei 25,4V soll das Einspeisen beendet werden. Dies ergibt eine durchschnittliche Zellenspannung von 3,175V
Den Korrekturfaktor habe ich auf NULL gesetzt, so sehe ich besser die exakte Spannung, wann die Abschaltung greift.
Meine bisherige externe Abschaltung habe ich auf U min von 3,1V herabgesetzt. So grätscht die nicht dazwischen.

Screenshot_1

Aus dem Text entnehme ich, dass die Berücksichtung der Spannung des BMS bereits implementiert ist?
Heute abend gibt es erste Daten

@schlimmchen
Copy link
Collaborator Author

i really like the progress and idea, of having the ability to use different "voltage sources"

Thanks!

how will this automatic decission and fallback to the next lower device handle the load correction factor?

@spcqike The voltage will be determined based on the priority I implemented, and the load correction factor will be applied afterwards.

You are right that a load correction factor (LCF) for each voltage source is technically necessary, however, the voltage data source is known given your particular setup. Tune the LCF for that voltage source. Be happy.

If you tuned your LCF for the BMS, and the DPL has to make due with the charge controller voltage, the LCF will not be ideal, yes. In that case, something is wrong with your BMS communication and you will be fixing it anyways once you notice. Once you fixed it, your voltage source will be the BMS again and your LCF is tuned.

Aus dem Text entnehme ich, dass die Berücksichtung der Spannung des BMS bereits implementiert ist?

Ja. Wenn du die verlinkten Artefakte nutzt, bzw. das vorhin veröffentlichte 2024.02.19, und dein JK BMS Interface funktioniert, dann wird die von ihm gemeldete Spannung im DPL als Berechnungsgrundlage verwendet.

@schlimmchen schlimmchen deleted the dpl-voltage-features branch February 19, 2024 15:36
@hoschiking
Copy link

@schlimmchen
gestern das wichtgste getestet, keine Fehler gefunden 👍
Durchgeführte Tests:
SOC nicht ignorieren -> die Einspeisung wird wie eingestellet EIN und AUSgeschaltet.
SOC ignorieren -> die Einspeisung wird wie eingestellet EIN und AUSgeschaltet.
Dabei wurde offensichtlich die BMS-Spannung als Trigger verwendet, siehe Screenshot.

Screenshot_3

Well done 👍

@schlimmchen schlimmchen mentioned this pull request Feb 20, 2024
Copy link

github-actions bot commented Apr 4, 2024

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

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