Feature Request: TimeOfUse controller: Discharge to grid

Hi all

User in Belgium here. I understand German rules are perhaps a bit different.

I have a 50kWh battery pack and have a dynamic energy contract.
Over the last few weeks, I see quite often some negative prices, which means I end up paying for injecting to the grid.
I have implemented a “disable feed” so I do not inject to the grid when the prices are negative.

Currently, I wake up with a battery pack at 80% capacity. It quickly fills up and by noon, the battery is full. As of then, I limit the injection to the grid and thus significantly impact my PV yield, as it only covers my consumption.

I have implemented a very basic: If SPOT price is high between midnight and noon, use the crtlFixActivePower to discharge to grid. However, I would like to be able to use the prediction values to actively discharge my battery pack when the prices are high.

Could the TimeOfUse controller handle this too? My java skills are not great - hence this feature request.

Hi,

that’s a very interesting use-case. I was not aware that this is already possible in Belgium. Could you share some more documentation to read up on the details of this? Is your feed-in-tariff directly coupled to day-ahead/spot prices?

I am still heavily working on restructuring the Time-of-Use Tariff Controller to make the features available for different multi-use applications, so I might not yet be ready to accept PRs here. But first step to start your “SELL_TO_GRID”-mode would be to add a new mode here → openems/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/StateMachine.java at develop · OpenEMS/openems · GitHub

And then check your Eclipse warnings and see where this change requires you to make adaptions. E.g. you will have to adjust the internal cost-function to handle SELL_TO_GRID “costs”. → openems/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java at develop · OpenEMS/openems · GitHub

Regards,
Stefan

Hey Stefan,

Thank you for your reply.

In terms of details; there aren’t any restrictions in Belgium (at least for residential or SME customers).

For residential customers, the only limitation is that your inverter can only output 10kWp. If you want to exceed this, you can ask for a (free) grid study so you can go up to 25kWp (which I did). If you want more, more restrictions apply. Unfortunately all documentation is very regionalised, so it’s only available in Dutch (my area). If you need more, I can translate it for you.

My dynamic tariff used to have a 1 on 1 mapping with the spot prices. Now, my energy provider has introduced a margin for injection: -0,9050 + 0,1000 x ESPOT, which basically means they are taking 0.01 euro per kWh. It means that if I inject when the SPOT price is less than 10 euro per MWh, I end up paying. I guess this has to do with the increased unbalance costs. There are also no grid costs when injecting.

When importing, there are a lot of taxes in BE added (grid costs), and the base formula is 1,1000 + 0,1000 x ESPOT.

I’ll have a look at the places to include this function.

Thanks again

Yves

Dear Stefan, dear Yves,

as almost a year passed since the last post, I wanted to ask if there is any update about this. I‘m in a very similar situation as Yves, only in Austria instead of Belgium: Using openEMS to manage a plant with PV and quite large BESS using dynamic prices for both buying from and selling to grid.

Generally ToU works good, thanks for all that work Stefan. However, already now, the BESS often stays above 70% and is fully charged already before noon. Then I have the option of either disabling PV, or selling to grid with very low, or even negative prices.

I also implemented some basic logic to control the grid feed based on variables, but I feel like the best option would be to include this in the ToU algorithm, making it complete for all use cases. Did any preparation for this happen in the last year, or is it maybe already in the make?

Thank for your work and help,

Alex

Hi Alex,

there is no finished version yet, but a lot of ground-work has happend in the Time-of-Use / Energy Scheduler (v2) implementation.

At least here in Germany dynamic-feed-to-grid is not yet as relevant as in Belgium, because it’s only allowed with an external trader (“Direktvermarkter”).

This thread might be interesting for you:

We are currently planning a OpenEMS Networking Friday on Energy Scheduler v2 for developers. It’s scheduled for 4th April 2025 at 2pm.

Regards,
Stefan

PS: My usual sentence: If you use OpenEMS in production it would be great if you could join OpenEMS Association e.V.; it’s not too expensive and supports the project a lot.

Dear Stefan,

first of all, thanks for your detailed answer! I already tried to get more into the changes introduced by EnergySchedulerV2, but still not having the full view.

Do I understand correctly: At the moment, ToU supports the three modes, but it is limited to a single ESS and not making use of any other assets such as EVs or Heat Pumps. With v2, this will change, at least including energy-consuming assets. What other fundamental changes in the usage field that Yves and me are covering are interesting?

Also, to me it seems that the function desired by Yves and Me will not be included therefore. In which way will it get easier to implement this behaviour? I assume, if it’s already common in AT and BE, it will also come to DE earlier or later and it might be nice to already support it from the begin on.

Also thanks for your offer to participate in the Association, will definitely consider that when proceeding further!

Best,

Alex

FYI: we are organizing a Networking Friday to gather all interesting people:

2 Likes

@yvesilknievil, @as_py: I’ve been playing with implementing this feature in Energy Scheduler v2 recently and it looks promising:


The code is already on develop branch. You just have to configure

As discussed in networking friday, you can of course also simulate it via the RunOptimizerApp.

I am very interested in hearing your feedback!

Regards,
Stefan

2 Likes

Dear Stefan,

wow, thank you a lot for the work! We will definitely test this in near future and come back to you about our experience!

Best, have a nice weekend,

Alex

Dear Stefan,

we implemented the new controller and Tuesday evening and unfortunately, it didn’t work so far. I did not have time to look into it in detail, will do that beginning of next week, but i still thought it might be nice to share it with you, in case you immediately spot the problem. It is a Sigenergy system with 30kWp and 96kWh.



(ignore the missing data in the second plot from 11-12, this is just a dashboard issue)

As you can see, it never fed in, even when the ToU controller said so: At 14:00, 100% SoC was reached and it actually reduced the production, even though the price would have been high enough to feed in.

Then, it gets even weirder: Whenever DISCHARGE_GRID is active, it completely disables the production and takes all power from the grid, not from the battery. From 18:45-19:00 BALANCING was active, at 19:00 DISCHARGE_GRID started again and actually used energy from grid to charge from 99% to 100%, which was completely unnecessary at this point.

Do you have any ideas what could cause this? As said before, I will have time to take a closer look at the beginning of next week.

Best and thanks again,

Alex

@as_py: Thanks for the experience report! I don’t know the Sigenergy implementation - is it open source somewhere?

It would be interesting if a discharge command (i.e. a positive set-point value) was sent to the ESS at all. Can you please plot the Channel ess0/DebugSetActivePower?

Hello Stefan,

thanks again for your reply! Unfortunately, the Sigenergy implementation is not publicly available at the moment, as it is still in development and apparently also not working correctly. I also didn’t implement it myself, but I will talk to the developer about a release.

As desired, I added the channel ess0/DebugSetActivePower to the plot:

So a discharge command was definitely sent to the ESS, but never executed.

Best,

Alex

Ok, then it’s as expected: DISCHARGE_TO_GRID was working, but the ESS implementation did not actually apply the set-point properly. I cannot help much without seeing the code then, sorry. Maybe consider switching to a well-supported FENECON system then… :wink:

1 Like

We actually also have a FENECON system running :wink:, as well as one from Huawei. We will conduct further tests and come back to you with feedback and/or code. Thanks! Also feel free to ping me at any time in case there is any update or question from your side!

Related question, just to make sure: Do I assume correctly that at the moment, the same price is considered for buying from and selling to grid? Mostly irrelevant at the stage we are right now, but in the future it might be necessary to differentiate (buying: EPEX price + fees + tax + grid costs, selling: EPEX price - fees).

We actually also have a FENECON system running :wink:, as well as one from Huawei. We will conduct further tests and come back to you with feedback and/or code. Thanks! Also feel free to ping me at any time in case there is any update or question from your side!

Thank you. If you can share the code, it would be beneficious for the community and I could surely support better.

Related question, just to make sure: Do I assume correctly that at the moment, the same price is considered for buying from and selling to grid? Mostly irrelevant at the stage we are right now, but in the future it might be necessary to differentiate (buying: EPEX price + fees + tax + grid costs, selling: EPEX price - fees).

Yes, but the current time-of-use controller logic does not contain a full arbitrage algorithm, i.e. it would never charge from grid just to discharge to grid later. The current logic essentially just evaluates if there is more energy in the battery than is required during the night and discharges accordingly at the highest EPEX price.

1 Like