# TeslaMate MQTT Integration: Architecture, Configuration, and Topic Structure

> Learn how TeslaMate integrates with MQTT for real-time vehicle telemetry. Explore its architecture, configuration, and clear topic structure for seamless data publishing under teslamate/<namespace>/cars/<car_id>/<key>.

- Repository: [TeslaMate/teslamate](https://github.com/teslamate-org/teslamate)
- Tags: architecture
- Published: 2026-06-18

---

**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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/application.ex), the supervision tree conditionally includes the MQTT component only when configuration exists:

```elixir
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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/mqtt/publisher.ex) provides the core publishing interface:

```elixir
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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs):

```elixir
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:

```elixir
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`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/config/runtime.exs).

### How do I configure TeslaMate MQTT integration?

Set environment variables or explicit config values in [`config/runtime.exs`](https://github.com/teslamate-org/teslamate/blob/main/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`](https://github.com/teslamate-org/teslamate/blob/main/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.