Profile
Back to NewsBack
GitHub Trending 11 min
Reader Mode
wimaha/TeslaBleHttpProxy: TeslaBleHttpProxy is a program written in Go that receives HTTP requests and forwards them via Bluetooth to a Tesla vehicle. The program can, for example, be easily used together with evcc.

wimaha/TeslaBleHttpProxy: TeslaBleHttpProxy is a program written in Go that receives HTTP requests and forwards them via Bluetooth to a Tesla vehicle. The program can, for example, be easily used together with evcc.

14 hours ago

TeslaBleHttpProxy

Note: This README describes the current development state (main, Docker :dev). For the latest release 2.4.0 (Docker :latest) see the README of 2.4.0. What changed since then is listed in the CHANGELOG. Sections marked (unreleased) are only in :dev.

TeslaBleHttpProxy is a program written in Go that receives HTTP requests and forwards them via Bluetooth to a Tesla vehicle. The program can, for example, be easily used together with evcc.

The program stores the received requests in a queue and processes them one by one. This ensures that only one Bluetooth connection to the vehicle is established at a time.

Table of Contents

- Docker compose - Build yourself - Vehicle Commands - Vehicle Data - Body Controller State - Version of Proxy

How to install

You can either compile and use the Go program yourself or install it in a Docker container. (detailed instruction)

Docker compose

Below you will find the necessary contents for your docker-compose.yml:

services:
  tesla-ble-http-proxy:
    image: wimaha/tesla-ble-http-proxy
    container_name: tesla-ble-http-proxy
    volumes:
      - ~/TeslaBleHttpProxy/key:/key
      - /var/run/dbus:/var/run/dbus
    restart: always
    privileged: true
    network_mode: host
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN

Please remember to create an empty folder where the keys can be stored later. In this example, it is ~/TeslaBleHttpProxy/key.

Pull and start TeslaBleHttpProxy with docker compose up -d.

Note that you can optionally set environment variables to override the default behavior. See environment variables for more information.

Key Security: Private keys are protected by UNIX file permissions (0600 - owner read/write only). Ensure the key directory has proper permissions and is not accessible to unauthorized users.

Build yourself

Download the code and save it in a folder named 'TeslaBleHttpProxy'. From there, you can easily compile the program.

go build .
./TeslaBleHttpProxy

Please remember to create an empty folder called key where the keys can be stored later.

Note that you can optionally set environment variables to override the default behavior. See environment variables for more information.

Generate key for vehicle

(Here, the simple, automatic method is described. Besides the automatic method, you can also generate the keys manually.)

Security Recommendation: We recommend using the Charging Manager role for security. It provides limited access suitable for charging management and works perfectly with evcc tesla-ble template. The Charging Manager role can:

  • Read vehicle data
  • Authorize charging-related commands: wake, charge_start, charge_stop, set_charging_amps
The Owner role provides full access to all vehicle functions (unlock, start, etc.) and should only be used if you need non-charging functions.

To generate the required keys browse to http://YOUR_IP:8080/dashboard. In the dashboard you will see that the keys are missing:

Picture of the Dashboard with missing keys.

Please click on Generate for the Charging Manager role (recommended for security). The keys will be automatically generated and saved. The Charging Manager key will be set as active by default.

Picture of the Dashboard with success message and keys.
Picture of the Dashboard with success message and keys.

After that please enter your VIN under Setup Vehicle. Before you proceed make sure your vehicle is awake! So you have to manually wake the vehicle before you send the key to the vehicle.

Picture of Setup Vehicle Part of the Dashboard.

The key is now sent to the vehicle. To complete the process, confirm by tapping your NFC card on the center console. (Note: There will be no message on the Tesla screen before confirmation with the NFC card.)

Picture of success message sent add-key request.

You can now close the dashboard and use the proxy. 🙂

Setup EVCC

You can use the following configuration in evcc (recommended):

vehicles:
  - name: tesla
    type: template
    template: tesla-ble
    title: Your Tesla (optional)
    capacity: 60 # Akkukapazität in kWh (optional)
    vin: VIN # Erforderlich für BLE-Verbindung
    url: IP # URL des Tesla BLE HTTP Proxy
    port: 8080 # Port des Tesla BLE HTTP Proxy (optional)

If you want to use this proxy only for commands, and not for vehicle data, you can use the following configuration. The vehicle data is then fetched via the Tesla API by evcc.

- name: model3
    type: template
    template: tesla
    title: Tesla
    icon: car
    commandProxy: http://YOUR_IP:8080
    accessToken: YOUR_ACCESS_TOKEN
    refreshToken: YOUR_REFRSH_TOKEN
    capacity: 60
    vin: YOUR_VIN

(Hint for multiple vehicle support: https://github.com/wimaha/TeslaBleHttpProxy/issues/40)

API

Vehicle Commands

The program uses the same interfaces as the Tesla Fleet API. Currently, the following requests are supported:

  • wake_up
  • charge_start
  • charge_stop
  • set_charging_amps
  • set_charge_limit
  • auto_conditioning_start
  • auto_conditioning_stop
  • charge_port_door_open
  • charge_port_door_close
  • flash_lights
  • honk_horn
  • door_lock
  • door_unlock
  • set_sentry_mode
  • add_charge_schedule
  • remove_charge_schedule
  • set_temps
  • actuate_trunk
By default, the program will return immediately after sending the command to the vehicle. If you want to wait for the command to complete, you can set the wait parameter to true. Without wait=true, a request is answered with success as soon as it is queued, so an invalid body of add_charge_schedule or remove_charge_schedule is only reported (with a reason) when wait=true is set.

Wake Up Behavior: Commands automatically wake up the vehicle if it is asleep. You don't need to manually wake the vehicle or use any parameters - the proxy handles this automatically to ensure commands execute successfully.

Example Request

(All requests with method POST.)

Start charging: http://localhost:8080/api/1/vehicles/{VIN}/command/charge_start

Start charging and wait for the command to complete: http://localhost:8080/api/1/vehicles/{VIN}/command/charge_start?wait=true

Stop charging: http://localhost:8080/api/1/vehicles/{VIN}/command/charge_stop

Set charging amps to 5A: http://localhost:8080/api/1/vehicles/{VIN}/command/set_charging_amps with body {"charging_amps": "5"}

Set the charge limit to 80 %: http://localhost:8080/api/1/vehicles/{VIN}/command/set_charge_limit with body {"percent": 80}

Turn Sentry Mode on (false turns it off): http://localhost:8080/api/1/vehicles/{VIN}/command/set_sentry_mode with body {"on": true}

Set cabin temperature to 21 °C (Celsius, 15-28; passenger_temp is optional and defaults to driver_temp): http://localhost:8080/api/1/vehicles/{VIN}/command/set_temps with body {"driver_temp": 21, "passenger_temp": 21}

Open or close the rear trunk (front opens the frunk; it cannot be closed remotely): http://localhost:8080/api/1/vehicles/{VIN}/command/actuate_trunk with body {"which_trunk": "rear"}

Notes on these two commands:

  • Both need a key with the Owner role. The car refuses them for a Charging Manager key.
  • rear is a toggle: it opens a closed trunk and closes an open one. A failed rear command is not retried, because the car may already have moved the trunk before the reply was lost; it is reported as result: false. Read closure_statuses.rear_trunk from body_controller_state before sending it again.
  • An invalid body (for example driver_temp out of range) is rejected with result: false before the proxy connects to the car, so it does not wake the car.
Explicitly wake up the vehicle: http://localhost:8080/api/1/vehicles/{VIN}/command/wake_up

Add a charging schedule (times are minutes after midnight, so 600 is 10:00): http://localhost:8080/api/1/vehicles/{VIN}/command/add_charge_schedule with body {"lat": 50.1, "lon": 14.4, "days_of_week": "Monday,Friday", "start_enabled": true, "start_time": 600, "end_enabled": true, "end_time": 720, "one_time": false, "enabled": true}

days_of_week is either the Fleet API bitmask (Sunday=1, Monday=2, Tuesday=4, Wednesday=8, Thursday=16, Friday=32, Saturday=64, so 34 is Monday and Friday) or text: All, Weekdays or comma-separated full day names. lat, lon and days_of_week are required: a schedule at 0,0 or without days would be stored but never apply. Every call without id creates a new schedule, so include id to change an existing one. Omitted enabled, start_enabled, end_enabled and one_time are false. A failed call without id is not retried, to avoid a duplicate schedule. Unknown day names, wrong types and times outside 0-1439 are rejected with an error.

Remove a charging schedule: http://localhost:8080/api/1/vehicles/{VIN}/command/remove_charge_schedule with body {"id": 3}

Vehicle Data

The vehicle data is fetched from the vehicle and returned in the response in the same format as the Fleet API. Since a ble connection has to be established to fetch the data, it takes a few seconds before the data is returned.

Caching: VehicleData responses are cached in memory for faster subsequent requests. Each endpoint (e.g., charge_state, climate_state) is cached separately per VIN. The cache time can be configured via the vehicleDataCacheTime environment variable (default: 30 seconds). If all requested endpoints are cached and valid, the response is returned immediately without establishing a BLE connection.

Wake Up Behavior: By default, the car is not automatically woken up before fetching vehicle data. This allows for efficient data retrieval when the vehicle is already awake. If your vehicle is asleep and you need to wake it up first, you can use the wakeup=true parameter. The proxy uses intelligent caching to minimize unnecessary wakeup calls - if the vehicle was confirmed awake within the last 9 minutes, the sleep status check is skipped.

Example Request

(All requests with method GET.)

Get vehicle data: http://localhost:8080/api/1/vehicles/{VIN}/vehicle_data

Get vehicle data with automatic wakeup: http://localhost:8080/api/1/vehicles/{VIN}/vehicle_data?wakeup=true

By default you will receive the following data:

  • charge_state
  • climate_state
If you want to receive specific data, you can add the endpoints to the request. This also lets you request additional endpoints that are not part of the default response, such as drive_state (which includes the odometer field in miles, delivered over BLE in the drive state). For example:

http://localhost:8080/api/1/vehicles/{VIN}/vehicle_data?endpoints=charge_state

Request the drive state including the odometer: http://localhost:8080/api/1/vehicles/{VIN}/vehicle_data?endpoints=drive_state

Get specific data with automatic wakeup: http://localhost:8080/api/1/vehicles/{VIN}/vehicle_data?endpoints=charge_state&wakeup=true

This is recommended if you want to receive data frequently, since it will reduce the time it takes to receive the data.

Body Controller State

The body controller state is fetched from the vehicle and returnes the state of the body controller. The request does not wake up the vehicle. The following information is returned:

  • vehicleLockState
- VEHICLELOCKSTATE_UNLOCKED - VEHICLELOCKSTATE_LOCKED - VEHICLELOCKSTATE_INTERNAL_LOCKED - VEHICLELOCKSTATE_SELECTIVE_UNLOCKED
  • vehicleSleepStatus
- VEHICLE_SLEEP_STATUS_UNKNOWN - VEHICLE_SLEEP_STATUS_AWAKE - VEHICLE_SLEEP_STATUS_ASLEEP
  • userPresence
- VEHICLE_USER_PRESENCE_UNKNOWN - VEHICLE_USER_PRESENCE_NOT_PRESENT - VEHICLE_USER_PRESENCE_PRESENT

Request

(All requests with method GET.)

Get body controller state: http://localhost:8080/api/1/vehicles/{VIN}/body_controller_state

Version of Proxy

Get version of proxy: http://localhost:8080/api/proxy/1/version

The response will contain the version of the proxy.

Troubleshooting

Vehicle Requirements

TeslaBleHttpProxy requires your Tesla vehicle to support Phone Key functionality, as it relies on Bluetooth Low Energy (BLE) for communication. Most Tesla models from 2021 onward support Phone Key, but some older models (e.g., Model X 2015–2020) may not. Please verify Phone Key support in your Tesla app or consult Tesla's Vehicle Keys Support Page before setting up the proxy.

Connection Timeouts

Due to BLE's power-saving design, Tesla vehicles may terminate connections after ~30 seconds, causing "connection timeout" logs. This is normal, and the proxy reconnects automatically, ensuring EVCC or other integrations work without issues. Keep the proxy device within ~5-10 meters of the vehicle for reliable connections.

BLE Device Limit (Maximum 3 Devices)

Problem: Intermittent connection failures, undefined loss of connections, or unreliable behavior with evcc.

Solution: Tesla vehicles only accept a maximum of 3 BLE keys/devices simultaneously. If you exceed this limit (e.g., multiple phones, smartwatches, and the proxy), you'll experience connection issues.

Fix: Close the Tesla app on mobile phones when not needed, especially if you're also wearing a smartwatch with the Tesla app. The proxy counts as one device, so limit other active BLE connections accordingly.

This is a Tesla vehicle constraint, not a limitation of TeslaBleHttpProxy.

Dashboard buttons return 403 Forbidden

(unreleased)

The proxy rejects state-changing requests that a browser sends from another website, so a page you visit cannot change your keys or send commands to the car. If you open the dashboard through a reverse proxy over plain HTTP that rewrites the Host header, your own requests can look cross-site too. Set the trustedOrigins environment variable to the address you open in the browser, e.g. trustedOrigins=http://nas.local:8080. Over HTTPS this is not needed.

The same applies to custom web pages or browser tools that call the API with POST from another origin: they get 403 unless their origin is listed in trustedOrigins.

The key management endpoints /gen_keys and /remove_keys accept POST only. Scripts that called them with GET, as older versions allowed, must switch to POST.

Chat with me