Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autopark & Homelink returning a 400 Bad Request #14

Open
sharfar opened this issue Jun 20, 2016 · 8 comments
Open

Autopark & Homelink returning a 400 Bad Request #14

sharfar opened this issue Jun 20, 2016 · 8 comments

Comments

@sharfar
Copy link

sharfar commented Jun 20, 2016

AutoPark returns 400 bad_request

@jsgoecke jsgoecke changed the title A Autopark returning a 400 Bad Request Jun 20, 2016
@jsgoecke
Copy link
Owner

I just gave it a try, indeed the Tesla API is now returning a 400 Bad Request whereas this worked before. I will have to track down what Tesla recently changed in their API, or if they are just intentionally disabling doing this now.

@sharfar
Copy link
Author

sharfar commented Jun 20, 2016

Thanks for confirming, it was driving me nuts during the weekend to figure out what had happened! I see you have another ticket opened so probably we can close this one.

@sharfar sharfar closed this as completed Jun 20, 2016
@jsgoecke
Copy link
Owner

Reopening as the other ticket is the fact that Homelink is also not working in addition to AutoPark.

@jsgoecke jsgoecke reopened this Jun 20, 2016
@jsgoecke jsgoecke self-assigned this Jun 20, 2016
@jsgoecke
Copy link
Owner

jsgoecke commented Jun 21, 2016

From @PolyPort here:

https://teslamotorsclub.com/tmc/posts/1591755/

Tesla switched to WebSockets for Summon and HomeLink.

They connect to wss://streaming.vn.teslamotors.com/

On a successful connection, the server responds with
{"autopark":{"autopark_pause_timeout":2000,"autopark_stop_timeout":10000,"heartbeat_frequency":500},"connection_timeout":20000,"msg_type":"control:hello"}
followed by:
{"autopark_state":"ready","msg_type":"autopark:status"}
{"homelink_nearby":true,"msg_type":"homelink:status"}

During auto park/summon, the server will send a heartbeat, like this:
{"msg_type":"autopark:heartbeat_car","timestamp":488163277436.176025}
{"msg_type":"autopark:heartbeat_car","timestamp":488163277936.211975}

When summon forward is requested, the server replies with:
{"cmd_type":"autopark:cmd_forward","msg_type":"autopark:cmd_result","reason":"","result":true}.E{"msg_type":"autopark:heartbeat_car","timestamp":488163276934.765991}

When summon is cancelled, the server sends:
{"cmd_type":"autopark:cmd_abort","msg_type":"autopark:cmd_result","reason":"","result":true}
{"autopark_state":"aborting","msg_type":"autopark:status"}

{"latitude":43.589033,"longitude":-121.858813,"msg_type":"vehicle_data:location"} (altered to not publish my house's location :) )
{"autopark_state":"ready","msg_type":"autopark:status"}

Obviously, this is missing what the client sends to the server. That's mostly because it's either compressed or not ASCII and I need to recompile my test code to give me hex bytes instead of ASCII in that situation before I can figure out the commands. 

@jsgoecke
Copy link
Owner

Here is the full API now over websockets for Autopark and Homelink:

timdorr/tesla-api#16

@jsgoecke jsgoecke changed the title Autopark returning a 400 Bad Request Autopark & Homelink returning a 400 Bad Request Jun 21, 2016
@jsgoecke
Copy link
Owner

@jsgoecke
Copy link
Owner

Ok, I have the basics working:

package main

import (
    "strconv"

    "github.com/jsgoecke/tesla"

    "encoding/base64"
    "log"
    "net/http"
    "net/url"
    "os"
    "os/signal"
    "time"

    "github.com/gorilla/websocket"
)

var (
    email    = "valid_email"
    server   = "streaming.vn.teslamotors.com"
    resource = "/connect/"
)

func main() {
    token, vehicleID := getTesla()
    interrupt := make(chan os.Signal, 1)
    signal.Notify(interrupt, os.Interrupt)

    u := url.URL{Scheme: "wss", Host: server, Path: resource + vehicleID}
    headers := setHeaders(token)
    log.Printf("%s", u.String())
    log.Println(headers)

    c, _, err := websocket.DefaultDialer.Dial(u.String(), headers)
    if err != nil {
        log.Fatal("dial:", err)
    }
    defer c.Close()

    done := make(chan struct{})

    go func() {
        defer c.Close()
        defer close(done)
        log.Println("launching listener")
        for {
            _, message, err := c.ReadMessage()
            if err != nil {
                log.Println("read:", err)
                return
            }
            log.Printf("recv: %s", message)
        }
    }()

    log.Println("launching watcher")
    for {
        select {
        case <-interrupt:
            log.Println("interrupt")
            select {
            case <-done:
                log.Println("done")
            case <-time.After(1 * time.Second):
            }
            c.Close()
            return
        }
    }
}

func setHeaders(token string) http.Header {
    req, _ := http.NewRequest("GET", "http://localhost", nil)
    data := []byte(email + ":" + token)
    encodedToken := base64.StdEncoding.EncodeToString(data)
    req.Header.Add("Authorization", "Basic "+encodedToken)
    return req.Header
}

func getTesla() (string, string) {
    client, err := tesla.NewClient(
        &tesla.Auth{
            ClientID:     os.Getenv("TESLA_CLIENT_ID"),
            ClientSecret: os.Getenv("TESLA_CLIENT_SECRET"),
            Email:        os.Getenv("TESLA_USERNAME"),
            Password:     os.Getenv("TESLA_PASSWORD"),
        })
    if err != nil {
        panic(err)
    }

    vehicles, err := client.Vehicles()
    if err != nil {
        panic(err)
    }
    vehicle := vehicles[0]
    return vehicle.Tokens[0], strconv.Itoa(vehicle.VehicleID)
}

Results in:

 {"autopark":{"autopark_pause_timeout":2000,"autopark_stop_timeout":10000,"heartbeat_frequency":500},"connection_timeout":20000,"msg_type":"control:hello"}

@jsgoecke
Copy link
Owner

jsgoecke commented Jun 22, 2016

Some of the data output:

2016/06/22 10:41:02 recv: {"autopark":{"autopark_pause_timeout":2000,"autopark_stop_timeout":10000,"heartbeat_frequency":500},"connection_timeout":20000,"msg_type":"control:hello"}
2016/06/22 10:41:03 recv: {"autopark_state":"ready","msg_type":"autopark:status"}
2016/06/22 10:41:03 recv: {"homelink_nearby":true,"msg_type":"homelink:status"}
2016/06/22 10:41:05 recv: {"autopark_state":"preparing","msg_type":"autopark:status"}
2016/06/22 10:41:08 recv: {"autopark_state":"active_reverse","msg_type":"autopark:status"}
2016/06/22 10:41:13 recv: {"autopark_state":"preparing","msg_type":"autopark:status"}
2016/06/22 10:41:13 recv: {"autopark_state":"aborting","msg_type":"autopark:status"}
2016/06/22 10:41:13 recv: {"latitude":30,"longitude":-120,"msg_type":"vehicle_data:location"}
2016/06/22 10:41:13 recv: {"autopark_state":"ready","msg_type":"autopark:status"}
2016/06/22 10:41:15 recv: {"latitude":30,"longitude":-120,"msg_type":"vehicle_data:location"}
2016/06/22 10:41:17 recv: {"latitude":30,"longitude":-120,"msg_type":"vehicle_data:location"}
2016/06/22 10:41:18 recv: {"autopark_state":"preparing","msg_type":"autopark:status"}
2016/06/22 10:41:21 recv: {"autopark_state":"active_forward","msg_type":"autopark:status"}
2016/06/22 10:41:23 recv: {"msg_type":"control:goodbye","reason":"vehicle_disconnected"}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants