batpred icon indicating copy to clipboard operation
batpred copied to clipboard

PV generation offset curve or time/curve based PV multipliers/%

Open Noodleyman opened this issue 1 year ago • 13 comments

Is your feature request related to a problem? Please describe. In our location, our property and thus panels are tucked behind a hill which means the morning sun does not hit our panels until later than expected every day. It does not directly track with sunrise. In the evenings, we have trees which the sun will set behind, thus we lose our evening generation earlier than anticipated. Although the PV forecasts drive the demand. This results in less optimal charging plans for first thing in the day and evenings (not so much of an issue in evenings). For example PredBat may calculate that 2kWh charge to the battery is optimal to get us between 5AM (cheap rate end) and enough PV generation to cover our needs, in reality due to shading we may actually require 3kWh as the meaningful generation of PV power is later than anticipated, thus we frequently end up with an empty battery for an hour or so in the mornings and use the grid. i am using a 10% uplift on anticipated consumption to try to avoid the issue, but this applies all the time rather than we we just need it.

Describe the solution you'd like The ability to add a PV generation/forecast multiplier by time slice, with the first slice starting from either sunset of the first slice each day where forecasted PV generation is > 0.

For example, assuming slice was the first time period with a PV forecast > 0. Slice | Time | PV Forecast kWh | % anticipated Slice 1: 06:00 - 06:15 | 0.25 | 0% Slice 2: 06:15 - 06:30 | 0.5 | 10 % Slice 3: 06:30 - 06:45 | 0.75 | 20 % Slice 4: 06:40 - 07:00 | 1 | 25% Slice 5: 07:00 - 07:15 | 1.25 | 50% Slice 6: 07:15 - 07:30 | 1.25 | 100%

The idea above, being that for the first slice, assume 0% of the 0.25kWh will actually be available, thus 0 forecast. Slice 2, 10% of the 0.5kWh expected thus 0.05kWh, slice 3 20% of the forecast, thus 0.15kWh etc. Until we hit slice 6 where we can just assume the forecast is correct. This would modify the plan generated to account for later than anticipated sun on panels due to shading and other conditions and should give a more accurate result.

The same can be applied in reverse for end of day generation, using the last slice in the day with a forecast > 0 and work backwards.

The above may need to be defined either by date range, or perhaps by week of the year / month to account for the change in azimuth

Describe alternatives you've considered Load scaling, but this applies all the time so doesn't fit the requirement

Noodleyman avatar Jun 18 '24 07:06 Noodleyman

If you are using the Solcast integration rather than Predbat calling Solcast, then I think you can already do this with the dampening factor that can be set hour by hour https://github.com/BJReplay/ha-solcast-solar

gcoan avatar Jun 18 '24 09:06 gcoan

Ah, I wasn't aware of that, however this seems to be more fixed time driven (per hour set by time of day) rather than dynamic based on predbat slices which would offer a more graunlar control. I guess it might be possible to use this feature and somehow updated the dampening values via automations with bespoke calculations which I'll have to check into. As the developer for ha-solcast-solar pulled the solution from github and the future of that integration is in question, the ability to do this in predbat would be more universal and accomodate all data sources in the future.

Noodleyman avatar Jun 18 '24 13:06 Noodleyman

The bjreplay fork of the solcast integration is being actively developed, I've been involved in several of the fixes including auto retries and caching. Give it a go and see if it does what you want - damping the early sun down will give predbat a reduced forecast to use in the plan.

I also have a concern about too much overloading of predbat with functionality that can be achieved elsewhere. There's a lot of controls switches and options already and the more that gets added the more daunting it is for new users. There's a balance of course.

gcoan avatar Jun 18 '24 13:06 gcoan

Ah supurb information, thank you. I'll explore it further and perhaps see if the bjreplay fork would consider evolving the dampening functionality as well. thanks for taking the time to provide your feedback :)

Noodleyman avatar Jun 18 '24 13:06 Noodleyman

just a quick follow up. I tested out the dampening feature and can confirm that after making changes to the factors predbat does pick up the refactored forecasts on its next cycle, this this will likely work for what I need. I just nbeed to figure out the exact logic I need it to use so I can get the service called with appropriate values for my use case via automation. I'l work on that when time allows. Thank you again :)

Noodleyman avatar Jun 18 '24 13:06 Noodleyman

No problem, happy to help. I'll put something in the documentation to highlight the damping function in the solcast integration for others with similar use cases 👍

gcoan avatar Jun 18 '24 14:06 gcoan

Thought I would follow up and share what I put together. it's crude and will get refined over time but it's a starting point for others who may be looking to do the same thing. I had some fun trying to get Home Assistant to stop seeing the generated CSV list as an object list rather than a string, but in the end stripping out the final parenthesis did the trick.

I am not really happy with the logic below, but will refine it over time. for now, it works as I want for the mornings and I'll factor in evenings once we get towards Autumn and winter.

I added a sensor which generates the dampening string, which you can then use in an automation to call the solcast service

      solcast_dampening_curve:
        friendly_name: "Solcast Dampening Curve"
        value_template: > 
            {% set midnight = 1 %}
            {% set oneAM = 1 %}
            {% set twoAM = 1 %}
            {% set threeAM = 1 %}
            {% set fourAM = 1 %}
            {% set fiveAM = 1 %}
            {% set sixAM = 1 %}
            {% set sevonAM = 1 %}
            {% set eightAM = 1 %}
            {% set nineAM = 1 %}
            {% set tenAM = 1 %}
            {% set elevenAM = 1 %}
            {% set midday = 1 %}
            {% set onePM = 1 %}
            {% set twoPM = 1 %}
            {% set threePM = 1 %}
            {% set fourPM = 1 %}
            {% set fivePM = 1 %}
            {% set sixPM = 1 %}
            {% set sevonPM = 1 %}
            {% set eightPM = 1 %}
            {% set ninePM = 1 %}
            {% set tenPM = 1 %}
            {% set elevenPM = 1 %}
            {% set sunrise_hour = as_timestamp(states.sun.sun.attributes.next_rising) | timestamp_custom("%I") | replace("0", "") | int %}

            {% if sunrise_hour == 4 %}
              {% set fiveAM = 0.4 %}
              {% set sixAM = 0.5 %}
              {% set sevonAM = 0.6 %}
            {% elif sunrise_hour == 5 %}
              {% set fiveAM = 0.4 %}
              {% set sixAM = 0.5 %}
              {% set sevonAM = 0.5 %}
              {% set eightAM = 0.6 %}
            {% elif sunrise_hour == 6 %}
              {% set sixAM = 0.4 %}
              {% set sevonAM = 0.5 %} 
              {% set eightAM = 0.6 %}
            {% elif sunrise_hour == 7 %}
              {% set sevonAM = 0.4 %} 
              {% set eightAM = 0.6 %}  
              {% set eightAM = 0.7 %}  
            {% elif sunrise_hour == 8 %}
              {% set eightAM = 0.6 %}  
              {% set eightAM = 0.7 %}    
              {% set nineAM = 0.8 %}
            {% endif %}

            {% set output = midnight,oneAM,twoAM,threeAM,fourAM,fiveAM,sixAM,sevonAM,eightAM,nineAM,tenAM,elevenAM,midday,onePM,twoPM,threePM,fourPM,fivePM,sixPM,sevonPM,eightPM,ninePM,tenPM,elevenPM %} 
            {% set output = output | replace(" ", "") %}
            {% set output = output | replace("(", "") %}
            {% set output = output | replace(")", "") %}

and calling the service from an automation:

service: solcast_solar.set_dampening
data:
  damp_factor: |
    {{states('sensor.solcast_dampening_curve') | string}}

Noodleyman avatar Jun 19 '24 05:06 Noodleyman

Thanks for sharing @Noodleyman if you get something you are happy with then maybe we can include it in the BjReplay documentation as an example of using the dampening curve.

Looking at the Jinja, the whole long list of if/then/elif's looks bad, I thought there was a 'case' statement that could be used, but a google search I couldn't find one so maybe I am thinking about the conditional branching in Automations rather than Jinja logic? I found this stack overflow article https://stackoverflow.com/questions/74706864/replicate-a-case-when-statement-in-jinja and whilst it focusses on a SQL output, did wonder whether could construct things as an array of tuples and iterate along that or even index along it, e.g. {% set charge_curves = [ [0,0,0,0], ..., [0,1,4,5], [0,1,10,20] ] %} {% fiveAM = charge_curves[sunrise][0] %} {% sixAM = charge_curves[sunrise][1] %} {% sevenAM = charge_curves[sunrise][2] %} {% eightAM = charge_curves[sunrise][3] %}

And I think you can chain the 'replace' strings at the end, e.g.

{% set output = output | replace(" ", "") | replace("(", "") | replace(")", "") %}

This is deliberately not trying to be 100% perfect Jinja, but hopefully you get the idea

PS: sevonAM spelt wrongly jumps out to me 😡

gcoan avatar Jun 19 '24 07:06 gcoan

ah the joys of multi tasking and spelling like a child :), now you've pointed it out the OCD in me must go and fix that hah.

I'll probably spend a few weeks messing about with this and evalauting the results. I'll check into what you've suggested. When I put that together I just assumed build a CSV list rather than approaching it like an array/object, but it does make more sense. Would be good to get some better math in there as well once I've reviewed the data in more detail.

Noodleyman avatar Jun 19 '24 07:06 Noodleyman

See info here: https://github.com/BJReplay/ha-solcast-solar/discussions/28#discussioncomment-9852030

I've paused the use of Dampening for now, there seems to be some glitches which when triggered make the system unusable. I'm assuming a bug but this is a guess on my part.

Noodleyman avatar Jun 26 '24 05:06 Noodleyman

See info here:

https://github.com/BJReplay/ha-solcast-solar/discussions/28#discussioncomment-9852030

I've paused the use of Dampening for now, there seems to be some glitches which when triggered make the system unusable. I'm assuming a bug but this is a guess on my part.

Yes I have seen that. There is I think a fixed version in test, but best to wait for now until its resolved

gcoan avatar Jun 26 '24 08:06 gcoan

@Noodleyman did you come up with any changes to the template sensor or shall I just propose it as-is for the solcast integration readme?

gcoan avatar Aug 20 '24 19:08 gcoan

Morning @gcoan ,

I did not change it yet, it's been in and working per my needs so I've been leaving it alone for now. I do intend (when time allows, which will be rare) to overhaul that code and make the inputs to the sensor UI configurable, and also code refinements as suggested. What I did put together is working well though and doing the job it needs to be doing so can be shared as a starting point.

Noodleyman avatar Aug 21 '24 06:08 Noodleyman

The Solcast integration now includes auto-dampening which retrieves Solcast's estimated actuals PV data (from high resolution satellite imagery) and compares that to your actual generation to calculate dampening factors.

It works brilliantly, a great piece of development.

Manual dampening is still available of course.

Closing this issue as Solcast can now meet the requirement

gcoan avatar Nov 05 '25 00:11 gcoan