Discord EV: dva výběry (odjezd × cíl) místo řady tlačítek
Arrival zpráva má dva persistent Selecty (custom_id ev:<site>:<charger>:dep a :tgt, obsluha on_interaction + regex → přežijí restart): „Kdy odjíždíš?" za 2 h | za 4 h | dnes večer 18:00 | zítra ráno 7:00 | zítra poledne 12:00 | pondělí ráno 7:00; „Kolik potřebuješ?" 30/50/70/100 % | Nenabíjet. Každý výběr okamžitě PATCHne session přes fn_ev_session_apply_patch jen ve své dimenzi (absolutní deadline Europe/Prague, nejbližší budoucí výskyt; pevná volba smí přes 48 h), druhý rozměr zůstává z fn_ev_session_defaults. Pak replan + export a edit zprávy přepočteným plánem (build_ev_plan_summary) + potvrzením. Whitelist DISCORD_ALLOWED_USER_IDS i bot-first/webhook fallback beze změny; legacy tlačítka h2/h4/morning/full/stop starších zpráv dál obsloužená. Testy: mapování výběr→patch, absolutní deadline z voleb (půlnoc, pondělí z pátku >48 h, pondělí ráno v pondělí), parse, legacy akce — bez DB/sítě. Docs: discord-ev-interaction.md (nové UI, no-click = pohotovostní režim 30 % + oportunismus). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,34 +15,59 @@ Plán nabíjení: 11:30–13:45; 02:15–04:30 — 34.2 kWh, ø 1.85 Kč/kWh
|
||||
Implementace: `_notify_ev_arrival_plan` v `telemetry_collector.py` (sloty
|
||||
`ev*_setpoint_w > 0` z aktivního plánu shlukované do oken).
|
||||
|
||||
## Fáze B — zpětná vazba tlačítkem — ✅ IMPLEMENTOVÁNO (2026-06-12)
|
||||
## Fáze B — zpětná vazba dvěma výběry — ✅ IMPLEMENTOVÁNO (2026-06-12)
|
||||
|
||||
**Architektura: Discord BOT přes gateway** — spojení jde Z backendu VEN
|
||||
(websocket), žádný veřejný endpoint do EMS (na rozdíl od interactions
|
||||
webhooku). Knihovna `discord.py`, token v `/opt/ems-deploy/.env`.
|
||||
|
||||
Zpráva z fáze A dostane tlačítka:
|
||||
`[Odjezd za 2 h] [za 4 h] [Ráno (typicky)] [Do plna hned] [Nenabíjet]`
|
||||
Zpráva z fáze A dostane **dva selecty** (místo dřívější řady tlačítek):
|
||||
|
||||
Callback tlačítka:
|
||||
1. `fn_ev_session_apply_patch(site, session, {"target_deadline": now+2h, …})`
|
||||
(„Do plna hned" navíc `target_soc_pct=100`; „Nenabíjet" `target_soc_pct=soc`),
|
||||
2. okamžitý `run_rolling_replan` + `export_setpoints` (vzor ev_arrival),
|
||||
3. bot **edituje původní zprávu** novým plánem (žádný spam).
|
||||
```
|
||||
🔌 Tesla Model Y připojeno
|
||||
Baterie auta: 55 % → cíl 90 % (~26 kWh)
|
||||
Deadline: po 15.06. 07:00
|
||||
Plán nabíjení: 11:30–13:45; 02:15–04:30 — 26.2 kWh, ø 1.85 Kč/kWh
|
||||
[ 🕑 Kdy odjíždíš? ▾ ] za 2 h | za 4 h | dnes večer 18:00 |
|
||||
zítra ráno 7:00 | zítra poledne 12:00 |
|
||||
pondělí ráno 7:00
|
||||
[ 🔋 Kolik potřebuješ? ▾ ] 30 % | 50 % | 70 % | 100 % | Nenabíjet
|
||||
```
|
||||
|
||||
**Sémantika:**
|
||||
- Každý výběr **okamžitě** PATCHne otevřenou session přes
|
||||
`fn_ev_session_apply_patch` — ale jen ve SVÉ dimenzi: výběr 1 nastaví
|
||||
`target_deadline` (absolutní čas Europe/Prague; pevné volby = nejbližší
|
||||
budoucí výskyt, „pondělí ráno" z pátku je validní i přes 48 h),
|
||||
výběr 2 nastaví `target_soc_pct`. Druhý rozměr zůstává beze změny
|
||||
(default z `fn_ev_session_defaults`, případně dřívější výběr).
|
||||
- „Nenabíjet" = stop akce (target = SoC při připojení → solver nic neplánuje).
|
||||
- **No-click = pohotovostní režim:** bez kliknutí jede session na defaultech
|
||||
z `ems.fn_ev_session_defaults` (týdenní požadavek `ev_weekly_requirement`
|
||||
→ forecast z rytmu → defaulty vozidla; viz `docs/04-modules/ev-charging.md`).
|
||||
S `min_target_soc_pct` 30 % to znamená: drž aspoň ~30 % pro pohotovost
|
||||
a zbytek doplňuj oportunisticky v levných/záporných slotech
|
||||
(`opportunistic_value_czk_kwh` — měkký cíl).
|
||||
|
||||
Po každém výběru: patch session → okamžitý `run_rolling_replan` +
|
||||
`export_setpoints` (vzor ev_arrival) → bot **edituje původní zprávu**
|
||||
přepočteným plánem (`build_ev_plan_summary`) + potvrzením
|
||||
`_(nastaveno: odjezd dnes večer 18:00)_` (žádný spam).
|
||||
|
||||
Bezpečnost: bot reaguje jen na whitelisted user ID (majitel), akce omezené
|
||||
na patch session + replan (žádné režimy/registry). Tlačítka expirují
|
||||
s koncem session.
|
||||
na patch session + replan (žádné režimy/registry). Selecty expirují
|
||||
s koncem session (uzavřená session → ephemeral „Session už není otevřená").
|
||||
|
||||
**Implementace:** `services/discord_bot.py` (lifespan task; discord.py
|
||||
gateway), `services/ev_notify.py` (sdílený souhrn plánu; bot-first, webhook
|
||||
fallback). custom_id `ev:<site>:<charger>:<akce>` — tlačítka přežijí restart.
|
||||
Env: `DISCORD_BOT_TOKEN`, `DISCORD_EV_CHANNEL_ID`, `DISCORD_ALLOWED_USER_IDS`
|
||||
(čárkami; prázdné = bot vypnut, jede fáze A webhook). Akce: h2/h4 (deadline
|
||||
teď+N), morning (další default_deadline_hour vozidla, Prague), full (100 % +
|
||||
deadline za 1 h → max tempo), stop (target = SoC při připojení). Po akci:
|
||||
patch session → okamžitý replan + export → bot zedituje zprávu novým plánem.
|
||||
Testy: tests/test_discord_bot.py (parse, patch akcí).
|
||||
fallback). custom_id `ev:<site>:<charger>:dep` / `:tgt` — obsluha přes
|
||||
`on_interaction` + regex (persistent vzor), selecty přežijí restart backendu.
|
||||
Legacy tlačítka `h2|h4|morning|full|stop` ze starších zpráv zůstávají
|
||||
obsloužená (`action_to_patch`). Env: `DISCORD_BOT_TOKEN`,
|
||||
`DISCORD_EV_CHANNEL_ID`, `DISCORD_ALLOWED_USER_IDS` (čárkami; prázdné =
|
||||
bot vypnut, jede fáze A webhook).
|
||||
Testy: tests/test_discord_bot.py (parse, výběr→patch, absolutní deadline
|
||||
z voleb vč. půlnoci a pondělí z pátku, legacy akce).
|
||||
|
||||
## Výhled (fáze C)
|
||||
Stejný bot = kanál pro ranní triáž s dotazy („proč jsi v 19:00 nabíjel?" →
|
||||
|
||||
Reference in New Issue
Block a user