WEBVTT

00:00.000 --> 00:12.080
Cool. Let me start. My name is this here. I work at Grafana in the AI team, which is why I'm

00:12.080 --> 00:17.320
giving a talk at the embedded track. I'm going to be talking about how I'm interacting with

00:17.320 --> 00:24.200
Tesla V. Cos locally, no internet, no nothing, over Bluetooth, low energy using ESP. Before

00:24.200 --> 00:29.760
I start, whenever we say Tesla, obviously we have to mention the richest man on the planet.

00:29.760 --> 00:33.800
So next time, I'll be a good European citizen and by a German car, because German

00:33.800 --> 00:37.880
car brands never did anything controversial.

00:37.880 --> 00:44.160
Let's start. Cool. Where did this start? It started with home assistance. About two

00:44.160 --> 00:48.440
years ago, I got into home assistance. If you haven't got into home assistance, don't

00:48.440 --> 00:54.720
because it's a rabbit hole. But I had an electric car, I had solar panels, I had a home

00:54.720 --> 00:58.080
battery, and I was like, there's something cool I can do here, right, with all these

00:58.080 --> 01:02.840
things. So I'm doing something called dynamic charging, which means like I'm using my solar

01:02.840 --> 01:07.560
excess, I'm using the battery, if I need to be some or quick to boost the charging speed,

01:07.560 --> 01:12.080
I can do load balancing. So if I, you know, somebody is turning on the furnace, it can

01:12.080 --> 01:17.240
like lower the amps going to the car, overload protection, which means like the house

01:17.240 --> 01:23.920
doesn't go over, in my case, like 9.2 kilobits maximum, I can do off-peak charging, and

01:23.920 --> 01:28.160
also in Belgium, I live in Belgium, by the way. We have this thing called capacity tire

01:28.160 --> 01:32.480
of limits, which is a great thing that our government did. And it means like, you know,

01:32.480 --> 01:35.920
if you have an electric car and you're charging, you need to make sure that you don't charge

01:35.920 --> 01:40.480
too much at the same time. It checks every 50 minutes, how much you've used, and uses

01:40.480 --> 01:47.480
that to basically you pay something extra every year. All of the system is hooked up, like,

01:47.480 --> 01:52.240
you know, in a home assistance, I've got like a few settings that I use. And I just update

01:52.320 --> 01:57.120
up to every 10 seconds. Every 10 seconds, I go, how much amps should I be sending to the car,

01:57.120 --> 02:01.280
whether it's plugged in, whether I have solar, whether I have software in my battery. So if you

02:01.280 --> 02:06.400
count it up, that's about like 8,000 more than 8,000 commands per day. And this was working

02:06.400 --> 02:11.040
all fine, right? My home assistance was going to the Tesla Cloud, the Tesla Cloud would send

02:11.040 --> 02:15.680
the command to the car, and every time there was an update, I would update the amps, use the

02:15.680 --> 02:23.520
Tesla API to send that to my car. But then sometime last year, Tesla introduced rate limits,

02:23.520 --> 02:27.520
right? And they would quite severe, right? They introduced rate limits, where you could only send

02:27.520 --> 02:33.120
50 commands per day to the car. I was sending more than 8,000. So obviously, this was not going to work.

02:34.320 --> 02:40.800
So I was like, okay, what can I do? Well, before this, I started getting into like ESP 32 devices,

02:40.800 --> 02:44.960
and they're quite nifty, you know, they're low cost, they're low power, they're pretty small,

02:44.960 --> 02:49.680
so you can like place them anywhere in your home. And they've got Bluetooth low NG built in,

02:49.680 --> 02:53.600
which is the protocol that Tesla uses even in their app to communicate with the car.

02:54.320 --> 02:58.160
But that does come with this challenges, right? There's only like two megabytes of flash,

02:58.160 --> 03:03.280
so it's quite limited. Not a lot of RAM. It's quite low power. It's just a single core running at

03:03.280 --> 03:11.920
160 megahertz. But I'm like, you know, ESP home, doing ESP on with custom C++ is not the easiest thing

03:11.920 --> 03:19.280
in the world, but we gave it a go. The good news, the good news is that Tesla actually open

03:19.280 --> 03:24.560
source their entire vehicle command. So they have their entire vehicle protocol, how to communicate

03:24.560 --> 03:30.000
with the car in an open source app actually to license to get repo, which is great, right?

03:30.000 --> 03:35.600
That this provide me a starting point. The only problem is like this was written in GoLang,

03:36.240 --> 03:42.480
and obviously doing GoLang on ESP 32. Well, technically possible, not the greatest idea in the world.

03:44.560 --> 03:51.040
One thing, well, the first thing you need to know about Tesla, actually has like two subsystems in the car,

03:51.040 --> 03:56.400
right? So there's a system called Vehicle Security, PCSec, and there's a system called Infotainment.

03:56.480 --> 04:01.760
Usually, like you're always talking to this PCSec subsystem first, it controls the locks,

04:01.760 --> 04:06.320
controls most start, it controls things like opening the trunk. You can also get some like simple

04:06.320 --> 04:11.680
data about the car, like, you know, is there a user present, are the doors unlocked or not,

04:11.680 --> 04:17.920
and it is the car awake or not, which is important. And the main thing that this system is always

04:17.920 --> 04:23.120
on, right? It's never go sleep, it's always listening. Infotainment is where the interesting

04:23.120 --> 04:26.960
commands are, right? Like the charging commands, they all live in infotainment. If you want to heat

04:26.960 --> 04:31.360
your car, death lives in infotainment, if you need more data about the car, like what's the current

04:31.360 --> 04:36.560
charging percentage? That lives in infotainment as well. And that's a recent change. That is one nice thing

04:36.560 --> 04:42.320
about Tesla cars is that you do get, I get more updates on it even on my iPhone, and like they added

04:42.320 --> 04:47.200
this in the recent update, just three months ago. The only thing with infotainment is like it consumes a lot of

04:47.200 --> 04:53.200
power, so it will go to sleep when it is not active. One more thing to note, each of these domains,

04:53.200 --> 04:58.080
they have their own public key, so they have their own separate tank shake, and also a separate

04:58.080 --> 05:05.280
session that you need to like authenticate with for each of the two. What else? This is kind of what

05:05.280 --> 05:10.480
it looks like when it's all finished, right? Like I own my ESP home device, there's a pair button,

05:10.480 --> 05:14.800
you click it, you go to your car, and suddenly this thing pops up, right? It says, oh, a new

05:14.800 --> 05:19.840
phone key wants to be added. When you add it, it actually shows up as an actual key in the car.

05:19.840 --> 05:24.000
So depending on like your permissions, you can even like drive the car within the ESP device,

05:24.000 --> 05:29.840
which is maybe cool, but also a security risk potentially. You get a few controls,

05:29.840 --> 05:34.800
like you know, you can change the charging apps, charging limit, this, like I've only implemented

05:34.800 --> 05:39.120
a few, but really we can implement all of the, like you can do the same thing you can do on the app,

05:39.200 --> 05:47.040
including driving off with the car. This is what the vehicle protocol actually looks like, right?

05:47.040 --> 05:51.520
Like this is what the message is, look like that you sent to the car, but also the message is that

05:51.520 --> 05:55.840
you get back from the car. Tesla has this thing called a universal message, and this is what

05:55.840 --> 06:00.960
looks like. It's encoded in ProtoBuff. For those that don't know about ProtoBuff, it's a binary format,

06:00.960 --> 06:06.960
kind of like imagine like Jason, but in binary format, so very efficient, and also it's strongly

06:07.280 --> 06:12.720
typed. So you know exactly what you're going to get at that point at that bite, and you know,

06:12.720 --> 06:17.920
so know how to encode and decode it. If you look at this message, for example, you know,

06:17.920 --> 06:21.680
you can see that like you know, kind of try to highlight it to give you an idea of what that looks like.

06:21.680 --> 06:27.280
You have a two destination. In this case, I'm sending a command to the Infotainment domain.

06:27.280 --> 06:31.920
You have a from destination that is just to tell the car where the message is coming from.

06:31.920 --> 06:36.800
You have a payload. This payload is encrypted, right? So this is a ProtoBuff message.

06:37.120 --> 06:41.920
That thing actually like if you decode it, this is a charging set limit message, and I think in

06:41.920 --> 06:49.520
this case it's like set the charging limit to 82%. And the car needs to figure out how to decode that

06:49.520 --> 06:55.120
using obviously you paired it key before, so it has a private key, but also you have to send a signature

06:55.120 --> 07:00.160
data at this signature data include some stuff you got from the session information. So things like,

07:00.160 --> 07:05.360
you know, every time you try to talk to the car, if you send it and it has an invalid signature,

07:05.440 --> 07:10.720
it will actually thank you back a session information and tell you like, okay, this is the latest

07:10.720 --> 07:17.280
counter, this latest like key identity, and this how you should like, you know, use this to encrypt

07:17.280 --> 07:22.560
the message that you're trying to send. And then finally, a request to you ID, this must be useful for

07:22.560 --> 07:28.560
debugging. You can use this to figure out like, you know, did my request to a true, why did not

07:28.640 --> 07:35.280
go through and so on. On last note, I use Nano PB, Nano PB is really useful for embedded devices.

07:35.280 --> 07:39.280
If you want to do anything with Protobuff, use Nano PB, it's a cool project.

07:41.040 --> 07:48.560
What else ESPBLE? ESP has some built-in Bluetooth low-energy APIs. I'm just giving you like a few

07:48.560 --> 07:54.000
pointers. There's these like events that you will get that you can hook into, and then tell like

07:54.000 --> 07:59.440
in your C++ note, you can basically like do a case statement and then switch between what you should

07:59.440 --> 08:04.240
do. So we have like an event for when the connection is open, we have an event when the connection is closed.

08:05.440 --> 08:10.720
Once we are connected to the car, we can also say like register to notify. We have the link

08:10.720 --> 08:15.440
coming data incoming data also pretty weird. It doesn't always come in one chunk, like sometimes you need

08:15.440 --> 08:20.000
to get like multiple chunks and add them up together, so you need to buffer them, and then also

08:20.000 --> 08:27.440
there's an API to send data. Then the final two things, I know I'm almost at the time, one thing I did

08:27.440 --> 08:32.880
because of this like the chunk incoming messages, and also just to make things easier for myself.

08:32.880 --> 08:37.520
Instead of trying to do everything in that event, I did implement a sort of queue system,

08:37.520 --> 08:41.680
so every time a message comes in, goes into the queue, and then like I can read that part set,

08:42.720 --> 08:47.360
fill in the chunks, same with writing, and same with commands. And the last thing is I'm going to

08:47.360 --> 08:52.800
talk about the command state machine. Like I said, there are two vehicle subsystems, so even if you

08:52.800 --> 08:57.760
want to do something simple, like I want to change the charging amps for the car, charging is in the

08:57.760 --> 09:03.360
infotainment domain, you can only talk to the infotainment domain if the car is awake. So first,

09:03.360 --> 09:09.520
we need to check is the car awake. Cool. If it's not wake up the car, oh wait, I haven't sent a message

09:09.520 --> 09:15.360
to the car for a while, the session info is updated, so now I need to get new session information,

09:15.360 --> 09:19.360
wait for that new session information, update the key information from the session,

09:19.360 --> 09:23.680
now wait for confirmation that the car is awake, then send the command and now wait for the

09:23.680 --> 09:30.240
command to be confirmed. Obviously, just for my own senti, I also have built and retries because

09:30.240 --> 09:34.640
Bluetooth, low energy, it can sometimes, you know, the communication can fail, sometimes the car,

09:34.640 --> 09:38.480
like you send the wake command, the car doesn't immediately wake up, you need to send the second wake command.

09:38.480 --> 09:44.320
And yeah, that's about it. Am I in time? Cool, that is it.

