cileni k vybiti pred ranem kdy nabiju z fve
Some checks failed
CI and deploy / migration-check (push) Failing after 13s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-26 14:25:12 +02:00
parent d1ba864fc0
commit 398e658d16
4 changed files with 132 additions and 8 deletions

View File

@@ -19,7 +19,9 @@ from services.planning_engine import (
_in_night_battery_export_window,
_neg_sell_day_phases,
_neg_sell_phases_enabled,
_neg_evening_reserve_soc_anchors,
_pre_neg_pv_export_bundle,
_prague_calendar_date,
_pre_neg_buy_soc_ceiling_wh,
_pre_neg_peak_sell_idx,
_pre_neg_pv_export_forecast_cushion_ok,
@@ -4093,6 +4095,52 @@ class NegSellPrepWindowV36Tests(unittest.TestCase):
"morning before 2nd neg day should allow pre-neg export",
)
def test_evening_reserve_anchor_before_neg_day(self) -> None:
base = datetime(2026, 6, 10, 10, 0, tzinfo=ZoneInfo("Europe/Prague")).astimezone(
timezone.utc
)
slots: list[PlanningSlot] = []
for i in range(120):
local = (base + timedelta(minutes=15 * i)).astimezone(
ZoneInfo("Europe/Prague")
)
h = local.hour + local.minute / 60.0
if local.date().day == 10:
sell = -0.2 if h >= 14 else 2.5
elif local.date().day == 11:
sell = -0.2 if 9 <= h < 15 else 2.8
else:
sell = 2.5
slots.append(
PlanningSlot(
interval_start=base + timedelta(minutes=15 * i),
buy_price=2.0,
sell_price=sell,
pv_a_forecast_w=3000,
pv_b_forecast_w=3000,
load_baseline_w=1500,
ev1_connected=False,
ev2_connected=False,
allow_charge=True,
allow_discharge_export=True,
)
)
bat = _battery(uc_wh=64_000.0, max_pct=95.0, arb_pct=20.0)
bat.planner_neg_sell_prep_soc_percent = 80.0
bat.planner_neg_sell_full_soc_tail_slots = 4
_ph, _tg, _w, meta = _neg_sell_day_phases(slots, bat)
anchors = _neg_evening_reserve_soc_anchors(slots, meta, bat)
self.assertGreaterEqual(len(anchors), 1)
t_a, tgt = anchors[0]
self.assertAlmostEqual(tgt, bat.reserve_soc_wh, delta=100.0)
self.assertEqual(_prague_calendar_date(slots[t_a]).day, 10)
# Kotva pro den 11: večer 10.6. (i když odpoledne 10.6. už bylo sell<0).
if len(meta["days"]) >= 2:
day11_first = int(meta["days"][1]["first_neg_idx"])
prev = _prague_calendar_date(slots[day11_first]) - timedelta(days=1)
a11 = [(t, w) for t, w in anchors if _prague_calendar_date(slots[t]) == prev]
self.assertEqual(len(a11), 1)
if __name__ == "__main__":
unittest.main()