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 points
  • Log.start_charging_process/3 – Creates a charging session record with location data
  • Log.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 GenStateMachine per 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →