BottlecapDave / HomeAssistant-OctopusEnergy

Unofficial Home Assistant integration for interacting with Octopus Energy
https://bottlecapdave.github.io/HomeAssistant-OctopusEnergy/
MIT License
553 stars 53 forks source link

Feature request: Service to re-evaluate target on demand #112

Closed corvus2606 closed 1 year ago

corvus2606 commented 1 year ago

Not sure how straightforward this would be, but I have a use case where I have a target set to run in the early morning, but want to use an Automation earlier in the evening to set charging times on my batteries(mostly so I can either choose to cancel it, or verify the time on the inverter)

From what I can see, the once a day targets seem to evaluate at midnight. would it be possible to have a service to trigger the evaluation on demand?

MycroftVonLipwig commented 1 year ago

I too would like to know if there is a method already, and if not then a feature for setting the evaluation time for targets.

In my use case its for charging from agile slots, the cheaper the better. I am currently experimenting with intermittent target for x hours which should choose the y cheapest slots. The limitation is this only works after midnight and often there is cheap energy to be had about 23:00 which would be missed out on as im looking for the 8 cheapest slots prior to 9am before my solar panels can be used. So i have to add 00:00 to 09:00 as a boundary to the target sensor otherwise it may end up choosing 4 slots in the am and then another 4 in the pm as those were the cheapest in a 24 hour period… but not useful when i needed the battery full so not to be pulling from grid at peak times as 4 slots will not make it through the day.

So I would like the evaluation for sensors to occur at say 7pm so then i can tell the target sensor to turn on for each intermittent slot between 8pm and 8am. It cant be achieved in two target sensors as in order to choose the cheapest slots it has to be one sensor otherwise the cheapest of slot one late eve may be very expensive but cheapest for that time then second target sensor has cheap which is irrelevant now as you have used expensive for no reason other than eval time is midnight onward only.

If the eval time is hard coded, happy to just change there but would be nice if that was a variable that is exposed to HA as a gui option if possible.

BottlecapDave commented 1 year ago

These two are very interesting scenarios. While I think a service is probably the wrong way to go, it sounds like you want to force the evaluation to over night. Therefore I might look at doing something similar to Home Assistant and support where the end time can be set to "before" the start time (e.g. start time is 22:00 and end time is 05:00)

MycroftVonLipwig commented 1 year ago

So for my scenario, and my apologies if i have hijacked your thread @corvus2606 but I think our desire for target rates evaluation to be variable is the same just from different angles. I apologise if I am wrong. For my scenario a picture is worth 1000 words.

89608B72-3AE6-40BB-A8BE-2B07160DFC98

You can see as the eval is midnight, my target rate of 4 hours intermittent would miss out on the cheap rates/negative rates prior to mid night. i have had to set start time to 00:00 and end to 09:00. This is so my battery is charged 100% before morning and not randomly throughout the day which with intermittent could and has left me pulling from grid at peak times as some were cheapest in the am and more in the pm. For me if the eval time was the same time the new rates for agile was published (4pm) or variable or after 4pm but before 00:00, i could charge from 8 cheap slots from 22:00 to 09:00. quite often the cheapest rates are in this range not after 00:00 only.

corvus2606 commented 1 year ago

My use case is more so I can see the next time when i check in the evening, it's not necessarily to have a period run from after midnight until the next morning.
That said, I think it would be very useful to have that ability, and I've learned to trust my setup and it hasn't failed me. robust automations ftw!

@andyvirus what are you using to populate the agile rates in that card?

andynash commented 1 year ago

@andyvirus what are you using to populate the agile rates in that card?

That looks like the Octopus Agile integration (I use it too).

@BottlecapDave The dev is no longer working on this, so you may find people coming from that integration to use this one (like myself!), and Agile-related features becoming more popular (as wholesale rates have fallen recently it makes more sense for those without the car/charger for Intelligent Octopus).

andynash commented 1 year ago

I'd like to see this too, and perhaps my similar but different use case makes more sense as a service?

Thanks for the integration @BottlecapDave! I've only just discovered targets after using it for some time and switching to Agile a week ago, and I'm using several already, great work!

Targets currently work well for relatively known quantities, such as turning on an appliance overnight with a known runtime, however more often I find I don't know (or HA cannot calculate) how many slots are needed and when they are required until near (or even at) the time the target is needed.

Specifically, I'd like to charge the car and our home battery dynamically. While there will be a default amount of energy (and number of Agile slots) required, this will change dependant on solar generation and forecast, and consumption for the battery. For the car, the time of departure will change as will the charge remaining and the total charge required.

There are three ways I think I could do this:

  1. By pulling all the slots and programmatically choosing those needed within the time available.

  2. Creating vast numbers of targets with different hours, starts and end times, the refer to the relevant one programmatically 😂

  3. By dynamically setting the start time, end time and hours required for an octopus_energy target.

I've simulated the latter, by manually configuring the target under Integrations.

This works perfectly (the correct slots are provided in the target attributes straightaway) but I know of no way of doing this via an automation or template - a service able to set those options would be perfect!

Presumably calling such a service without specifying any options would evaluate the target, and would satisfy the needs of @andyvirus and @corvus2606?

Having the target provide a set of slots either side of midnight is also essential of course.

Alternatively, without creating a service, I guess you could have a number of targets built in to the integration, and allow them to be configured via integration entities for each of the options?

It seems to me the service would be the most flexible way for my use case, and would likely be repeatably useful for many, including those on Go, Intelligent, Cosy tariffs also.

MycroftVonLipwig commented 1 year ago

@andynash So what I use for that use case for my house battery (which will likely be 10x smaller than your car is full elec) is I have 1 automation that look for battery SOC % remaining, so below 30%, between 30 and 50, between 50 and 70, between 70 and 100.

Each of the above is a "choice" condition in the Action of a single Automation. The Action for each choice is then to enable one of 4 further Automations. Depending on which automation is enabled by the above, determines how many "slots" is going to be used with the action of that to enable charging of the house battery.

At 9am I then reset all 4 to disabled so when the midnight evaluation for target rates comes round, the selection is made once more.

So for each of the 4 automations, I have 4 Octopus Agile Target rates on Intermittent, number of hours (1 hour = 2 slots, and yes you can do 0.5 as I have tried) and start time 00:00 end time 09:00. Intermittent will chose the BEST agile slots in that time frame (of time frame defined or it will default to 00:00 to 00:00 24 hours)

What I need is a way to set the time frame to 21:00 to 09:00 so that when the cheap night energy comes around I can charge using the 8 cheapest slots in that time frame.

I can't use another 4 intermittent target rates from 21:00 to 00:00 as that fails to work and if I do 21:00 to 23:59, it does not include the slot at 23:30 to 00:00 which is often one of the cheapest. Even if I could I could end up charging the battery on slots that are expensive at night then when the 00:00 to 09:00 slot come round I have wasted money as potentialy the slot prior were more expensive than these... Hence the need to evaluate the entire block of slots from prior to midnight.

Hope that makes sense. While a service would be nice, I personally would like to be able to retain the logic of automations. Just need to figure how to factor Solar forecasting into this now so not to charge as much if x hours of solar is going to be available.

@corvus2606 see https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues/88 for the rates card.

andynash commented 1 year ago

@andyvirus That all makes sense given what we have to work with right now.

If targets returned periods straddling midnight, that would clearly be more useful for overnight charging.

Our car is a hybrid so only 15kWh by the way, so usually we'd want to fill the battery, unless we know the next day will see little use and/or rates are very high. Sometimes we'd add a bit more during the day.

Regarding a service, that wouldn't be an alternative to automations, as an automation would call the service? It would simply make the result of your logic more accurate than your eg 30-40% range, by allowing you to specify an exact % instead. It would also reduce your automations to one.

For me, as things stand I'll probably need to create something myself, but targets would make things very much simpler, if they were able to straddle midnight and their options could be defined on demand.

MycroftVonLipwig commented 1 year ago

ah that makes sense. yes if the service could take the input of battery soc and determine number of slots in a dynamic target, then yeah that would be awesome.

andynash commented 1 year ago

Well I was assuming the service would remain neutral - i.e. not be tied to any particular purpose like battery charging, but the automation would still be simple - here's an example:

description: ""
mode: single
trigger:
  - platform: time_pattern
    minutes: /30
condition:
  - condition: sun
    after: sunset
    before: sunrise
action:
  - service: octopus_energy.update_trigger [or some other means of updating a trigger]
    data: [all optional]
      hours: sensor.battery_charging_slots_needed [template: ( ( battery capacity - battery SOC ) / battery charge rate per hour ) | round(0,ceil)]
      start: input_select.battery_charge_from [19:30]
      end: input_select.battery_charge_by [09:00]
    target:
      entity_id: binary_sensor.charge_battery_trigger
  - if:
      - condition: state
        entity_id: binary_sensor.charge_battery_trigger
        state: "on"
    then:
      - service: homeassistant.turn_on
        data: {}
        target:
          entity_id: input_boolean.force_battery_charging
    else:
      - service: homeassistant.turn_off
        data: {}
        target:
          entity_id: input_boolean.force_battery_charging
BottlecapDave commented 1 year ago

Thanks for all of your very detailed scenarios - they are very helpful. I plan to look at introducing the"evaluation time" suggested by @andyvirus , which can be used to set when you want the cut off time to be. This will default to the current midnight, but you could set it to something like 22:00, so it would look from 22:00 today to 22:00 tomorrow.

In the future, I'll also look at introducing a service to support updating config on target rate sensors for the more "dynamic" configuration, but this will require some further investigation.

@BottlecapDave The dev is no longer working on this, so you may find people coming from that integration to use this one

Thanks @andynash. I was made aware of this recently with the request of the inclusion of the agile card (https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues/88). However I don't want to step on the developers toes despite it no longer being maintained.

andynash commented 1 year ago

@BottlecapDave When you come to look at the service, I found this earlier, which may come in handy for setting the options 👍

BottlecapDave commented 1 year ago

This has now been updated in v5.2.0. The following changes have been made.

  1. Evaluation time didn't make sense when you included from and to time restrictions. However I've now made adjustments to the from and to times to support adjusting the evaluation period. I've included some examples in the readme to demonstrate this, but basically you set the from and to to 16:00, you adjust the evaluation period to start at 16:00.

  2. With the above changes, the from and to has also been updated to support having evaluation periods only occur overnight spanning over midnight. If you set from to 20:00 and to to 06:00 then it will find rates between 20:00 on one day and 06:00 the next day. Again some examples in the readme have been included.

  3. I've added a service for updating the config for a given target rate sensor. This first iteration won't persist between restarts. This should satisfy your example of updating the target hours on demand.

Hopefully the combination of these changes will help with your scenarios :)

MycroftVonLipwig commented 1 year ago

Thankyou! Ill test 1 & 2 tonight. changed the intermittent target sensors to 20:00 to 09:00 so will see at 20:00 when it evaluates how it goes.

  1. I will have a play with when i am more awake and can wrap my noodle around it :-)

Thanks again!

Edit: Tested and works perfectly for my use case of evaluation prior to midnight and for the defined period.

SteveHarrisHolt commented 1 year ago

HI. I'm also trying to do something similar in order to automate car charging.

I'm reading the current SOC and setting the desired target SOC. As the car charges at approx. 7.2kWh I can work out how many hours of charging I need.

I have sensors and auomations set up for most of this but I can't set the number of hours when calling the "update target rate config" service. I'm using the following to calculate the number of hours required and to ensure it's divisible by 0.5:

So if the car is currently at 80% SOC and I set the desired target to 90% this results in 1.0

If I then try to call the service using:

action: call-service service: octopus_energy.update_target_config data: target_hours: sensor.ev_charging_hrs_required target: entity_id: binary_sensor.octopus_energy_target_ev_target_rate_sensor

I get an error stating "Failed to call service octopus_energy/update_target_config. Target hours must be in half hour increments."

BottlecapDave commented 1 year ago

Hi @SteveHarrisHolt, there was an issue in the release when used with templates so I've issued out a fix (v5.2.1). In addition, I've updated the readme with an example of how you might create an automation using this service.

Unfortunately, I setup the service with the wrong type around target hours, and instead of fixing and introducing a breaking change I'm going to leave as is and fix in the future when I need to introduce another breaking change.

I hope this works out for you :)

SteveHarrisHolt commented 1 year ago

Hi Dave, that's great. Many thanks for the reply and the great integration.

SteveHarrisHolt commented 1 year ago

I've now tried this. I've created an input_number.test_number helper to use as a test. I've then created the following automation:

When I change the value of input_number.test_number I get the following in the automation trace:

_Triggered by the state of input_number.test_number at 17 January 2023 at 08:14:14 Octopus Energy: Update target rate config Stopped because an error was encountered at 17 January 2023 at 08:14:14 (runtime: 0.03 seconds) expected str for dictionary value @ data['targethours']

Any help much appreciated.

MycroftVonLipwig commented 1 year ago

I think I have found a bug with the overnight intermittent target rate.

So I have a 4 hour intermittent target sensor. This last night worked as expected (though was not what was required last night so just fyi). The 3 hour intermittent target sensor chose/turned on 5.5 hours from 20:00 to 09:00 The 2 hour intermittent target sensor chose/turned on 4.5 hours from 20:00 to 09:00 The 1 hour intermittent target sensor chose/turned on 2.5 hours from 20:00 to 09:00

So oddly the 4 hours from 20:00 to 09:00 worked as expected, selected 8 x 30 min slots at the cheapest rates from 20:00 to 09:00 the following day.

Let me know what detail to provide: Top of image is the Battery charge status followed by: The 4 hour intermittent target sensor The 3 hour intermittent target sensor The 2 hour intermittent target sensor The 1 hour intermittent target sensor As you can see last night I only needed 3 hours but the sensor actually turned on for 5.5 hours not 3.

16-17-Jan-2023

Any ideas why this may be?

SteveHarrisHolt commented 1 year ago

@andyvirus Do you have the sensor set to evaluate once per day or multiple times? If the latter, would that explain the charging pattern (e.g. the 1 hour pattern has a maximum charge time of 1 hour, the 3 hour has 3)? It may be charging, then re-evaluating and charging again on the lowest rates after that time.

MycroftVonLipwig commented 1 year ago

@SteveHarrisHolt it would but no, its set to Once per day, same as the 4 hour target sensor which works as expected, or did last night anyway.

3 Hour Target Sensor (MPANs Partly Redacted): Screenshot 2023-01-17 at 10 56 17

That said.... @BottlecapDave Does the new evaluation ONLY evaluate at "minimum time to start the device" or does it ALSO evaluate at midnight as it used to before this new function was added? So Is there now effectively a re-evaluate forced at midnight on top of the the new optional evaluation time?

andynash commented 1 year ago

_Triggered by the state of input_number.test_number at 17 January 2023 at 08:14:14 Octopus Energy: Update target rate config Stopped because an error was encountered at 17 January 2023 at 08:14:14 (runtime: 0.03 seconds) expected str for dictionary value @ data['targethours']

I too had the problem with the type for the target_hours, even after adding "| string".

I messed around with various seemingly valid yaml formats and in the end found this was the only way to make it work error-free:

target_hours: | "{{ states('sensor.battery_charge_hours_needed') | string }}"

N.b. I've had to include these two lines as separate sections of code, as otherwise Github seems to concatenate them on the same line. It was specifically having them on separate lines which got this working.

SteveHarrisHolt commented 1 year ago

Thanks @andynash that works for me.

MycroftVonLipwig commented 1 year ago

@andynash and @SteveHarrisHolt I would love to see how you have set up your automations to dynamically charge/select hours based on capacity of the battery. I feel I am doing this is a primitive way but it does work (well sort of)

OK so the 3 hour sensor for tonight has selected the 6 best half our slots from 20:00 to 00:00 by the looks of it instead of selecting the 6 cheapest slots from 20:00 to 09:00.

Name - 3hour_overnight_intermittent_charge Hours - 3 Type - Intermittent MPAN 27000041xxxx Rolling target - false Start time - 20:00 End time - 09:00 Is target export - false

Target times

Next time - 17 January 2023 at 20:00:00

But from 00:00 to 09:00 there are 8 sub 30p but they are not selected and higher cost times have been as they are prior to 00:00.

So does the logic select x cheapest slots from start time to finish time OR is it selecting 6 slots from start time to 00:00 then at 00:00 selecting additional slots?

Ill change back to 00:00 to 09:00 for now.

SteveHarrisHolt commented 1 year ago

@andyvirus At the moment I'm looking at the rates on the OE website then setting a price per kWh below which I want the battery to charge. I have a 5kWh battery so it takes about 2 hours to charge fully. At the moment I use the current_rate trigger to switch the battery mode to charging (when below the price threshold) or consuming (when above). This way, the battery will charge in 30 minute cycles. The idea is to look at the current charge and determine how many hours it will take to reach 100% and use @BottlecapDave 's new target_hours to control the charge so I don't have to check the rates and set the threshold each day.

I'm also looking to do something similar with the car. That charges at about 7.2kWh so will determine the number of hours required to get from current charge to target charge and set accordingly. I'm also considering leaving the target charge in the car set at 100% but use HA to control the desired target charge so I don't have to change the target in 2 places.

BottlecapDave commented 1 year ago

Triggered by the state of input_number.test_number at 17 January 2023 at 08:14:14 Octopus Energy: Update target rate config Stopped because an error was encountered at 17 January 2023 at 08:14:14 (runtime: 0.03 seconds) expected str for dictionary value @ data['target_hours']

Hi @andynash and @SteveHarrisHolt. Sorry that you encountered this issue, but I think this is something in HA's domain rather than this integration's. However I'm glad that you found the solution similar to in the docs.

OK so the 3 hour sensor for tonight has selected the 6 best half our slots from 20:00 to 00:00 by the looks of it instead of selecting the 6 cheapest slots from 20:00 to 09:00.

@andyvirus I think this might be related to https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/issues/123, which is where the target rate sensor is caching calculated rates and not recalculating until they're all in the past. This was done to speed up the states. However I think it might also be due to it being calculated using partial agile rates. So I'll look at a fix for that as soon as possible.

So I have a 4 hour intermittent target sensor. This last night worked as expected (though was not what was required last night so just fyi). The 3 hour intermittent target sensor chose/turned on 5.5 hours from 20:00 to 09:00 The 2 hour intermittent target sensor chose/turned on 4.5 hours from 20:00 to 09:00 The 1 hour intermittent target sensor chose/turned on 2.5 hours from 20:00 to 09:00

...also not too sure what's happening here, but might be related. Need a bit more investigation.

Sorry again everyone for the issues you're having.

SteveHarrisHolt commented 1 year ago

@BottlecapDave Not a problem, we appreciate the work you do.

MycroftVonLipwig commented 1 year ago

@BottlecapDave No need to apologise, as @SteveHarrisHolt said: we appreciate the work you do. End of the day you are helping us as we are unable (i know i am at least) to do this with out the kind effort of someone like yourself. Bugs are to be expected in my opinion. Thanks again!

BottlecapDave commented 1 year ago

Hello again - this should now be fixed in the new release (https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/releases/tag/v5.3.0). If you could let me know, that would be great :)

MycroftVonLipwig commented 1 year ago

@BottlecapDave I have been running for 2 days now and all seems fixed. I will continue to test but last 2 days it seems to have selected the cheapest slots of the time period. Thankyou!

BottlecapDave commented 1 year ago

Glad to hear. I'm going to close this issue as the original request has been implemented.

MycroftVonLipwig commented 1 year ago

HI. I'm also trying to do something similar in order to automate car charging.

I'm reading the current SOC and setting the desired target SOC. As the car charges at approx. 7.2kWh I can work out how many hours of charging I need.

I have sensors and auomations set up for most of this but I can't set the number of hours when calling the "update target rate config" service. I'm using the following to calculate the number of hours required and to ensure it's divisible by 0.5:

  • platform: template sensors: ev_charging_hrs_required: value_template: "{{ (((states('input_number.desired_ev_charge_target') | float(80) - states('sensor.audi_e_tron_state_of_charge') | float(0)) /7.2) | round (0, 'ceil')) /2 | float(0) }}"

So if the car is currently at 80% SOC and I set the desired target to 90% this results in 1.0

If I then try to call the service using:

action: call-service service: octopus_energy.update_target_config data: target_hours: sensor.ev_charging_hrs_required target: entity_id: binary_sensor.octopus_energy_target_ev_target_rate_sensor

I get an error stating "Failed to call service octopus_energy/update_target_config. Target hours must be in half hour increments."

@SteveHarrisHolt I am trying to set up a similar sensor. I have it working, as in it's returning a value but how does this determine the battery capacity?

So I have a 9.5kwh battery, it is 70% charged, I want to change to 100% (100%DoD Battery). I have the input.number desired set to 100 yet I get a value of 7.0. At a change rate of 2.4Kwh which is approx what my inverter can handle (2.6 really but base load on house is about 200w)

My Config:

template:

I don't get what float(80) means but also don't see where capacity is defined. Apologies if obvious, I am reasonably new to HomeAssistant and YAML.

My goal is to charge with what ever the cheapest slots are so the following day I don't use the cap price. If there is solar to be had then I will adjust input_number.desired_house_battery_charge_target accordingly based on forecast. So in summer that would be 0 but right now anywhere from 50 to 100 forecast dependant.

Any help appreciated as dynamic charging would be the ideal.

SteveHarrisHolt commented 1 year ago

@andyvirus

float(80) converts to a float but sets the value to 80 (so 80% for target charge) if an error occurs (e.g. the target charge can't be read). I also found an error in my calc so I think yours should read:

{{ (((states('input_number.desired_house_battery_charge_target') | float(100) - states('sensor.givtcp_dx2226g096_battery_soc') | float(0)) /2.4) | round (0, 'ceil')) | float(0) }}

My ev battery is 95kWh so just assumed 100 kWh to keep things easy.

As you'll need to keep to multiples of 0.5 hrs I'd change your code to work out how many half hour periods you'd need (by halving the charge rate) then divide this by 2:

{{ (((((states('input_number.desired_house_battery_charge_target') | float(100) - states('sensor.givtcp_dx2226g096_battery_soc') | float(0))/100*9.5) /1.2) | round (0, 'ceil')) | float(0)) /2 }}

Using: desired soc: 100% current soc: 70%

This should resolve as

(100-70)/100*9.5) to give the required 30% charge of a 9.5kWh battery (so 2.85kWh) which would take 3 charging periods so 1.5 hours

MycroftVonLipwig commented 1 year ago

@SteveHarrisHolt Thankyou! That works!