oprava
Some checks failed
CI and deploy / migration-check (push) Failing after 28s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-29 23:04:27 +02:00
parent 877f5b6180
commit b73c3323e1
4 changed files with 115 additions and 53 deletions

View File

@@ -243,7 +243,8 @@ class EveningPushBudgetTests(unittest.TestCase):
per_slot_discharge_wh=per_slot,
discharge_slot_buffer=1.5,
)
self.assertEqual(push, [2], "push jen slot(y) s max sell v nočním úseku")
self.assertIn(2, push, "00:00 max sell musí být v push")
self.assertEqual(max(float(slots[t].sell_price) for t in push), 3.586)
def test_evening_push_budget_matches_r063_formula(self) -> None:
bat = _battery(uc_wh=64_000.0, min_pct=10.0, max_pct=95.0)
@@ -2621,7 +2622,7 @@ class ChargeAcquisitionArbitrageTests(unittest.TestCase):
self.assertEqual(r.export_mode, "BATTERY_SELL")
def test_evening_no_spread_export_below_segment_peak_home01(self) -> None:
"""home-01 večer: plný export jen v max-sell slotu, ne rozpliznutí do levnějších sousedů."""
"""home-01 večer: plný export v top push slotech dle rozpočtu Wh, ne v levnějších mimo push."""
prague = ZoneInfo("Europe/Prague")
sells = [3.834, 3.518, 3.204, 3.204, 3.136, 3.020]
base = datetime(2026, 5, 29, 20, 15, tzinfo=prague)
@@ -2662,14 +2663,58 @@ class ChargeAcquisitionArbitrageTests(unittest.TestCase):
)
self.assertEqual(snap["planner_build_tag"], PLANNER_BUILD_TAG)
push_iso = set(snap["inputs"].get("evening_push_ts") or [])
self.assertGreaterEqual(len(push_iso), 3, "rozpočet Wh → víc než jeden push slot")
self.assertIn(slots[0].interval_start.isoformat(), push_iso)
self.assertGreaterEqual(abs(results[0].grid_setpoint_w), 12_500)
for i in range(1, 6):
self.assertGreaterEqual(
results[i].grid_setpoint_w,
-500,
msg=f"slot {i} sell={sells[i]} must not export below segment peak",
for i, r in enumerate(results):
iso = slots[i].interval_start.isoformat()
if iso in push_iso:
self.assertEqual(r.export_mode, "BATTERY_SELL")
self.assertLessEqual(r.grid_setpoint_w, -12_500)
else:
self.assertGreaterEqual(
r.grid_setpoint_w,
-500,
msg=f"slot {i} sell={sells[i]} mimo push nesmí exportovat",
)
def test_evening_push_respects_wh_budget_not_all_profitable_slots(self) -> None:
"""Při malém SoC jen top-N drahých slotů; zbytek noci ge_bat=0."""
prague = ZoneInfo("Europe/Prague")
sells = [4.0 - 0.05 * i for i in range(10)]
base = datetime(2026, 5, 25, 18, 0, tzinfo=prague)
slots = [
PlanningSlot(
interval_start=base + timedelta(minutes=15 * i),
buy_price=2.0,
sell_price=sells[i],
pv_a_forecast_w=0,
pv_b_forecast_w=0,
load_baseline_w=1800,
ev1_connected=False,
ev2_connected=False,
allow_discharge_export=True,
charge_acquisition_buy_czk_kwh=0.5,
)
for i in range(10)
]
battery = _battery(uc_wh=64_000.0, terminal_soc_value_factor=0.0)
battery.max_discharge_power_w = 18_000
per_slot = min(18_000, 13_500) * 0.95 * 0.25
soc_limited = battery.min_soc_wh + 3.2 * per_slot
push = _evening_battery_export_push_indices(
slots,
charge_acquisition_czk_kwh=0.5,
degrad_czk_kwh=0.15,
current_soc_wh=soc_limited,
min_soc_wh=battery.min_soc_wh,
soc_max_wh=battery.soc_max_wh,
per_slot_discharge_wh=per_slot,
discharge_slot_buffer=1.5,
)
self.assertGreaterEqual(len(push), 3)
self.assertLessEqual(len(push), 4)
self.assertEqual(push, [0, 1, 2, 3][: len(push)])
def test_no_pv_export_at_low_sell_when_evening_peak_much_higher(self) -> None:
"""Odpolední sell ~1,4 a večer ~5,5 — PV do baterie, ne FVE→síť za haléř."""