Core Components of TeslaMate: Architecture and Source Code Guide
TeslaMate is built around a fault-tolerant OTP supervision tree that coordinates an API client, per-vehicle GenStateMachine processes, an Ecto-based logging layer, an optional MQTT bridge, and a Phoenix LiveView web interface.
TeslaMate is a self-hosted telemetry collector for Tesla vehicles written in Elixir. Understanding the core components of TeslaMate reveals how it authenticates with Tesla's cloud API, manages state machines for multiple vehicles, and persists high-frequency telemetry data to PostgreSQL. The architecture follows OTP principles, organizing functionality into isolated processes under a unified supervision tree defined in lib/teslamate/application.ex.
Application and Supervision Tree
The entry point TeslaMate.Application constructs the supervision tree at runtime. It dynamically builds a list of child processes based on configuration, including the Ecto repository, vault, HTTP client, API client, and optional MQTT connector.
defp children do
[
TeslaMate.Repo,
TeslaMate.Vault,
TeslaMate.HTTP,
TeslaMate.Api,
TeslaMate.Updater,
{Phoenix.PubSub, name: TeslaMate.PubSub},
TeslaMateWeb.Endpoint,
TeslaMate.Terrain,
TeslaMate.Vehicles,
if(mqtt_config, do: {TeslaMate.Mqtt, mqtt_config}),
TeslaMate.Repair
]
|> Enum.reject(&is_nil/1)
end
This structure ensures that if the API client or a vehicle process crashes, the supervisor restarts it according to the defined strategy. The TeslaMate.Vehicles supervisor, stored in the @name module attribute, spawns child processes dynamically after discovering vehicles via the API.
API Client and Token Management
TeslaMate.Api is a GenServer that manages authentication with Tesla's cloud services. It stores the current TeslaApi.Auth struct in an ETS table and automatically refreshes access tokens before expiration.
def handle_call({:sign_in, args}, _, %State{} = state) do
# … perform Auth.refresh/1, store new tokens, restart vehicle registry …
end
The module proxies all API calls—including list_vehicles/0, get_vehicle/2, and stream/3—and implements circuit breaker logic. When the API returns :unauthorized, the process triggers a fuse that forces a sign-out and token refresh. Secure encryption of refresh and access tokens is handled by TeslaMate.Vault using the :crypto module, while TeslaMate.Auth and TeslaMate.Auth.Tokens manage the encryption/decryption logic.
Vehicle Registry and State Machines
The TeslaMate.Vehicles module acts as a supervisor that discovers vehicles via Api.list_vehicles/0 and spawns a dedicated process for each car. It provides public helper functions like list/0, summary/1, and suspend_logging/1 that forward calls to the respective vehicle processes.
def list do
Supervisor.which_children(@name)
|> Task.async_stream(fn {_, pid, _, _} -> Vehicle.summary(pid) end, ...)
|> Enum.map(&elem(&1, 1))
|> Enum.sort_by(&{&1.car.display_priority, &1.car.id})
end
Per-Vehicle GenStateMachine
Each vehicle runs an isolated GenStateMachine implemented in TeslaMate.Vehicles.Vehicle. This process maintains the car's current state and transitions between:
:asleep/:offline– Low-frequency polling while waiting for wake-up:online– Regular polling or streaming API connection when the vehicle is awake{:driving, …}– Active drive session with GPS tracking{:charging, …}– Charging process with energy monitoring{:suspended, …}– Logging temporarily disabled by user settings{:updating, …}– Firmware update in progress
Key callbacks include handle_event(:internal, {:update, {:online, vehicle}}, state, data) which processes incoming telemetry and decides whether to initiate a drive or charging session. The process also installs per-vehicle fuses (:vehicle_not_found, :api_error) to protect against repeated API failures.
Data Persistence with Ecto
All telemetry is persisted through the TeslaMate.Log context, which uses Ecto to write to PostgreSQL. The logging system creates records for every state change, drive, charge session, and GPS position.
Important functions include:
Log.start_state/3– Begins a new state entry (e.g., transitioning to:online)Log.insert_position/2– Stores GPS coordinates, battery level, temperature, and other telemetry pointsLog.start_charging_process/3– Creates a charging session record with location dataLog.close_drive/2– Finalizes a drive record with calculated distance and duration
Schema files are located in lib/teslamate/log/ and define tables for cars, drives, charges, and positions. The repository TeslaMate.Repo is configured in config/*.exs and supervised by the root application.
MQTT Bridge for External Systems
When configured, TeslaMate.Mqtt publishes live vehicle data to an MQTT broker. The module subscribes to internal Phoenix PubSub topics and forwards updates to topics like teslamate/<car_id>/summary. It also subscribes to command topics (e.g., wake_up) and forwards incoming commands to the appropriate vehicle process, enabling integration with home automation systems.
Configuration and Settings
User preferences are managed through the TeslaMate.Settings context. The CarSettings struct contains configurable fields such as suspend_min, use_streaming_api, and custom polling intervals. When settings change, the Vehicle process receives a message containing the %CarSettings{} struct and reconfigures its timers or streaming connection accordingly.
Phoenix LiveView Web Interface
The web layer resides in lib/teslamate_web and provides real-time visualization. The router (lib/teslamate_web/router.ex) mounts LiveViews for car overviews, drive details, and settings panels. These LiveViews subscribe to the same Phoenix PubSub topics used by the vehicle processes, ensuring the browser receives instant updates when telemetry changes.
def mount(_params, _session, socket) do
car_id = socket.assigns[:car_id]
Phoenix.PubSub.subscribe(TeslaMate.PubSub, TeslaMate.Vehicles.Vehicle.summary_topic(car_id))
{:ok, assign(socket, :summary, nil)}
end
def handle_info({:summary, summary}, socket) do
{:noreply, assign(socket, :summary, summary)}
end
Supporting Infrastructure
Terrain and Geofencing
TeslaMate.Terrain lazily downloads SRTM elevation tiles and caches them to provide altitude data for drives. The TeslaMate.Locations context resolves GPS coordinates to human-readable addresses and evaluates whether positions fall within user-defined geofences.
CSV Import Pipeline
TeslaMate.Import handles batch ingestion of historic CSV files exported from older TeslaMate instances. It uses Import.Csv to read rows and Import.LineParser to transform them before writing to the standard log tables.
Secure Updates and Token Vault
TeslaMate.Updater can download newer releases from GitHub and replace the current binary, while TeslaMate.Vault securely encrypts API tokens using the Erlang :crypto module, keeping credentials safe on disk.
Summary
- TeslaMate.Application builds a dynamic supervision tree that orchestrates all components
- TeslaMate.Api manages Tesla cloud authentication and token refresh via
GenServer - TeslaMate.Vehicles supervises a
GenStateMachineper vehicle to handle state transitions like driving and charging - TeslaMate.Log provides the Ecto context for persisting all telemetry to PostgreSQL
- TeslaMate.Mqtt optionally bridges live data to external MQTT brokers
- TeslaMateWeb delivers real-time visualization through Phoenix LiveView
- Supporting modules handle terrain data, CSV imports, self-updates, and secure token storage
Frequently Asked Questions
How does TeslaMate handle authentication with Tesla's API?
TeslaMate uses TeslaMate.Api to store the TeslaApi.Auth struct in an ETS table and automatically refreshes access tokens before they expire. The TeslaMate.Vault module encrypts tokens using Erlang's :crypto module, while TeslaMate.Auth handles the encryption/decryption logic, ensuring credentials remain secure on disk.
What database does TeslaMate use for data persistence?
TeslaMate uses PostgreSQL accessed through Ecto. The TeslaMate.Log context provides functions like insert_position/2 and start_charging_process/3 to write telemetry data, while TeslaMate.Repo manages the database connection pool under the OTP supervision tree.
How does TeslaMate support multiple vehicles?
The TeslaMate.Vehicles supervisor discovers all vehicles via the API and spawns a separate GenStateMachine process for each car using Vehicle.child_spec/1. Each process maintains independent state (asleep, driving, charging) and publishes updates to unique Phoenix PubSub topics, allowing the system to track an unlimited number of vehicles concurrently.
What is the purpose of the MQTT bridge in TeslaMate?
The optional TeslaMate.Mqtt component publishes live telemetry to an MQTT broker on topics like teslamate/<car_id>/summary, enabling integration with home automation platforms. It also subscribes to command topics, allowing external systems to send commands such as wake-up requests back to the vehicle processes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →