-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
1,128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# Decode /tedapi API Payloads | ||
|
||
This tool is to help decode `/tedapi` API payloads (requests and responses) using a Protobuf schema definition file [tedapi.proto](tedapi.proto). | ||
|
||
## Tool | ||
|
||
```bash | ||
# Build python bindings for protobuf schema - tedapi_pb2.py | ||
protoc --python_out=. tedapi.proto | ||
|
||
# Decode payload | ||
python decode.py <filename> | ||
``` | ||
|
||
## Background | ||
|
||
* This requires using the gateway WiFi access point (for PW2/+ systems this is TEG-xxx and for PW3 it is TeslaPW_xxx) and the https://192.168.91.1 endpoint. It seems that this is required for the /tedapi endpoints (LAN or other access results in "User does not have adequate access rights" 403 Error) | ||
* The /tedapi API calls are using binary Protocol Buffers ([protobuf](https://protobuf.dev/)) payloads. | ||
|
||
## APIs | ||
|
||
### GET /tedapi/din | ||
|
||
This API fetches the Powerwall DIN (device identification number). It uses basic auth that appears to be: Tesla_Energy_Device:GW_PWD where the GW_PWD is the password near the QR code on the Powerwall that you scan with the Tesla Pros app. | ||
|
||
```bash | ||
curl -v -k -u "Tesla_Energy_Device:GW_PWD"" https://192.168.91.1/tedapi/din | ||
``` | ||
It only returns a simple string that contains the DIN: | ||
``` | ||
1232100-00-E--TG123456789012 | ||
``` | ||
### POST /tedapi/v1 | ||
This appears to be the workhorse function. It uses basic auth that appears to be: `Tesla_Energy_Device:GW_PWD` where the GW_PWD is the password near the QR code on the Powerwall that you scan with the Tesla Pros app. | ||
```bash | ||
curl -v -k -H 'Content-type: application/octet-string' -u "Tesla_Energy_Device:GW_PWD" --data-binary @request.bin https://192.168.91.1/tedapi/v1 | ||
``` | ||
Payloads are binary Protocol Buffers (protobufs). | ||
* The [decode.py](decode.py) tool will help decode this using the proto file. | ||
* Or you can use `protoc --decode_raw < v1_request` to decode the raw response. | ||
There appear to be different types of request sent. One is for `config` which gets a payload that contains the configuration of the Powerwall. Another is for `query` that gets current data (e.g. systemStatus, realPowerW, voltages, frequencies, etc.). | ||
#### CONFIG Example | ||
```bash | ||
# Request Config Data from Powerwall | ||
curl -v -k -H 'Content-type: application/octet-string' -u "Tesla_Energy_Device:GW_PWD" --data-binary @request.bin https://192.168.91.1/tedapi/v1 > response.bin | ||
# Decode Config Data | ||
python3 decode.py response.bin | ||
``` | ||
An example response shows the system config data in the JSON `text` (removed to protect the innocent) and a `code` payload (TBD). | ||
``` | ||
message { | ||
head: 1 | ||
response { | ||
din: "1232100-00-E--TG123456789012" | ||
} | ||
request { | ||
value: 1 | ||
} | ||
config { | ||
recv { | ||
file { | ||
name: "config.json" | ||
text: "{...JSON Payload Removed...}" | ||
} | ||
code: "...Binary Data Removed..." | ||
} | ||
} | ||
} | ||
tail { | ||
value: 1 | ||
} | ||
``` | ||
#### QUERY Example | ||
To get the status of the Powerwall, send a binary query.bin payload. The structure of the query payload has a `text` query string that seems to be an exhaustive list of labels. The `code` field is a binary payload. | ||
``` | ||
message { | ||
head: 1 | ||
response { | ||
value: 1 | ||
} | ||
request { | ||
din: "1232100-00-E--TG123456789012" | ||
} | ||
payload { | ||
send { | ||
num: 2 | ||
payload { | ||
value: 1 | ||
text: " query DeviceControllerQuery {\n control {\n systemStatus {\n nominalFullPackEnergyWh...Truncated..." | ||
} | ||
code: "0\201\210...Truncated..." | ||
b { | ||
value: "{}" | ||
} | ||
} | ||
} | ||
} | ||
tail { | ||
value: 1 | ||
} | ||
``` | ||
```bash | ||
# Request Status Data from Powerwall | ||
curl -v -k -H 'Content-type: application/octet-string' -u "Tesla_Energy_Device:GW_PWD" --data-binary @query.bin https://192.168.91.1/tedapi/v1 > response.bin | ||
# Decode Config Data | ||
python3 decode.py response.bin | ||
``` | ||
An example response shows the system status data in the JSON `text` field (truncated). | ||
``` | ||
message { | ||
head: 1 | ||
response { | ||
din: "1232100-00-E--TG121048001E4G" | ||
} | ||
request { | ||
value: 1 | ||
} | ||
payload { | ||
recv { | ||
value: 1 | ||
text: "{\"control\":{\"alerts\":{\"active\":[\"SystemConnectedToGrid\",\"FWUpdateSucceeded\",\"GridCodesWrite\",\"PodCommissionTime\"]},\"batteryBlocks\":[{\"din\":\"2012170-25-E#TG123456789012\", ...Truncated...\"updateUrgencyCheck\":null}}" | ||
} | ||
} | ||
} | ||
tail { | ||
value: 1 | ||
} | ||
``` | ||
## Credit | ||
* Thanks to [zigam](https://github.com/zigam) for starting this research and the initial discovery, [post](https://github.com/jrester/tesla_powerwall/issues/20#issuecomment-1810848383) and tips. | ||
* Thanks to [jesaf00](https://github.com/jesaf00) for opening the [Powerwall 3 Support issue](https://github.com/jasonacox/Powerwall-Dashboard/issues/387) and help testing. | ||
* Thanks to others helping test: [longzheng](https://github.com/longzheng) [pbburkhalter](https://github.com/pbburkhalter) [stevecastaneda](https://github.com/stevecastaneda) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Python module to decode tedapi protobuf data | ||
Requires: | ||
- Protobuf pip install protobuf | ||
- Generate tedapi_pb2.py with protoc --python_out=. tedapi.proto | ||
Author: Jason A. Cox | ||
For more information see https://github.com/jasonacox/pypowerwall | ||
""" | ||
|
||
import tedapi_pb2 | ||
import sys | ||
|
||
FILENAME = 'request.bin' | ||
|
||
# Set filename from command line if specified | ||
filename = FILENAME | ||
if len(sys.argv) > 1: | ||
filename = sys.argv[1] | ||
|
||
# Open request or response file and read data | ||
with open(filename, 'rb') as f: | ||
data = f.read() | ||
|
||
# Decode protobuf data | ||
tedapi = tedapi_pb2.ParentMessage() | ||
tedapi.ParseFromString(data) | ||
print(tedapi) | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
// Tesla tedapi API Protocol Buffer definition (tedapi.proto) | ||
// | ||
// Create tedapi_pb2.py for use in projects using the protoc compiler: | ||
// protoc --python_out=. tedapi.proto | ||
// | ||
// Author: Jason A. Cox - Date: 21 Nov 2023 - Version: 1.0 | ||
// | ||
// For more information see https://github.com/jasonacox/pypowerwall | ||
|
||
syntax = "proto3"; | ||
|
||
package tedapi; | ||
|
||
|
||
// ***** Parent ***** | ||
|
||
message ParentMessage { | ||
Message message = 1; | ||
Tail tail = 2; | ||
} | ||
|
||
message Message { | ||
int32 head = 1; | ||
StringNumber response = 2; | ||
StringNumber request = 3; | ||
optional ConfigType config = 15; | ||
optional QueryType payload = 16; | ||
} | ||
|
||
message StringNumber { // 2 | ||
optional string din = 1; | ||
optional int32 value = 3; | ||
} | ||
|
||
message Tail { | ||
int32 value = 1; | ||
} | ||
|
||
// ***** Query = 16 ***** | ||
|
||
message QueryType { // 16 | ||
optional PayloadQuerySend send = 1; | ||
optional PayloadString recv = 2; | ||
} | ||
|
||
message PayloadQuerySend { // 1 | ||
optional int32 num = 1; | ||
optional PayloadString payload = 2; | ||
optional bytes code = 3; | ||
optional StringValue b = 4; | ||
} | ||
|
||
// ***** Config = 15 ***** | ||
|
||
message ConfigType { // 15 | ||
optional PayloadConfigSend send = 1; | ||
optional PayloadConfigRecv recv = 2; | ||
} | ||
|
||
message PayloadConfigSend { // 1 | ||
PayloadString file = 1; | ||
} | ||
|
||
message PayloadConfigRecv { // 2 | ||
ConfigString file = 1; | ||
bytes code = 2; | ||
} | ||
|
||
message ConfigString { | ||
string name = 1; | ||
string text = 100; | ||
} | ||
|
||
// ***** General ***** | ||
|
||
message PayloadString { | ||
int32 value = 1; | ||
string text = 2; | ||
} | ||
|
||
message StringValue { | ||
string value = 1; | ||
} | ||
|
||
message NumberValue { | ||
int32 value = 3; | ||
} | ||
|
||
// ***** BASED ON RAW DECODED PAYLOADS ***** | ||
// | ||
// REQUEST - config | ||
// 1 { | ||
// 1: 1 | ||
// 2 { | ||
// 3: 1 | ||
// } | ||
// 3 { | ||
// 1: "1232100-00-E--TG123456789012" | ||
// } | ||
// 15 { | ||
// 1 { | ||
// 1: 1 | ||
// 2: "config.json" | ||
// } | ||
// } | ||
// } | ||
// 2 { | ||
// 1: 1 | ||
// } | ||
// | ||
// RESPONSE - config | ||
// 1 { | ||
// 1: 1 | ||
// 2 { | ||
// 1: "1232100-00-E--TG123456789012" | ||
// } | ||
// 3 { | ||
// 3: 1 | ||
// } | ||
// 15 { | ||
// 2 { | ||
// 1 { | ||
// 1: "config.json" | ||
// 100: "{}" | ||
// } | ||
// 2: "\255\177t+5\35..." | ||
// } | ||
// } | ||
// } | ||
// 2 { | ||
// 1: 1 | ||
// } | ||
// | ||
// | ||
// REQUEST - query | ||
// 1 { | ||
// 1: 1 | ||
// 2 { | ||
// 3: 1 | ||
// } | ||
// 3 { | ||
// 1: "1232100-00-E--TG123456789012" | ||
// } | ||
// 16 { | ||
// 1 { | ||
// 1: 2 | ||
// 2 { | ||
// 1: 1 | ||
// 2: " query DeviceControllerQuery {..." | ||
// } | ||
// 3: "0\201\210\002B\0026\335T\310\02..." | ||
// 4 { | ||
// 1: "{}" | ||
// } | ||
// } | ||
// } | ||
// } | ||
// 2 { | ||
// 1: 1 | ||
// } | ||
// | ||
// RESPONSE - query | ||
// 1 { | ||
// 1: 1 | ||
// 2 { | ||
// 1: "1232100-00-E--TG123456789012" | ||
// } | ||
// 3 { | ||
// 3: 1 | ||
// } | ||
// 16 { | ||
// 2 { | ||
// 1: 1 | ||
// 2: "{...}" | ||
// } | ||
// } | ||
// } | ||
// 2 { | ||
// 1: 1 | ||
// } |
Oops, something went wrong.