Fleet Telemetry: Streaming Data from Your Tesla
Tags: tutorial, opensource
Published: 2024-02-24 10:01:29

Tesla's recent rollout of [fleet-telemetry](https://github.com/teslamotors/fleet-telemetry) empowers authorized users to seamlessly stream real-time data directly from Tesla vehicles. Let's delve into the process of initiating live data streaming from a Tesla vehicle.

To make this as smooth as possible, a few important notes:
- I created a [Postman collection](https://www.postman.com/patrickdemers6/workspace/tesla-fleet-api) to help with the API requests sent during this tutorial.
- The latest documentation for Tesla's Fleet API is available [here](https://developer.tesla.com/docs/fleet-api).

## Create a Developer Account

To begin your quest for data, first create a developer account on Tesla's official developer portal: [developer.tesla.com](https://developer.tesla.com).

I recommend selecting all scopes as there is no downside. Here is my configuration for Client Details:

![Client Details of Tesla developer application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rcjk1gp7jfdlydxifhuk.png)

## Finishing Application Registration

Once your developer application is created, you must register it with Fleet API.

This includes submitting a certificate signing request (CSR) to Tesla. To create one, first generate a private key.
```shell
openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
```

Now, derive its public key.

```
openssl ec -in private-key.pem -pubout -out public-key.pem
```

Make this public key accessible at: `https://your-domain.com/.well-known/appspecific/com.tesla.3p.public-key.pem`

> Note: there are two domains you may use throughout this tutorial. The first one is your public domain users are familiar with (such as your-domain.com). This is the domain you host your public key on. The second domain is the domain your fleet-telemetry server is exposed on (such as tesla-telemetry.your-domain.com).

Now, using the private key, create a CSR.

```
openssl req -out your-domain.com.csr -key private_key.pem -subj /CN=your-domain.com/ -new
```

With all this created, let's send it to Tesla.

1. In Postman, fill in your environment variables (client id, client secret, scopes, audience, redirect uri).
2. Send the "Generate Partner Token" request.
3. Send the "Register Partner Account" request.
  - Input the appropriate `domain` and `csr` in the body.

Sample body:
```json
{
  "domain": "your-domain.com",
  "csr": "-----BEGIN CERTIFICATE REQUEST-----\ncert_data\n-----END CERTIFICATE REQUEST-----\n
}
```

Once this is submitted, Tesla will process the CSR and update your account on the backend accordingly. It may take a few weeks to process. In the meanwhile, check out all the capabilities of [Fleet API](https://developer.tesla.com/docs/fleet-api).

## After CSR Confirmation

Once you receive a confirmation email from Tesla, you can begin configuring your fleet-telemetry server. Since the server will need to be accessible to the world, I am using a [Linode nano](https://www.linode.com/lp/refer/?r=1d59b066db56b58778f5e5859ee4e9ed96a56b9f) server to run everything.

### 1. Create another CSR (optional)

If the domain your fleet-telemetry server will be on is different from the domain used in the CSR above, create a new CSR for this domain.

### 2. Obtain a Certificate and CA Bundle

Next, we need to obtain a certificate for fleet-telemetry to use for TLS connections. There are many ways to do this, but I opted for a free and simple soution: LetsEncrypt and Certbot.

> Note: Ensure your server's DNS is configured for this to work.

```sh
# install certbot
sudo snap install --classic certbot

# ensure certbot command can be run
sudo ln -s /snap/bin/certbot /usr/bin/certbot

# create the certificate
# when offered http server or validation files, I opted for http server (option 1)
certbot certonly -d tesla-telemetry.your-domain.com --csr tesla-telemetry.your-domain.com.csr

```

The output of this last command should tell you where the certificate and full certificate chain are located. Copy these files into an easy to access directory.

```
Successfully received certificate.
Certificate is saved at:            /root/fleet-telemetry/0000_cert.pem
Intermediate CA chain is saved at:  /root/fleet-telemetry/0000_chain.pem
Full certificate chain is saved at: /root/fleet-telemetry/0001_chain.pem
```

## Create fleet-telemetry config

The fleet-telemetry server takes a JSON configuration file. You can take this template and customize accordingly:

```json
{
  "host": "0.0.0.0",
  "hostname": "tesla-telemetry.your-domain.com",
  "port": 443,
  "log_level": "debug",
  "json_log_enable": true,
  "namespace": "telemetry",
  "reliable_ack": false,
  "rate_limit": {
    "enabled": false,
    "message_limit": 100
  },
  "records": {
    "alerts": [
        "logger"
    ],
    "errors": [
        "logger"
    ],
    "V": [
          "logger"
      ]
  },
  "tls": {
    "server_cert": "path to certificate from previous step",
    "server_key": "path to private key"
  },
  "ca": "content of full certificate chain file from previous step"
}
```

> The `hostname` and `ca` fields are not required. They must be included to use the `check_server_cert.sh` script later in tutorial.

## Start your server

There are many ways to start your fleet-telemetry server. I opted to use Docker with the following `docker-compose.yml`:

```yml
version: '3.8'

services:
  app:
    build:
      context: ./repo
    ports:
      - 0.0.0.0:443:443
    volumes:
      - /path/on/host/to/certs:/config
      - /path/on/host/to/config.json:/etc/fleet-telemetry/config.json
```

This requires having `fleet-telemetry` cloned to the `repo` directory:
```
git clone https://github.com/teslamotors/fleet-telemetry.git repo
```

Then, start the server with `docker compose up`.

However you run fleet-telemetry, ensure your server is accessible to the outside world on port 443. This is the port vehicles use when connecting.

## Validate server configuration

Tesla provides a handy [check_server_cert.sh](https://github.com/teslamotors/fleet-telemetry/blob/main/tools/check_server_cert.sh) script to ensure your server is configured properly.

From your local machine, run the script. Pass in the path to your server's `config.json`:

```
./check_server_cert.sh config.json
```

Before moving on, be sure to get the success message from this script.

## Add Fleet Key to Vehicle
Before configuring a vehicle, it needs your Fleet Key (public key) to be added. To do this, send the owner to [https://tesla.com/_ak/your-domain.com](https://tesla.com/_ak/your-domain.com). This will prompt them to add your key to the vehicle.

## Send configuration to vehicle

Once the server configuration is validated, it's time to try sending data from a real vehicle.

The endpoints we used earlier required Partner Account tokens. The endpoints we will be using here act on behalf of a customer account.

When we called the "Generate Partner Token" endpoint earlier, an environment variable `AUTHORIZE_URL` was created in Postman. Grab that URL and paste it into your browser. This redirects to Tesla for authenticating with a customer account.

Once Tesla redirects to the redirect URI, extract the `code` from the URL parameters and paste it into the `CALLBACK_CODE` environment variable in Postman.

Now, go back to Collections in Postman. Send the "Code Exchange" request.

Next, let's setup and send the "Send Fleet Telemetry Config" request. This places your streaming config on a vehicle.

Here is an example body for the request:

```json
{
    "vins": [
        "VIN"
    ],
    "config": {
        "hostname": "tesla-telemetry.your-domain.com",
        "port": 443,
        "ca": "full certificate chain (actual contents, not path)",
        "fields": {
            "Soc": {
                "interval_seconds": 30
            }
        }
    }
}
```

> You can view all possible fields [in this file](https://github.com/teslamotors/fleet-telemetry/blob/main/protos/vehicle_data.proto).

Once you send the request, the impacted VINs will begin trying to send data shortly.

## Receiving Data

If everything went smoothly, the logs from your fleet-telemetry server should begin showing realtime vehicle data.

Here's a sample of what I received:

```json
{
    "data": [
        {
            "key": "Soc",
            "value": {
                "stringValue": "79.147"
            }
        }
    ],
    "createdAt": "2024-02-24T07:23:58.314605660Z",
    "vin": "TESLA00000001"
}
```

If you aren't receiving data or are seeing TLS errors, send a request to the "Fleet Telemetry Errors" endpoint. It shows any errors the vehicle is encountering.

```json
{
    "response": {
        "fleet_telemetry_errors": [
            {
                "created_at": "2024-02-24T06:54:20.660684365Z",
                "error": "\"webconnection error: x509: certificate relies on legacy Common Name field, use SANs instead\" cm_type=stream",
                "error_name": "cloud_manager_error",
                "hostname": "your-domain.com",
                "name": "121c18bba1fc-4058-bd98-687727180599",
                "port": "443",
                "txID": "edf2ba8d-cc8b-4d03-b619-74bd5a0e0be8",
                "vin": "TESLA00000001"
            }
    }
}
```

## Congratulations

If you made it this far, hopefully you are seeing realtime data from your vehicle. Nice work! Hopefully you can leverage this data to build something awesome 😎