EV spotřební forecast: týdenní rytmus vozidla → target SoC a deadline session
Myšlenka uživatele: pondělní služebka ~150 km (~35 kWh) chce skoro plnou, konec týdne stačí míň, víkend = levné sloty na přípravu pondělka. - V089: ev_vehicle_obs (odometer+SoC při příjezdu/ODJEZDU — auto v obou okamžicích vzhůru, žádné buzení navíc), ev_trip (km z odometru, kWh z ΔSoC; nabíjení cestou → charged_away flag), ev_usage_stats per (vozidlo, DOW); asset_vehicle: target_soc_forecast_enabled (default false), min_target_soc_pct - R__096: fn_ev_build_trips (párování), fn_update_ev_usage_stats (job 00:50), fn_ev_next_departure (příští typický odjezd, >=4 vzorky, >=3 km), fn_ev_required_soc (P80 spotřeby dne + 10 p.b., clamp [min_target, 100]) - R__016: session při příjezdu bere forecast target+deadline (za per-vozidlo flagem, fallback defaulty, ruční patch vždy vyhrává) → víkendová session s pondělním deadline = v2 solver přirozeně nabije v levných slotech - tesla_client: + vehicle_state endpoint (odometer v MÍLÍCH → km), collector: departure hook, lifespan: job 00:50 Aktivace po nasbírání dat: update asset_vehicle set target_soc_forecast_enabled=true. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,18 +32,27 @@ HTTP_TIMEOUT_S = 15.0
|
||||
ACCESS_EXPIRY_MARGIN_S = 120
|
||||
|
||||
|
||||
MILES_TO_KM = 1.609344
|
||||
|
||||
|
||||
def parse_charge_state(vehicle_data: dict[str, Any]) -> dict[str, Any] | None:
|
||||
"""Čistý parser odpovědi vehicle_data → {battery_level, charge_limit_soc, charging_state}."""
|
||||
"""Parser vehicle_data → battery_level, charge_limit_soc, charging_state, odometer_km.
|
||||
|
||||
POZOR: Tesla API vrací odometer v MÍLÍCH → převod na km.
|
||||
"""
|
||||
resp = vehicle_data.get("response") or {}
|
||||
cs = resp.get("charge_state") or {}
|
||||
vs = resp.get("vehicle_state") or {}
|
||||
level = cs.get("battery_level")
|
||||
if level is None:
|
||||
return None
|
||||
odo_miles = vs.get("odometer")
|
||||
return {
|
||||
"vin": resp.get("vin"),
|
||||
"battery_level": int(level),
|
||||
"charge_limit_soc": int(cs.get("charge_limit_soc") or 0) or None,
|
||||
"charging_state": cs.get("charging_state"),
|
||||
"odometer_km": round(float(odo_miles) * MILES_TO_KM, 1) if odo_miles is not None else None,
|
||||
}
|
||||
|
||||
|
||||
@@ -135,7 +144,7 @@ async def get_charge_state(
|
||||
|
||||
r = await client.get(
|
||||
f"{API_BASE}/api/1/vehicles/{chosen['id']}/vehicle_data",
|
||||
params={"endpoints": "charge_state"},
|
||||
params={"endpoints": "charge_state;vehicle_state"},
|
||||
)
|
||||
if r.status_code == 408:
|
||||
logger.info("Tesla: vozidlo spí / nedostupné (408) — SoC nedoplněno")
|
||||
|
||||
Reference in New Issue
Block a user