fix nabijeni z gridu u fixnich tarifu
Some checks failed
CI and deploy / migration-check (push) Failing after 11s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-16 16:38:45 +02:00
parent 49d0aa68a2
commit 27323fd77a
3 changed files with 102 additions and 39 deletions

View File

@@ -27,6 +27,8 @@ def _select_charge_slots(
slots: list[PlanningSlot],
battery: SimpleNamespace,
current_soc_wh: float,
*,
purchase_pricing_mode: str = "spot",
) -> set[int]:
"""Kopie logiky z ems.fn_load_planning_slots_full (charge mask)."""
charge_buf = float(getattr(battery, "charge_slot_buffer", 0) or 0)
@@ -72,6 +74,10 @@ def _select_charge_slots(
selected.add(t)
cum += min(pv_surplus_w, max_p_w) * eta * INTERVAL_H
# B) Non-PV grid charge — jen spot nákup (u fixed je buy všude stejný → jen FVE)
if purchase_pricing_mode == "fixed":
return selected
# B) Non-PV: AM budget (OTE-first)
am_candidates = [
(t, getattr(slots[t], "is_predicted_price", False), float(slots[t].buy_price))
@@ -112,6 +118,8 @@ def _select_discharge_export_slots(
battery: SimpleNamespace,
current_soc_wh: float,
charge_slots: set[int] | None = None,
*,
purchase_pricing_mode: str = "spot",
) -> set[int]:
"""Kopie logiky z ems.fn_load_planning_slots_full (discharge-export mask)."""
discharge_buf = float(getattr(battery, "discharge_slot_buffer", 0) or 0)
@@ -138,10 +146,14 @@ def _select_discharge_export_slots(
default=min(float(s.buy_price) for s in slots),
)
if purchase_pricing_mode == "fixed":
sell_min = degrad
else:
sell_min = ref_buy + degrad
candidates = [
(t, float(slots[t].sell_price))
for t in range(len(slots))
if float(slots[t].sell_price) > ref_buy + degrad
if float(slots[t].sell_price) > sell_min
]
candidates.sort(key=lambda x: (-x[1], -x[0]))
@@ -330,5 +342,39 @@ class SelectDischargeExportSlotsTests(unittest.TestCase):
self.assertNotIn(1, discharge, "sell 0.5 < ref 0.4 + 0.15")
class FixedPurchasePricingTests(unittest.TestCase):
"""purchase_pricing_mode=fixed: žádné grid CHARGE, export dle sell."""
def test_fixed_skips_non_pv_grid_charge_slots(self) -> None:
slots = [
_slot(buy=6.35, sell=2.0, hour_utc=14, load=500),
_slot(buy=6.35, sell=3.5, hour_utc=18, load=500),
]
battery = _battery(charge_buf=1.3, uc_wh=12_500.0)
out = _select_charge_slots(
slots,
battery,
current_soc_wh=0.4 * battery.usable_capacity_wh,
purchase_pricing_mode="fixed",
)
self.assertEqual(out, set(), "fixed buy must not enable non-PV grid charge")
def test_fixed_allows_discharge_on_high_sell(self) -> None:
slots = [
_slot(buy=6.35, sell=1.0, hour_utc=10),
_slot(buy=6.35, sell=3.8, hour_utc=18),
_slot(buy=6.35, sell=3.2, hour_utc=19),
]
battery = _battery(uc_wh=12_500.0, discharge_buf=2.0, degrad=0.3)
discharge = _select_discharge_export_slots(
slots,
battery,
current_soc_wh=0.5 * battery.usable_capacity_wh,
purchase_pricing_mode="fixed",
)
self.assertIn(1, discharge)
self.assertIn(2, discharge)
if __name__ == "__main__":
unittest.main()