- 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>
99 lines
4.5 KiB
Markdown
99 lines
4.5 KiB
Markdown
# Tesla Fleet API — napojení EMS (čtení SoC vozidla)
|
||
|
||
Cíl: po příjezdu EV přečíst skutečné SoC → `ev_session.energy_needed_wh`
|
||
přesně místo defaultu. Doména `ems.vojacek.eu` slouží JEN jako veřejná
|
||
vizitka pro Tesla (cert + public key + jednorázový OAuth callback) — EMS
|
||
samotné zůstává na VPN.
|
||
|
||
## 1. Doména (jednorázově, na serveru)
|
||
|
||
```bash
|
||
bash /opt/ems-deploy/app/deploy/tesla/setup_tesla_domain.sh
|
||
# → přidat vypsaný blok do /etc/caddy/Caddyfile a `systemctl reload caddy`
|
||
```
|
||
|
||
Veřejné je pouze:
|
||
- `https://ems.vojacek.eu/.well-known/appspecific/com.tesla.3p.public-key.pem`
|
||
- `https://ems.vojacek.eu/tesla/callback` (statická stránka zobrazí `?code=`)
|
||
- vše ostatní → 404; certifikát řeší Caddy (Let's Encrypt) automaticky.
|
||
|
||
## 2. Tesla developer portál (developer.tesla.com)
|
||
|
||
Vytvořit aplikaci:
|
||
- **Allowed Origin:** `https://ems.vojacek.eu`
|
||
- **Allowed Redirect URI:** `https://ems.vojacek.eu/tesla/callback`
|
||
- **Scopes:** `openid offline_access vehicle_device_data` (čtení SoC stačí;
|
||
`vehicle_charging_cmds` až kdybychom chtěli vozidlu poroučet my — teď řídí
|
||
wallbox, ne auto)
|
||
|
||
→ získáš `CLIENT_ID` a `CLIENT_SECRET`.
|
||
|
||
## 3. Partner account registrace (jednorázově)
|
||
|
||
```bash
|
||
# partner token (client_credentials):
|
||
curl -s https://fleet-auth.prd.vn.cloud.tesla.com/oauth2/v3/token \
|
||
-d grant_type=client_credentials -d client_id=$CLIENT_ID \
|
||
-d client_secret=$CLIENT_SECRET \
|
||
-d scope='openid vehicle_device_data' \
|
||
-d audience=https://fleet-api.prd.eu.vn.cloud.tesla.com | jq -r .access_token
|
||
|
||
# registrace domény (ověří si public key na .well-known):
|
||
curl -s -X POST https://fleet-api.prd.eu.vn.cloud.tesla.com/api/1/partner_accounts \
|
||
-H "Authorization: Bearer $PARTNER_TOKEN" -H 'Content-Type: application/json' \
|
||
-d '{"domain":"ems.vojacek.eu"}'
|
||
```
|
||
|
||
## 4. Uživatelský OAuth (jednorázově, z prohlížeče)
|
||
|
||
```
|
||
https://fleet-auth.prd.vn.cloud.tesla.com/oauth2/v3/authorize?
|
||
response_type=code&client_id=$CLIENT_ID&
|
||
redirect_uri=https://ems.vojacek.eu/tesla/callback&
|
||
scope=openid%20offline_access%20vehicle_device_data&state=ems
|
||
```
|
||
Přihlásíš se Tesla účtem → redirect na callback stránku → zkopíruješ `code` →
|
||
výměna za tokeny:
|
||
|
||
```bash
|
||
curl -s https://fleet-auth.prd.vn.cloud.tesla.com/oauth2/v3/token \
|
||
-d grant_type=authorization_code -d client_id=$CLIENT_ID \
|
||
-d client_secret=$CLIENT_SECRET -d code=$CODE \
|
||
-d redirect_uri=https://ems.vojacek.eu/tesla/callback
|
||
# → access_token (krátký) + refresh_token (ULOŽIT — viz krok 5)
|
||
```
|
||
|
||
## 5. EMS integrace (plán implementace)
|
||
|
||
- env: `TESLA_CLIENT_ID`, `TESLA_CLIENT_SECRET`, `TESLA_REFRESH_TOKEN`
|
||
(`/opt/ems-deploy/.env`); refresh token rotuje → po každém refreshi uložit
|
||
nový (tabulka `ems.tesla_token` nebo aktualizace .env jobem — rozhodnout).
|
||
- `services/tesla_client.py`: refresh → access token (cache ~8 h),
|
||
`GET /api/1/vehicles`, `GET /api/1/vehicles/{id}/vehicle_data`
|
||
→ `charge_state.battery_level`, `charge_state.charge_limit_soc`.
|
||
- Hook v `_on_ev_arrival` (telemetry_collector): po detekci příjezdu zavolat
|
||
API, `energy_needed_wh = max(0, (limit − level)/100 × battery_capacity_kwh
|
||
× 1000 / účinnost nabíjení)` → `fn_ev_session_apply_patch`; replan už běží.
|
||
- Mapování vozidlo↔wallbox: `asset_vehicle.api_type='tesla'` + VIN sloupec
|
||
(doplnit migrací), heuristika „Tesla je na chargeru X" dle
|
||
`default_charger_id`.
|
||
- Pozn.: vehicle_data budí auto (vampire drain) — volat jen při příjezdu
|
||
a max 1× za session.
|
||
|
||
## Stav (2026-06-11 večer)
|
||
|
||
- [x] skript + callback + dokumentace v repu
|
||
- [x] uživatel: doména + Caddy + developer portál (CLIENT_ID/SECRET získány)
|
||
- [x] EMS implementace: `services/tesla_client.py` (refresh s rotací do
|
||
`ems.tesla_token`, vehicles → vehicle_data charge_state, 408=spící auto),
|
||
hook `_patch_session_from_tesla` v telemetry_collector (po příjezdu, před
|
||
replanem; selhání neblokuje plán), `fn_tesla_arrival_context`,
|
||
`fn_ev_session_apply_patch` + soc_at_connect_pct, VIN auto-learn,
|
||
V086 (vin, api_type='tesla' pro tesla-my, tabulka tesla_token)
|
||
- [ ] uživatel: partner registrace (§3) + OAuth (§4) → `TESLA_CLIENT_ID`,
|
||
`TESLA_CLIENT_SECRET`, `TESLA_REFRESH_TOKEN` do `/opt/ems-deploy/.env`
|
||
a `docker compose -f /opt/ems-deploy/docker-compose.yml --env-file
|
||
/opt/ems-deploy/.env up -d backend` (recreate kvůli env)
|
||
- [ ] ověření: po příjezdu Tesly log `Tesla SoC -> session …` +
|
||
`select soc_at_connect_pct, target_soc_pct from ems.ev_session order by id desc limit 1`
|