DEV Community

Patrick Demers
Patrick Demers

Posted on • Edited on

Fleet Telemetry: Streaming Data from Your Tesla

Tesla's recent rollout of 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 to help with the API requests sent during this tutorial.
  • The latest documentation for Tesla's Fleet API is available here.

Create a Developer Account

To begin your quest for data, first create a developer account on Tesla's official developer portal: 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

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.



openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem


Enter fullscreen mode Exit fullscreen mode

Now, derive its public key.



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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

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.

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 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.



# 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



Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

Create fleet-telemetry config

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



{
  "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"
}


Enter fullscreen mode Exit fullscreen mode

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:



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


Enter fullscreen mode Exit fullscreen mode

This requires having fleet-telemetry cloned to the repo directory:



git clone https://github.com/teslamotors/fleet-telemetry.git repo


Enter fullscreen mode Exit fullscreen mode

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 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


Enter fullscreen mode Exit fullscreen mode

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. 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:



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


Enter fullscreen mode Exit fullscreen mode

You can view all possible fields in this file.

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:



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


Enter fullscreen mode Exit fullscreen mode

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.



{
"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"
}
}
}
Enter fullscreen mode Exit fullscreen mode




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 😎

Top comments (38)

Collapse
 
bre77 profile image
Brett Adams

I was considering writing an article just like this a few hours ago, so glad to see you already have. I got access to Fleet Telemetry this morning and have successfully implemented it on teslemetry.com to send Webhooks or Server Side Events.

Collapse
 
sjhill01 profile image
Steve Hill

So you subscribe on their behalf and post it back out to their provided webhook on each report?

Collapse
 
slashmili profile image
Milad

One question, why do we need to send ca in the body of Send Fleet Telemetry Config?

I'm asking because in practice it means every 3 months that the TLS certificate changes(assuming I'm using let's encrypt) I have to resubmit my whole fleet configs.

Collapse
 
slashmili profile image
Milad

Or is it only needed on the first time when the vehicle is configured?

Collapse
 
patrickdemers6 profile image
Patrick Demers

Theoretically the CA shouldn't change if you generate with the same CA each time. It's probably easiest to self-sign your certificate. I will update the article soon to show how to do this.

Collapse
 
urkman profile image
Stefan Sturm

when editing the config.json I need to fill the content of the full certificate chain file:
"ca": "content of full certificate chain file from previous step"

But the content is multiline code like this:
-----BEGIN CERTIFICATE-----
12345
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
abcde
-----END CERTIFICATE-----

How can I add this multiline code to the config.json?

Collapse
 
urkman profile image
Stefan Sturm

OK, found it. Every line need a \n and then join to one line...

Now I can use the check script but it gives me:

The server certificate has a valid partial chain, and may work with the root chain.

What can be the problem here?

Collapse
 
patrickdemers6 profile image
Patrick Demers

Looks like verification is passing with -partial_chain flag. From openssl docs:

Allow verification to succeed if an incomplete chain can be built. That is, a chain ending in a certificate that normally would not be trusted (because it has no matching positive trust attributes and is not self-signed) but is an element of the trust store. This certificate may be self-issued or belong to an intermediate CA.

Collapse
 
vbarrier profile image
Vincent Barrier • Edited

Hi Patrick, thank you for this tutorial. I helps a lot! I still have some questions?

=> My app domain is registered like www.your-domain.com not with a classic your-domain.com (newbie error), will it work to have : telemetry.your-domain.com? (certificate has been generated properly)

=> I have sent a CSR to tesla for your-domain.com, I got a response 200 with :

"response": {
"account_id": "4625141***",
"domain": "www.*****.com",
"name": "***",
"description": "***",
"csr": null,
"client_id": "****",
"ca": null,
"created_at": "2023-10-25T17:17:48.744Z",
"updated_at": "2023-11-17T23:14:46.079Z",
"enterprise_tier": "free",
"issuer": null,
"csr_updated_at": null,
"public_key": "0451016f6299****"
}

But I see null for CA and CSR. Do you think that the CSR will be processed? Should I do something else?

Thank you!

Collapse
 
sjhill01 profile image
Steve Hill

Yes, that will work. I'm using "tesla.mydomain.com" for my app registration and "telemetry.mydomain.com" for the fleet-telemetry server and it seems ok with that. Granted I can't get my certs to load correctly yet so I can't prove it...

Collapse
 
jaypio profile image
jay zh

Hi Steve,

I'm wondering if your CSR was accepted and successful? I also want to confirm that you meant for the CSR you used "domain": "tesla.mydomain.com" (or "mydomain.com") instead of the "telemetry.mydomain.com"?

Collapse
 
blizzfire profile image
Patrick

Hello and thanks for this great post!
May I ask you how long it took for Tesla to get back to you after you submitted the CSR?
In step 9 of their fleet api Github repo they mention it may take up to two weeks
github.com/teslamotors/fleet-telem...

Have you contacted them via email or just waited for them to get back to you?

Collapse
 
vbarrier profile image
Vincent Barrier

Did they get back to you?

I'm still waiting since 2024-03-31

Collapse
 
sjhill01 profile image
Steve Hill

It took more than the advertised 2 weeks for me - just got my response this week and probably submitted it around the same time you did.

Thread Thread
 
vbarrier profile image
Vincent Barrier

Thank you Steve, There were a problem on my account CSR was not attached but it is fixed!

Collapse
 
jaypio profile image
jay zh

when checking the csr i kept getting an error, any feedback is appreciated!

./repo/tools/check_server_cert.sh config.json

CN = tesla-telemetry.your-domain.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error /tmp/tmp.MB7flNLa0Z: verification failed
CN = tesla-telemetry.your-domain.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error /tmp/tmp.MB7flNLa0Z: verification failed
The server certificate is invalid

Collapse
 
bts profile image
bts

the impacted VINs will begin trying to send data shortly

How long is shortly? Just to have an idea. I've sent the config to a MY 2023 model, which accepted it. When requesting its config, the 'synced' field remains 'false'. Even after > 1 hour and waking up de tesla and even driving it for 2 minutes...

Collapse
 
bts profile image
bts

ok, the vehicle now states 'synced'='true'. I guess it may take a while...

Collapse
 
patrickdemers6 profile image
Patrick Demers

Yeah, there's no hard rule on when the vehicle will receive the config. It depends on if it's connected to the server, has a solid internet connection, etc.

Collapse
 
bushal profile image
Alastair Breingan

Hi - I hope someone can answer a simple question.
I already have Fleet API working and want to add Fleet Telemetry.
I assume I can use the same account.
Can I use the same app or does this need to be a separate app? (the Generate Partner Token step looks identical).
Thanks in advance for any help

Collapse
 
bts profile image
bts • Edited

Strange, the telemetry-config has been synced to the car, my server is running, the CSR-request was accepted by Tesla, check_server_cert states 'The server certificate is valid.', but I do not get any data... If I query the Fleet Telemetry Errors endpoint with my partner bearer token, I get an empty fleet_telemetry_errors return...

Collapse
 
bts profile image
bts

Ok, seems like I missed only one step. Although I think the README.md on the github page did not described it a week ago. You need to redirect the owner of the vehicle you want to install the virtual key on to tesla.com/_ak/your-domain.com and let the owner accept this with his app... After doing this last step, data began streaming into my server.

Collapse
 
patrickdemers6 profile image
Patrick Demers

I updated the readme to make the steps clearer a while back. I'll update this post as well.

Collapse
 
ciumagcatalin profile image
ciumagcatalin

I am trying to deploy this and I getting the "read /etc/fleet-telemetry/config.json: is a directory" error. I tired all I could but could not find the issue. Any help is appreciated!

Attaching to app-1
app-1 | 2024/09/23 13:48:31 maxprocs: Leaving GOMAXPROCS=1: CPU quota undefined
app-1 | time="2024-09-23T13:48:31Z" level=error msg=read_application_configuration_error context=fleet-telemetry error="read /etc/fleet-telemetry/config.json: is a directory"
app-1 | panic: error=load_service_config value="read /etc/fleet-telemetry/config.json: is a directory"
app-1 |
app-1 | goroutine 1 [running]:
app-1 | main.main()
app-1 | /go/src/fleet-telemetry/cmd/main.go:23 +0x25f