Package: carson
carsonOverviewInstallationAuthenticationStates And CommandsExamplesStreamingOverviewcarsonis a simple Python interface for Tesla's unofficial JSON API and includes some utilities to work with data it
generates.  Lots of work to discover and document the API was done by Tim Dorr and dozens of contributors to histesla-apiproject as well as Mark Seminatore andTeslaJS.  So, thanks to them for the head start.Among the goals for this project is to have anasynciobased
library.  As a result, Python 2 is not supported.  In fact, it seems like it has been a decade since theprovisionaltag was removed from theasynciolibrary because it has evolved so much.  There are many guides, articles, and posts
based on early features ofasyncio.  The best way to stay up to date is by starting with Python's standard library
documentation forasyncio.DependenciesThere is one dependency for basic usage —aiohttp.InstallationAs with most python projects, you should create an isolated python environment.  The following
example will use Python'svenvmodule.  But you can use any virtual environment manager you wish
(e.g. pipenv, poetry, virtualenv, conda).Windowspython3.exe -m venv .venv
.venv\Scripts\activate
python -m pip install "carson[jwt]"
carson --version
carson/1.2.1+0d5c31dLinux/Macpython3 -m venv .venv
source .venv/bin/activate
python -m pip install "carson[jwt]"
carson --version
carson/1.2.1+0d5c31dFor command line usage,carsoncan be invoked either as a Python modulepython -m carsonor as a
script (simply namedcarson) which gets created during installation.  Both invoke the same entry
point essentially making the following two statements the same.python -m carson --versionis equivalent tocarson --versionAuthenticationThis project isBYOT(bring your own token) only.  OAuth and authentication flows arenotgoals of this project.   There are many apps and utilities that provide this if you need help
creating access and/or refresh tokens to use Tesla's API.At a minimum, anaccess tokenis required.  This can be set with the environment variable namedCARSON_ACCESS_TOKENor passed to thecarson.Sessionconstructor.  Values passed as arguments
take priority over environment variables.If you wantcarsonto refresh expired access tokens, you will also need to supply a validrefresh tokenthat matches the suppliedaccess token.  Likewise, this can be set as an
environment variableCARSON_REFRESH_TOKENor passed to thecarson.Sessionconstructor.You can register a callable (e.g. function, lambda, callable object, etc.) to be invoked when tokens
have refreshed.  Thiscallableshould take one positional argument which will be adictand
contain the tokens that have updated.Seedocs/examples.mdfor more examples.States And CommandsWith its most basic usage, you can usecarsonto get the current state of car with the following:>>>importasyncio>>>fromcarsonimportSession>>>asyncdefmain():...asyncwithSession()assession:...car=awaitsession.vehicle...print(f'{car.name}is{car.state!r}')>>>asyncio.run(main())DarkNebulais'asleep'From the command line, you can invokecarson --listto get a list of vehicles associated with the
access token you are using:$ carson --list
Car #1 Vehicle('Dark Nebula' state='asleep' id=1234567890123456)
Car #2 Vehicle('photon' state='online' id=1234567890123456)If you have more than one vehicle and want to specify which car to show, you can pass--nameto disambiguate which car
you want to show.carson --name photon
Vehicle('photon' state='online' miles=52,809 software='2023.7.30' battery_level=72)To get a sense of what is happening, you can increase verbosity and see the requests being made.carson -v --name photon
2023-08-31 11:54:44,615 D carson  Req 1 GET /api/1/vehicles HTTP/1.1 200 OK
2023-08-31 11:54:44,929 D carson  Req 2 GET /api/1/vehicles/1234567890123456/vehicle_data HTTP/1.1 200 OK
2023-08-31 11:54:44,929 I carson  Vehicle('photon' state='online' miles=52,809 software='2023.7.30' battery_level=72)Further increasing the verbosity will produce more detailed output.$ carson -vv --name photon
2023-08-31 11:56:52,296 D carson  Req 1 status=200 dur=0:00:00.131960
2023-08-31 11:56:52,297 D carson  GET https://owner-api.teslamotors.com/api/1/vehicles
2023-08-31 11:56:52,297 D carson  < Host: owner-api.teslamotors.com
2023-08-31 11:56:52,297 D carson  < User-Agent: carson/1.2.1+0d5c31d
2023-08-31 11:56:52,297 D carson  < Accept: application/json
2023-08-31 11:56:52,297 D carson  < Authorization: Bearer e***ng
2023-08-31 11:56:52,297 D carson  < Accept-Encoding: gzip, deflate
2023-08-31 11:56:52,297 D carson
2023-08-31 11:56:52,297 D carson  HTTP 200 OK HttpVersion(major=1, minor=1)
2023-08-31 11:56:52,297 D carson  > x-xss-protection: 1; mode=block
2023-08-31 11:56:52,298 D carson  > Content-Type: application/json; charset=utf-8
2023-08-31 11:56:52,298 D carson  > Vary: Accept
2023-08-31 11:56:52,298 D carson  > Content-Length: 416
2023-08-31 11:56:52,298 D carson  > x-envoy-upstream-service-time: 97
2023-08-31 11:56:52,298 D carson  > x-envoy-upstream-cluster: owner-api
2023-08-31 11:56:52,298 D carson  > x-frame-options: DENY
2023-08-31 11:56:52,298 D carson  > x-content-type-options: nosniff
2023-08-31 11:56:52,298 D carson  > strict-transport-security: max-age=31536000; includeSubDomains
2023-08-31 11:56:52,298 D carson  > Cache-Control: no-cache, no-store, private, s-max-age=0
2023-08-31 11:56:52,298 D carson  > Date: Thu, 31 Aug 2023 16:56:52 GMT
2023-08-31 11:56:52,298 D carson  > Server: envoy
2023-08-31 11:56:52,298 D carson
2023-08-31 11:56:52,298 D carson  response={'count': 1, 'response': [{'id': 1234567890123456, 've...
2023-08-31 11:56:52,299 D carson
2023-08-31 11:56:52,600 D carson  Req 2 status=200 dur=0:00:00.300726
2023-08-31 11:56:52,600 D carson  GET https://owner-api.teslamotors.com/api/1/vehicles/1234567890123456/vehicle_data
2023-08-31 11:56:52,600 D carson  < Host: owner-api.teslamotors.com
2023-08-31 11:56:52,600 D carson  < User-Agent: carson/1.2.1+0d5c31d
2023-08-31 11:56:52,600 D carson  < Accept: application/json
2023-08-31 11:56:52,600 D carson  < Authorization: Bearer e***ng
2023-08-31 11:56:52,600 D carson  < Accept-Encoding: gzip, deflate
2023-08-31 11:56:52,600 D carson
2023-08-31 11:56:52,600 D carson  HTTP 200 OK HttpVersion(major=1, minor=1)
2023-08-31 11:56:52,600 D carson  > x-xss-protection: 1; mode=block
2023-08-31 11:56:52,600 D carson  > Content-Type: application/json; charset=utf-8
2023-08-31 11:56:52,600 D carson  > Vary: Accept
2023-08-31 11:56:52,601 D carson  > Content-Length: 7047
2023-08-31 11:56:52,601 D carson  > x-envoy-upstream-service-time: 298
2023-08-31 11:56:52,601 D carson  > x-envoy-upstream-cluster: owner-api-vehicle-data
2023-08-31 11:56:52,601 D carson  > x-frame-options: DENY
2023-08-31 11:56:52,601 D carson  > x-content-type-options: nosniff
2023-08-31 11:56:52,601 D carson  > strict-transport-security: max-age=31536000; includeSubDomains
2023-08-31 11:56:52,601 D carson  > Cache-Control: no-cache, no-store, private, s-max-age=0
2023-08-31 11:56:52,601 D carson  > Date: Thu, 31 Aug 2023 16:56:52 GMT
2023-08-31 11:56:52,601 D carson  > Server: envoy
2023-08-31 11:56:52,601 D carson
2023-08-31 11:56:52,601 D carson  response={'response': {'id': 1234567890123456, 'user_id': 123456...
2023-08-31 11:56:52,602 D carson
2023-08-31 11:56:52,602 I carson  Vehicle('photon' state='online' miles=52,809 software='2023.7.30' battery_level=72)From this point, you can imagine any kind of state query or command supported by Tesla's API can be queried or invoked.carson --command wake_up
carson --command door_lockNote: In the case of waking up a car, the command linecarson --command wake_upis effectively
the same as as the short handcarson --wake-upcommand.Pythonic FeaturesPython is a fantastic language.  One of my favorite features is its ability to customize attribute access.  That ability
allows aVehicleclass instance to basically act like a chameleon.  As Tesla changes its data structure and command
interface for its cars, it's pretty easy for a Python class to essentially keep itself up to date.Recursive Dot-NotationConsider this JSON response from Tesla when getting making a call tovehicle_data:{"response":{"id":98765432109876543,"vehicle_id":1234567890,"display_name":"Dark Nebula","state":"online",..."vehicle_state":{"api_version":7,..."sentry_mode":false,"sentry_mode_available":true,"smart_summon_available":true,"software_update":{"download_perc":0.85279,"expected_duration_sec":2700,"install_perc":0,...Withcarson, after you make the call to get the vehicle data, you can access the JSON response that is returned, or
simply reference its associated JSON path on the instance ofVehicleusing standard Python dot-notation like this:car=awaitmy_session.vehicles('Dark Nebula')json_response=awaitcar.vehicle_data()# I have options here.  I can access the JSON data as a normal Python `dict`perc=json_response['vehicle_state']['software_update']['download_perc']# Or as a Python attributeperc=car.vehicle_state.software_update.download_percif0<perc<1:print(f'Downloading:{perc:.2%}complete.')else:print('Download complete'ifperc==1else'N/A')Endpoint Commands Asawaitable AttributesSimilarly, commands can that are mapped to an endpoint accessed via Python's class instance attribute mechanism will
return anawaitable coroutine.  For example, theVehicleclass incarsondoes not have an attribute namedstart_charge.  The endpoints mapping, however, does mapSTART_CHARGEto a POST request to the URIapi/1/vehicles/{vehicle_id}/command/charge_start.  This makes it possible to start charging your Tesla with either
this code:car=awaitmy_session.vehicles('Dark Nebula')awaitcar.start_charge()or this command> carson -v --command start_charge
2020-01-01 11:51:44,349 D carson  Req# 1:  Method=GET url='https://owner-api.teslamotors.com/api/1/vehicles' status=200 duration=0:00:02.460019
2020-01-01 11:51:44,350 I carson  Vehicle('Dark Nebula' state='online')
2020-01-01 11:51:44,350 I carson  Performing 'start_charge'...
2020-01-01 11:51:44,753 D carson  Req# 2:  Method=POST url='https://owner-api.teslamotors.com/api/1/vehicles/1234567890123456/command/charge_start' status=200 duration=0:00:00.403062
2020-01-01 11:51:44,754 I carson  Result=
{'carsonRequest': {'method': 'POST',
                   'url': 'https://owner-api.teslamotors.com/api/1/vehicles/1234567890123456/command/charge_start'},
 'carsonTimestamp': '2020-01-01T17:51:44.350726',
 'error': None,
 'error_description': '',
 'response': {'reason': 'complete', 'result': True},
 'status': 200}ExamplesSee thedocsdirectory for more examples and advanced usage:docs/examples.mddocs/streaming.md