TeslaMate MQTT Integration: Architecture, Configuration, and Topic Structure

TeslaMate integrates with MQTT using the Tortoise311 Elixir client library to publish real-time vehicle telemetry through a supervision tree that maps internal vehicle state to hierarchical topics under teslamate/<namespace>/cars/<car_id>/<key>.

The teslamate-org/teslamate repository implements a robust MQTT integration that enables real-time streaming of Tesla vehicle data to IoT platforms and home automation systems. This integration leverages Erlang/OTP supervision patterns to ensure reliable message delivery while maintaining a lightweight footprint by delegating protocol handling to the Tortoise311 library.

How TeslaMate MQTT Integration Works

Configuration and Initialization

The MQTT broker connection is configured in config/runtime.exs using environment variables or explicit config values. When a non-nil :mqtt configuration is present, the application automatically launches the MQTT supervision tree.

Key configuration parameters include:

  • Host and Port: Broker connection endpoints
  • Credentials: Username/password authentication
  • Client ID: Identifier for the MQTT connection
  • QoS: Quality of Service level (defaults to 1)
  • Namespace: Topic prefix (defaults to "teslamate")

Application Startup Sequence

In lib/teslamate/application.ex, the supervision tree conditionally includes the MQTT component only when configuration exists:

if(mqtt_config != nil, do: {TeslaMate.Mqtt, mqtt_config}),

This pattern ensures that TeslaMate.Mqtt starts as a supervised child only when explicitly configured, preventing connection errors in MQTT-less deployments.

Supervision Tree Architecture

The TeslaMate.Mqtt module (defined in lib/teslamate/mqtt.ex) orchestrates two supervised children:

  • TeslaMate.Mqtt.Publisher: A GenServer that wraps Tortoise311.publish/4 and handles outgoing messages with configurable QoS and retention
  • TeslaMate.Mqtt.PubSub: A Supervisor that spawns a VehicleSubscriber process for each registered vehicle retrieved via Vehicles.list/0

This hierarchy ensures that if the publisher or any vehicle subscriber crashes, only that specific process restarts without affecting the entire MQTT integration.

Publishing Vehicle Telemetry

VehicleSubscriber Process

Each vehicle in the fleet gets its own subscriber process via lib/teslamate/mqtt/pubsub/vehicle_subscriber.ex. These processes:

  1. Subscribe to vehicle summary streams using Vehicles.subscribe_to_summary/1
  2. Receive %TeslaMate.Vehicles.Vehicle.Summary{} structs containing telemetry data
  3. Extract fields including battery level, speed, location, geofence, and active route
  4. Publish updates concurrently using Task.async_stream/3 with failure logging via Logger.warning/1

Topic Structure and Naming Convention

TeslaMate MQTT integration uses a hierarchical topic pattern:


teslamate/<namespace>/cars/<car_id>/<key>

  • <namespace>: Configurable prefix (defaults to "teslamate")
  • <car_id>: Numeric vehicle identifier
  • <key>: Telemetry field name such as battery_level, latitude, longitude, charging_state, or heading

The publish/3 helper function in the publisher module constructs these topics automatically, converting Elixir values to strings before transmission.

Retained Messages and Cleanup

The system differentiates between retained and non-retained messages:

  • Retained: Most telemetry fields (battery level, location) are retained so new subscribers immediately receive the last known state
  • Non-retained: Fields like healthy that appear in the @do_not_retain list are published without the retained flag

On startup, each subscriber calls clear_retained/3 to wipe stale retained messages for keys that should no longer persist, preventing outdated data from surviving across application restarts.

Implementation Details

The Publisher Module

lib/teslamate/mqtt/publisher.ex provides the core publishing interface:

def publish(topic, value, opts \\ []) do
  # Converts value to string, builds full topic

  # Calls Tortoise311.publish/4 with QoS and retain flags

end

The module supports QoS 1 delivery semantics and handles connection state transparently through the underlying Tortoise311 client.

Connection Handling

lib/teslamate/mqtt/handler.ex implements the Tortoise311.Handler behaviour, providing callbacks for:

  • connection_up/3: Logs successful broker connections
  • connection_down/3: Handles disconnections
  • terminate/3: Cleans up on client termination

These callbacks ensure visibility into MQTT connection health through standard Elixir logging.

Configuring TeslaMate MQTT Integration

To enable MQTT publishing, add the following to config/runtime.exs:

config :teslamate, :mqtt,
  host: System.get_env("MQTT_HOST") || "localhost",
  port: System.get_env("MQTT_PORT") && String.to_integer(System.get_env("MQTT_PORT")) || 1883,
  username: System.get_env("MQTT_USERNAME") || "teslamate",
  password: System.get_env("MQTT_PASSWORD") || "mqttpassword",
  client_id: System.getFollowersByUsername("USERNAME")_id: "teslamate",
  qos: 1,
  retain: true,
  namespace: "teslamate"

To publish custom metrics from your own code:

topic = "teslamate/custom/cars/1/custom_metric"
value = 99.9
TeslaMate.Mqtt.Publisher.publish(topic, value, retain: true, qos: 1)

Summary

  • Tortoise311 Foundation: TeslaMate MQTT integration relies on the Tortoise311 Elixir library for protocol handling, providing reliable QoS 1 messaging
  • Supervised Architecture: The system uses TeslaMate.Mqtt as a supervisor coordinating Publisher and PubSub processes, with per-vehicle VehicleSubscriber processes ensuring fault isolation
  • Hierarchical Topics: Data publishes to teslamate/<namespace>/cars/<car_id>/<key>, supporting configurable namespaces and comprehensive telemetry including battery, location, and charging state
  • Retained Message Management: Critical fields use retained messages for immediate state availability, while clear_retained/3 prevents stale data persistence
  • Configuration-Driven: Activation requires only :mqtt config in config/runtime.exs, with the TeslaMate.Application conditionally starting the supervision tree

Frequently Asked Questions

What MQTT broker does TeslaMate use?

TeslaMate uses the Tortoise311 MQTT client library (an actively maintained fork of Tortoise) to connect to any standards-compliant MQTT broker. The integration supports brokers like Mosquitto, RabbitMQ, HiveMQ, and cloud-based IoT platforms, requiring only standard host, port, and credential configuration in config/runtime.exs.

How do I configure TeslaMate MQTT integration?

Set environment variables or explicit config values in config/runtime.exs under the :mqtt key for the :teslamate application. Required fields include host, port, username, password, and optionally qos, retain, and namespace. The application detects this configuration in lib/teslamate/application.ex and starts the MQTT supervision tree only when present.

What is the topic structure for TeslaMate MQTT messages?

TeslaMate publishes to topics following the pattern teslamate/<namespace>/cars/<car_id>/<key>. The default namespace is "teslamate", <car_id> is the numeric vehicle identifier, and <key> represents specific telemetry fields like battery_level, charging_state, latitude, or speed. This structure allows fine-grained subscription to individual vehicles or specific data points.

Does TeslaMate support MQTT QoS levels and retained messages?

Yes. TeslaMate MQTT integration supports QoS 1 (at least once delivery) by default, configurable via the :qos setting. Retained messages are enabled by default for most telemetry keys, ensuring new subscribers receive the last known vehicle state immediately. The TeslaMate.Mqtt.Publisher module handles retention logic, excluding specific keys defined in @do_not_retain (such as healthy) from retention to prevent misleading status indicators.

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 →