Tesla Fleet API: čtení SoC po příjezdu k wallboxu
- 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>
This commit is contained in:
37
backend/tests/test_tesla_client.py
Normal file
37
backend/tests/test_tesla_client.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""Tesla Fleet API – čisté parsery (bez sítě/DB)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from services.tesla_client import parse_charge_state
|
||||
|
||||
|
||||
class ParseChargeStateTests(unittest.TestCase):
|
||||
def test_full_response(self) -> None:
|
||||
data = {
|
||||
"response": {
|
||||
"vin": "5YJYGDEE0MF000000",
|
||||
"charge_state": {
|
||||
"battery_level": 47,
|
||||
"charge_limit_soc": 80,
|
||||
"charging_state": "Stopped",
|
||||
},
|
||||
}
|
||||
}
|
||||
out = parse_charge_state(data)
|
||||
self.assertEqual(out["battery_level"], 47)
|
||||
self.assertEqual(out["charge_limit_soc"], 80)
|
||||
self.assertEqual(out["vin"], "5YJYGDEE0MF000000")
|
||||
|
||||
def test_missing_level_returns_none(self) -> None:
|
||||
self.assertIsNone(parse_charge_state({"response": {"charge_state": {}}}))
|
||||
self.assertIsNone(parse_charge_state({}))
|
||||
|
||||
def test_zero_limit_normalized_to_none(self) -> None:
|
||||
data = {"response": {"charge_state": {"battery_level": 10, "charge_limit_soc": 0}}}
|
||||
self.assertIsNone(parse_charge_state(data)["charge_limit_soc"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user