ChargeCosts
Tesla EV Companion App with Full Fleet API Integration
Rust (Axum, Tokio) · React 19 (TypeScript) · Vite · Cloudflare Pages · Protocol Buffers (prost)
Overview
ChargeCosts is a full-stack Tesla companion app with real-time vehicle telemetry, remote controls, and detailed charging analytics including cost per mile, cost per kWh, carbon emissions, and gas vehicle cost comparisons. The Rust backend implements the full Tesla Vehicle Command Protocol (TVCP) signing pipeline required by all 2024+ Tesla firmware.
Highlights
- Built full Tesla Fleet API integration: real-time vehicle telemetry (battery, range, drive state, location, charging metrics), remote vehicle controls (trunk, charge port, flash lights, climate, wake), and charging history with per-session cost breakdowns and invoice retrieval
- Implemented the full Tesla Vehicle Command Protocol (TVCP) signing pipeline in Rust: P-256 ECDH key exchange → SHA-1 KDF → AES-128 key → HMAC-SHA256 subkey via 'authenticated command' derivation → TLV-encoded metadata signing → Protocol Buffer serialization → signed RoutableMessage over HTTPS
- Engineered Virtual Key pairing via RFC 8615 .well-known endpoint: registered P-256 public key with Tesla, implemented one-time vehicle pairing via deep link, verified pairing cryptographically via live vehicle_data fetch
- Implemented OAuth 2.0 with PKCE for Tesla auth: server-side-only token storage (frontend never sees tokens), automatic token refresh with 60-second expiry buffer to prevent race conditions
- Managed two independent TVCP signing domains (VCSEC=2 for structural commands, Infotainment=3 for cabin controls) with per-domain session caching, monotonic anti-replay counters, and automatic session resync on epoch/counter fault
- Designed concurrent AppState with Rust concurrency primitives: Mutex<Option<T>> for complex shared state, AtomicBool for lock-free single-flip pairing flag, tokio::sync::Mutex for async-held charge port state
- Diagnosed and resolved multiple undocumented TVCP edge cases: from_destination must be 16 random bytes (not the 65-byte public key); FLAGS_ENCRYPT_RESPONSE = 2 (bit 1, not 1); P-256 key loading requires fallback DER parser for Tesla's explicit-curve-parameter encoding