Skip to content

Commit

Permalink
Powerwall: revert unification with tesla identity
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Feb 19, 2024
1 parent 4d0c46e commit a740983
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 64 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/basgys/goxml2json v1.1.0
github.com/basvdlei/gotsmart v0.0.3
github.com/benbjohnson/clock v1.3.5
github.com/bogosj/tesla v1.3.1
github.com/cenkalti/backoff/v4 v4.2.1
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/containrrr/shoutrrr v0.8.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bogosj/tesla v1.3.1 h1:2iTieXh8jqG8FGWs63aQfRWbD7toLUm6fQ7677eevIE=
github.com/bogosj/tesla v1.3.1/go.mod h1:JvkjZAswd288BeRYd37fKqyYKLcDj3E5oY/OuLzndaI=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
Expand Down
94 changes: 44 additions & 50 deletions meter/powerwall.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ import (
"time"

"github.com/andig/go-powerwall"
"github.com/bogosj/tesla"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/provider"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/util/sponsor"
"github.com/evcc-io/evcc/vehicle"
"github.com/evcc-io/evcc/vehicle/tesla"
teslaclient "github.com/evcc-io/tesla-proxy-client"
"golang.org/x/oauth2"
)

Expand All @@ -27,7 +24,7 @@ type PowerWall struct {
usage string
client *powerwall.Client
meterG func() (map[string]powerwall.MeterAggregatesData, error)
energySite *teslaclient.EnergySite
energySite *tesla.EnergySite
}

func init() {
Expand All @@ -42,7 +39,7 @@ func NewPowerWallFromConfig(other map[string]interface{}) (api.Meter, error) {
cc := struct {
URI, Usage, User, Password string
Cache time.Duration
Tokens vehicle.Tokens
RefreshToken string
SiteId int64
battery `mapstructure:",squash"`
}{
Expand Down Expand Up @@ -73,15 +70,12 @@ func NewPowerWallFromConfig(other map[string]interface{}) (api.Meter, error) {
cc.Usage = "solar"
}

return NewPowerWall(cc.URI, cc.Usage, cc.User, cc.Password, cc.Cache, cc.Tokens, cc.SiteId, cc.battery)
return NewPowerWall(cc.URI, cc.Usage, cc.User, cc.Password, cc.Cache, cc.RefreshToken, cc.SiteId, cc.battery)
}

// NewPowerWall creates a Tesla PowerWall Meter
func NewPowerWall(uri, usage, user, password string, cache time.Duration, tokens vehicle.Tokens, siteId int64, battery battery) (api.Meter, error) {
log := util.NewLogger("powerwall").Redact(
user, password,
tokens.Access, tokens.Refresh,
)
func NewPowerWall(uri, usage, user, password string, cache time.Duration, refreshToken string, siteId int64, battery battery) (api.Meter, error) {
log := util.NewLogger("powerwall").Redact(user, password, refreshToken)

httpClient := &http.Client{
Transport: request.NewTripper(log, powerwall.DefaultTransport()),
Expand All @@ -99,49 +93,23 @@ func NewPowerWall(uri, usage, user, password string, cache time.Duration, tokens
meterG: provider.Cached(client.GetMetersAggregates, cache),
}

// decorate api.MeterEnergy
var totalEnergy func() (float64, error)
if m.usage == "load" || m.usage == "solar" {
totalEnergy = m.totalEnergy
}

// decorate api.BatterySoc
var batterySoc func() (float64, error)
var batteryCapacity func() float64
if usage == "battery" {
batterySoc = m.batterySoc

res, err := m.client.GetSystemStatus()
if err != nil {
return nil, err
}

batteryCapacity = func() float64 {
return res.NominalFullPackEnergy / 1e3
var batteryControl bool
if refreshToken != "" || siteId != 0 {
if refreshToken == "" {
return nil, errors.New("missing refresh token")
}
batteryControl = true
}

// decorate api.BatteryController
var batModeS func(api.BatteryMode) error
if batteryControl {
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, request.NewClient(log))

token, err := tokens.Token()
if err == nil {
if !sponsor.IsAuthorized() {
return nil, api.ErrSponsorRequired
}
options := []tesla.ClientOption{tesla.WithToken(&oauth2.Token{
RefreshToken: refreshToken,
Expiry: time.Now(),
})}

identity, err := tesla.NewIdentity(log, token)
if err != nil {
return nil, err
}

hc := request.NewClient(log)
hc.Transport = &oauth2.Transport{
Source: identity,
Base: hc.Transport,
}

cloudClient, err := teslaclient.NewClient(context.Background(), teslaclient.WithClient(hc))
cloudClient, err := tesla.NewClient(ctx, options...)
if err != nil {
return nil, err
}
Expand All @@ -167,7 +135,33 @@ func NewPowerWall(uri, usage, user, password string, cache time.Duration, tokens
return nil, err
}
m.energySite = energySite
}

// decorate api.MeterEnergy
var totalEnergy func() (float64, error)
if m.usage == "load" || m.usage == "solar" {
totalEnergy = m.totalEnergy
}

// decorate api.BatterySoc
var batterySoc func() (float64, error)
var batteryCapacity func() float64
if usage == "battery" {
batterySoc = m.batterySoc

res, err := m.client.GetSystemStatus()
if err != nil {
return nil, err
}

batteryCapacity = func() float64 {
return res.NominalFullPackEnergy / 1e3
}
}

// decorate api.BatteryController
var batModeS func(api.BatteryMode) error
if batteryControl {
batModeS = battery.LimitController(m.socG, func(limit float64) error {
return m.energySite.SetBatteryReserve(uint64(limit))
})
Expand Down
27 changes: 13 additions & 14 deletions templates/definition/meter/tesla-powerwall.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ capabilities: ["battery-control"]
requirements:
description:
de: |
Benötigt `access` und `refresh` Tokens. Diese können über [tesla.evcc.io](https://tesla.evcc.io) erstellt werden.
Die optionale Batteriesteuerung erfolgt über einen evcc Proxy-Server und erfordert ein Sponsor Token.
Siehe https://tesla.evcc.io.
Um die optionale Entladesteuerung der Battery zu nutzen wird ein `refresh` Token für die Kommunikation mit der Tesla API benötigt.
Folgende Apps ermöglichen das Erstellen des Tokens:
- [Auth app for Tesla (iOS)](https://apps.apple.com/us/app/auth-app-for-tesla/id1552058613#?platform=iphone)
- [Tesla Tokens (Android)](https://play.google.com/store/apps/details?id=net.leveugle.teslatokens)
- [Tesla Auth (macOS, Linux)](https://github.com/adriankumpf/tesla_auth)
en: |
Teska `access` and `refresh` tokens are required. These can be generated through [tesla.evcc.io](https://tesla.evcc.io).
Optional battery control is done via an evcc proxy server and requires a sponsor token.
Siehe https://tesla.evcc.io.
evcc: ["sponsorship"]
To use the optional battery control you need to generate a `refresh` token for communicating with the Tesla API.
The following apps allow to create the token:
- [Auth app for Tesla (iOS)](https://apps.apple.com/us/app/auth-app-for-tesla/id1552058613#?platform=iphone)
- [Tesla Tokens (Android)](https://play.google.com/store/apps/details?id=net.leveugle.teslatokens)
- [Tesla Auth (macOS, Linux)](https://github.com/adriankumpf/tesla_auth)
params:
- name: usage
choice: ["grid", "pv", "battery"]
Expand All @@ -25,10 +30,6 @@ params:
help:
en: Password of the user "customer". By default this is the last 5 characters of password stated on the Tesla Gateway.
de: Passwort des Benutzers "Kunde". Default sind die letzten 5 Zeichen des auf dem Tesla Gateway genannten Passworts.
- name: accessToken
help:
en: "See https://docs.evcc.io/en/docs/devices/meters#tesla-powerwall"
de: "Siehe https://docs.evcc.io/docs/devices/meters#tesla-powerwall"
- name: refreshToken
help:
en: "See https://docs.evcc.io/en/docs/devices/meters#tesla-powerwall"
Expand All @@ -55,9 +56,7 @@ render: |
usage: {{ .usage }}
user: customer
password: {{ .password }} # for user 'customer'
tokens:
access: {{ .accessToken }}
refresh: {{ .refreshToken }}
refreshToken: {{ .refreshToken }}
siteId: {{ .siteId }}
minSoc: {{ .minSoc }}
maxSoc: {{ .maxSoc }}

0 comments on commit a740983

Please sign in to comment.