Welcome to Tesla Motors Club
Discuss Tesla's Model S, Model 3, Model X, Model Y, Cybertruck, Roadster and More.
Register

I love having access to my car remotely through the API

This site may earn commission on affiliate links.
Here's a small Python code I wrote tonight (don't be hard, it's my first Python program, learned it tonight as I wrote this). It queries my weather station (Acurite 5in1) through its WeeWX URL and if it detects it rains and the car's windows are open, it closes them :)

import teslapy from urllib.request import urlopen import json print("Reading car") with teslapy.Tesla('[EMAIL][email protected][/EMAIL]') as tesla: if not tesla.authorized: tesla.refresh_token(refresh_token=input('Enter SSO refresh token: ')) vehicles = tesla.vehicle_list() vehicleData = vehicles[0].get_vehicle_data() fd_window = int(vehicleData['vehicle_state']['fd_window']) fp_window = int(vehicleData['vehicle_state']['fp_window']) rd_window = int(vehicleData['vehicle_state']['rd_window']) rp_window = int(vehicleData['vehicle_state']['rp_window']) windows = fd_window + fp_window + rd_window + rp_window print(windows) print("Reading WeeWX") response = urlopen("[URL]http://192.168.2.103/weewx/daily.json[/URL]") data = response.read().decode("utf-8") rain = json.loads(data)['current']['rainRate'] rain = float(rain) print(rain) moving = vehicleData['drive_state']['shift_state'] print(moving) if moving is None and windows > 0 and rain > 0.0: print("Closing the windows!") latitude=vehicleData['drive_state']['latitude'] longitude=vehicleData['drive_state']['longitude'] vehicles[0].sync_wake_up() vehicles[0].command('WINDOW_CONTROL', command='close', lat=latitude, lon=longitude) else: print("All is fine")

I'm planning on running it every five minutes either from a cron job or on loop itself in the Python code on a Raspberry Pi (the same one running the WeeWX software).

Having access to the car's API is very cool (and fun) :)
 
Last edited by a moderator:
  • Like
Reactions: jmaddr and rpiotro
If your weather station is anything like mine (Ambient Weather WS-2000), the rain gauge may be slow to register and by the time it reports rainfall, you may already have a soaked interior.

Also, continuously polling your car every five minutes probably means it will not be going to sleep (that much, if at all). That will lead to excess consumption of the batteries range.

Something like this should be programmed into the car's software so no external workarounds are required. But again, that probably means more energy being drawn off the battery.
 
  • Like
Reactions: rpiotro
It takes 0,2mm of rain to tip the cup inside and record rainfall.I never bothered to check before. I'll keep an I at it for the next rain.

When it's hot and sunny, I usually vent the windows and that's the main reason why I wrote this, not for when the windows are fully down.

The call I'm making (GET /api/1/vehicles/{id}/vehicle_data) doesn't wake or prevent the car from sleeping when ran from my Garmin watch (which also polls every five minutes for the Crytstal-Tesla watch face and every 6 seconds for the Quick Tesla widget). It's the first time I'm running it from this Python module so I haven't checked yet how it's implemented there.
 
Yep, it doesn't wake the car. Teslamate still shows the car asleep (I've waited until the time asleep increased since I ran the code to confirm)
1649423517283.png


And this debug code in my watch confirms that calls doesn't wake the car

Below is seven sequences of such calls with 5 minutes between each call. For the first two, the car was awake and responded with 200 and valid data. At 15:30, it changed to a response code of 408 and no data was returned. To me it means the car fell asleep. Subsequent calls kept returning 408. Launching the Tesla app on my phone confirmed the car was asleep because it took over 10 seconds for the car to come online. Once online, it restarted responding with 200 and valid data.


15:21:02 : onReceiveVehicleData responseCode is 200
15:26:01 : onReceiveVehicleData responseCode is 200
15:30:00 : onReceiveVehicleData responseCode is 408
15:36:00 : onReceiveVehicleData responseCode is 408
15:41:00 : onReceiveVehicleData responseCode is 408
15:46:02 : onReceiveVehicleData responseCode is 200
15:51:01 : onReceiveVehicleData responseCode is 200
 
  • Like
Reactions: MaskedRacerX
Good job. Better form might be to first check with the "vehicle_state" command. If it returns asleep, first wake it, then send the commands.

Though, for your use case, I would run the rain check *first* and only then do the queries/commands if rain is detected. The Tesla API is not public and abuse is good for no one.

Better yet would be if your rain station sends a webhook....nothing worse than it registering rain 1 second after your previous query and your script not finding that out for 4m 59s. 5 minutes even with vent could introduce a bunch of water.
 
Good job. Better form might be to first check with the "vehicle_state" command. If it returns asleep, first wake it, then send the commands.

Though, for your use case, I would run the rain check *first* and only then do the queries/commands if rain is detected. The Tesla API is not public and abuse is good for no one.

Better yet would be if your rain station sends a webhook....nothing worse than it registering rain 1 second after your previous query and your script not finding that out for 4m 59s. 5 minutes even with vent could introduce a bunch of water.
WeeWX doesn't support webhook that I can see, but since it's running on the same Raspberry as this python script (I changed the IP address to 127.0.0.1), I can poll as often as I want. I've put the reading of the weather station code at top like suggested so I'm not polling the car unless there is rain and I can throttle the calls to the car and only poll when rain starts.

I doubt a poll per 5 minutes will create havoc in Tesla's environment and as for the widget that polls every 6 seconds, a widget only remains active for a maximum of one minute before going back to sleep so the impact is also minimal there.
 
  • Like
Reactions: jmaddr
There, in an infinite loop, pausing for two seconds and only check the car when the rain starts

Reading WeeWX
Rain: 1.4mm
Reading car
Number of windows open: 0
Driving: None
It's raining but our windows are closed
Reading WeeWX
Rain: 1.4mm
Already checked for this rain period, skipping
Reading WeeWX
Rain: 1.4mm
Already checked for this rain period, skipping

import teslapy from urllib.request import urlopen import json import time raining = False while True: print("Reading WeeWX") response = urlopen("http://127.0.0.1/weewx/daily.json") data = response.read().decode("utf-8") rain = json.loads(data)['current']['rainRate'] rain = float(rain) print('Rain: ' + str(rain) + 'mm') if rain > 0.0: if raining == False: raining = True print("Reading car") with teslapy.Tesla('[email protected]') as tesla: if not tesla.authorized: tesla.refresh_token(refresh_token=input('Enter SSO refresh token: ')) vehicles = tesla.vehicle_list() vehicles[0].sync_wake_up() vehicleData = vehicles[0].get_vehicle_data() fd_window = int(vehicleData['vehicle_state']['fd_window']) fp_window = int(vehicleData['vehicle_state']['fp_window']) rd_window = int(vehicleData['vehicle_state']['rd_window']) rp_window = int(vehicleData['vehicle_state']['rp_window']) windows = fd_window + fp_window + rd_window + rp_window print('Number of windows open: ' + str(windows)) moving = vehicleData['drive_state']['shift_state'] print('Driving: ' + str(moving)) if moving is None and windows > 0: print("Closing the windows!") latitude=vehicleData['drive_state']['latitude'] longitude=vehicleData['drive_state']['longitude'] print(latitude) print(longitude) vehicles[0].command('WINDOW_CONTROL', command='close', lat=latitude, lon=longitude) else: print("It's raining but our windows are closed") else: print("Already checked for this rain period, skipping") else: raining = False print("All is fine") time.sleep(2)

I don't know why but when I enclose de code into 'Inline code' anchor, it loses the whitespace formating :-(
 
Last edited by a moderator:
If your weather station is anything like mine (Ambient Weather WS-2000), the rain gauge may be slow to register and by the time it reports rainfall, you may already have a soaked interior.

Also, continuously polling your car every five minutes probably means it will not be going to sleep (that much, if at all). That will lead to excess consumption of the batteries range.

Something like this should be programmed into the car's software so no external workarounds are required. But again, that probably means more energy being drawn off the battery.
Even if it did, there is no reason to poll the car at all until it rains, so that is easily fixed. And congratulations to the OP on his first Python code .. needs a little work, but baby steps!!! :)
 
  • Like
Reactions: TunaBug
Even if it did, there is no reason to poll the car at all until it rains, so that is easily fixed. And congratulations to the OP on his first Python code .. needs a little work, but baby steps!!! :)
Yeah, that was my first test of talking to the car from Python, the file was even called x.py lol. It has been fixed since then as can be seen later on in the thread. Now it loops indefinitely and check the cars only when rain as been detected and stop testing until rain stops and starts again, My next addition will be to monitor the sleepiness of the car, like every five minutes and don't even check the car if it has not awaken since the last rain check.
 
New version, this one leveraging my Home Assistant MQTT broker when the WeeWX data is sent as soon as they are received by the probe, which is 18 seconds. Plus, it's event driven and no longer polling so it's immediate acting now :)

#!/usr/bin/env python3 import teslapy import paho.mqtt.client as mqtt import json import time from datetime import datetime raining = False # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, flags, rc): print("Connected with result code "+str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. client.subscribe("acurite/loop") # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): # print(msg.topic+" "+str(msg.payload.decode('utf-8'))) jsondata = json.loads(str(msg.payload.decode('utf-8'))) rain_cm = jsondata.get('rain_cm') if rain_cm is not None: now = datetime.now() current_time = now.strftime("%H:%M:%S") print(current_time + ": " + rain_cm) rain = float(rain_cm) if rain > 0.0: if raining == False: raining = True print("Reading car") tesla = teslapy.Tesla('[email protected]') if not tesla.authorized: tesla.refresh_token(refresh_token=input('Enter SSO refresh token: ')) vehicles = tesla.vehicle_list() vehicles[0].sync_wake_up() # We need to get up to date data so no choice but to wake it vehicleData = vehicles[0].get_vehicle_data() fd_window = int(vehicleData['vehicle_state']['fd_window']) fp_window = int(vehicleData['vehicle_state']['fp_window']) rd_window = int(vehicleData['vehicle_state']['rd_window']) rp_window = int(vehicleData['vehicle_state']['rp_window']) windows = fd_window + fp_window + rd_window + rp_window print('Number of windows open: ' + str(windows)) moving = vehicleData['drive_state']['shift_state'] print('Driving: ' + str(moving)) if moving is None and windows > 0: print("Closing windows!") latitude=vehicleData['drive_state']['latitude'] longitude=vehicleData['drive_state']['longitude'] print(latitude) print(longitude) vehicles[0].command('WINDOW_CONTROL', command='close', lat=latitude, lon=longitude) else: print("It's raining but our windows are closed") tesla.close() else: print("Already checked for this rain period, skipping") else: raining = False print("All is fine") client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message #client.tls_set() client.username_pw_set(username="username", password="password") print("Connecting...") client.connect("hostname", 1883, 60) # Blocking call that processes network traffic, dispatches callbacks and # handles reconnecting. # Other loop*() functions are available that give a threaded interface and a # manual interface. client.loop_forever()
 
New version, this one leveraging my Home Assistant MQTT broker when the WeeWX data is sent as soon as they are received by the probe, which is 18 seconds. Plus, it's event driven and no longer polling so it's immediate acting now :)

#!/usr/bin/env python3 import teslapy import paho.mqtt.client as mqtt import json import time from datetime import datetime raining = False # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, flags, rc): print("Connected with result code "+str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. client.subscribe("acurite/loop") # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): # print(msg.topic+" "+str(msg.payload.decode('utf-8'))) jsondata = json.loads(str(msg.payload.decode('utf-8'))) rain_cm = jsondata.get('rain_cm') if rain_cm is not None: now = datetime.now() current_time = now.strftime("%H:%M:%S") print(current_time + ": " + rain_cm) rain = float(rain_cm) if rain > 0.0: if raining == False: raining = True print("Reading car") tesla = teslapy.Tesla('[email protected]') if not tesla.authorized: tesla.refresh_token(refresh_token=input('Enter SSO refresh token: ')) vehicles = tesla.vehicle_list() vehicles[0].sync_wake_up() # We need to get up to date data so no choice but to wake it vehicleData = vehicles[0].get_vehicle_data() fd_window = int(vehicleData['vehicle_state']['fd_window']) fp_window = int(vehicleData['vehicle_state']['fp_window']) rd_window = int(vehicleData['vehicle_state']['rd_window']) rp_window = int(vehicleData['vehicle_state']['rp_window']) windows = fd_window + fp_window + rd_window + rp_window print('Number of windows open: ' + str(windows)) moving = vehicleData['drive_state']['shift_state'] print('Driving: ' + str(moving)) if moving is None and windows > 0: print("Closing windows!") latitude=vehicleData['drive_state']['latitude'] longitude=vehicleData['drive_state']['longitude'] print(latitude) print(longitude) vehicles[0].command('WINDOW_CONTROL', command='close', lat=latitude, lon=longitude) else: print("It's raining but our windows are closed") tesla.close() else: print("Already checked for this rain period, skipping") else: raining = False print("All is fine") client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message #client.tls_set() client.username_pw_set(username="username", password="password") print("Connecting...") client.connect("hostname", 1883, 60) # Blocking call that processes network traffic, dispatches callbacks and # handles reconnecting. # Other loop*() functions are available that give a threaded interface and a # manual interface. client.loop_forever()
Latest version is up on GitHub


With the following changes
  • It has its own configuration file for the parameters
  • It now will only wake up the car to close its windows if they are open. The state of the windows is taken while the car is awake but it will not prevent it to sleep
  • It only tell it to close its windows if it's close to the station
  • Query time to see i it's awake will be every minute when parked and close to the station; and every five minutes when moving (to see when we switch to Park) or when far from the station. If awake, it will grab the windows' state.
  • It has its own watchdog thread to make sure MQTT data is received
  • It will email you
    • if rain is detected and windows need to be close (need to make it less chatty)
    • if the MQTT server didn't send us data in over a minute
Once it's working fine, I'll reduce the chatting it does. It's quite chatty right now. Still a work i progress :)