helgeerbe / OpenDTU-OnBattery

Software for ESP32 to talk to Hoymiles Inverters and Victrons MPPT battery chargers (Ve.Direct)
GNU General Public License v2.0
287 stars 62 forks source link

[Request] DPL: Limit Battery discharge current #657

Open schlimmchen opened 7 months ago

schlimmchen commented 7 months ago

Is your feature request related to a problem? Please describe.

Some people use batteries with a rather low capacity together with very potent inverters and/or solar charge controllers. Limiting the charge current is out of scope for OpenDTU-OnBattery, but limiting the discharge current is very well in the realm of this project. The upper power limit is generally suited for this application, however, it will also limit the inverter power if more solar power is available that could be used to produce AC power.

Describe the solution you'd like

A new parameter shall be introduced which limits the inverter power such that the battery discharge power current is limited.

This new parameter shall only be available if solar passthrough is enabled. Otherwise, the existing upper power limit is redundant. While solar passthrough is active, the DPL will try to match the household consumption by using the solar power available. If the battery can be discharged and the houshold consumption is bigger than the solar power being produced, the DPL will increase the inverter limit, but not more than this new "battery discharge power limit" by what amount the respective maximum battery discharge current allows (calculation required).

Describe alternatives you've considered

No response

Additional context

See https://github.com/helgeerbe/OpenDTU-OnBattery/discussions/221#discussioncomment-8410828

peff74 commented 7 months ago

Sounds great :-)

spcqike commented 7 months ago

Is there a reason why it should be only available if solar passthrough is enabled?

As I mentioned in #221

Dazu kommt ja auch, dass der WR rein leistungsbasiert arbeitet, ohne die EIngangsspannung zu berücksichtigen. die Akkuspannung liegt ja aber zwischen 44,5V und 53,5V, oder? Will man also , sagen wir 1.200W (am AC Ausgang), zieht der WR gut und gern 1.263W_DC (bei 95% Effizienz) und damit zwischen 23,6A (voll) und 28,4A (leer) , oder? Ein Entladestrombegrenzer würde natürlich die Ausgangsleistung ebenfalls begrenzen, so wie das bereits vorhandene obere Leistungslimit es tut, aber eben dynamisch, in Abhängigkeit der Akkuspannung. Als Workaround könnte man zwar das vorhandene obere Limit entsprechend der minimalen Akkuspannung und maximalen Entladestrom und der Wechselrichtereffizienz grob berechnen, begrenzt sich damit aber im Bereich des vollen Akkus. Im obrigen Beispiel wäre dann 1.056W das generelle obere Limit (25A bei 44,5V und 95%Effizienz).

in this case a 25A limited battery can produce between 1056W(low charge state) and 1270W (full battery). A difference of about 214W or 20%.

Wouldn’t it be more suitable to put such a current limit into the battery menu and use it as additional overall limitation, whenever the battery is used? As we do not limit the inverter itself (upper inverter limit in DPL) but the battery itself.

peff74 commented 7 months ago

If this is not too complicated, taking the maximum current that can flow from the battery as a basis would of course be even more interesting. But I'm happy with any suggestion :-)

spcqike commented 7 months ago

In term of limiting code, shouldn’t it be enough to change this line?

https://github.com/helgeerbe/OpenDTU-OnBattery/blob/b794f46ef0807b6f10fe056ae3fb2ee5e980242d/src/PowerLimiter.cpp#L530

so that it uses the min out of three values? newPowerLimit, config.PowerLimiter.UpperPowerLimit and the result of config.battery.maxDischargeCurrentbattery.getVoltage()inverter.efficency

battery.getVoltage() would need to be defined in accordance with #655

config.battery.maxDischargeCurrent could be a field in battery menu which the user can use.

Edit: After sleeping on it for a night, this little change wouldn’t be enough to handle the mentioned solarpassthrough with battery discharge use case :) but it would be ok for empty at night and empty when full only.

And maybe one could just use a new battery.getMaxDischargePower() function.

schlimmchen commented 7 months ago

Is there a reason why it should be only available if solar passthrough is enabled?

I thought there was. But there isn't. Changed the description accordingly.

If this is not too complicated, taking the maximum current that can flow from the battery as a basis would of course be even more interesting.

That is actually a good idea. The allowed increase in the power limit must be calculated, based on battery voltage and inverter efficiency. I don't see why that should be complicated. Changed the title and description accordingly.

@peff74 I am having second thoughts about this feature again: I already explained that you still need to take care that the batteries are not charged by a too high current by yourself. The same is true for discharging: Let the inverter be set to a particular power limit such that the batteries are discharged at the specified maximum current. That limit was calculated with a significant amount of solar power. Now a cloud comes along and the solar output plummets. That happens frequently and you know it. Until the DPL has a chance to instruct the inverter to use a new, lower power limit, the batteries will be discharged with a much higher current. Hence I still think that you absolutely must scale your battery to your inverter and charge controller. Or use an upper power limit that is always safe.

Maybe you only want to slow down deterioration of the battery and your house will not burn down if the inverter actually does produce at its full power. Or maybe the BMS will save your because you set it up properly. Other users however, certainly new users, will read this setting as "nice, the DPL will take care that the battery discharge current is always limited to the value I set here", which is just not true and which simply cannot be true.

I am back to thinking that this setup is just not safe unless you globally limit the inverter output power (which is already supported) and also limit the solar charger output accordingly.

alexseuf commented 7 months ago

If there is a battery connected where BMS Data could be read Out, the BMS will tell the Inverter the Maximum discharge current. So there should be a Software Switch which decide If User provided discharge current Limit or BMS provided discharge current Limit should be used. This Switch could react in the same condition as the Switch which decide lower and upper discharge start/Stop condition ( User Set SoC or User Set voltage).

schlimmchen commented 6 months ago

If there is a battery connected where BMS Data could be read Out, the BMS will tell the Inverter the Maximum discharge current.

The BMS will tell the inverter how? This project is aimed at Hoymiles inverters. Those communicate only via their wireless interface and that is what OpenDTU does.

I don't know about your BMS, but mine will not regulate the current being drawn, but shut off the battery if the current exceeds the maximum and only enable the battery again after a configurable amount of time. So I don't know how the BMS can help here except prevent the worst.

alexseuf commented 6 months ago

You are right If BMS is "old Style" JK BMS IT does not tell the Open DTU a maximum discharge current. But If BMS is:

schlimmchen commented 6 months ago

That does not solve the problem that transient changes in the power consumption, which can be drastic, lead to respective drastic changes in the current draw from the battery. OpenDTU can try to be fast with sending new power limits, but it will always take time. Much time if you use multiple inverters. Multiple Seconds. Especially since the communication medium is wireless. You might even need to retransmit a power limit request.

I don't see how knowing how much current to draw because the BMS tells us leads to any improvement.

I still maintain that it is important that your battery can handle the maximum current the charge controller outputs and the maximum current the inverter might draw safely at least but also with sufficient margin such that the battery does not degrade early.

My setup is on the other side of the spectrum with 16 cells with 230Ah each. The current draw or current input is less than 0.2C (2000W from the charge controller, 1500W inverter). I know that's not the best choice for everyone.

However, as an example, if you use an HM-1500 and a battery at 24V, that's 60A DC if the inverter outputs at full power. If you want to always discharge safely, you need cells that handle 60A without an issue, i.e., 8 LiFoPo4 cells with 60Ah at least, as that's 1C.

Choosing a lower capacity with that setup is not sound.

Or, on the other hand, you have a battery and you will not upgrade, limit the charge current and discharge current globally in the charge controller and inverter. I think that you then have to live with the fact that you cannot use the full solar power while it is there. As I explained above.

peff74 commented 6 months ago

Hi Schlimmchen,

But there is one point that should not be ignored: it makes sense to reduce the load on a battery that is more than half empty. Simply to hit the "empty" point more accurately. Of course, you can play with the load correction for a long time, but if the load is reduced towards the end, it becomes much easier. That is why it is built into HoymilesZeroExport. I would also map it via the "upper power limit" so as not to give it the appearance of a safety aspect.

MalteSchm commented 6 months ago

I considered adding something along these lines and think it is useful despite the issue that we can't control MPPT charging.

The motivation for me is not so much driven by small batteries but by the fact that the maximum charge and discharge currents signaled by the (Pylontech) BMS vary with:

I think it would be good to take the BMS limits into account to the extend this is possible. I thought that:

I agree that we may run over the set limits as the control loop has some latency but I think that

spcqike commented 6 months ago

this also could come in handy, if its ever possible to use multiple inverters with the DPL, as one could draw to much power very quickly.

further thinking: maybe it would be possible to add batterys, like you can add inverters. and assign batterys to inverters at inverter level (like, where you can name your strings and such). i guess this would be overkill for like 95% of the users, as most users most likly just have 1 battery as big as possible, but it would be neat and would allow to use different physical locations with dedicated batterys and inverters, without the need of very long DC cables or some AC-chargers.

like: adding battery1 with 50Ah and 25A continuous discharge current (or select a BMS, that belongs to this battery) and maybe 100A for 15s. configure inverter1, that is connected to battery1 and set upper and lower power limit for this specific inverter. maybe connect inverter2, also to battery1, with its own lower and upper limits. configure inverter3 and dont use a battery, its PV only, also with or without its own lower and upper limit. activate DPL with DPL overall upper and lower limit. and let DPL decide, which inverter and battery to use at which point.

MalteSchm commented 6 months ago

I think we should cross that bridge when we get there.

Right now openDTU is one battery and one inverter. When this changes one can think about power limiting aspects

ButterBetzi commented 6 months ago

spcqike correctly linked my request as duplicate. I would also like to have this feature! :)

peff74 commented 4 months ago

Any news in this case?

ButterBetzi commented 2 months ago

Hi @schlimmchen @spcqike, any progress on that topic?

If not: I would try to contribute here myself, but I would need some starting help. So if you could give me a hint to where in the code I could start and what your overall plan for this functionality would look like, I can try to realize it.

spcqike commented 1 month ago

as i dont have a battery, i can't really help or test anything. but i guess i would define a max discharge current in the overall battery settings. first as selectable switch that is visible regardless of the selected battery interface.

for battery interfaces, that don't give a max discharge current themself (i think pylontec does, doesn't it? at least it looks like in some pictures) we would need a user input field.

as we only can set a power limit, and not a (dc) current limit, maybe its also a good idea to create a function in the battery class, that returns the max discharge power. like battery.getMaxDischargePower(), which would just calculate battery.maxDischargeCurrent * battery.voltage

and, as the battery.cpp doesn't give us the voltage as a function, maybe we could also create this. right know, we have a set of calls in the DPL, which gets the voltages from multiple sources (inverter, MPPT, BMS). IMO MPPT and BMS could and should be retrieved from battery.cpp

see function https://github.com/helgeerbe/OpenDTU-OnBattery/blob/b90da210bedb5fcbd34cab0fa762be3c28b85ecd/src/PowerLimiter.cpp#L307

we than must update the calcPowerLimit function to also consider the max discharge current, if we use a battery (case 3 and 4) https://github.com/helgeerbe/OpenDTU-OnBattery/blob/b90da210bedb5fcbd34cab0fa762be3c28b85ecd/src/PowerLimiter.cpp#L428

i guess, something like this 😄

spcqike commented 1 month ago

further thinking:

to get everything cleaner, maybe we should also move the "normal" battery settings to the battery page, beforehand.

what i mean: right now, if we have a stupid battery, without mppt, shunt, bms, .... we don't define anything except in the DPL settings.

so, to get everything "clean", maybe it would be good to also refactor this. this could be 1) create a 5th, "plain" battery selector, 2) define battery parameters like nominal voltage, discharge stop and start voltage (basicly the thresholds that are defined in the DPL right now) in the battery settings. 3) clean up DPL, so that we maybe only define the ac power limits within DPL (and maybe the battery discharge strategy like empty at night ), and keep all the battery relevant things (voltages, SoC thresholds, ...) in the battery settings.

IMO this would be very clean, but its probably a lot of work. and we would need a "translator" to create the new config file once we update a module.

schlimmchen commented 1 month ago

but its probably a lot of work

Yes, and it contradicts #656, which would like to see these settings in that newly created battery watchdog instead.

spcqike commented 1 month ago

it contradicts

does it?

wouldn't it be possible (and IMO way cleaner), to define the battery settings in the battery tab. the watchdog can run on its own and overwrite the DPL, as it likes. respectively it could be part of the battery tab, couldn't it? it could be active, when a battery is used.

something like this grafik

spcqike commented 1 month ago

so one could let the battery handler handle everything, like battery.getVoltage , battery.isDischargeAllowed, battery.maxDischargePower (which would be battery voltage times max current, either userdefined or in case of some bms reported), ....

the only thing, that i can't get my head around, would be a generic battery. a simple 24V or 48V battery without BMS or MPPT/Shunt. it would be necessary to create a provider like "generic". but how do we get the actual voltage? as this than only can be read from inverters inputs, which isn't present in battery handler right now.

Condor-XYZ commented 2 weeks ago

Hello, I wanted to dynamically set the maximum permissible output power via the MQTT point solar/powerlimiter/status/upper_power_limit. In other words (Max Bat(W) + Solar(W) =upper_power_limit) ... but unfortunately the solar/powerlimiter/status/upper_power_limit always writes the ESP32 is flashing ... it won't survive long. Is there a solution for this?

schlimmchen commented 2 weeks ago

See the docs. The topic is powerlimiter/cmd/upper_power_limit.