How TeslaMate Uses GenServer and Supervisor Patterns for Vehicle Management

TeslaMate models each physical Tesla vehicle as a separate GenStateMachine process supervised by a dynamic Supervisor, ensuring fault-tolerant fleet management where a crash in one vehicle process does not affect others.

TeslaMate is a self-hosted data logger for Tesla vehicles built with Elixir. According to the teslamate-org/teslamate source code, the application leverages Erlang/OTP's GenServer and Supervisor patterns to isolate each vehicle into its own managed process, creating a resilient architecture that scales from a single car to an entire fleet without code changes.

Supervisor Architecture with TeslaMate.Vehicles

The TeslaMate.Vehicles module acts as the central supervisor for all vehicle processes. Defined in lib/teslamate/vehicles.ex, it use Supervisor to implement a dynamic supervision tree that manages the lifecycle of every vehicle in the fleet.

Application Startup and Initialization

The application boot sequence begins in lib/teslamate/application.ex, where the root supervisor starts TeslaMate.Vehicles via Supervisor.start_link/3. During initialization, the init/1 callback queries the Tesla API to retrieve the vehicle list, then builds a child specification for each car using TeslaMate.Vehicles.Vehicle.child_spec/1. This creates a uniquely-named process for each vehicle under the supervisor's control.

Fault Isolation with One-for-One Strategy

The supervisor employs a :one_for_one restart strategy. If a single vehicle process crashes—perhaps due to a malformed API response or network timeout—only that specific process is restarted. This isolation ensures that a fault in one vehicle's data stream never interrupts logging for other vehicles in the fleet.

Runtime Fleet Control

Helper functions in lib/teslamate/vehicles.ex provide operational control over the entire fleet:

  • kill/0 terminates all vehicle processes using Supervisor.stop/2
  • restart/0 triggers a complete supervisor restart
  • list/0 returns active children via Supervisor.which_children/1

Vehicle Processes as State Machines

Each vehicle runs as an independent process managed by TeslaMate.Vehicles.Vehicle, which uses GenStateMachine (a GenServer extension) to model complex vehicle states and transitions.

Process Registration and Naming

In lib/teslamate/vehicles/vehicle.ex, the start_link/1 function creates a uniquely named process for each car using an atom derived from the vehicle ID: :"#{car.id}". This global registration allows other processes to send messages to specific vehicles without maintaining PID references.

State Machine Implementation

The handle_event/4 callback implements a finite state machine with distinct states including :start, :online, :asleep, :offline, :driving, :charging, :suspended, and :updating. Each state encapsulates specific logic for data polling, streaming API connections, and transition conditions. For example, the process transitions from :online to :driving when the vehicle begins moving, while the :charging state handles power flow monitoring and charge session tracking.

Public API and Messaging

Public functions provide a clean interface for interacting with vehicle processes:

  • summary/1 retrieves current vehicle state via GenStateMachine.call/2
  • suspend_logging/1 and resume_logging/1 control data collection
  • subscribe_to_summary/1 integrates with Phoenix PubSub for real-time updates

Circuit Breakers for API Resilience

To handle Tesla API instabilities, the vehicle process installs two fuse circuits—:vehicle_not_found and :api_error. When repeated failures blow these fuses, the supervisor kills and restarts the entire fleet, forcing a fresh connection to the Tesla API rather than allowing cascading failures.

Integration with Supporting GenServers

The vehicle processes coordinate with specialized GenServers for cross-cutting concerns.

MQTT Publishing

The TeslaMate.Mqtt.Publisher GenServer, defined in lib/teslamate/mqtt/publisher.ex, handles all MQTT message publishing. Vehicle processes communicate with this server via GenServer.call/3 to broadcast telemetry data to external systems.

Token Management and Updates

TeslaMate.Vault (in lib/teslamate/vault.ex) stores API tokens in a centralized GenServer using use GenServer, ensuring all vehicle processes use valid authentication without duplicating token state. Additionally, TeslaMate.Updater (in lib/teslamate/updater.ex) runs as a separate GenServer under the application supervisor to periodically check for new TeslaMate releases.

Practical Implementation Examples

The following examples demonstrate how to interact with the supervision tree and vehicle processes at runtime:


# Starting the vehicle supervisor (typically done at application boot)

{:ok, _pid} = TeslaMate.Vehicles.start_link(name: TeslaMate.Vehicles)

# Dynamically adding a new vehicle to the supervision tree

vehicle_spec = TeslaMate.Vehicles.Vehicle.child_spec(car: %Car{id: 42, name: "Model 3"})
{:ok, _pid} = Supervisor.start_child(TeslaMate.Vehicles, vehicle_spec)

# Querying vehicle state via the GenStateMachine API

%Vehicle.Summary{} = TeslaMate.Vehicles.summary(42)

# Suspending data collection for a specific vehicle

:ok = TeslaMate.Vehicles.suspend_logging(42)

# Restarting the entire fleet (useful after configuration changes)

TeslaMate.Vehicles.restart()

Summary

  • Process Isolation: Each vehicle operates as a separate GenStateMachine process in lib/teslamate/vehicles/vehicle.ex, ensuring faults remain localized and do not crash the entire fleet.
  • Supervision Tree: The TeslaMate.Vehicles supervisor uses a :one_for_one strategy to automatically restart failed vehicle processes, maintaining continuous data collection.
  • State-Driven Design: Finite state machines cleanly separate concerns between driving, charging, sleeping, and offline states, simplifying complex polling logic in handle_event/4.
  • Dynamic Scalability: Adding vehicles requires only adding new child specifications to the supervisor, allowing the system to scale without architectural changes.
  • Operational Control: Functions like kill/0 and restart/0 in lib/teslamate/vehicles.ex enable graceful fleet-wide restarts for configuration reloads or API reconnection.

Frequently Asked Questions

What is the difference between GenServer and GenStateMachine in TeslaMate?

While both are built on GenServer, GenStateMachine (used in lib/teslamate/vehicles/vehicle.ex) provides explicit state handling through handle_event/4 callbacks. This allows TeslaMate to model complex vehicle lifecycle states—such as transitioning from :online to :driving to :charging—more cleanly than a standard GenServer, which would require manual state tracking in the process dictionary.

How does TeslaMate handle a crashed vehicle process?

The TeslaMate.Vehicles supervisor implements a :one_for_one restart strategy. When a vehicle process crashes, the supervisor automatically restarts only that specific process using the original child specification from TeslaMate.Vehicles.Vehicle.child_spec/1, leaving all other vehicle processes unaffected and maintaining data continuity for the rest of the fleet.

Can TeslaMate manage multiple vehicles simultaneously?

Yes. The supervision tree is designed for dynamic scalability. Each vehicle gets its own named process (e.g., :"42" for vehicle ID 42), and the supervisor in lib/teslamate/vehicles.ex can manage dozens of concurrent vehicle processes. Adding a new vehicle simply requires starting a new child under the existing supervisor.

What happens when the Tesla API returns repeated errors?

The vehicle process implements circuit breaker patterns using fuse circuits named :vehicle_not_found and :api_error. When these fuses blow due to repeated API failures, the supervisor kills and restarts the entire vehicle fleet. This forces a clean reconnection to the Tesla API rather than allowing the system to persist in a degraded state with invalid authentication or stale connections.

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 →