From 044eb8732e9a0867bdb3d616268f7a111ef320ba Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 19 May 2020 07:28:33 +0200 Subject: [PATCH] Fix various issues in NRGKick implementation (#164) --- charger/nrgble/nrg_linux.go | 50 +++++++++++++++++++----------------- charger/nrgble_linux.go | 51 ++++++++++++++++++++----------------- charger/nrgconnect.go | 10 ++++---- 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/charger/nrgble/nrg_linux.go b/charger/nrgble/nrg_linux.go index bf79b671d..680a52d2f 100644 --- a/charger/nrgble/nrg_linux.go +++ b/charger/nrgble/nrg_linux.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "strings" + "time" "github.com/muka/go-bluetooth/api" "github.com/muka/go-bluetooth/bluez/profile/adapter" @@ -11,19 +12,19 @@ import ( "github.com/muka/go-bluetooth/bluez/profile/device" ) -func FindDevice(a *adapter.Adapter1, hwaddr string) (*device.Device1, error) { - dev, err := Discover(a, hwaddr) +func FindDevice(a *adapter.Adapter1, hwaddr string, timeout time.Duration) (*device.Device1, error) { + dev, err := Discover(a, hwaddr, timeout) if err != nil { return nil, err } if dev == nil { - return nil, errors.New("Device not found, is it advertising?") + return nil, errors.New("device not found, is it advertising?") } return dev, nil } -func Discover(a *adapter.Adapter1, hwaddr string) (*device.Device1, error) { +func Discover(a *adapter.Adapter1, hwaddr string, timeout time.Duration) (*device.Device1, error) { err := a.FlushDevices() if err != nil { return nil, err @@ -34,28 +35,31 @@ func Discover(a *adapter.Adapter1, hwaddr string) (*device.Device1, error) { return nil, err } - defer cancel() + timer := time.NewTimer(timeout) - for ev := range discovery { - dev, err1 := device.NewDevice1(ev.Path) - if err != nil { - return nil, err1 + for { + select { + case ev := <-discovery: + dev, err := device.NewDevice1(ev.Path) + if err != nil { + return nil, err + } + if dev == nil || dev.Properties == nil { + continue + } + + p := dev.Properties + if p.Address != hwaddr { + continue + } + + cancel() + return dev, nil + case <-timer.C: + cancel() + return nil, errors.New("discovery timeout exceeded") } - - if dev == nil || dev.Properties == nil { - continue - } - - p := dev.Properties - - if p.Address != hwaddr { - continue - } - - return dev, nil } - - return nil, nil } func Connect(dev *device.Device1, ag *agent.SimpleAgent, adapterID string) error { diff --git a/charger/nrgble_linux.go b/charger/nrgble_linux.go index 97dccf41c..7e00faed0 100644 --- a/charger/nrgble_linux.go +++ b/charger/nrgble_linux.go @@ -18,16 +18,20 @@ import ( "github.com/muka/go-bluetooth/hw" ) +const nrgTimeout = 30 * time.Second + // NRGKickBLE charger implementation type NRGKickBLE struct { - log *util.Logger - timer *time.Timer - adapter *adapter.Adapter1 - agent *agent.SimpleAgent - dev *device.Device1 - device string - macaddress string - pin int + log *util.Logger + timer *time.Timer + adapter *adapter.Adapter1 + agent *agent.SimpleAgent + dev *device.Device1 + device string + macaddress string + pin int + pauseCharging bool + current int } // NewNRGKickBLEFromConfig creates a NRGKickBLE charger from generic config @@ -107,9 +111,9 @@ func NewNRGKickBLE(device, macaddress string, pin int) *NRGKickBLE { } func (nrg *NRGKickBLE) connect() (*device.Device1, error) { - dev, err := nrgble.FindDevice(nrg.adapter, nrg.macaddress) + dev, err := nrgble.FindDevice(nrg.adapter, nrg.macaddress, nrgTimeout) if err != nil { - return nil, fmt.Errorf("findDevice: %s", err) + return nil, fmt.Errorf("find device: %s", err) } err = nrgble.Connect(dev, nrg.agent, nrg.device) @@ -196,15 +200,16 @@ func (nrg *NRGKickBLE) write(service string, val interface{}) error { return nil } -func (nrg *NRGKickBLE) defaultSettings(info nrgble.Info) nrgble.Settings { +func (nrg *NRGKickBLE) mergeSettings(info nrgble.Info) nrgble.Settings { return nrgble.Settings{ PIN: nrg.pin, ChargingEnergyLimit: 19997, // magic const for "disable" KWhPer100: info.KWhPer100, AmountPerKWh: info.AmountPerKWh, Efficiency: info.Efficiency, - PauseCharging: info.PauseCharging, BLETransmissionPower: info.BLETransmissionPower, + PauseCharging: nrg.pauseCharging, // apply last value + Current: nrg.current, // apply last value } } @@ -215,7 +220,7 @@ func (nrg *NRGKickBLE) Status() (api.ChargeStatus, error) { return api.StatusF, err } - nrg.log.TRACE.Printf("power: %+v", res) + nrg.log.TRACE.Printf("read power: %+v", res) switch res.CPSignal { case 3: @@ -237,7 +242,7 @@ func (nrg *NRGKickBLE) Enabled() (bool, error) { return false, err } - nrg.log.TRACE.Printf("info: %+v", res) + nrg.log.TRACE.Printf("read info: %+v", res) return !res.PauseCharging, nil } @@ -249,10 +254,10 @@ func (nrg *NRGKickBLE) Enable(enable bool) error { return err } - nrg.log.TRACE.Printf("info: %+v", res) + nrg.pauseCharging = !enable // use cached value to work around API roundtrip delay + settings := nrg.mergeSettings(res) - settings := nrg.defaultSettings(res) - settings.PauseCharging = !enable + nrg.log.TRACE.Printf("write settings: %+v", settings) return nrg.write(nrgble.SettingsService, &settings) } @@ -264,10 +269,10 @@ func (nrg *NRGKickBLE) MaxCurrent(current int64) error { return err } - nrg.log.TRACE.Printf("info: %+v", res) + nrg.current = int(current) // use cached value to work around API roundtrip delay + settings := nrg.mergeSettings(res) - settings := nrg.defaultSettings(res) - settings.Current = int(current) + nrg.log.TRACE.Printf("write settings: %+v", settings) return nrg.write(nrgble.SettingsService, &settings) } @@ -279,7 +284,7 @@ func (nrg *NRGKickBLE) CurrentPower() (float64, error) { return 0, err } - nrg.log.TRACE.Printf("power: %+v", res) + nrg.log.TRACE.Printf("read power: %+v", res) return float64(res.TotalPower) * 10, nil } @@ -291,7 +296,7 @@ func (nrg *NRGKickBLE) TotalEnergy() (float64, error) { return 0, err } - nrg.log.TRACE.Printf("energy: %+v", res) + nrg.log.TRACE.Printf("read energy: %+v", res) return float64(res.TotalEnergy) / 1000, nil } @@ -303,7 +308,7 @@ func (nrg *NRGKickBLE) Currents() (float64, float64, float64, error) { return 0, 0, 0, err } - nrg.log.TRACE.Printf("voltage/current: %+v", res) + nrg.log.TRACE.Printf("read voltage/current: %+v", res) return float64(res.CurrentL1) / 100, float64(res.CurrentL2) / 100, diff --git a/charger/nrgconnect.go b/charger/nrgconnect.go index 7eb7314b6..7aca1098b 100644 --- a/charger/nrgconnect.go +++ b/charger/nrgconnect.go @@ -131,7 +131,7 @@ func (nrg *NRGKickConnect) Status() (api.ChargeStatus, error) { // Enabled implements the Charger.Enabled interface func (nrg *NRGKickConnect) Enabled() (bool, error) { var settings NRGSettings - err := nrg.getJSON(nrg.apiURL(apiSettings), settings) + err := nrg.getJSON(nrg.apiURL(apiSettings), &settings) return *settings.Values.ChargingStatus.Charging, err } @@ -157,7 +157,7 @@ func (nrg *NRGKickConnect) MaxCurrent(current int64) error { // CurrentPower implements the Meter interface func (nrg *NRGKickConnect) CurrentPower() (float64, error) { var measurements NRGMeasurements - err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements) + err := nrg.getJSON(nrg.apiURL(apiMeasurements), &measurements) return 1000 * measurements.ChargingPower, err } @@ -165,7 +165,7 @@ func (nrg *NRGKickConnect) CurrentPower() (float64, error) { // TotalEnergy implements the MeterEnergy interface func (nrg *NRGKickConnect) TotalEnergy() (float64, error) { var measurements NRGMeasurements - err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements) + err := nrg.getJSON(nrg.apiURL(apiMeasurements), &measurements) return measurements.ChargingEnergyOverAll, err } @@ -173,7 +173,7 @@ func (nrg *NRGKickConnect) TotalEnergy() (float64, error) { // Currents implements the MeterCurrent interface func (nrg *NRGKickConnect) Currents() (float64, float64, float64, error) { var measurements NRGMeasurements - err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements) + err := nrg.getJSON(nrg.apiURL(apiMeasurements), &measurements) if len(measurements.ChargingCurrentPhase) != 3 { return 0, 0, 0, fmt.Errorf("unexpected response: %v", measurements) @@ -189,6 +189,6 @@ func (nrg *NRGKickConnect) Currents() (float64, float64, float64, error) { // NOTE: apparently shows energy of a stopped charging session, hence substituted by TotalEnergy // func (nrg *NRGKickConnect) ChargedEnergy() (float64, error) { // var measurements NRGMeasurements -// err := nrg.getJSON(nrg.apiURL(apiMeasurements), measurements) +// err := nrg.getJSON(nrg.apiURL(apiMeasurements), &measurements) // return measurements.ChargingEnergy, err // }