400 invalid_grant = spálený token rotací NEBO ~10min výpadek po revokaci
souhlasu (Tesla) — místo tracebacku log s návodem a return None (EMS jede
dál na defaultech). deploy/tesla/reauth.sh: authorize URL → výměna → DB →
ověření v jednom kroku (žádná příležitost pro rotační past).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Uživatel: 'potřebuju do X % (tvrdý), ale klidně dobij na 100 % když je to
skoro zadarmo; při záporných cenách radši do auta než nechat na střeše'.
- V094 asset_vehicle.opportunistic_value_czk_kwh (default 1.0; = hodnota
ušetřeného BUDOUCÍHO nabíjení — auto neumí zpět, žádný noční prodej)
- R__039 ev_sessions: + headroom_wh ((100−target) % kapacity) + opp value;
session se nenuluje po dosažení targetu, dokud má headroom
- solver_v2: dekompozice Σ(EV) == needed − unmet + opp, opp ∈ [0, headroom],
odměna opp×value; zároveň FIX latentního bugu — při buy<0 chyběl strop
celkové energie do auta (model mohl pumpovat bez limitu)
- 3 testy (neg ceny sají nad target po strop; běžné ceny ne; cap při opp=0);
eval fixtures beze změny (sessions null)
Víkend (pátek nízký tvrdý cíl + víkendová negativa → samo doplní do 100 %)
vyplývá z mechanismu, žádná speciální logika.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- R__097: vw_latest_pool_pump + vw_pool_pump_day_energy (denní kWh z delty
čítače, minuty běhu) + ems_anon granty
- PoolCard na Dashboardu: stav/W/dnešní kWh+hodiny/7denní mini sloupce
- _notify_ev_arrival_plan: po příjezdu EV Discord souhrn (SoC auta → cíl,
deadline, nabíjecí okna shlukovaná ze slotů aktivního plánu, ø cena)
- docs/discord-ev-interaction.md: fáze B (bot s tlačítky přes gateway —
žádný veřejný endpoint; čeká na DISCORD_BOT_TOKEN od uživatele)
- docs: pool-shelly + ev-charging aktualizovány (pravidlo docs 1:1)
První commit na dev větvi (nová kadence: deploy až s milníkovým merge).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
KV1 pozorování uživatele: ráno baterie na 11 % (min 10), prodává se do sítě
— nenadálý odběr/mrak by se kupoval za fixních 6.35. v1 mělo denní rampu
(safety_soc_target_wh z R__063: reserve 30 % ráno → reserve+noc večer,
6-19 h, flag planner_daytime_charge_target_enabled) — v2 ji ignoroval.
Mechanismus (vzor nočního polštáře): deficit pod rampou platí za KAŽDÝ slot
nájem buy×faktor (V091 asset_battery.planner_safety_soc_risk_factor,
default 0.05; 0=vypnuto) → ráno se nejdřív doplní rezerva (4 h deficitu
1 kWh při buy 6.35 ≈ 5.1 Kč > sell ~2.5), extrémní sell špička smí deficit
racionálně podstoupit. R__039 + db_io + 2 testy (KV1 scénář, spike).
Eval fixtures beze změny (sloupec v context_json fixtures není → 0);
živá produkce dostane faktor přes fn_planning_site_context.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v1 to řešil rampou (plný výkon než se řeže pole A — zelený bonus B, riziko
večerního mraku). v2 byl k načasování v okně sell<0 indiferentní (PV zdarma
kdykoliv) a směl nabíjení odložit — odklad ale spoléhá na predikci.
Mechanismus: malá prémie za držení energie dřív (objective −= soc[t] ×
frontload v neg slotech). Rozbíjí indiferenci směrem k front-loadu, nikdy
nepřebije skutečné ceny. Velikost z DB: asset_battery.
planner_pv_risk_frontload_czk_kwh (V090, default 0.01; 0 = vypnuto),
přes fn_planning_site_context (R__039). Test: 4 sloty plným tempem od startu.
Eval fixtures beze změny (sloupec v nich není → 0).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Postřeh uživatele: v1 držel přes noc rezervu nad min_soc (chyba predikce
noční spotřeby = neplánovaný drahý nákup); v2 slot fieldy night_baseload_*
ignoroval a směl plánovat vybití až na min_soc.
Mechanismus ve filozofii v2 (riziko jako cena, ne okno/penalta):
soft floor soc[t] >= min_soc + night_baseload_buffer_wh[t] (z DB
planner_night_baseload_buffer_percent, počítá R__063, klesá k 0 do rána);
porušení placené buy cenou slotu → extrémní sell špička smí polštář
racionálně prodat, běžná noc ne (buy > sell).
Eval na fixtures: v2 stále lepší na všech (+221.9 Kč vs v1; −10 Kč proti
stavu bez polštáře = cena robustnosti). BONUS: těsnější LP zrychlil extrémní
fixtures z 10 s timeoutu na 0.3–2.6 s. +3 testy (drží/spike prodá/feasible).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- services/tesla_client.py: access token s cache + ROTACE refresh tokenu do
ems.tesla_token (env jen seed — Tesla refresh token je jednorázový),
vehicles → vehicle_data?endpoints=charge_state, 408 (spící auto) = tiché
přeskočení, výběr vozidla dle VIN / jediného na účtu (VIN se auto-naučí)
- hook _patch_session_from_tesla v _on_ev_arrival: PŘED replanem doplní
soc_at_connect_pct (+ target z charge_limit_soc) do otevřené session přes
fn_ev_session_apply_patch (rozšířena o soc_at_connect_pct) — energii si
odvodí fn_planning_site_context (SQL-first); selhání neblokuje replan
- V086: asset_vehicle.vin, api_type='tesla' pro tesla-my (Model Y, home-01),
singleton ems.tesla_token; R__095: fn_tesla_token_get/upsert,
fn_tesla_arrival_context, fn_vehicle_set_vin
- config: TESLA_CLIENT_ID/SECRET/REFRESH_TOKEN (prázdné = vypnuto)
- testy parserů; plná sada beze změny
Aktivace: env do /opt/ems-deploy/.env + recreate backendu (docs/tesla-fleet-api.md §Stav).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bod 1 — write_ev_setpoints reálně (konec TODO stubu):
- reg 15 (0=stop, 6–32 A) z plánu přes _current_limit_for_charger; plná
journal pipeline (create_modbus_commands → execute, verify job 2 min generic)
- watchdog reg 19=300 s + reg 20=8 A: výpadek EMS → wallbox po 5 min failsafe
8 A (auto se přes noc nabije); drop-unchanged → zapisuje se jen při změně
- fn_modbus_last_verified_map: + p_asset_type (drop 2-arg; dosud hardcoded
'inverter' — pro chargery vracela {})
- verify: SELF_SUSTAIN fallback explicitně jen pro asset_type='inverter' —
mismatch wallboxu nesmí degradovat režim celé site
- journal register_name: mimo inverter platí jméno od volajícího
Bod 2 — telemetry_collector: přechod available→connected spustí fire-and-forget
run_rolling_replan(triggered_by=ev_arrival:<code>) + export_setpoints přes BG
pool — reakce na příjezd ~60 s místo až 15 min.
Bod 3 (Tesla API SoC) čeká na developer credentials.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- nová funkce na konci souboru + jeden řádek v run_telemetry_loop
(minimální dotyk kvůli souběžným změnám na main)
- čte vw_asset_pool_pump_http_poll, zapisuje fn_telemetry_pool_pump_sample
- při výpadku čtení nic nezapisuje (žádná fabrikovaná nula)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
poll_ev_chargers četl placeholder ('available'/0 W) — EV spotřeba se nikdy
neodečítala z bazálu a session detekce nefungovala. Nyní: blok registrů 0-40
jedním FC 3 (oficiální protokol rev 0.5), parse_teltocharge_frame (status z
reg 6 → available/preparing/charging/..., výkon reg 38, energie session reg 39,
proud max L1-L3 reg 3-5). Při selhání čtení se vzorek NEzapisuje (fabrikovaný
available by falešně ukončoval session).
fn_telemetry_ev_charger_sample: + p_current_a (drop staré 7-arg signatury).
6 nových testů parseru; plná sada beze změny. Docs: modbus-registers-teltocharge.md.
Po deployi: home-01 ev-charger-1/2 začnou posílat reálná data; bazál se začne
čistit od EV (EMA 00:30); rebuild stats má smysl až po ~2 týdnech čisté historie.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
services/planning/solver_v2.py: MILP s objective = reálné peníze (cash +
degradace − terminal SoC value z DB faktoru). Tvrdá pravidla: bilance, SoC
dynamika, breaker (tvrdý), curtail jen A, GEN cutoff binárka, neg-buy/neg-sell
export bloky, export z baterie ⇒ arb floor (p.19), zákaz současného imp+exp,
EV deadline (placený slack 50 Kč/kWh místo infeasibility), TUV look-ahead,
provozní režimy. SQL masky allow_* vědomě ignorovány (heuristika, ne fyzika).
solver_v2_eval.py: v2 vs v1 na golden fixtures (SoC-fér):
v2 lepší na VŠECH 5 řešitelných (+231.5 Kč ≈ +22 %), extreme_neg_buy den
v1=INFEASIBLE → v2 OK (−674.5 Kč). Časy 0.4–10 s (2× na time limitu — TODO).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SoC série, neg-sell fáze/okna, evening push, pre-neg logika — čistý přesun,
fasáda v planning_engine.py beze změny chování (golden 5/5, baseline faily
beze změny). Roztroušené konstanty MORNING_PRENEG_* doplněny do constants.py.
planning_engine.py: 6345 → 3925 řádků (zbývá: solver, orchestrace, compare).
heuristics.py nese warning: hlavní kandidáti na prune ve Fázi 2/3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Čistý přesun 57 konstant (vč. SOLVER_RELAX_STEPS) z planning_engine.py;
engine je importuje zpět (fasáda, beze změny chování). Golden replay 5/5,
unit testy beze změny vůči baseline (4+1 předexistující faily).
Ekonomické penalty/váhy tím získaly jedno místo — kandidáti na DB ve Fázi 2.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>