Skip to content

Commit

Permalink
Tesla: require personal developer account (#17982)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Jan 11, 2025
1 parent bc6e035 commit 10b9f31
Show file tree
Hide file tree
Showing 19 changed files with 105 additions and 103 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v6
push: true
build-args: |
TESLA_CLIENT_ID=${{ secrets.TESLA_CLIENT_ID }}
tags: |
evcc/evcc:nightly
Expand Down Expand Up @@ -106,7 +104,6 @@ jobs:
args: --snapshot -f .goreleaser-nightly.yml --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TESLA_CLIENT_ID: ${{ secrets.TESLA_CLIENT_ID }}

- uses: actions/setup-python@v5
with:
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ jobs:
push: true
build-args: |
RELEASE=1
TESLA_CLIENT_ID=${{ secrets.TESLA_CLIENT_ID }}
tags: ${{ steps.meta.outputs.tags }}

apt:
Expand Down Expand Up @@ -100,7 +99,6 @@ jobs:
env:
# use GH_TOKEN for access to evcc-io/homebrew-tap
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
TESLA_CLIENT_ID: ${{ secrets.TESLA_CLIENT_ID }}

- uses: actions/setup-python@v5
with:
Expand Down
6 changes: 3 additions & 3 deletions .goreleaser-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ builds:
- -trimpath
- -tags=release
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -s -w
env:
- CGO_ENABLED=0
goos:
Expand All @@ -36,11 +36,11 @@ builds:
- goos: darwin
goarch: arm64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -s -w -B gobuildid
- goos: darwin
goarch: amd64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -s -w -B gobuildid

archives:
- builds:
Expand Down
6 changes: 3 additions & 3 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ builds:
- -trimpath
- -tags=release
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -s -w
env:
- CGO_ENABLED=0
goos:
Expand All @@ -41,11 +41,11 @@ builds:
- goos: darwin
goarch: arm64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -s -w -B gobuildid
- goos: darwin
goarch: amd64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -s -w -B gobuildid

env:
- CGO_ENABLED=0
Expand Down
5 changes: 4 additions & 1 deletion api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ var ErrMustRetry = errors.New("must retry")
var ErrSponsorRequired = errors.New("sponsorship required, see https://github.com/evcc-io/evcc#sponsorship")

// ErrMissingCredentials indicates that user/password are missing
var ErrMissingCredentials = errors.New("missing credentials")
var ErrMissingCredentials = errors.New("missing user/password credentials")

// ErrMissingToken indicates that access/refresh tokens are missing
var ErrMissingToken = errors.New("missing token credentials")

// ErrOutdated indicates that result is outdated
var ErrOutdated = errors.New("outdated")
Expand Down
4 changes: 3 additions & 1 deletion charger/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import (
"context"
"testing"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util/templates"
"github.com/evcc-io/evcc/util/test"
)

var acceptable = []string{
api.ErrMissingCredentials.Error(),
api.ErrMissingToken.Error(),
"invalid plugin source: ...",
"missing mqtt broker configuration",
"mqtt not configured",
Expand All @@ -29,7 +32,6 @@ var acceptable = []string{
"sponsorship required, see https://github.com/evcc-io/evcc#sponsorship",
"eebus not configured",
"context deadline exceeded",
"missing credentials",
"timeout", // ocpp
"must have uri and password", // Wattpilot
}
Expand Down
3 changes: 2 additions & 1 deletion meter/tapo/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/url"
"strings"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/insomniacslk/tapo"
)
Expand Down Expand Up @@ -33,7 +34,7 @@ func NewConnection(uri, user, password string) (*Connection, error) {
}

if user == "" || password == "" {
return nil, fmt.Errorf("missing user or password")
return nil, api.ErrMissingCredentials
}

log := util.NewLogger("tapo").Redact(user, password)
Expand Down
5 changes: 3 additions & 2 deletions meter/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ import (
"context"
"testing"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util/templates"
"github.com/evcc-io/evcc/util/test"
)

var acceptable = []string{
api.ErrMissingCredentials.Error(),
api.ErrMissingToken.Error(),
"invalid plugin source: ...",
"missing mqtt broker configuration",
"missing token",
"mqtt not configured",
"not a SunSpec device",
"connect: connection refused", // sockets
"missing credentials", // sockets
"power: timeout", // sockets
"missing password", // Powerwall
"connect: no route to host",
Expand Down
3 changes: 1 addition & 2 deletions meter/tibber-pulse.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package meter
import (
"context"
"encoding/json"
"errors"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -38,7 +37,7 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
}

if cc.Token == "" {
return nil, errors.New("missing token")
return nil, api.ErrMissingToken
}

log := util.NewLogger("pulse").Redact(cc.Token, cc.HomeID)
Expand Down
2 changes: 1 addition & 1 deletion tariff/amber.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewAmberFromConfig(other map[string]interface{}) (api.Tariff, error) {
}

if cc.Token == "" {
return nil, errors.New("missing token")
return nil, api.ErrMissingToken
}

if cc.SiteID == "" {
Expand Down
12 changes: 7 additions & 5 deletions tariff/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import (
"context"
"testing"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util/templates"
"github.com/evcc-io/evcc/util/test"
)

var acceptable = []string{
"missing token", // amber, tibber
"invalid zipcode", // grünstromindex
"invalid apikey format", // octopusenergy
"missing region", // octopusenergy
"missing securitytoken", // entsoe
api.ErrMissingCredentials.Error(),
api.ErrMissingToken.Error(),
"invalid zipcode", // grünstromindex
"invalid apikey format", // octopusenergy
"missing region", // octopusenergy
"missing securitytoken", // entsoe
"cannot define region and postcode simultaneously", // ngeso
}

Expand Down
3 changes: 1 addition & 2 deletions tariff/tibber.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package tariff

import (
"context"
"errors"
"slices"
"sync"
"time"
Expand Down Expand Up @@ -41,7 +40,7 @@ func NewTibberFromConfig(other map[string]interface{}) (api.Tariff, error) {
}

if cc.Token == "" {
return nil, errors.New("missing token")
return nil, api.ErrMissingToken
}

if err := cc.init(); err != nil {
Expand Down
41 changes: 32 additions & 9 deletions templates/definition/vehicle/tesla.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,56 @@ products:
requirements:
description:
de: |
Benötigt `access` und `refresh` Tokens. Diese können über [tesla.evcc.io](https://tesla.evcc.io) erstellt werden.
Die Steuerung von Fahrzeugen im Zusammenspiel mit einem Tesla Wall Connector erfolgt über einen evcc Proxy-Server und benötigt ein Sponsor Token. Der virtuelle evcc Schlüssel muss auf dem Fahrzeug installiert sein.
Siehe [tesla.evcc.io](https://tesla.evcc.io).
Tesla bietet eine offizielle, aber kostenpflichtige Fahrzeug-API an.
Für private Nutzung kannst du dir einen [Tesla Developer Account](https://developer.tesla.com/) erstellen und erhältst ein monatliches API-Guthaben von $10. Das ist für die gängigen evcc-Anwendungsfälle in der Regel ausreichend.
Die Anleitung von [myteslamate.com](https://www.myteslamate.com/tesla-api-application-registration/) erklärt den Prozess und generiert dir kostenfrei die für evcc benötigten Access- und Refresh-Token.
Mit diesem Tokenpaar und deiner im Tesla Developer Account erstellten Client ID kann evcc direkt mit der Tesla API kommunizieren. Dein verbrauchtes Guthaben kannst du bei Tesla einsehen.
Für die Nutzung des "Tesla Wall Connectors" benötigst du einen öffentlichen Command-Proxy-Server. [myteslamate.com](https://app.myteslamate.com/) stellt diesen Dienst für 12€/Jahr bereit. Konfiguriere dafür bei myteslamate.com die Command-Berechtigungen und trage das Proxy-Token hier ein. Start-, Stopp- und Stromstärken-Kommandos werden über diesen Proxy an Tesla geschickt.
en: |
Tesla `access` and `refresh` tokens are required. These can be generated through [tesla.evcc.io](https://tesla.evcc.io).
Controlling vehicles in conjunction with a Tesla Wall Connector is done via an evcc proxy server and requires a sponsor token. The evcc virtual key must be installed on the vehicle.
See [tesla.evcc.io](https://tesla.evcc.io).
Tesla offers an official, but paid vehicle API.
For private use, you can create a [Tesla Developer Account](https://developer.tesla.com/) and receive a monthly API credit of $10. This is usually sufficient for the common evcc use cases.
The [myteslamate.com](https://www.myteslamate.com/tesla-api-application-registration/) guide explains the process and generates a free Access and Refresh Token. With this token pair and your Client ID created in the Tesla Developer Account, evcc can directly communicate with the Tesla API. You can see your used credit at Tesla.
To use a Tesla Wall Connector, you need a public Command Proxy Server. [myteslamate.com](https://app.myteslamate.com/) provides this service for 12€/year. Configure the Command permissions at myteslamate.com and enter the Proxy Token here. Start, stopp and current commands are sent to Tesla via this proxy.
evcc: ["sponsorship"]
params:
- preset: vehicle-common
- name: clientId
help:
en: Client ID of your [Tesla Developer App](https://developer.tesla.com/dashboard).
de: Kunden ID deiner [Tesla Developer App](https://developer.tesla.com/dashboard).
required: true
advanced: true
- name: accessToken
help:
en: From [myteslamate.com](https://app.myteslamate.com/).
de: Von [myteslamate.com](https://app.myteslamate.com/).
required: true
mask: true
- name: refreshToken
help:
en: From [myteslamate.com](https://app.myteslamate.com/).
de: Von [myteslamate.com](https://app.myteslamate.com/).
required: true
mask: true
- name: vin
example: W...
- name: control
deprecated: true
- name: commandProxy
default: https://tesla.evcc.io/
default: https://api.myteslamate.com
advanced: true
help:
en: "When using a TWC3 (or other 'dumb' charger not capable of control), evcc can manage the charge directly by communicating with the vehicle through a Command Proxy. By default the [myteslamate.com](https://app.myteslamate.com/) proxy is used. With this parameter, you set the base URL of a custom Command Proxy. See for example [TeslaBleHttpProxy](https://github.com/wimaha/TeslaBleHttpProxy) for a proxy sending commands via bluetooth."
de: "Bei Verwendung eines TWC3 (oder eines anderen 'dummen' Ladegeräts, das nicht steuerbar ist) kann evcc die Ladung direkt verwalten, indem es über einen Command Proxy mit dem Fahrzeug kommuniziert. Standardmäßig wird der [myteslamate.com](https://app.myteslamate.com/) Proxy verwendet. Mit diesem Parameter kannst du die Basis-URL ändern. Siehe zum Beispiel [TeslaBleHttpProxy](https://github.com/wimaha/TeslaBleHttpProxy) für einen Proxy, der Kommandos über Bluetooth sendet."
- name: proxyToken
advanced: true
help:
en: "When using a TWC3 (or other 'dumb' charger not capable of control), evcc can manage the charge directly by communicating with the vehicle through a Command Proxy. By default, the proxy provided by evcc is used. With this parameter, you set the base URL of a custom Command Proxy to use instead of the default evcc one. See for example https://github.com/wimaha/TeslaBleHttpProxy for a proxy sending commands via bluetooth."
de: "Bei Verwendung eines TWC3 (oder eines anderen 'dummen' Ladegeräts, das nicht steuerbar ist) kann evcc die Ladung direkt verwalten, indem es über einen Command Proxy mit dem Fahrzeug kommuniziert. Standardmäßig wird der von evcc bereitgestellte Proxy verwendet. Dieses parameter setzt die Basis-URL eines benutzerdefinierten Command Proxy, der anstelle des standardmäßigen evcc-Proxy verwendet werden soll. Siehe zum Beispiel https://github.com/wimaha/TeslaBleHttpProxy für einen Proxy, der Kommandos über Bluetooth sendet."
en: Token for the [myteslamate.com](https://app.myteslamate.com/) command proxy (12€/year fee). Ensure, that you've installed their Virtual Key and granted 'Charge Start', 'Charge Stop' and 'Set Charging Amps' permissions.
de: Token für den Command Proxy von [myteslamate.com](https://app.myteslamate.com/) (12€/Jahr). Stelle sicher, dass du den Virtual Key installiert hast und die Berechtigungen 'Ladung starten', 'Ladung stoppen' und 'Ladestrom setzen' erteilt hast.
- name: cache
default: 15m
render: |
Expand All @@ -44,6 +66,7 @@ render: |
access: {{ .accessToken }}
refresh: {{ .refreshToken }}
commandProxy: {{ .commandProxy }}
proxyToken: {{ .proxyToken }}
{{ include "vehicle-common" . }}
features: ["coarsecurrent"]
cache: {{ .cache }}
3 changes: 2 additions & 1 deletion vehicle/niu/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"time"

"github.com/evcc-io/evcc/api"
"golang.org/x/oauth2"
)

Expand Down Expand Up @@ -35,7 +36,7 @@ func (t *Token) UnmarshalJSON(data []byte) error {
if msg := res.Data.Desc; msg != "" {
return errors.New(msg)
}
return errors.New("missing token")
return api.ErrMissingToken
}

(*t) = (Token)(res.Data.Token.Token)
Expand Down
13 changes: 7 additions & 6 deletions vehicle/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ import (
"context"
"testing"

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util/templates"
"github.com/evcc-io/evcc/util/test"
)

var acceptable = []string{
api.ErrMissingCredentials.Error(),
api.ErrMissingToken.Error(),
"missing client id",
"invalid plugin source: ...",
"missing mqtt broker configuration",
"received status code 404 (INVALID PARAMS)", // Nissan
Expand All @@ -20,12 +24,9 @@ var acceptable = []string{
"network is unreachable",
"error connecting: Network Error",
"unexpected status: 401",
"missing credentials", // Tesla
"missing credentials id", // Tronity
"missing access and/or refresh token, use `evcc token` to create", // Tesla
"login failed: code not found", // Polestar
"empty instance type- check for missing usage", // Merces
"invalid vehicle type: tesla", // Tesla
"discussions/17501", // Tesla
"login failed: code not found", // Polestar
"empty instance type- check for missing usage", // Merces
}

func TestTemplates(t *testing.T) {
Expand Down
Loading

0 comments on commit 10b9f31

Please sign in to comment.