[BETA] Tesla Vehicle via TeslaMate MQTT

I've wanted to pull some basic information from my Tesla, but the primary API is polling-heavy and not really something I wanted running on my hub. The WebSocket API is complex to implement and I've done almost nothing in Groovy prior, so I didn't really want to go down that road again. Plus you can only have one WebSocket client active at a time, and that position is already occupied for me by running TeslaMate.

But wait! TeslaMate exposes a fairly rich MQTT surface, which I'm already consuming in another project, MMM-Powerwall. Hubitat has an MQTT client in-box. Thus was a potential match and solution made.

Not yet available through HPM, but I plan to do that after a few others have banged on it or I've let it bake for a while on my system. In the meantime, I'd love some help shaking bugs out if others are in a similar situation or want to install the right bits.

What you need:

  • One or more Tesla vehicles on your Tesla account; nothing to do otherwise!
  • A working install of TeslaMate, with the MQTT server reachable from the Hubitat
  • Install these two drivers on your Hubitat
  • Configure a new virtual device with the TeslaMate driver and point it to your MQTT server

It will pick up the vehicle(s) TeslaMate is issuing data about and create the child devices using the other driver, including renaming the child device whenever the vehicle's display name is published. The MQTT events can be very chatty, especially while driving or charging, so I took a note from OWM-Alerts: the behaviors are grouped into clusters of related information, and you only subscribe to the clusters you need. (I've entirely dropped a few properties I don't think anyone needs to automate, but if you need to trigger some action based on when your car color changes, they're easy to add back.)

It's my first Hubitat driver, and it was a big chunk to bite off. I drew heavily on a couple of other drivers for inspiration and reference:

Important to note that because this is purely an MQTT consumer, it can't change anything about the car, only display it. Even though it has the Lock/Unlock commands, all those will do is log a warning that you can't do that.

Happy to engage here or on GitHub. Let me know what I missed, or even where my code could be neater.

4 Likes

I like what you did here! I had setup something similar with mqtt and Teslamate, so I could interact with presence in a more real time manner. What I setup is pretty hacky though, what you’ve put together sounds a lot more comprehensive!

Might have to take a look!

I implemented presence by letting you specify the name of a TeslaMate Geofence, since that's not nearly as chatty as lat/long. If the Geofence matches what's in the setting (default is "Home"), it reports as present; otherwise, not present.

Yeah that’s what I ended up doing as well. Initially was going to attempt via last/long but doing it via the Teslamate geofence is a much better option. I just was lazy in what I threw together and hard coded in the geofence for what I had setup.

RE: Using node-red to really take advantage of TeslaMate

Moved it here as to not derail OPs topic and hard work.

Yes, node-red looks interesting and is probably worth some attention in the near future. But for right now, I mostly wanted to be able to reference a couple of Tesla vehicle properties in a few of my existing rules.

@mbishop thanks for putting this together. I just got TeslaMate up and running and would like to get this data into Hubitat. Can you help clarify for me what I would put for the broker port, username, and password? I don't remember setting up any credentials - only providing TeslaMate with the token and refresh token.

Sure! I don't use authentication on mine, since the MQTT server is only accessible within the network, so username/password are optional. I assume you set up TeslaMate using docker-compose. In the default version of that file, the ports for mosquitto are commented out; you'd want to uncomment them (so that you can reach them from outside the local Docker network). Then the broker is the machine running the Docker containers and the port is the one exposed by mosquitto (1883 by default).

Awesome! That worked like a charm. It'll be fun to use some of this data now within Hubitat. Out of curiosity, are you using this information on any dashboards? If so, which template are you using?

I have a Garage dashboard that shows the state of the garage door, garage lights, and the presence/power state of each car. (Using this driver for the Tesla, and this Zigbee device for my wife's ICE.) Presence is the presence template, obviously; the Attribute template can be used to display the powerSource.

It's kind of ironic that my rules have to have inverted logic for each car -- the Tesla switches to battery when it's getting ready to leave, but when the ICE car stops being on battery, it's preparing to leave. :wink:

1 Like

I stumbled across this in HPM today and figured I'd give it a try. I was already pulling in some info about my cars from Teslamate using an MQTT driver and virtual presence sensors, but your driver may be a cleaner way to consolidate everything from Teslamate. My current solution creates one MQTT child device for each parameter, which can clutter up the devices page.

After installing, I started getting some errors from the parent device:

java.lang.NullPointerException: Cannot invoke method xor() on null object on line 332 (method parse)

This is line 332:

if( settings?.temperatureIndoor ^ property == "outside_temp" ) {

I noticed that neither car was showing the inside temp or outside temp values.

While playing around with that line to try to eliminate the error, I caused this error:

groovy.lang.MissingMethodException: No signature of method: java.math.BigDecimal.round() is applicable for argument types: (java.lang.Integer) values: [1] Possible solutions: round(java.math.MathContext), find(), pow(int), power(java.lang.Integer), and(java.lang.Number), find(groovy.lang.Closure) on line 331 (method parse)

which refers to line 331, which is:

value = value.round(1)

I commented out the original lines and inserted modified versions of those 2 lines, so my driver now looks like this:

                //value = value.round(1)
                value = value.doubleValue().round(1)
                //if( settings?.temperatureIndoor ^ property == "outside_temp" ) {
                if( settings?.temperatureIndoor == "outside_temp" ) {

Converting the value to double fixed the one error, and removing the XOR fixed the other error. I don't know if this is something unique to my setup or if others might have the same issue. I'm also not sure exactly what I did by removing that XOR, but the inside/outside temp values are now showing for both cars.

If it matters, this is my config in the parent device:

1 Like

What you're discovering are the groups of attributes that I coded for completeness, but don't use myself. :wink:

Yes, the second one results from Hubitat's celsiusToFahrenheit() method returning a BigDecimal, which doesn't have the round() method. I think I'd rather change it to the preferred type within the if block, but your change amounts to the same thing.

The first one is more broken than your fix accounts for, but it's still an easy fix. There's a setting that indicates whether the stock temperature attribute reflects indoor or outdoor temp, but both will be present as custom attributes. Your fix will never be true, so it just doesn't publish the temperature attribute.

I'll get a fixed version on HPM shortly; I'll turn on the climate attributes on my local hub first and re-test that section.

Edit: Published. Let me know if you encounter any others, please!

Thanks for getting this going, I'm trying to use it as a presence detector for one of my homes. I followed this video here TeslaMate Overview and Install | Self-Hosted Tesla Data Logger | Tesla Dashboards - YouTube and setup my own domain etc. Can you help with the values? I read the previous response about commenting out the port, but can you show an example of exactly what modifications would be needed on the yml they are using and this video setup? I can't seem to get a connection, they do have a htpasswd file in use that I'd like to keep there too.

The .htpasswd doesn't matter as much for this, because that's for the web interface. This driver points at the MQTT server, which is the mosquitto container. The example you pointed to has it running in the cloud; I haven't tried setting up TLS on mosquitto myself, but Hubitat's MQTT client can do a secure connection.

Looks like it needs specific calls, though; I'll try to take a look this weekend.

1 Like

Thank's so much, lmk if there's a link I can buy you coffee or something. I appreciate this :+1:

On your side, you'll need to expose the MQTT port. Since you're running in the cloud, you'd presumably want TLS via Traefik and authentication in mosquitto. There are some articles out there, but I haven't seen a Teslamate-specific one.

1 Like

Trying to set this up for the first time. TeslaMate is up and running. I have entered my local server address and port 1883, which is the default in my .yml file for mosquito, and I have un-commented out those lines there. Getting the following errors:

Looks like I'm not connecting, and that is what's causing the line 260 error, but I don't know what would be the issue, since I'm point to the address where TeslaMate is running and using the mosquito port in the .yml file. I did put a password in the .yml file, but it looks like it's for the database and not mosquito. I also am not sure if mosquito is actually running as it should be, because I can't find a way to access it directly (although it does show running in docker).

Any help would be greatly appreciated!

This is line 260:

At a quick glance, I have a bug in the reconnect logic if the connection has never succeeded; I'll get a fix for that ASAP. Edit: Fixed in main, but not bumping the version number because it won't affect anyone who already has it installed and running. Running a repair will grab the new code.

The inciting problem, it looks like it's failing to connect to the MQTT server -- have you verified with another MQTT client (e.g. MQTT Explorer) that the server is reachable? The default Teslamate config doesn't expose the port publicly (since the other containers can reach it anyway); does docker ps show that the container has a public port?

Thanks! Below is what docker ps shows. I tried using MQTT Explorer, and I can't seem to connect using that either, so I'm not sure what's wrong.

Okay, Docker says it's exposing the port, so that's a good sign. Next thing I'd check is if there's a firewall blocking access. When you tried MQTT Explorer, was that on the same machine or a different one?