87 lines
1.6 KiB
Go
87 lines
1.6 KiB
Go
package sma
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/evcc-io/evcc/util"
|
|
"github.com/imdario/mergo"
|
|
"gitlab.com/bboehmke/sunny"
|
|
)
|
|
|
|
// Device holds information for a Device and provides interface to get values
|
|
type Device struct {
|
|
*sunny.Device
|
|
|
|
log *util.Logger
|
|
mux sync.Mutex
|
|
wait *util.Waiter
|
|
values map[sunny.ValueID]interface{}
|
|
once sync.Once
|
|
}
|
|
|
|
// StartUpdateLoop if not already started
|
|
func (d *Device) StartUpdateLoop() {
|
|
d.once.Do(func() {
|
|
go func() {
|
|
for range time.NewTicker(time.Second * 5).C {
|
|
if err := d.UpdateValues(); err != nil {
|
|
d.log.ERROR.Println(err)
|
|
}
|
|
}
|
|
}()
|
|
})
|
|
}
|
|
|
|
func (d *Device) UpdateValues() error {
|
|
d.mux.Lock()
|
|
defer d.mux.Unlock()
|
|
|
|
values, err := d.Device.GetValues()
|
|
if err == nil {
|
|
err = mergo.Merge(&d.values, values, mergo.WithOverride)
|
|
d.wait.Update()
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (d *Device) Values() (map[sunny.ValueID]interface{}, error) {
|
|
// ensure update loop was started
|
|
d.StartUpdateLoop()
|
|
|
|
d.mux.Lock()
|
|
defer d.mux.Unlock()
|
|
|
|
if late := d.wait.Overdue(); late > 0 {
|
|
return nil, fmt.Errorf("update timeout: %v", late.Truncate(time.Second))
|
|
}
|
|
|
|
// return a copy of the map to avoid race conditions
|
|
values := make(map[sunny.ValueID]interface{}, len(d.values))
|
|
for key, value := range d.values {
|
|
values[key] = value
|
|
}
|
|
return values, nil
|
|
}
|
|
|
|
func AsFloat(value interface{}) float64 {
|
|
switch v := value.(type) {
|
|
case float64:
|
|
return v
|
|
case int32:
|
|
return float64(v)
|
|
case int64:
|
|
return float64(v)
|
|
case uint32:
|
|
return float64(v)
|
|
case uint64:
|
|
return float64(v)
|
|
case nil:
|
|
return 0
|
|
default:
|
|
util.NewLogger("sma").WARN.Printf("unknown value type: %T", value)
|
|
return 0
|
|
}
|
|
}
|