From 5eb5a086819d97cab5d268fde6063384ac66729b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20B=C3=B6hmke?= Date: Sat, 19 Jun 2021 15:02:19 +0200 Subject: [PATCH] SMA: upgrade library (#1155) --- go.mod | 2 +- go.sum | 7 +++-- meter/sma.go | 78 ++++++++++++++++++++++------------------------------ 3 files changed, 39 insertions(+), 48 deletions(-) diff --git a/go.mod b/go.mod index 57c449805e..2190723f99 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( github.com/thoas/go-funk v0.8.0 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c github.com/volkszaehler/mbmd v0.0.0-20210526131012-e1fec7232ed7 - gitlab.com/bboehmke/sunny v0.12.2 + gitlab.com/bboehmke/sunny v0.13.0 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect golang.org/x/net v0.0.0-20210614182718-04defd469f4e golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 diff --git a/go.sum b/go.sum index 74b5a42f9f..39c5dbd1e9 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,7 @@ github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMS github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dmarkham/enumer v1.5.2/go.mod h1:jZ3PNbNJDEkFGx54MlkSjnDQUo7445l7/guoKdh9cY8= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= @@ -520,6 +521,7 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1/go.mod h1:eD5JxqMiuNYyFNmyY9rkJ/slN8y59oEu4Ei7F8OoKWQ= +github.com/pascaldekloe/name v1.0.0/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= github.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf/go.mod h1:+AwQL2mK3Pd3S+TUwg0tYQjid0q1txyNUJuuSmz8Kdk= github.com/pbnjay/strptime v0.0.0-20140226051138-5c05b0d668c9/go.mod h1:6Hr+C/olSdkdL3z68MlyXWzwhvwmwN7KuUFXGb3PoOk= @@ -658,8 +660,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -gitlab.com/bboehmke/sunny v0.12.2 h1:hKH1dfTmFIUpl/roQy8jkvIJLV9Frsaq6Y+cgn1C0Gk= -gitlab.com/bboehmke/sunny v0.12.2/go.mod h1:o0e0jA5xTQ7JpQ2FO/C8N21gSV47g64EC+dRUQui+CM= +gitlab.com/bboehmke/sunny v0.13.0 h1:B9bJQOEFyE/MhempCdvYe59Lb6ARZTjz3bJ7dDmAlk8= +gitlab.com/bboehmke/sunny v0.13.0/go.mod h1:F5AIuL7kYteSJFR5E+YEocxIdpyCXmtDciFmMQVjP88= go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -933,6 +935,7 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= diff --git a/meter/sma.go b/meter/sma.go index 0a08e2850f..7b41518118 100644 --- a/meter/sma.go +++ b/meter/sma.go @@ -4,10 +4,11 @@ import ( "context" "errors" "fmt" + "os" "sort" - "strings" "sync" "sync/atomic" + "text/tabwriter" "time" "github.com/andig/evcc/api" @@ -79,7 +80,7 @@ type SMA struct { mux *util.Waiter uri string iface string - values map[string]interface{} + values map[sunny.ValueID]interface{} scale float64 device *sunny.Device } @@ -131,7 +132,7 @@ func NewSMA(uri, password, iface string, serial uint32, scale float64) (api.Mete log: log, uri: uri, iface: iface, - values: make(map[string]interface{}), + values: make(map[sunny.ValueID]interface{}), scale: scale, } @@ -178,7 +179,7 @@ func NewSMA(uri, password, iface string, serial uint32, scale float64) (api.Mete return nil, err } - if _, ok := vals["battery_charge"]; ok { + if _, ok := vals[sunny.BatteryCharge]; ok { soc = sm.soc } } @@ -208,7 +209,7 @@ func (sm *SMA) updateValues() { } } -func (sm *SMA) hasValue() (map[string]interface{}, error) { +func (sm *SMA) hasValue() (map[sunny.ValueID]interface{}, error) { elapsed := sm.mux.LockWithTimeout() defer sm.mux.Unlock() @@ -222,40 +223,20 @@ func (sm *SMA) hasValue() (map[string]interface{}, error) { // CurrentPower implements the api.Meter interface func (sm *SMA) CurrentPower() (float64, error) { values, err := sm.hasValue() - - var power float64 - if sm.device.IsEnergyMeter() { - power = sm.asFloat(values["active_power_plus"]) - sm.asFloat(values["active_power_minus"]) - } else { - power = sm.asFloat(values["power_ac_total"]) - } - - return sm.scale * power, err + return sm.scale * (sm.asFloat(values[sunny.ActivePowerPlus]) - sm.asFloat(values[sunny.ActivePowerMinus])), err } // TotalEnergy implements the api.MeterEnergy interface func (sm *SMA) TotalEnergy() (float64, error) { values, err := sm.hasValue() - - var energy float64 - if sm.device.IsEnergyMeter() { - energy = sm.asFloat(values["active_energy_plus"]) / 3600000 - } else { - energy = sm.asFloat(values["energy_total"]) / 1000 - } - - return energy, err + return sm.asFloat(values[sunny.ActiveEnergyPlus]) / 3600000, err } // Currents implements the api.MeterCurrent interface func (sm *SMA) Currents() (float64, float64, float64, error) { values, err := sm.hasValue() - measurements := []string{"l1_current", "l2_current", "l3_current"} - if !sm.device.IsEnergyMeter() { - measurements = []string{"current_ac1", "current_ac2", "current_ac3"} - } - + measurements := []sunny.ValueID{sunny.CurrentL1, sunny.CurrentL2, sunny.CurrentL3} var vals [3]float64 for i := 0; i < 3; i++ { vals[i] = sm.asFloat(values[measurements[i]]) @@ -267,40 +248,47 @@ func (sm *SMA) Currents() (float64, float64, float64, error) { // soc implements the api.Battery interface func (sm *SMA) soc() (float64, error) { values, err := sm.hasValue() - return sm.asFloat(values["battery_charge"]), err + return sm.asFloat(values[sunny.BatteryCharge]), err } // Diagnose implements the api.Diagnosis interface func (sm *SMA) Diagnose() { - fmt.Printf(" IP: %s\n", sm.device.Address()) - fmt.Printf(" Serial: %d\n", sm.device.SerialNumber()) - fmt.Printf(" EnergyMeter: %v\n", sm.device.IsEnergyMeter()) - fmt.Printf("\n") + w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) + + fmt.Fprintf(w, " IP:\t%s\n", sm.device.Address()) + fmt.Fprintf(w, " Serial:\t%d\n", sm.device.SerialNumber()) + fmt.Fprintf(w, " EnergyMeter:\t%v\n", sm.device.IsEnergyMeter()) + fmt.Fprintln(w) if name, err := sm.device.GetDeviceName(); err == nil { - fmt.Printf(" Name: %s\n", name) + fmt.Fprintf(w, " Name:\t%s\n", name) } if devClass, err := sm.device.GetDeviceClass(); err == nil { - fmt.Printf(" Device Class: 0x%X\n", devClass) + fmt.Fprintf(w, " Device Class:\t0x%X\n", devClass) } - fmt.Printf("\n") + fmt.Fprintln(w) if values, err := sm.device.GetValues(); err == nil { - keys := make([]string, 0, len(values)) - keyLength := 0 + ids := make([]sunny.ValueID, 0, len(values)) for k := range values { - keys = append(keys, k) - if len(k) > keyLength { - keyLength = len(k) - } + ids = append(ids, k) } - sort.Strings(keys) - for _, k := range keys { - fmt.Printf(" %s:%s %v %s\n", k, strings.Repeat(" ", keyLength-len(k)), values[k], sm.device.GetValueInfo(k).Unit) + sort.Slice(ids, func(i, j int) bool { + return ids[i].String() < ids[j].String() + }) + + for _, id := range ids { + switch values[id].(type) { + case float64: + fmt.Fprintf(w, " %s:\t%f %s\n", id.String(), values[id], sunny.GetValueInfo(id).Unit) + default: + fmt.Fprintf(w, " %s:\t%v %s\n", id.String(), values[id], sunny.GetValueInfo(id).Unit) + } } } + w.Flush() } func (sm *SMA) asFloat(value interface{}) float64 {