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

EV charging support/integration #121

Open
mergwyn opened this issue Feb 13, 2024 · 210 comments
Open

EV charging support/integration #121

mergwyn opened this issue Feb 13, 2024 · 210 comments
Assignees
Labels
enhancement New feature or request long term Good idea but not a priority

Comments

@mergwyn
Copy link

mergwyn commented Feb 13, 2024

Is your feature request related to a problem? Please describe.
I'm all electric at home with ASHP, Solar, storage and and an EV charger. PV Opt does a good job of managing my solar and storage but I also need to be able schedule EV charging

Describe the solution you'd like
I'd really like pvopt to ensure that charging the EV is synchronised such that ir does not discharge the storage battery. At its simplest level the EV is just another battery which needs be charged to a target SOC in the cheapest slots so hopefully there is an overlap in the algorithm. This could either be done fully within PV Opt or via hooks that allow users to build their own automation using the results (eg publishing x cheapest slots)

Describe alternatives you've considered
At the moment, I am using zappi 'agile knowledge' to set a schedule that only charges when the tariff is below a certain level, but obviously this may or may not cause the storage battery to discharge. (I also have to change schedule manually depending on the latest tariff)

I've tried using Predbat, but this is soo complicated and I've not been able to understand the charging plans it puts together and am struggling with the amount of 'hold' and 'reserve' charging that does on.

Additional context
I understand that this might not be where you want or need to take PV Opt and appreciate all that you have done so far. I wish I could program in python to help out but that it beyond me! If I can help in any other way please let me know.

@SzosszeNET
Copy link
Contributor

SzosszeNET commented Feb 13, 2024

Like this idea. While you get a response as an alternative not sure if you looked into it, but zappi seems to have its own integration.
https://github.com/CJNE/ha-myenergi

Could imagine to have both, and create an automation (under settings in HA) if not already one in the myenergi repo, that would watch the myenergi integration and if it's scheduled to charge, at the beginning of the charge window:
Stop AppDaemon (or maybe less drastic to set pv_opt to read only)
Set a static charge window to the inverter (to hold charge
Just to be sure 00 the discharge window and current

And potentially a second one that would start AppDaemon when the myenergi charge is finished/is outside the charge window?

@fboundy
Copy link
Owner

fboundy commented Feb 13, 2024

Keen to support this as an idea but I don't want to get as complicated as PredBat!

One starting point would be the entity that already exists called switch.pvopt_charge_active - this is On when pv_opt is charging so is a good starting point. If I knew how much charge your needed for Zappi in a given window and at what rate I could probably call the zappi integration too.

It sounds like installing the Zappi integration would be a start. I would then need to know what sensors and services it exposes.

@mergwyn
Copy link
Author

mergwyn commented Feb 14, 2024 via email

@fboundy fboundy added the long term Good idea but not a priority label Mar 20, 2024
@stevebuk1
Copy link
Collaborator

stevebuk1 commented Mar 23, 2024

Seconded for an EV integration. I'm on IOG so all I'd be looking for is a "hold SOC" whilst the EV is charging. I'd prefer a charge current = 0 to do the hold function rather than setting Backup/Reserve, as in Backup/Reserve my inverter doesnt respect Bit 6 in the Energy Storage register to prevent grid charging, causing oscillations between full rate charging and full rate discharging during EV charging. This rules me out of Pv-opt for now.

I'm currently running Predbat and am contributing to Solis code changes for IOG, but I can see that the fundamental way it works is never going to work properly for Agile due to GivEnergy functions Solis inverters just don't have (like Freeze Charging) - and I figure one day I'll be moving to Agile.

I have an ID4 and Zappi so similar to [mergwyn] and will happily assist with Alpha/Beta testing.

@fboundy
Copy link
Owner

fboundy commented Mar 25, 2024

I think that setting charge current to zero for the Solis is a better method of holding SOC anyway so I'm about to start testing that.

How would you flag up the EV charging slots with IOG?

@mergwyn
Copy link
Author

mergwyn commented Mar 25, 2024

BottlecapDave's integration has a sensor: binary_sensor.octopus_energy_{{ACCOUNT_ID}}_intelligent_dispatching which is used to determine if you're currently in a planned dispatch period (i.e. "smart-charge" determined by Octopus Energy) or are within the standard off peak period. This sensor will not come on during a bump charge which I think is an OK limitation.

There are some limitations: https://github.com/BottlecapDave/HomeAssistant-OctopusEnergy/blob/b06499c86548847b5c75c17a487a87178f59b64a/_docs/entities/intelligent.md?plain=1#L9

This doesn't cover how to make EV charging work with Agile rather than IOG which is a harder problem I suspect. I'm probably going to switch to IOG shortly until the Autumn, so again this is a limitation I can live with for a while at least!

Thanks again for your great work on pv_opt.

@fboundy
Copy link
Owner

fboundy commented Mar 25, 2024

OK - so looking at the attributes for this would it be reasonable to assume that pv_opt should simply "hold SOC" for all entries in planned_dispatches?

@stevebuk1 - I'm a bit confused by your comment regarding Bit 6 for Energy Storage as this is the Feed In Priority bit. Do you mean this or Bit 5 which is Grid Charging? How does this interact with setting Backup Mode (Bit 4) and Backup SOC? One of the current limitations with the Solax integration is that the control switch isn't set bit-wise or by number but using a select. That said I've successfully added modes to the integration before.

@mergwyn
Copy link
Author

mergwyn commented Mar 25, 2024

For me, the ideal situation would be for pv_opt to do its thing regarding whether the solar batteries need to be charged. If this is at the same time as the EV needs to be charged (indicated by intelligent_dispatching for IOG) is it possible just to set the discharge current to zero (or some equivalent) such that both the EV and solar batteries can be charged at the same time?

@stevebuk1
Copy link
Collaborator

I'm a bit confused by your comment regarding Bit 6 for Energy Storage as this is the Feed In Priority bit. Do you mean this or Bit 5 which is Grid Charging?

Apologies, I was responding to an Issue in the Solis Inverters Facebook group where people were labelling the 8 bits as Bit1 to Bit 8, and I forgot to reset my language to the traditional LSB = 0, MSB = 7 nomenclature. It is indeed Bit 5.

Regarding the Solax integration, it currently has two options for Backup/Reserve:

"Backup/Reserve"
"Backup/Reserve - No Grid Charging".

and I imagine the 2nd one clears Bit 5.

What I was trying to say in my previous post is that there is no change in behavior between these modes (both charge from grid when battery SOC is below backup SOC), so I'd prefer using charge/discharge slots and current (amps) setting to do it instead.

@stevebuk1
Copy link
Collaborator

OK - so looking at the attributes for this would it be reasonable to assume that pv_opt should simply "hold SOC" for all entries in planned_dispatches?

Yes, this is the way Predbat works, or rather it does now in my local copy since the addition of setting charge slots and current = zero for Solis inverters. Note: I'd toyed with using discharge start/end times and discharge current = 0, but Predbat doesnt clear out old charge start/end times anyway, so I just used the charge start/end times. I guess either would work as long as there are no conflicts between charge and discharge times.

@fboundy
Copy link
Owner

fboundy commented Mar 25, 2024 via email

@fboundy
Copy link
Owner

fboundy commented Mar 25, 2024 via email

@stevebuk1
Copy link
Collaborator

I wrote some of the initial Solis code for PredBat but I gave up on it because I found it too heavily predicated on GivEnergy behaviour. I also couldn’t get my head around the optimiser which often didn’t seem very optimal for Agile.

I remember you saying in the Solis Facebook group you authored some of the code in Predbat. I've carried on making some changes and additions for getting it working in IOG (e.g. I've disabled it using Backup/Reserve mode to fix low rate charging) but the target SOC changes wildly through the 6 hours cheap rate period for what looks like no input changes (solcast, power forecast etc), resulting in a mess of high rate and low rate charging with constant writes to the inverter all night. For this reason I've just started trying to figure out the optimizer too but not encouraged by your experience. With EV hold functionality PV_opt will do the job, although getting in an electrician to add a Henley block for the Zappi is the other way ;-)

@stevebuk1
Copy link
Collaborator

Regarding consumption data, I'm not sure if the current algorithm just uses what the Solis supplied to the house as energy, or takes account of the house load coming from grid during charging slots and hold slots. If one load shifts to co-inside with charging slots to avoid battery losses (as I do) then its likely direct use of grid energy will be a significant portion of consumption, so I assume grid energy forms part of the consumption data calculations?

If the assumption is correct, then car charging is going to add to (and corrupt) any existing method of grid use being factored into consumption data.
This means the energy consumed from the grid use for car charging will need discounting from any consumption data, so it doesn't influence the charging plans for the house battery. Ultimately, we are compensating for the fact that the Solis CT clamp sees both the EV and the house as consumption.

I see 3 different ways of doing this:

  1. Assume any grid draw above 6kW will mean the EV is charging, so subtract 7kw (the actual EV charge rate) from the consumption figures
  2. Utilise a Zappi entity that tracks consumption "sensor.myenergi_zappi_{Serial number}_charge_added_session", and subtract this from the consumption figures. Note this resets to zero when the car is plugged in.
  3. Utilise the "completed dispatches" attribute within the "_intelligent_dispatching" entity mentioned above and subtract it from the consumption figures.

Apologies if this was already obvious.

@fboundy
Copy link
Owner

fboundy commented Mar 26, 2024 via email

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Mar 26, 2024

Make sense?

Not really. Looking at the log file, consumption is loaded from "sensor.solis_house_load_today". The plot of that sensor is below, and it includes the 26kWh ish of car charging that I did last night. It can't be blind to it, otherwise the we wouldn't have the problem of the house battery discharging into the EV in the first place?

image

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

OK - got it.

I think all 3 of your suggestions would work. I'd probably prioritise them in terms of what is available on a per case basis:

  1. Zappi (or other EV charger entity)
  2. IO dispatches (would only work for IO I presume)
  3. Charge threshold power which is the crudest and might pick up
    cooking Sunday Roast in error

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

I'm hoping to have something out to test later today as a pre-release I don't think it will work fully but hopefully it will log enough stuff to gather the necessary info.

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

v3.13.0-ev-beta-1 should now be available as a pre-release via HACS. It adds:

If you can load it up and check it doesn;t bust anything. If it doesn't then could you run it for at least 24 hours and then send me the pv_opt.log and error.log (if any errors occur)?

If this works OK then next step is to isolate the IO charging intervals from the optimisation.

Thanks

@fboundy fboundy added the enhancement New feature or request label Mar 27, 2024
@stevebuk1
Copy link
Collaborator

Great - I've now installed it and its up and running. Its scheduled a house battery charge for this evening (the weather in Scotland is currently awful solar-wise) and I'll plug in the car.

I assume there aren't any changes needed to apps.yaml?

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Mar 27, 2024

I think all 3 of your suggestions would work. I'd probably prioritise them in terms of what is available on a per case basis:

  1. Zappi (or other EV charger entity)
  2. IO dispatches (would only work for IO I presume)
  3. Charge threshold power which is the crudest and might pick up
    cooking Sunday Roast in error

Agree that Option1 is the best, and should easily be configurable for other chargers.
2) agree thats only useful for IO, so no use for Agile or the other tariffs
3) is crude and it would probably work for me as during the day as I try and keep all consumption below 3kW (max battery discharge rate in my 3.6kW inverter) so I don't draw from grid. Overnight is similar (I offset all appliances), but I doubt it would work for those having G99 inverters and bigger battery banks.

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

Great - I've now installed it and its up and running. Its scheduled a house battery charge for this evening (the weather in Scotland is currently awful solar-wise) and I'll plug in the car.

I assume there aren't any changes needed to apps.yaml?

Shouldn't be any changes needed. It should just check for the io and zappi entities and then spit out their contents to the log file.

@stevebuk1
Copy link
Collaborator

Apologies, I spoke too soon. I flicked the toggle on Consumption to go fixed, and have since realised that it did a restart of PV_opt ok but the first run had hung. I've now restarted AppDeamon and Pv_Opt is stuck in "Loading Tarrifs".

Error log code is:

15:58:03 WARNING pv_opt: ------------------------------------------------------------
15:58:03 WARNING pv_opt: Unexpected error running initialize() for pv_opt
15:58:03 WARNING pv_opt: ------------------------------------------------------------
15:58:03 WARNING pv_opt: Traceback (most recent call last):
File "/usr/lib/python3.11/site-packages/appdaemon/app_management.py", line 162, in initialize_app
await utils.run_in_executor(self, init)
File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 304, in run_in_executor
response = future.result()
^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/homeassistant/appdaemon/apps/pv_opt/pv_opt.py", line 407, in initialize
self._check_for_zappi()
File "/homeassistant/appdaemon/apps/pv_opt/pv_opt.py", line 472, in _check_for_zappi
for entity_id in self.self.io:
^^^^^^^^^
AttributeError: 'PVOpt' object has no attribute 'self'

15:58:03 WARNING pv_opt: ------------------------------------------------------------

I thought it might be a duplicate "self" at line 472, but removing it didnt make any difference:

16:03:22 WARNING pv_opt: ------------------------------------------------------------
16:05:16 WARNING pv_opt: ------------------------------------------------------------
16:05:16 WARNING pv_opt: Unexpected error in worker for App pv_opt:
16:05:16 WARNING pv_opt: Worker Ags: {}
16:05:16 WARNING pv_opt: ------------------------------------------------------------
16:05:16 WARNING pv_opt: Traceback (most recent call last):
File "/usr/lib/python3.11/site-packages/appdaemon/app_management.py", line 162, in initialize_app
await utils.run_in_executor(self, init)
File "/usr/lib/python3.11/site-packages/appdaemon/utils.py", line 304, in run_in_executor
response = future.result()
^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/homeassistant/appdaemon/apps/pv_opt/pv_opt.py", line 407, in initialize
self._check_for_zappi()
File "/homeassistant/appdaemon/apps/pv_opt/pv_opt.py", line 472, in _check_for_zappi
for entity_id in self.io:
TypeError: 'bool' object is not iterable

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

If you are happy to edit it yourself it's just a simple typo. Line 472 should be:

        for entity_id in self.self.io_entities:

Didn't flag in my system because it was an empty list for me and the prior if caught it

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Mar 27, 2024 via email

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

Any changes to the .py files or config.yaml should cause AD to restart it

@mergwyn
Copy link
Author

mergwyn commented Mar 27, 2024

I've also installed this version and made the edit to py_opt.py, but I get a different error:

16:45:14 WARNING pv_opt: ------------------------------------------------------------
16:46:15 WARNING pv_opt: ------------------------------------------------------------
16:46:15 WARNING pv_opt: Unexpected error running initialize() for pv_opt
16:46:15 WARNING pv_opt: ------------------------------------------------------------
16:46:15 WARNING pv_opt: Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/appdaemon/app_management.py", line 162, in initialize_app
    await utils.run_in_executor(self, init)
  File "/usr/local/lib/python3.10/site-packages/appdaemon/utils.py", line 304, in run_in_executor
    response = future.result()
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home-assistant/appdaemon/apps/pv_opt/pv_opt.py", line 407, in initialize
    self._check_for_zappi()
  File "/home-assistant/appdaemon/apps/pv_opt/pv_opt.py", line 472, in _check_for_zappi
    for entity_id in self.self.io_entities:
AttributeError: 'PVOpt' object has no attribute 'self'

I'm also seeing something I've not noticed before:

16:45:14 WARNING pv_opt: ------------------------------------------------------------
16:45:14 WARNING pv_opt: Unexpected error running initialize() for pv_opt
16:45:14 WARNING pv_opt: ------------------------------------------------------------
16:45:14 WARNING pv_opt: Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/appdaemon/app_management.py", line 162, in initialize_app
    await utils.run_in_executor(self, init)
  File "/usr/local/lib/python3.10/site-packages/appdaemon/utils.py", line 304, in run_in_executor
    response = future.result()
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home-assistant/appdaemon/apps/pv_opt/pv_opt.py", line 372, in initialize
    while (not self.inverter.is_online()) and (retry_count < ONLINE_RETRIES):
AttributeError: 'InverterController' object has no attribute 'is_online'

@fboundy
Copy link
Owner

fboundy commented Mar 27, 2024

OK hopefully 3.14.0-ev-beta-2 fixes all these issues. Too many beta versions flying around...

@mergwyn
Copy link
Author

mergwyn commented Aug 6, 2024

@stevebuk1 Thanks so much for tracking this down and supplying a fix. I've installed Beta-9 this morning and discharge slots have returned! However, as you suggest above, the timing of the slots doesn't look right: I have discharge slots at 16:30 when it makes more sense to discharge immediately before the cheap rate at 23:30.

Also, given there is good solar today and the battery looks like it will be at 100% from around 10:30 this morning, there are opportunities to discharge and then recharge from solar at at 15p per kWh nominal gain.

Here are the logs for an optimiser run starting at 10:213:23 with debug on:
pv_opt.06.log
pv_opt.05.log
pv_opt.04.log
pv_opt.03.log
pv_opt.02.log
pv_opt.01.log
pv_opt.log
error.log

@mergwyn
Copy link
Author

mergwyn commented Aug 6, 2024

@stevebuk1

If the algorithm instead tried one slot of low rate charging and then ran through all of the slots of discharging to see if that saved you any money, then it would find a battery that had spare charge in it at 11pm and discharge it. Both of these slots would then be locked in, so the next low rate charging slot added would give more energy in the battery that could be discharged in another discharge slot, and so on and so forth. I guess doing that might be theoretically possible, but wasn't chosen when Pv Opt was originally written and at first glance, would be an architectural rewrite from scratch.

I don't pretend to fully understand the subtleties of what you are saying, but I think my expectation is roughly what you describe. At a high level the goal is the same irrespective of Agile or IOG, ie to use cheap rate slots to charge the battery such that battery + solar can bridge higher rate slots. As I think you explain above the devil is in the detail!

Taking the simple case of IOG, I would hope that the algorithm can can determine whether to force discharge before the cheap rate slot, as well as not charge during the cheap rate slot if there is enough battery capacity to meet the forecast demand until solar generation can take over and start filling the battery.

Whilst I don't claim to understand Predbat (and find it hugely complicated), it does produce differer very different results for the next day or so:
Screenshot 2024-08-06 at 17 32 27

Screenshot 2024-08-06 at 17 31 28

@fboundy
Copy link
Owner

fboundy commented Aug 15, 2024

HI guys - I've been busy with other things. Should I pull a latest Dev branch yet?

@stevebuk1
Copy link
Collaborator

the timing of the slots doesn't look right: I have discharge slots at 16:30 when it makes more sense to discharge immediately before the cheap rate at 23:30.

Sorry for the delay, I had a look at the logs. All thats happenning is that the discharge algorithm runs through the slots in time order and works out if disharging for that slot saves you money - if it does that slot is "banked" (set as a discharge slot) and the next slot is tried. The 16:30 slot is the first one that saves you money, it banks the next few until it works out that banking any more doesn't save you money, in this case its because after a few theres insufficient battery to then last you to 11.30pm. In other words it is ensuring your battery is discharged by 11.30pm, and whether it does that at 16:30 or 22:00 probably makes no cost difference.

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Aug 15, 2024

HI guys - I've been busy with other things. Should I pull a latest Dev branch yet?

@fboundy Yes, its ready. I haven't made any changes since Beta9, and that was just to fix the error introduced in 3.15.4. Mines been left to its own devices for weeks now and its doing what I expect.

Longer term:

  1. I will do the Agile EV charging at some point but thats all in pseudocode at the moment.
  2. I will give the algorithm some more thought. A slight issue I have is that on a time of use tariff where the lowest cost slots are always a minimum of 4 contiguous hours, for the high cost swaps part of the algorithm theres quite a step change between doing no charging and setting inverter to hold for the full four hours i.e. using the grid for four hours. What would be cost optimum would be to hold for some of that time and revert to self use for the rest of the time. One way of doing that would be to artificially change the import price of the cheap slots so they are all slightly different, then it would use those slots first, just like it does on Agile. However that does also have disadvantages w.r.t inverter writes, and also the spreading the charging at a low charge rate would then be lost. I'm not sure the cost saving makes it worth the effort, and in any case I think is unique to those having no export tariff, which won't be many.

@stevebuk1
Copy link
Collaborator

@fboundy Yes, its ready. I haven't made any changes since Beta9, and that was just to fix the error introduced in 3.15.4. Mines been left to its own devices for weeks now and its doing what I expect.

@fboundy I forgot to add the PR is already raised.

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 1, 2024

@mergwyn: just to let you know I'm probably only a couple of weeks away from a beta release that will do car charging on Agile.

I've largely based it on how IOG works, as thats all I know:

  1. a "candidate plan" will be generated on each optimiser run, based on the car battery capacity, a "% charge to add" setting, a "ready by" time and a 'max price per slot' setting
  2. upon car plugin the candidate plan will be transfered to an 'active plan'.

The active plan remains fixed unless updated via an HA button press, or if 4pm is reached (new Agile rates are available)

For a first release I think 'charge to add%' keeps it simple and allows an external automation to set it based on battery capacity, target charge and car current SOC - this is what I currently do on IOG with two EVs and it works well.

I'm thinking that a "little and often" strategy is best for Agile, in that you'd plug the car in most nights and set a max cost. If you really needed it to be full for the next day then you'd up the max cost and let the car charge in accordance with charge to add.

Obviously all this will be integrated with current Pv_opt functionality so that any car charging doesn't discharge the house battery. In my trial runs I've found the EV wants more slots than the house, but in your situation I'd imagine its the other way around.

Given your previous experience with EV charging on Agile do you think this generally what you'd expect?

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 1, 2024

@mergwyn I forgot to add that for now I'm just going to quantise the EV charge plan to 1/2 hour slots, i.e for a 7kW charger the plan will be 3.5kWh or 7kWh or 10.5kWh and so on. The algorithm will always round up - i.e. it will not leave you with a lesser percentage charge than requested. Will consider something more complex based on kWh tracking and/or actively redoing the plan based on car SOC incrementing at a later stage. I think with a large car battery then a 3.5kWh resolution is an acceptable approximate.

@mergwyn
Copy link
Author

mergwyn commented Sep 5, 2024

Hi @stevebuk1

Given your previous experience with EV charging on Agile do you think this generally what you'd expect?

Yes this is just about what I'd expect. I did have a thought: I pretty much have the car plugged in every night - I think I need to comfort blanket of knowing that the car will be charged when I need it in the morning. I assume that even when increasing the max cost, pv_opt will always use the cheapest slots to achieve the charge?

I think with a large car battery then a 3.5kWh resolution is an acceptable approximate.

This sounds reasonable.

Thanks for all your work on this!

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 5, 2024

I pretty much have the car plugged in every night - I think I need to comfort blanket of knowing that the car will be charged when I need it in the morning.

To achieve this, set max cost to something like 40p. This then will schedule enough slots to ensure the car gets the "charge to add %" by the "Ready by" time that you set.

I assume that even when increasing the max cost, pv_opt will always use the cheapest slots to achieve the charge?

Yes, it will always use the cheapest slots (between plugin time and ready by time, to achieve the charge it needs), regardless of the max cost setting.

I tend to charge once a week and add about 40kWh, so the concept of a max cost was that I'd set a level I'd be happy with paying, and plug in every night. Some nights I'd then get maybe nothing and other nights I'd end up with a full charge. Whilst writing the code though, I've noticed that Agile is either generally expensive or generally cheap, so maybe its of limited use, in which case set it to max and forget about it.

I think with a large car battery then a 3.5kWh resolution is an acceptable approximate.

This sounds reasonable.

Thanks. Its only for the first release. I'll sort out something that measures kWh and can charge for partial slots later, once the bugs are ironed out on the interfacing. I think it will be worth it as the partial slot will always be the most expensive slot. The big unknown is the Zappi itself, which I'm certain will actually apply random delays to the start/stop commands its sent, which may then mean its not worth doing.

@stevebuk1
Copy link
Collaborator

@mergwyn I've now finished development and have started testing (which I can do by forcing the Agile tariff).

Let me know if/when you swap back to the Agile tariff and I'll find a place to upload the new code.
(As my last PR is still outstanding, it probably won't be to the Dev fork)

@mergwyn
Copy link
Author

mergwyn commented Sep 19, 2024

@stevebuk1 that's great news. Notwithstanding the price increase announced today, the Octoprice app is suggesting that it currently doesn't make sense for me to swap to agile until February 2025!

IMG_3361

@stevebuk1
Copy link
Collaborator

lol - ok no rush then!

Its relatively easy for me to test anyway, even with live EV charging - I just do a tariff override in config.yaml and turn off smart charging in the Octopus app. I note that in reality IOG smart slots tend to follow Agile relative pricing which I guess isn't a surprise. I'll carry on with testing and also add the other bits and pieces like partial slots.

@fboundy
Copy link
Owner

fboundy commented Sep 21, 2024

@stevebuk1 - testing this on my system now. There is something funny going on with the `_create_windows' method. When the current slot has (say) 3500W but there is only 15 minutes left it is scaling this up to 7000W which the inverter cannot physically do. This is down to this comment:

        # However, a factored "forced" value means that it result in a seperate charge window for the remaining time, and for IOG that will result in needless
        # writes to the inverter every 10 minutes and an increasing charge power towards the end of the night to compensate.
        # As the .flows calls are all done with now, the "forced" power can be set back to what the inverter needs it to be, which is the original value prior to factoring```

It seems to be complicating what should be a very simple method.  If this has do be done here for the IOG logic to work then I suggest you put a switch in so that it is only done for IOG and the original logic is kept for non IOG setups

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 21, 2024 via email

@fboundy
Copy link
Owner

fboundy commented Sep 22, 2024

To be clear the optimiser returns the optimum power for the remainder of the 1st period. If we are already in the 1st period the SOC at the end is calculated on the remaining time at that power but I'm struggling to see why the power itself would need adjusting, Maybe I'm missing something.

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 22, 2024

I've checked my design notes; reproduced below. (the logging excerpt is pre the mods)

image

Why when 10 mins into a slot does the forced power decrease?
The factor is a representation of how much of the slot window is left. This should not decrease the power, but it probably does it to ensure .flows doesn’t have to be time aware, so factoring power is done so that energy transfer is factored. However the inverter still needs the same power regardless of how many minutes it is into the current slot, which it gets from 'forced'. We need to factor that back up by the same amount it was reduced by.

Problem - the factoring back up will assume the same factor has been applied for each high cost swap. This is a valid assumption unless the slot is full, then reversing the factor will result in a charge rate higher than the converter can do. However - does this matter? .flows remains correct, and the inverter cannot do more than it is capable of, so should be ok? For a 3.6kW inverter its only ever going to occur for people who have more than 20kWh of batteries.

For Agile any charging slots will always tend to be full because the high cost swaps fill one 1/2 hour slot at a time (the cheapest), but for time of use tariffs with a fixed cheap rate period (Octopus Go, Octopus Intelligent Go, Eco 7 etc) the algorithm spreads the charge equally between all slots for each high cost swap. Its very unlikely that any slot is full for any of these tariffs, i.e. you'd be needing to charge at full rate all night. However, the reverse is true for Agile - its very unlikely that any slot is not full. When the slot is full, factoring back up isnt needed and causes the issue you've seen.

I'll spend some time trying to sort a better solution that suits all tariffs. One could easily solve the problem by treating the constant cheap rate tariffs like Agile in that each high cost swap gets allocated to a particular slot until its full, then another is chosen, but I do like the the fact that high cost swaps are spread across all slots of the same price because it means a constant low charge rate all night which IMHO is better for the inverter.

@fboundy
Copy link
Owner

fboundy commented Sep 23, 2024 via email

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Sep 23, 2024 via email

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Oct 22, 2024

Hi @mergwyn, I presume you are running on Beta-9 still and its working ok for you. I've mostly finished the Agile EV charging now on another branch. However there are other issues that I'm working on that require changes to fix, and the overhead of maintaining 3 separate branches has come to a head.

To alleviate this I intend to merge them all together so I can work on one code set. I'll be doing this over the next couple of days. You are free to continue to use Beta-9 but the next version with the resultant merge will involve a change to an entity name that Pv_opt uses to display the Car charge plan results. Basically sensor.pvopt_iog_slots is renamed sensor.pvopt_car_slots, to reflect that the latest code supports more than just IOG. I'll provide an updated dashboard with the edits in it but thought I'd point this out if the dashboard you are using is heavily customised and it breaks without warning!

@mergwyn
Copy link
Author

mergwyn commented Oct 22, 2024

Hi @stevebuk1 , yes I'm still using beta-9 with no issues. I've not customised the dashboard so it will be trivial to drop that in when you are ready. It still make sense for me to stay on IOG for the moment but I will almost certainly be on agile before Christmas.

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Oct 23, 2024

Thanks for the explanation. Let me think that through and see if I can come up with something. If I understand correctly that logic would apply to any tariff with a fixed price not just IOG so Flux, E7 etc. It may be down to the way the factor is applied in pvpy.py. That would be a better place to sort it.

@fboundy not sure if you are looking at this but after a lot of head scratching and pondering I can now properly see the issue. I also manged to replicate the issue in Agile when we had a lot of overnight slot prices being of identical values. I think the fix is relatively simple: SCPA needs a factored lower limit when partway through a slot to act as the "slot full" indicator. Then we reapply the reverse before loading the charge current to the inverter. This will then work for all tariffs. I'll move it to pypy.py as you suggest.

I think it's a simple as storing "forced" for the 1st entry in a local variable, doing all the
factoring (in the partial slot and then between all slots) for each high cost swap, and then restoring the value of "forced" at the end? My only concern was that we do the partial slot first and then factor between all slots, which in my head would mean a different factor applied to the other slots when 5 or 10 mins in on the current slot, but I'm not sure I've seen that actually occur.

To confirm, it does occur, and should occur. The algorithm to apply slot factors to all slots of the same price and to a slot already part way through is entirely correct. So storing forced is not the right answer, factoring SCPA is.

@stevebuk1
Copy link
Collaborator

stevebuk1 commented Oct 30, 2024

I'm picking up from Facebook groups that IOG charge plans are now going to include extra metrics from the grid and thus dynamically update overnight more frequently. Whilst IOG charge plans have always been subject to update, it now appears it will be a more regular occurrence and I've seen this happenning over the last few nights.

For those running Beta-9 (or later), the charge plan is loaded on car plugin and updated at midnight and at 4:40am, but if frequent reschedules are now going to be a thing a better plan will be to update on each optimiser run - the overhead is likely minimal as it is just a case of reading "planned_dispatches" from the Octopus Energy integration. I'll endeavour to make these changes over the next week or two.

@stevebuk1
Copy link
Collaborator

For those running Beta-9 (or later), the charge plan is loaded on car plugin and updated at midnight and at 4:40am, but if frequent reschedules are now going to be a thing a better plan will be to update on each optimiser run - the overhead is likely minimal as it is just a case of reading "planned_dispatches" from the Octopus Energy integration. I'll endeavour to make these changes over the next week or two.

Fixes made in 3.17.0-Beta-12 for the above: car charging plan now reloads every optimiser run.

https://github.com/stevebuk1/pv_opt/tree/dev/apps/pv_opt

Note, the slot prices used for house battery charging are currently not reloaded. I'll keep an eye on this over the next week or two but suspect its not needed - if anyone sees any battery charging after 5.30am in a slot originally deemed cheap but then cancelled, let me know.

@stevebuk1
Copy link
Collaborator

I agree that pypy.py is the place to do this. It will affect all tariffs where it's unlikely any one slot will be full, which I think is all tariffs that have multiple cheap slots all at the same price. i.e for uses of Go that have a 10kWh battery and 3.6kW inverter, I'd never expect any full slots because one can fully charge the battery in four hours at a power of less than 3kW (the max battery charger power)

@fboundy I've now fixed this. As you suggested it wasnt complicated. I now note that self.initial_soc is designed to maintain a fixed starting value throughout a half hour slot, which means the following code which applies a factor if partway through a slot is not longer needed:


                            for slot in window:
                                if pd.Timestamp.now() > slot.tz_localize(None):
                                    factors.append(
                                        (
                                            (slot.tz_localize(None) + pd.Timedelta(30, "minutes")) - pd.Timestamp.now()
                                        ).total_seconds()
                                        / 1800
                                    )
                                else:
                                    factors.append(1)

The fix is to change to:

                        for slot in window:
                            factors.append(1)

There are no further fixes required - SCPA can remain as is.

I've yet to PR to your repo as would like to test for a few more weeks.

@stevebuk1
Copy link
Collaborator

I've fixed a fairly major bug in that when I merged the changes made to support the Solarman integration with updates from the production code, the "Update times" button on the Solax integration was only then pressed if end minutes changed. Updates to the other times were not written to the inverter. Whilst most of the time on IOG this works as the end minutes is set to 30 on a charge plan and 00 when it finishes, any additional slots allocated beyond 5:30 ending on the hour would mean that end hours, start hours and start minutes wouldn't get loaded.

3.19.0-Beta-21 fixes this, available at both
https://github.com/stevebuk1/pv_opt/tree/dev/apps/pv_opt
and
https://github.com/fboundy/pv_opt/tree/dev/apps/pv_opt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request long term Good idea but not a priority
Projects
None yet
Development

No branches or pull requests

5 participants