diff --git a/deploy/tesla/callback.html b/deploy/tesla/callback.html
new file mode 100644
index 0000000..5d20559
--- /dev/null
+++ b/deploy/tesla/callback.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ EMS – Tesla OAuth callback
+
+
+
+
+
Tesla OAuth callback
+
Autorizační kód (zkopíruj do EMS kroku výměny tokenu):
+
—
+
Stránka je statická, kód se nikam neodesílá. Po výměně za
+ refresh token už není potřeba.
+
+
+
+
diff --git a/deploy/tesla/setup_tesla_domain.sh b/deploy/tesla/setup_tesla_domain.sh
new file mode 100755
index 0000000..607b0c4
--- /dev/null
+++ b/deploy/tesla/setup_tesla_domain.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+# Jednorázová příprava domény ems.vojacek.eu pro Tesla Fleet API.
+# SPOUŠTĚT NA SERVERU (tam, kde běží hostovský Caddy): bash setup_tesla_domain.sh
+#
+# Co udělá:
+# 1. vygeneruje EC keypair (prime256v1) pro Tesla Fleet API
+# - privátní klíč: /opt/ems-deploy/secrets/tesla-fleet-private.pem (0600)
+# - veřejný klíč: /opt/ems-deploy/public/.well-known/appspecific/com.tesla.3p.public-key.pem
+# 2. nakopíruje statickou OAuth callback stránku
+# 3. vypíše Caddy blok k přidání do Caddyfile + reload příkaz
+#
+# Veřejně vystavené je POUZE: public key (.pem) a callback.html. Vše ostatní 404.
+# EMS aplikace zůstává na VPN.
+
+set -euo pipefail
+
+ROOT="${EMS_DEPLOY_ROOT:-/opt/ems-deploy}"
+PUB="$ROOT/public"
+SEC="$ROOT/secrets"
+WELLKNOWN="$PUB/.well-known/appspecific"
+PRIV_KEY="$SEC/tesla-fleet-private.pem"
+PUB_KEY="$WELLKNOWN/com.tesla.3p.public-key.pem"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+mkdir -p "$WELLKNOWN" "$SEC" "$PUB/tesla"
+chmod 700 "$SEC"
+
+if [[ -f "$PRIV_KEY" ]]; then
+ echo "Privátní klíč už existuje: $PRIV_KEY (negeneruji znovu)"
+else
+ openssl ecparam -name prime256v1 -genkey -noout -out "$PRIV_KEY"
+ chmod 600 "$PRIV_KEY"
+ echo "Vygenerován privátní klíč: $PRIV_KEY"
+fi
+
+openssl ec -in "$PRIV_KEY" -pubout -out "$PUB_KEY" 2>/dev/null
+echo "Veřejný klíč: $PUB_KEY"
+
+install -m 0644 "$SCRIPT_DIR/callback.html" "$PUB/tesla/callback.html"
+echo "Callback stránka: $PUB/tesla/callback.html"
+
+cat <<'CADDY'
+
+================================================================
+Přidej do /etc/caddy/Caddyfile (a pak: systemctl reload caddy):
+================================================================
+
+ems.vojacek.eu {
+ root * /opt/ems-deploy/public
+
+ # Tesla Fleet API: veřejný klíč pro partner account registraci
+ handle /.well-known/appspecific/com.tesla.3p.public-key.pem {
+ file_server
+ }
+
+ # Jednorázový OAuth callback (statická stránka zobrazí ?code=)
+ handle /tesla/callback* {
+ file_server
+ }
+
+ # Nic dalšího neexponovat — EMS žije jen na VPN
+ handle {
+ respond 404
+ }
+}
+
+================================================================
+Ověření (z venku):
+ curl -sI https://ems.vojacek.eu/.well-known/appspecific/com.tesla.3p.public-key.pem
+ -> 200 + platný Let's Encrypt certifikát
+ curl -sI https://ems.vojacek.eu/cokoliv -> 404
+================================================================
+CADDY
diff --git a/docs/tesla-fleet-api.md b/docs/tesla-fleet-api.md
new file mode 100644
index 0000000..2bd7afe
--- /dev/null
+++ b/docs/tesla-fleet-api.md
@@ -0,0 +1,88 @@
+# 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
+
+- [x] skript + callback + dokumentace v repu
+- [ ] uživatel: spustit setup na serveru + Caddy blok + reload
+- [ ] uživatel: developer portál (CLIENT_ID/SECRET) + partner registrace + OAuth
+- [ ] EMS: tesla_client.py + hook (čeká na credentials)