From c3c18a588d0febb37c25ebb7b08ccc6a1241055c Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 26 Jan 2021 09:59:38 +0100 Subject: [PATCH] Minor fixes (#614) --- charger/mcc_test.go | 2 +- charger/nrgconnect.go | 12 +++++++--- cmd/dumper.go | 6 +++++ meter/sma/listener_test.go | 8 +++---- meter/sma_test.go | 4 ++-- meter/tesla.go | 47 +++++++++++++++----------------------- util/request/functions.go | 5 +++- util/request/json.go | 4 ++++ vehicle/audi.go | 25 +++++++++++--------- vehicle/id.go | 25 +++++++++++--------- vehicle/tesla.go | 11 --------- vehicle/vw.go | 25 +++++++++++--------- 12 files changed, 91 insertions(+), 83 deletions(-) diff --git a/charger/mcc_test.go b/charger/mcc_test.go index 43a74c50a..39f5b45fd 100644 --- a/charger/mcc_test.go +++ b/charger/mcc_test.go @@ -39,7 +39,7 @@ func NewTestClient(fn roundTripFunc) *http.Client { func NewTestMobileConnect(t *testing.T, responses []apiResponse) *MobileConnect { mcc := &MobileConnect{ Helper: request.NewHelper(util.NewLogger("foo")), - uri: "http://192.168.1.1", + uri: "http://192.0.2.2:502", password: "none", token: "token", tokenValid: time.Now().Add(10 * time.Minute), diff --git a/charger/nrgconnect.go b/charger/nrgconnect.go index 7c295aba5..a53e16c8e 100644 --- a/charger/nrgconnect.go +++ b/charger/nrgconnect.go @@ -10,6 +10,8 @@ import ( "github.com/andig/evcc/util/request" ) +// https://www.nrgkick.com/wp-content/uploads/2019/08/20190814_API-Dokumentation_04.pdf + const ( nrgSettings = "settings" nrgMeasurements = "measurements" @@ -89,7 +91,7 @@ func NewNRGKickConnect(uri, mac, password string) (*NRGKickConnect, error) { nrg := &NRGKickConnect{ log: log, Helper: request.NewHelper(log), - uri: uri, + uri: util.DefaultScheme(uri, "http"), mac: mac, password: password, } @@ -130,11 +132,15 @@ func (nrg *NRGKickConnect) Status() (api.ChargeStatus, error) { func (nrg *NRGKickConnect) Enabled() (bool, error) { var res NRGSettings err := nrg.GetJSON(nrg.apiURL(nrgSettings), &res) - if err != nil && res.Message != "" { + if err != nil { + if res.Message != "" { err = errors.New(res.Message) } - return *res.Values.ChargingStatus.Charging, err + return false, err + } + + return *res.Values.ChargingStatus.Charging, nil } // Enable implements the Charger.Enable interface diff --git a/cmd/dumper.go b/cmd/dumper.go index 46674ce53..c7e93f6af 100644 --- a/cmd/dumper.go +++ b/cmd/dumper.go @@ -74,6 +74,12 @@ func (d *dumper) Dump(name string, v interface{}) { // charger if v, ok := v.(api.Charger); ok { + if status, err := v.Status(); err != nil { + fmt.Fprintf(w, "Status:\t%v\n", err) + } else { + fmt.Fprintf(w, "Status:\t%s\n", status) + } + if enabled, err := v.Enabled(); err != nil { fmt.Fprintf(w, "Enabled:\t%v\n", err) } else { diff --git a/meter/sma/listener_test.go b/meter/sma/listener_test.go index 06dc07149..57c8f5fb1 100644 --- a/meter/sma/listener_test.go +++ b/meter/sma/listener_test.go @@ -19,7 +19,7 @@ func TestListenerProcessMessage(t *testing.T) { }{ { "SMA Home Manager - success", - []byte{192, 168, 1, 4}, + net.ParseIP("192.0.2.2"), 33168, []byte{ 0x53, 0x4d, 0x41, 0x00, 0x00, 0x04, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x10, @@ -63,7 +63,7 @@ func TestListenerProcessMessage(t *testing.T) { }, false, Telegram{ - Addr: "192.168.1.4", + Addr: "192.0.2.2", Serial: "0", Values: map[string]float64{ "1:1.4.0": 0, "1:1.8.0": 6.89131908e+09, @@ -103,7 +103,7 @@ func TestListenerProcessMessage(t *testing.T) { }, { "SMA Energy Manager - success", - []byte{192, 168, 1, 4}, + net.ParseIP("192.0.2.2"), 33168, []byte{ 0x53, 0x4d, 0x41, 0x00, 0x00, 0x04, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x10, @@ -147,7 +147,7 @@ func TestListenerProcessMessage(t *testing.T) { }, false, Telegram{ - Addr: "192.168.1.4", + Addr: "192.0.2.2", Serial: "0", Values: map[string]float64{ "1:1.4.0": 0, "1:1.8.0": 1.2385008e+08, diff --git a/meter/sma_test.go b/meter/sma_test.go index 11c4301e7..6b4e295a3 100644 --- a/meter/sma_test.go +++ b/meter/sma_test.go @@ -10,7 +10,7 @@ import ( func TestSMAUpdateMeterValues(t *testing.T) { tests := []struct { name string - messsage sma.Telegram + message sma.Telegram wantPower float64 wantCurrentL1 float64 wantCurrentL2 float64 @@ -56,7 +56,7 @@ func TestSMAUpdateMeterValues(t *testing.T) { mux: util.NewWaiter(udpTimeout, func() {}), } - sm.updateMeterValues(tt.messsage) + sm.updateMeterValues(tt.message) if sm.values.power != tt.wantPower { t.Errorf("Listener.processMessage() got Power %v, want %v", sm.values.power, tt.wantPower) } diff --git a/meter/tesla.go b/meter/tesla.go index 932211af6..5b8d3476d 100644 --- a/meter/tesla.go +++ b/meter/tesla.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "errors" "fmt" - "net/url" "strings" "github.com/andig/evcc/api" @@ -64,16 +63,6 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Meter, error) { return nil, errors.New("missing usage setting") } - url, err := url.ParseRequestURI(cc.URI) - if err != nil { - return nil, fmt.Errorf("invalid uri %s", cc.URI) - } - - uri := "https://" + url.Hostname() - if url.Port() != "" { - uri += ":" + url.Port() - } - // support default meter names switch strings.ToLower(cc.Usage) { case "grid": @@ -82,14 +71,16 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Meter, error) { cc.Usage = "solar" } - return NewTesla(uri, cc.Usage) + return NewTesla(cc.URI, cc.Usage) } // NewTesla creates a Tesla Meter func NewTesla(uri, usage string) (api.Meter, error) { + log := util.NewLogger("tesla") + m := &Tesla{ - Helper: request.NewHelper(util.NewLogger("tesla")), - uri: uri, + Helper: request.NewHelper(log), + uri: util.DefaultScheme(uri, "https"), usage: strings.ToLower(usage), } @@ -114,12 +105,12 @@ func NewTesla(uri, usage string) (api.Meter, error) { // CurrentPower implements the Meter.CurrentPower interface func (m *Tesla) CurrentPower() (float64, error) { var res teslaMeterResponse - err := m.GetJSON(m.uri+teslaMeterURI, &res) + if err := m.GetJSON(m.uri+teslaMeterURI, &res); err != nil { + return 0, err + } - if err == nil { - if o, ok := res[m.usage]; ok { - return o.InstantPower, nil - } + if o, ok := res[m.usage]; ok { + return o.InstantPower, nil } return 0, fmt.Errorf("invalid usage: %s", m.usage) @@ -128,16 +119,16 @@ func (m *Tesla) CurrentPower() (float64, error) { // totalEnergy implements the api.MeterEnergy interface func (m *Tesla) totalEnergy() (float64, error) { var res teslaMeterResponse - err := m.GetJSON(m.uri+teslaMeterURI, &res) + if err := m.GetJSON(m.uri+teslaMeterURI, &res); err != nil { + return 0, err + } - if err == nil { - if o, ok := res[m.usage]; ok { - if m.usage == "load" { - return o.EnergyImported, nil - } - if m.usage == "solar" { - return o.EnergyExported, nil - } + if o, ok := res[m.usage]; ok { + if m.usage == "load" { + return o.EnergyImported, nil + } + if m.usage == "solar" { + return o.EnergyExported, nil } } diff --git a/util/request/functions.go b/util/request/functions.go index 58350aaee..2f88db3f8 100644 --- a/util/request/functions.go +++ b/util/request/functions.go @@ -14,7 +14,10 @@ var ( URLEncoding = map[string]string{"Content-Type": "application/x-www-form-urlencoded"} // JSONEncoding specifies application/json - JSONEncoding = map[string]string{"Content-Type": "application/json"} + JSONEncoding = map[string]string{ + "Content-Type": "application/json", + "Accept": "application/json", + } ) // StatusError indicates unsuccessful http response diff --git a/util/request/json.go b/util/request/json.go index 15eae2684..258471ad7 100644 --- a/util/request/json.go +++ b/util/request/json.go @@ -17,6 +17,10 @@ func (r *errorReader) Read(p []byte) (int, error) { // MarshalJSON marshals JSON into an io.Reader func MarshalJSON(data interface{}) io.Reader { + if data == nil { + return nil + } + body, err := json.Marshal(data) if err != nil { return &errorReader{err: err} diff --git a/vehicle/audi.go b/vehicle/audi.go index d8666c743..afadf3193 100644 --- a/vehicle/audi.go +++ b/vehicle/audi.go @@ -1,6 +1,7 @@ package vehicle import ( + "fmt" "net/url" "strings" "time" @@ -55,18 +56,20 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) { }) err := identity.Login(query, cc.User, cc.Password) - if err == nil { - api := vw.NewAPI(log, identity, "Audi", "DE") - - if cc.VIN == "" { - cc.VIN, err = findVehicle(api.Vehicles()) - if err == nil { - log.DEBUG.Printf("found vehicle: %v", cc.VIN) - } - } - - v.Provider = vw.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + if err != nil { + return v, fmt.Errorf("login failed: %w", err) } + api := vw.NewAPI(log, identity, "Audi", "DE") + + if cc.VIN == "" { + cc.VIN, err = findVehicle(api.Vehicles()) + if err == nil { + log.DEBUG.Printf("found vehicle: %v", cc.VIN) + } + } + + v.Provider = vw.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + return v, err } diff --git a/vehicle/id.go b/vehicle/id.go index 70aa071c9..b630ef8fe 100644 --- a/vehicle/id.go +++ b/vehicle/id.go @@ -1,6 +1,7 @@ package vehicle import ( + "fmt" "net/url" "strings" "time" @@ -53,18 +54,20 @@ func NewIDFromConfig(other map[string]interface{}) (api.Vehicle, error) { }) err := identity.Login(query, cc.User, cc.Password) - if err == nil { - api := id.NewAPI(log, identity) - - if cc.VIN == "" { - cc.VIN, err = findVehicle(api.Vehicles()) - if err == nil { - log.DEBUG.Printf("found vehicle: %v", cc.VIN) - } - } - - v.Provider = id.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + if err != nil { + return v, fmt.Errorf("login failed: %w", err) } + api := id.NewAPI(log, identity) + + if cc.VIN == "" { + cc.VIN, err = findVehicle(api.Vehicles()) + if err == nil { + log.DEBUG.Printf("found vehicle: %v", cc.VIN) + } + } + + v.Provider = id.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + return v, err } diff --git a/vehicle/tesla.go b/vehicle/tesla.go index f6e1a5d03..895bd2ec8 100644 --- a/vehicle/tesla.go +++ b/vehicle/tesla.go @@ -130,14 +130,3 @@ func (v *Tesla) chargedEnergy() (float64, error) { func (v *Tesla) ChargedEnergy() (float64, error) { return v.chargedEnergyG() } - -// depends on https://github.com/jsgoecke/tesla/issues/28 -// -// CurrentPower implements the ChargeRater.CurrentPower interface -// func (v *Tesla) CurrentPower() (float64, error) { -// state, err := v.vehicle.ChargeState() -// if err != nil { -// return 0, err -// } -// return state.ChargerPower, err -// } diff --git a/vehicle/vw.go b/vehicle/vw.go index 4494d7754..6d62fd72a 100644 --- a/vehicle/vw.go +++ b/vehicle/vw.go @@ -1,6 +1,7 @@ package vehicle import ( + "fmt" "net/url" "strings" "time" @@ -53,18 +54,20 @@ func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) { }) err := identity.Login(query, cc.User, cc.Password) - if err == nil { - api := vw.NewAPI(log, identity, "VW", "DE") - - if cc.VIN == "" { - cc.VIN, err = findVehicle(api.Vehicles()) - if err == nil { - log.DEBUG.Printf("found vehicle: %v", cc.VIN) - } - } - - v.Provider = vw.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + if err != nil { + return v, fmt.Errorf("login failed: %w", err) } + api := vw.NewAPI(log, identity, "VW", "DE") + + if cc.VIN == "" { + cc.VIN, err = findVehicle(api.Vehicles()) + if err == nil { + log.DEBUG.Printf("found vehicle: %v", cc.VIN) + } + } + + v.Provider = vw.NewProvider(api, strings.ToUpper(cc.VIN), cc.Cache) + return v, err }