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.