diff --git a/go.mod b/go.mod index 20a8ea71c7..6a6fc45857 100644 --- a/go.mod +++ b/go.mod @@ -106,3 +106,5 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) + +replace github.com/foogod/go-powerwall => github.com/andig/go-powerwall v0.2.1-0.20220205120646-e5220ad9a9a0 diff --git a/go.sum b/go.sum index d2a40985e2..9d9041508d 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alvaroloes/enumer v1.1.2 h1:5khqHB33TZy1GWCO/lZwcroBFh7u+0j40T83VUbfAMY= github.com/alvaroloes/enumer v1.1.2/go.mod h1:FxrjvuXoDAx9isTJrv4c+T410zFi0DtXIT0m65DJ+Wo= +github.com/andig/go-powerwall v0.2.1-0.20220205120646-e5220ad9a9a0 h1:9fQ/afZNwqEnlAfozBiROWew2FjF2PctrEUVxUncM0Q= +github.com/andig/go-powerwall v0.2.1-0.20220205120646-e5220ad9a9a0/go.mod h1:NA12RXBKXFQFx3Nb9xMTQjHIphu1Fl64i/gQMuRdMZc= github.com/andig/gosunspec v0.0.0-20211108155140-af2e73b86e71 h1:tnjVNZjuz+CK6fdc7ohJpMHjcEGFI5APp0l5T5Ocr/Y= github.com/andig/gosunspec v0.0.0-20211108155140-af2e73b86e71/go.mod h1:c6P6szcR+ROkqZruOR4f6qbDKFjZX6OitPpj+yJ/r8k= github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= @@ -213,8 +215,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foogod/go-powerwall v0.2.0 h1:T/sSc/+3y9sUee7pLh9U2pCqidmX1lnENF8cGs9+PJc= -github.com/foogod/go-powerwall v0.2.0/go.mod h1:NA12RXBKXFQFx3Nb9xMTQjHIphu1Fl64i/gQMuRdMZc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= diff --git a/meter/tesla.go b/meter/powerwall.go similarity index 55% rename from meter/tesla.go rename to meter/powerwall.go index ca975cb8c9..4e1f4e1239 100644 --- a/meter/tesla.go +++ b/meter/powerwall.go @@ -3,27 +3,31 @@ package meter import ( "errors" "fmt" + "net/http" "strings" + "time" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/request" "github.com/foogod/go-powerwall" ) -// Tesla is the tesla powerwall meter -type Tesla struct { +// PowerWall is the tesla powerwall meter +type PowerWall struct { usage string client *powerwall.Client } func init() { - registry.Add("tesla", NewTeslaFromConfig) + registry.Add("tesla", NewPowerWallFromConfig) + registry.Add("powerwall", NewPowerWallFromConfig) } -//go:generate go run ../cmd/tools/decorate.go -f decorateTesla -b *Tesla -r api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.Battery,SoC,func() (float64, error)" +//go:generate go run ../cmd/tools/decorate.go -f decoratePowerWall -b *PowerWall -r api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.Battery,SoC,func() (float64, error)" -// NewTeslaFromConfig creates a Tesla Powerwall Meter from generic config -func NewTeslaFromConfig(other map[string]interface{}) (api.Meter, error) { +// NewPowerWallFromConfig creates a PowerWall Powerwall Meter from generic config +func NewPowerWallFromConfig(other map[string]interface{}) (api.Meter, error) { cc := struct { URI, Usage, User, Password string }{} @@ -48,17 +52,24 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Meter, error) { cc.Usage = "solar" } - return NewTesla(cc.URI, cc.Usage, cc.User, cc.Password) + return NewPowerWall(cc.URI, cc.Usage, cc.User, cc.Password) } -// NewTesla creates a Tesla Meter -func NewTesla(uri, usage, user, password string) (api.Meter, error) { - client := powerwall.NewClient(uri, user, password) +// NewPowerWall creates a Tesla PowerWall Meter +func NewPowerWall(uri, usage, user, password string) (api.Meter, error) { + log := util.NewLogger("tesla") + + httpClient := &http.Client{ + Transport: request.NewTripper(log, powerwall.DefaultTransport()), + Timeout: time.Second * 2, // Timeout after 2 seconds + } + + client := powerwall.NewClient(uri, user, password, powerwall.WithHttpClient(httpClient)) if _, err := client.GetStatus(); err != nil { return nil, err } - m := &Tesla{ + m := &PowerWall{ client: client, usage: strings.ToLower(usage), } @@ -75,19 +86,19 @@ func NewTesla(uri, usage, user, password string) (api.Meter, error) { batterySoC = m.batterySoC } - return decorateTesla(m, totalEnergy, batterySoC), nil + return decoratePowerWall(m, totalEnergy, batterySoC), nil } -var _ api.Meter = (*Tesla)(nil) +var _ api.Meter = (*PowerWall)(nil) // CurrentPower implements the api.Meter interface -func (m *Tesla) CurrentPower() (float64, error) { +func (m *PowerWall) CurrentPower() (float64, error) { res, err := m.client.GetMetersAggregates() if err != nil { return 0, err } - if o, ok := (*res)[m.usage]; ok { + if o, ok := res[m.usage]; ok { return float64(o.InstantPower), nil } @@ -95,13 +106,13 @@ func (m *Tesla) CurrentPower() (float64, error) { } // totalEnergy implements the api.MeterEnergy interface -func (m *Tesla) totalEnergy() (float64, error) { +func (m *PowerWall) totalEnergy() (float64, error) { res, err := m.client.GetMetersAggregates() if err != nil { return 0, err } - if o, ok := (*res)[m.usage]; ok { + if o, ok := res[m.usage]; ok { switch m.usage { case "load": return float64(o.EnergyImported), nil @@ -114,7 +125,7 @@ func (m *Tesla) totalEnergy() (float64, error) { } // batterySoC implements the api.Battery interface -func (m *Tesla) batterySoC() (float64, error) { +func (m *PowerWall) batterySoC() (float64, error) { res, err := m.client.GetSOE() if err != nil { return 0, err diff --git a/meter/tesla_decorators.go b/meter/powerwall_decorators.go similarity index 54% rename from meter/tesla_decorators.go rename to meter/powerwall_decorators.go index 29e8d2332e..de5dcc7e8b 100644 --- a/meter/tesla_decorators.go +++ b/meter/powerwall_decorators.go @@ -6,44 +6,44 @@ import ( "github.com/evcc-io/evcc/api" ) -func decorateTesla(base *Tesla, meterEnergy func() (float64, error), battery func() (float64, error)) api.Meter { +func decoratePowerWall(base *PowerWall, meterEnergy func() (float64, error), battery func() (float64, error)) api.Meter { switch { case battery == nil && meterEnergy == nil: return base case battery == nil && meterEnergy != nil: return &struct { - *Tesla + *PowerWall api.MeterEnergy }{ - Tesla: base, - MeterEnergy: &decorateTeslaMeterEnergyImpl{ + PowerWall: base, + MeterEnergy: &decoratePowerWallMeterEnergyImpl{ meterEnergy: meterEnergy, }, } case battery != nil && meterEnergy == nil: return &struct { - *Tesla + *PowerWall api.Battery }{ - Tesla: base, - Battery: &decorateTeslaBatteryImpl{ + PowerWall: base, + Battery: &decoratePowerWallBatteryImpl{ battery: battery, }, } case battery != nil && meterEnergy != nil: return &struct { - *Tesla + *PowerWall api.Battery api.MeterEnergy }{ - Tesla: base, - Battery: &decorateTeslaBatteryImpl{ + PowerWall: base, + Battery: &decoratePowerWallBatteryImpl{ battery: battery, }, - MeterEnergy: &decorateTeslaMeterEnergyImpl{ + MeterEnergy: &decoratePowerWallMeterEnergyImpl{ meterEnergy: meterEnergy, }, } @@ -52,18 +52,18 @@ func decorateTesla(base *Tesla, meterEnergy func() (float64, error), battery fun return nil } -type decorateTeslaBatteryImpl struct { +type decoratePowerWallBatteryImpl struct { battery func() (float64, error) } -func (impl *decorateTeslaBatteryImpl) SoC() (float64, error) { +func (impl *decoratePowerWallBatteryImpl) SoC() (float64, error) { return impl.battery() } -type decorateTeslaMeterEnergyImpl struct { +type decoratePowerWallMeterEnergyImpl struct { meterEnergy func() (float64, error) } -func (impl *decorateTeslaMeterEnergyImpl) TotalEnergy() (float64, error) { +func (impl *decoratePowerWallMeterEnergyImpl) TotalEnergy() (float64, error) { return impl.meterEnergy() }