Repository navigation
Charge the car on forecast solar surplus - #5195
romain-intel wants to merge 9 commits into
Conversation
|
I reopened this because I didn't get any feedback on the other one so I wondered if it fell out (it was old). Apologies if you meant to just not merge them (in which case I will stop keeping them in sync and just maintain my own branch). |
|
@romain-intel I hope this gets merged one day. |
|
@romain-intel good idea to re-raise it. I had a similar experience of a PR that got overlooked and then was 3 months behind in a backlog of other PR's. Seems a good idea, does it keep the existing Predbat cost optimisation approach, i.e. takes account of export rates and overnight import rates in deciding whether to charge the car or not from solar? Needs @springfall2008 to review |
|
Yes, it does keep the optimization. You can set a priority for the powerwall in the current PR. I am actually revamping it right now because I didn't like that too much. Now what you will be able to have:
Anyways, short answer is that yes, it does take into account export and import rates. For me right now for example, since I am in CA and export rates are high for 2h per day in Aug and Sept, it's been not charging the car as much and instead charging the battery to be then able to export it. I've been pretty good over the past two months and have accumulated several hundreds of $ in "credits". I should write up how I got it setup, it was a bit annoying to "trick" the Powerwall to export when I wanted to but now it does quite well. If you want to install the full version I am running btw, just use the main branch on my fork. You just need this line in your apps.yaml: NOTE: It works for me but I haven't tested very widely. It also has a bit of configuration in apps.yaml and what not. Happy to take feedback though if you have suggestions. |
|
@romain-intel ok but you keep your fork updated like the official one? Because the update rate is crazy... |
|
I've been updating fairly regularly but as you see it's out of sync. I'll get it resyncd and updated. I actually want to test out my new feature with the 'ready by time' so i'll do that either today or this weekend. And yes, it is winter but I do want to see if it still handles everything. |
Car slots were placed on import price alone, with no awareness of sunshine, so a car could be scheduled to buy energy overnight while the next day's surplus was exported instead. New switch.predbat_car_charging_solar (off by default) places slots on forecast PV first, and because the existing loop stops once the car's requirement is met, the price-based pass then only covers the shortfall. A slot qualifies on two tests, mirroring the pair iBoost already has for the same "divert rather than export" decision: - forecast PV power at least car_charging_solar_excess (default 1kW) - export rate no higher than car_charging_rate_threshold_export (default 99p), which is what "it isn't worth exporting" means in practice car_charging_plan_min_soc splits the plan in two, for setups where only part of the charge is worth paying for. Bought slots stop at that percentage and must complete by the ready time, so it is the charge guaranteed whatever the weather; solar slots carry on past it to the full car_charging_limit. Left at its 100% default both targets are identical and nothing changes. This mirrors the minimum slider in Tesla's Charge on Solar, so Predbat's forecast of the car's draw can be kept in step with what the car will actually do. Because solar is opportunistic rather than a promise, solar windows run to the forecast horizon while bought windows stop at the ready time - otherwise an early morning deadline would exclude every daylight hour. Overlapping candidates are planned once, and solar windows bypass car_charging_plan_max_price since their energy is not bought. They are priced at the export rate given up, which is their real cost. Slots carry a solar flag through to the car plan attributes. Car planning now runs after the PV forecast is fetched rather than before it; nothing between the two positions reads the car plan. No new mechanism was needed for the battery-versus-export trade-off: the car's demand is already part of the prediction, so an export that drains the battery is priced against the import the car then needs. Measured with car_charging_from_battery on, a 5p export rate keeps the charge and 60p sells it, and letting the battery serve the car cut grid import from 8.4kWh to 6.4kWh. Pinned by a test, since it is not obvious from reading either module alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit adf0db9e17c681b6439b5d8c1077f001d9873d3d)
…'s rating A charge-on-solar charger modulates to whatever the sun leaves over the house, but the plan assumed it drew its full rated power for the whole slot - a 7kW charger booked 3.5kWh into every half hour regardless of whether there was 7kW spare or 1kW. That error does not stay inside the car plan. The car's predicted draw is part of the load the battery is planned around, so demand the sun cannot meet went into the forecast and the battery looked like it had to cover the difference, skewing the charge and export decisions that followed. Solar slots are now sized as forecast PV less forecast house load, capped at what the charger can take. Surplus is computed per five minute bucket and floored at zero in each, because a car cannot charge on an average - a bright half hour either side of a dark one yields the bright half, not their sum. The same measure now backs the car_charging_solar_excess gate, which is what that setting's name has always claimed: 4kW of sun against a 4kW house left the car nothing and used to qualify anyway. The house load forecast this needs is the one calculate_plan builds, which does not exist yet when car slots are planned during the fetch, so it is rebuilt here from the same inputs. Car planning moves after the modal filter, the historical load forecast and load_inday_adjustment, all three of which feed that load; nothing in between reads the car plan. It is built once per car plan rather than per window, as step_data_history walks every previous day for every bucket. The historical load it derives from already has car charging subtracted out of it, so the car's own draw cannot feed back in as house load. Bought slots are unchanged: there Predbat is asking for the charger's full rate, and gets it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit e2c6863667b8d0e5fae6a015ad05a39e06009437)
New input_number.predbat_car_charging_solar_battery_soc, default 0% so nothing changes for anyone who leaves it alone. Below that level surplus solar goes to the house battery and no car window is offered; at or above it the car has first call as before. Solar car charging gives the car the surplus whenever there is any, which is the right default but not always what is wanted: a car that does not need a full charge today is a worse home for a kWh than a battery facing an expensive evening. This is the mirror of car_charging_plan_min_soc - that one caps how much of the car you pay for, this one says how much battery you want banked before the car is worth more than the pack. The level is judged per slot from a battery estimate walked forward as the held surplus fills it, not from the SoC at planning time, so a pack that reaches the level mid-morning releases the car mid-morning rather than holding all day. What the battery cannot physically absorb within a slot is not held back either, since that surplus would otherwise be exported at whatever midday pays. The value is clamped to 0-100 rather than trusted, so a mistyped level cannot produce a threshold above the pack that holds the car back forever. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New select.predbat_manual_car_away, a per-slot override in the same shape as the other manual overrides. Slots marked away are skipped when planning car charging. car_charging_planned reports whether the car is plugged in now, which is exactly right for deciding whether to charge in this moment and no use at all for planning. A plan made this morning will schedule an afternoon charge for a car that is going to be out, and only discovers otherwise when the afternoon arrives - by which point the surplus it reserved has been spent on nothing. Marking the afternoon away instead lets Predbat move the charge to a slot the car is actually there for, and use the sun it would have spent on the house battery. Skipped entirely rather than shortened or repriced: a car that is not there cannot take cheap import or surplus solar, so there is nothing to reprice. The test sits before the have-enough check rather than after, or the first away slot would break out of the loop and take every later slot with it, silently emptying the plan - which is what the second regression test pins. Overlap rather than an exact start match, so a marker suppresses any window it touches rather than only one beginning on the same minute. Deliberately not added to manual_all_times: that set forces charge and export windows into existence, and this does the opposite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hile it is here The battery-priority hold assumes the car can catch up later, which stops being true the moment the afternoon is marked away. With the level at 100% the car never saw a solar window at all: every slot was either withheld for the battery in the morning or suppressed as away in the afternoon, so the plan fell through to buying at the day rate - reported from a live system as "plenty of solar but it doesn't use it". The hold now gives up exactly what the car can still take from the slots it will be present for. That figure is what it needs, capped by what those slots can actually deliver, so the battery keeps everything beyond it - it has the rest of the day, the car does not. Zero when no away time is set, so the everyday behaviour is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…later solar car_charging_plan_min_soc is the charge that must be there by the ready time whatever the weather, but solar windows were satisfying it with sunshine that arrives long after the deadline has passed. Solar windows are planned first so free energy is used before paid import, they reach for the full car_charging_limit rather than the minimum, and they run to the forecast horizon rather than stopping at the ready time. All three are right on their own, but a single running car_soc is shared with the bought pass, so tomorrow's sun - and the day after's - counted towards tonight's guarantee. Once that total reached the limit the loop broke out and not one overnight slot was bought. Reported from a live system at 01:28: a car at 35.5kWh with a 60% (42.6kWh) minimum due by 07:30 was offered 39p import every half hour until dawn and bought none of it, because 23kWh of solar spread over the following two afternoons had already carried the running total past the 80% limit. The plan was not wrong about the car reaching 80%; it was wrong about when, and the guarantee is the whole point of the setting. Solar that lands before the ready time still counts towards the minimum and is still planned first. Solar after it is held back until the bought slots are placed, then tops the car up to the full limit as before. Ordering is the only change: no window is newly eligible or newly excluded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The everyday guarantee is car_charging_plan_min_soc by car_charging_plan_time, which covers a routine and not an event. A trip at 15:00 that needs 80% does not fit a 07:30 ready time, and editing the standing settings for it means remembering to put them back. New select.predbat_manual_car_deadline, set from the plan page's time cells as "Car ready by" with a level, stored the way manual_soc stores a time and a value, and cleared on its own once its slot has passed. There is only ever one: setting another replaces it. It is a guarantee in the same way the everyday minimum is, and the two stack. Each deadline in time order gets the free sun that fully lands before it, then buys whatever that leaves before it passes. The one-off buys from any import slot rather than only low_rates, and ignores car_charging_plan_max_price: a midday deadline on a tariff whose cheap band is overnight would otherwise find nothing it may buy, and the user has said the charge is needed. The everyday minimum keeps its existing rules exactly. A battery-priority hold would bank the very sun the deadline is counting on and then buy for the car instead, so the deadline claims the sun before it the same way away time claims the sun the car is present for. Away slots are skipped for the deadline's purchases too, and when away time leaves too few slots to deliver the level at the charger's rate, Predbat plans what it can and logs a warning rather than letting the car be found short. The level is a percentage of one car's battery, so it applies to the first car, and is capped at car_charging_limit - the car will not charge past its own limit, and planning energy it refuses would put phantom load into the forecast the battery is planned against. manual_rates() now tolerates a None value, which a select gated on "enable" reads back before it is enabled - the same crash manual_times() had for manual_car_away. Valued selects are routed on a name substring and an unrecognised one is dropped with a warning, so the deadline has its own branch in both routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es carry the urgency car_charging_solar_battery_soc let the user say how much house battery to bank before the car was offered surplus solar. In practice it was being moved by hand to stand in for something the planner could not know: whether the car actually needed the sun today. It now can - a one-off deadline says the car needs a level by a time, and away time says when the car will not be there - so the slider has nothing left to express and is removed. Spare sun goes to the house battery first, and the car is offered a window once the pack is predicted full. A kWh in the pack displaces the evening peak; one in a car that has been promised nothing displaces at most a cheap overnight top-up, so the pack is the better home for it. Where the car does need the sun, car_solar_reserved_for_car already releases exactly that much ahead of the hold - the sun before a deadline, or the sun the car is present for when it will be away later. This is the old slider fixed at 100%, which is where it was being run on the live system this was built against. It never shipped upstream, so no existing setup changes behaviour. The solar-sizing tests now start from a full house battery, since they are about how the car's share is sized rather than who gets it; the slider's own test becomes one pinning battery-first, including the car being released mid-morning once the pack is predicted full. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6b58795 to
a44f741
Compare
A car charging while the sun is up is load the inverter feeds from the surplus before it charges the battery, so a slot Predbat buys from the grid still takes the battery's solar. The plan priced those slots on the import rate alone. Reported from a live system: off-peak cost the same at 14:00 as at midnight, ties went to the earliest slot, and the car was planned at 14:00 in full sun every cycle. With solar car charging on, among equally priced grid slots the sunless ones now go first. It only reorders ties, so it cannot make a plan dearer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Predbat places car slots on import price alone, with no awareness of sunshine. A car can be scheduled to buy overnight while the next day's surplus is exported instead.
This adds solar-aware car charging, and then fixes three things that surfaced after I ran it over the past few months with my Tesla at home.
NOTE: This is modeled on Tesla's "charge on solar" and may not be applicable to all other cars (I only have the one car to test :)).
Nothing changes unless you turn it on. The feature switch is off by default.
What it does
switch.predbat_car_charging_solar (default off) places car slots on forecast PV first. The existing loop stops once the car's requirement is met, so the price-based pass only covers the shortfall. A slot qualifies on the same pair of tests iBoost already uses for the same "divert rather than export" decision: forecast PV at least car_charging_solar_excess, and an export rate no higher than car_charging_rate_threshold_export.
Slots are sized on the surplus so even if a car can pull in 7 kW (so 3.5 kW in a 30 minute slot), it will only be predicted to pull in the amount that is left after the predicted load. This is, again, reminiscent of what Tesla's charge on solar does.
I added a few other options to control how this works:
Tests
Two new suites, car_solar and car_away, 17 test functions. They cover per-bucket surplus sizing, the battery-priority release etc.
Docs in docs/car-charging.md and docs/customisation.md.