evcc-io/vehicle/octopusde.go

132 lines
2.7 KiB
Go

package vehicle
import (
"fmt"
"strings"
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/vehicle/octopuskraken"
)
// OctopusDe is an api.Vehicle implementation for the Octopus Energy Germany Kraken API
type OctopusDe struct {
*embed
*octopuskraken.API
account string
device string
deviceID string
dataG func() (octopuskraken.Device, error)
}
func init() {
registry.Add("octopus-de", NewOctopusDeFromConfig)
}
// NewOctopusDeFromConfig creates a new vehicle
func NewOctopusDeFromConfig(other map[string]any) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
Email string
Password string
AccountNumber string
Device string
Cache time.Duration
}{
Cache: interval,
}
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
if cc.Email == "" || cc.Password == "" {
return nil, api.ErrMissingCredentials
}
log := util.NewLogger("octopus-de").Redact(cc.Email, cc.Password)
api, err := octopuskraken.NewAPI(log, octopuskraken.BaseURI, cc.Email, cc.Password)
if err != nil {
return nil, err
}
v := &OctopusDe{
embed: &cc.embed,
API: api,
account: cc.AccountNumber,
device: cc.Device,
}
v.dataG = util.Cached(v.status, cc.Cache)
return v, nil
}
// status fetches the live state of the configured device, resolving the account
// and matching device on first use.
func (v *OctopusDe) status() (octopuskraken.Device, error) {
account, err := v.Account(v.account)
if err != nil {
return octopuskraken.Device{}, err
}
v.account = account
devices, err := v.Devices(account)
if err != nil {
return octopuskraken.Device{}, err
}
for _, d := range devices {
// match the configured device by id or name, or take the first one
if v.deviceID != "" {
if d.ID == v.deviceID {
return d, nil
}
continue
}
if v.device == "" || strings.EqualFold(d.ID, v.device) || strings.EqualFold(d.Name, v.device) {
v.deviceID = d.ID
v.fromVehicle(d.Name, 0)
return d, nil
}
}
if v.device == "" {
return octopuskraken.Device{}, api.ErrNotAvailable
}
return octopuskraken.Device{}, fmt.Errorf("device not found: %s", v.device)
}
// Soc implements the api.Vehicle interface
func (v *OctopusDe) Soc() (float64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
soc, ok := res.Soc()
if !ok {
return 0, api.ErrNotAvailable
}
return soc, nil
}
var _ api.SocLimiter = (*OctopusDe)(nil)
// GetLimitSoc implements the api.SocLimiter interface
func (v *OctopusDe) GetLimitSoc() (int64, error) {
res, err := v.dataG()
if err != nil {
return 0, err
}
soc, ok := res.TargetSoc()
if !ok {
return 0, api.ErrNotAvailable
}
return int64(soc), nil
}