feat(ev): event-driven replan i na odjezd EV (ne jen příjezd)
Odjezd auta (≠available → available) teď spouští okamžitý rolling replan + export, symetricky k příjezdu — místo čekání na */15 tick. Řeší stale plán spočítaný těsně před odjezdem, který držel fantomovou EV alokaci (~4–11 kW do už odjetého auta). Session už zavřela fn_ev_session_transition synchronně v poll smyčce, takže replan vidí 'žádná session' a alokaci shodí. Replan i pozorování jízdy každý ve vlastním try+conn (pád solveru ani spící auto se navzájem neshodí). +2 regresní testy, +docs (changelog, ev-charging). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -129,13 +129,38 @@ async def _on_ev_arrival(site_id: int, charger_code: str) -> None:
|
||||
|
||||
|
||||
async def _on_ev_departure(site_id: int, charger_code: str) -> None:
|
||||
"""Odjezd: zapsat pozorování (odometer+SoC) — auto právě jede, je vzhůru.
|
||||
"""Odjezd: okamžitý replan + export, pak zapsat pozorování jízdy.
|
||||
|
||||
Pár odjezd→příjezd dává jízdu (km, kWh) pro ev_usage_stats. Spící/nečitelné
|
||||
auto (408) = tiché přeskočení, jízda se dopočítá z příštích pozorování.
|
||||
Session už zavřela fn_ev_session_transition v poll smyčce (synchronně, PŘED
|
||||
tímto fire-and-forget taskem), takže replan uvidí 'žádná session' a shodí
|
||||
fantomovou EV alokaci místo čekání na */15 tick — symetricky k _on_ev_arrival.
|
||||
Přebytek pak rovnou exportuje, ne aby ho plán virtuálně cpal už odjetému autu.
|
||||
|
||||
Pozorování (odometer+SoC): pár odjezd→příjezd dává jízdu (km, kWh) pro
|
||||
ev_usage_stats. Spící/nečitelné auto (408) = tiché přeskočení; je best-effort
|
||||
a NESMÍ blokovat ani shodit replan výše (proto vlastní conn + try).
|
||||
"""
|
||||
if _BG_POOL is None:
|
||||
return
|
||||
# 1) Okamžitý replan + export (kritické — uvolnit přebytek z fantomové EV alokace).
|
||||
try:
|
||||
from services.control_exporter import export_setpoints
|
||||
from services.planning_engine import run_rolling_replan
|
||||
|
||||
async with _BG_POOL.acquire() as conn:
|
||||
await run_rolling_replan(
|
||||
site_id, conn, triggered_by=f"ev_departure:{charger_code}"
|
||||
)
|
||||
await export_setpoints(site_id, conn)
|
||||
logger.info(
|
||||
"EV departure replan+export done (site=%s, charger=%s)",
|
||||
site_id, charger_code,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"EV departure replan failed (site=%s, charger=%s)", site_id, charger_code
|
||||
)
|
||||
# 2) Pozorování jízdy (jen Tesla; nezávislé na replanu výše).
|
||||
try:
|
||||
from app.db_json import fetch_json
|
||||
from services.tesla_client import get_charge_state
|
||||
|
||||
Reference in New Issue
Block a user