OPT-11 P3: price runs per battery
checks / unit (pull_request) Successful in 13m45s
infra-pin / fresh (pull_request) Successful in 1s

Cheap and expensive hours as runs of consecutive firm price slots
(priceruns.py); each battery's role per tick from its mode (modetrade.py):
grid charging for Leftover solar / Cheap hours only, never Solar first;
holding for the expensive runs; selling per battery (pack_sell) above the
spread and the floor. The site trade is sized inside the modes (loop bound)
and the peak guard's headroom; a run edge reseeds the loop. Cheap hours only
and selling are enabled on the Batteries screen and in the HA select
(appended). The site Why row no longer says "held back" when the peak limit
pushes power up (F2). Modes off: byte-identical to 7a00f12 on the trade path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Claude dev agent
2026-09-29 02:37:44 +02:00
parent 7a00f12c76
commit 902524ae5e
19 changed files with 2202 additions and 113 deletions
+22 -8
View File
@@ -87,19 +87,20 @@
"on": "On", "off": "Off",
"choice": {
"solar_first": {"name": "Solar first", "description": "Charges from solar before the other batteries and covers the house."},
"leftover_solar": {"name": "Leftover solar", "description": "Charges from solar the other batteries cannot take, and covers the house."},
"leftover_solar": {"name": "Leftover solar", "description": "Gets solar the others cannot take, charges in cheap hours and gives power in expensive ones."},
"cheap_hours": {"name": "Cheap hours only", "description": "Charges in the cheapest hours and gives power in the expensive ones."},
"off": {"name": "Off", "description": "Rests, and helps only when the peak limit needs it."}
},
"later": "Cheap hours only, coming later",
"today": "Today", "why": "Why",
"sell": {"name": "Sell in expensive hours", "description": "Selling comes in a later update."},
"sell": {"name": "Sell in expensive hours", "description": "Also sells to the grid in the most expensive hours.", "off": "Not for Solar first."},
"modes_off": {"name": "Battery modes are off"},
"how": {"name": "How the modes work", "description": "Which battery gets solar first, and when each gives power.",
"solar_first": {"description": "Solar first gets spare solar before the other batteries, and covers the house at any hour."},
"leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, and also covers the house."},
"leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, charges in cheap hours, and saves its power for expensive hours."},
"cheap_hours": {"description": "Cheap hours only charges in the cheapest hours and gives power in the expensive ones."},
"off": {"description": "Off rests the battery and starts no monthly cycle, but the peak limit may still use it."},
"rules": {"description": "The peak limit and the safety stops always come first, and charging from the grid and selling come later."}},
"toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}."}},
"rules": {"description": "The peak limit and the safety stops come first, and while one battery charges from the grid the others rest."}},
"toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}.", "sell_on": "{name} sells in expensive hours.", "sell_off": "{name} does not sell."}},
"settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"}
},
"choices_later": {
@@ -250,7 +251,7 @@
},
"home_words": {
"mode_house": "Follows the house",
"modes": {"solar_first": "Solar first", "leftover_solar": "Leftover solar", "off": "Off"},
"modes": {"solar_first": "Solar first", "leftover_solar": "Leftover solar", "cheap_hours": "Cheap hours only", "off": "Off"},
"attn_shadow": "Shadow mode is on",
"attn_shadow_body": "The add-on decides everything, but every inverter stays at 0 W.",
"zero_held": "Held at 0 W",
@@ -326,10 +327,19 @@
"leftover": "It gets the solar that Solar first batteries cannot take.",
"leftover_alone": "No Solar first battery is on, so it gets solar first.",
"covers_house": "It gives power to cover the house.",
"other_refuses": "{name} refuses to give power, so this battery takes over."
"other_refuses": "{name} refuses to give power, so this battery takes over.",
"grid_charge": "Prices are low, so it charges from the grid.",
"rests_charge": "Another battery charges from the grid, so it rests.",
"selling": "Prices are high, so it sells to the grid.",
"expensive": "Prices are high, so it covers the house.",
"saves": "Saves its power for {at}.",
"saves_later": "Saves its power for higher prices.",
"no_prices": "No prices, so it follows the house.",
"no_spread": "Prices differ too little, so it follows the house."
},
"today": {
"not_planned": "Not planned yet.",
"no_runs": "No cheap or expensive hours left today.",
"off": "Off, so no monthly cycle today.",
"house": "Follows the house.",
"house_would": "Would follow the house.",
@@ -356,6 +366,10 @@
"give_what": "Gives up to {kwh}, to the house first.",
"give_what_would": "Would give up to {kwh}, to the house first.",
"give_why": "Highest published price, {eur} per kWh.",
"sell_what": "Sells up to {kwh}, to the house first.",
"sell_what_would": "Would sell up to {kwh}, to the house first.",
"cheap_why": "Cheapest hours, about {eur} per kWh.",
"dear_why": "Expensive hours, about {eur} per kWh.",
"give_amount": "Worth up to {eur} at that price.",
"cycle_start": "Starts the monthly battery cycle.",
"cycle_start_would": "Would start the monthly battery cycle.",
+22 -8
View File
@@ -84,19 +84,20 @@
"on": "Aan", "off": "Uit",
"choice": {
"solar_first": {"name": "Eerst zonne-energie", "description": "Laadt met zonne-energie vóór de andere batterijen en dekt het huis."},
"leftover_solar": {"name": "Overschot zonne-energie", "description": "Laadt met zonne-energie die de andere batterijen niet opnemen, en dekt het huis."},
"leftover_solar": {"name": "Overschot zonne-energie", "description": "Krijgt zonne-energie die de andere niet opnemen, laadt in goedkope uren en levert in dure uren."},
"cheap_hours": {"name": "Alleen goedkope uren", "description": "Laadt in de goedkoopste uren en levert in de dure uren."},
"off": {"name": "Uit", "description": "Rust, en helpt alleen als de piekgrens haar nodig heeft."}
},
"later": "Alleen goedkope uren, volgt later",
"today": "Vandaag", "why": "Waarom",
"sell": {"name": "Verkopen in dure uren", "description": "Verkopen komt in een latere update."},
"sell": {"name": "Verkopen in dure uren", "description": "Verkoopt ook aan het net in de duurste uren.", "off": "Niet voor Eerst zonne-energie."},
"modes_off": {"name": "Batterijmodi staan uit"},
"how": {"name": "Zo werken de modi", "description": "Welke batterij eerst zonne-energie krijgt, en wanneer elke batterij levert.",
"solar_first": {"description": "Eerst zonne-energie krijgt het overschot vóór de andere batterijen, en dekt het huis op elk uur."},
"leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, en dekt ook het huis."},
"leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, laadt in goedkope uren en spaart haar stroom voor dure uren."},
"cheap_hours": {"description": "Alleen goedkope uren laadt in de goedkoopste uren en levert in de dure uren."},
"off": {"description": "Uit laat de batterij rusten en start geen maandelijkse cyclus, maar de piekgrens mag haar nog gebruiken."},
"rules": {"description": "De piekgrens en de veiligheidsstops gaan altijd voor, en laden van het net en verkopen volgen later."}},
"toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}."}},
"rules": {"description": "De piekgrens en de veiligheidsstops gaan voor, en terwijl een batterij van het net laadt rusten de andere."}},
"toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}.", "sell_on": "{name} verkoopt in dure uren.", "sell_off": "{name} verkoopt niet."}},
"settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"}
},
"choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}},
@@ -224,7 +225,7 @@
},
"home_words": {
"mode_house": "Volgt het huis",
"modes": {"solar_first": "Eerst zonne-energie", "leftover_solar": "Overschot zonne-energie", "off": "Uit"},
"modes": {"solar_first": "Eerst zonne-energie", "leftover_solar": "Overschot zonne-energie", "cheap_hours": "Alleen goedkope uren", "off": "Uit"},
"attn_shadow": "Schaduwmodus staat aan",
"attn_shadow_body": "De add-on beslist alles, maar elke omvormer blijft op 0 W.",
"zero_held": "Op 0 W gehouden",
@@ -268,10 +269,19 @@
"leftover": "Ze krijgt de zonne-energie die de batterijen met Eerst zonne-energie niet opnemen.",
"leftover_alone": "Geen batterij met Eerst zonne-energie staat aan, dus zij krijgt eerst zonne-energie.",
"covers_house": "Ze levert stroom om het huis te dekken.",
"other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over."
"other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over.",
"grid_charge": "De prijs is laag, dus ze laadt van het net.",
"rests_charge": "Een andere batterij laadt van het net, dus deze rust.",
"selling": "De prijs is hoog, dus ze verkoopt aan het net.",
"expensive": "De prijs is hoog, dus ze dekt het huis.",
"saves": "Spaart haar stroom voor {at}.",
"saves_later": "Spaart haar stroom voor hogere prijzen.",
"no_prices": "Geen prijzen, dus ze volgt het huis.",
"no_spread": "De prijzen verschillen te weinig, dus ze volgt het huis."
},
"today": {
"not_planned": "Nog niet gepland.",
"no_runs": "Vandaag geen goedkope of dure uren meer.",
"off": "Uit, dus vandaag geen maandelijkse cyclus.",
"house": "Volgt het huis.",
"house_would": "Zou het huis volgen.",
@@ -298,6 +308,10 @@
"give_what": "Levert tot {kwh}, eerst aan het huis.",
"give_what_would": "Zou tot {kwh} leveren, eerst aan het huis.",
"give_why": "Hoogste gepubliceerde prijs, {eur} per kWh.",
"sell_what": "Verkoopt tot {kwh}, eerst aan het huis.",
"sell_what_would": "Zou tot {kwh} verkopen, eerst aan het huis.",
"cheap_why": "Goedkoopste uren, ongeveer {eur} per kWh.",
"dear_why": "Dure uren, ongeveer {eur} per kWh.",
"give_amount": "Tot {eur} waard aan die prijs.",
"cycle_start": "Start de maandelijkse batterijcyclus.",
"cycle_start_would": "Zou de maandelijkse batterijcyclus starten.",