Add identifier api (#947)

This commit is contained in:
andig 2021-05-09 11:06:39 +02:00 • committed by GitHub
parent 9e1e681b63
commit 0934a22563
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 144 additions and 82 deletions

View file

@ -92,9 +92,15 @@ type ChargeRater interface {
ChargedEnergy() (float64, error)
}
// Identifier identifies a vehicle and is implemented by the charger
type Identifier interface {
Identify() (string, error)
}
// Vehicle represents the EV and it's battery
type Vehicle interface {
Battery
Identifier
Title() string
Capacity() int64
}

View file

@ -113,9 +113,9 @@ func (d *dumper) Dump(name string, v interface{}) {
if v, ok := v.(api.VehicleRange); ok {
if rng, err := v.Range(); err != nil {
fmt.Fprintf(w, "Vehicle range:\t%v\n", err)
fmt.Fprintf(w, "Range:\t%v\n", err)
} else {
fmt.Fprintf(w, "Vehicle range:\t%vkm\n", rng)
fmt.Fprintf(w, "Range:\t%vkm\n", rng)
}
}
@ -141,6 +141,16 @@ func (d *dumper) Dump(name string, v interface{}) {
}
}
// Identity
if v, ok := v.(api.Identifier); ok {
if id, err := v.Identify(); err != nil {
fmt.Fprintf(w, "Identifier:\t%v\n", err)
} else {
fmt.Fprintf(w, "Identifier:\t%s\n", id)
}
}
if v, ok := v.(api.Diagnosis); ok {
fmt.Fprintln(w, "Diagnostic dump:")
v.Diagnose()

View file

@ -2,7 +2,6 @@ package core
import (
"errors"
"fmt"
"math"
"strings"
"sync"
@ -424,7 +423,7 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
_ = lp.setLimit(float64(lp.MinCurrent), false)
}
} else {
lp.log.ERROR.Printf("charger error: %v", err)
lp.log.ERROR.Printf("charger: %v", err)
}
// allow charger to access loadpoint
@ -441,7 +440,7 @@ func (lp *LoadPoint) syncCharger() {
}
if err != nil {
lp.log.ERROR.Printf("charger error: %v", err)
lp.log.ERROR.Printf("charger: %v", err)
}
}
@ -580,10 +579,41 @@ func (lp *LoadPoint) setActiveVehicle(vehicle api.Vehicle) {
// findActiveVehicle validates if the active vehicle is still connected to the loadpoint
func (lp *LoadPoint) findActiveVehicle() {
// find vehicles by id
if identifier, ok := lp.charger.(api.Identifier); ok {
id, err := identifier.Identify()
if err == nil {
lp.log.DEBUG.Println("charger vehicle id:", id)
// find exact match
for _, vehicle := range lp.vehicles {
if vid, err := vehicle.Identify(); err == nil && vid == id {
lp.setActiveVehicle(vehicle)
return
}
}
// find placeholder match
for _, vehicle := range lp.vehicles {
if vid, err := vehicle.Identify(); err == nil && vid == "*" {
lp.setActiveVehicle(vehicle)
return
}
}
} else {
lp.log.ERROR.Println("charger vehicle id:", err)
}
// TODO implement removing vehicle
// lp.setActiveVehicle(nil)
}
if len(lp.vehicles) <= 1 {
return
}
// find vehicles by charge state
if vs, ok := lp.vehicle.(api.ChargeState); ok {
status, err := vs.Status()
@ -614,6 +644,8 @@ func (lp *LoadPoint) findActiveVehicle() {
}
}
}
} else {
lp.log.ERROR.Println("vehicle charge state:", err)
}
}
}
@ -768,8 +800,7 @@ func (lp *LoadPoint) updateChargePower() {
}, retryOptions...)
if err != nil {
err = fmt.Errorf("updating charge meter: %v", err)
lp.log.ERROR.Printf("%v", err)
lp.log.ERROR.Printf("charge meter: %v", err)
}
}
@ -783,7 +814,7 @@ func (lp *LoadPoint) updateChargeCurrents() {
i1, i2, i3, err := phaseMeter.Currents()
if err != nil {
lp.log.ERROR.Printf("charge meter error: %v", err)
lp.log.ERROR.Printf("charge meter: %v", err)
return
}
@ -813,13 +844,13 @@ func (lp *LoadPoint) publishChargeProgress() {
if f, err := lp.chargeRater.ChargedEnergy(); err == nil {
lp.chargedEnergy = 1e3 * f // convert to Wh
} else {
lp.log.ERROR.Printf("charge rater error: %v", err)
lp.log.ERROR.Printf("charge rater: %v", err)
}
if d, err := lp.chargeTimer.ChargingTime(); err == nil {
lp.chargeDuration = d.Round(time.Second)
} else {
lp.log.ERROR.Printf("charge timer error: %v", err)
lp.log.ERROR.Printf("charge timer: %v", err)
}
lp.publish("chargedEnergy", lp.chargedEnergy)
@ -870,7 +901,7 @@ func (lp *LoadPoint) publishSoCAndRange() {
// we need a value- so retry on error
lp.socUpdated = lp.clock.Now()
lp.log.ERROR.Printf("vehicle error: %v", err)
lp.log.ERROR.Printf("vehicle: %v", err)
}
// range
@ -912,7 +943,7 @@ func (lp *LoadPoint) Update(sitePower float64) {
// read and publish status
if err := lp.updateChargerStatus(); err != nil {
lp.log.ERROR.Printf("charger error: %v", err)
lp.log.ERROR.Printf("charger: %v", err)
return
}

View file

@ -308,7 +308,18 @@ func (c *Keba) Currents() (float64, float64, float64, error) {
return float64(kr.I1) / 1e3, float64(kr.I2) / 1e3, float64(kr.I3) / 1e3, err
}
// Diagnose implements the Diagnosis interface
var _ api.Identifier = (*Keba)(nil)
// Identify implements the api.Identifier interface
func (c *Keba) Identify() (string, error) {
var kr keba.Report100
err := c.roundtrip("report", 100, &kr)
return kr.RFIDTag, err
}
var _ api.Diagnosis = (*Keba)(nil)
// Diagnose implements the api.Diagnosis interface
func (c *Keba) Diagnose() {
var kr keba.Report100
if err := c.roundtrip("report", 100, &kr); err == nil {

View file

@ -27,8 +27,7 @@ func init() {
// NewAudiFromConfig creates a new vehicle
func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -40,7 +39,7 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Audi{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
log := util.NewLogger("audi")

View file

@ -47,8 +47,7 @@ func init() {
// NewBMWFromConfig creates a new vehicle
func NewBMWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -62,7 +61,7 @@ func NewBMWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("bmw")
v := &BMW{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
user: cc.User,
password: cc.Password,

View file

@ -27,8 +27,7 @@ func init() {
// NewCarWingsFromConfig creates a new vehicle
func NewCarWingsFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, Region string
Cache time.Duration
}{
@ -41,7 +40,7 @@ func NewCarWingsFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &CarWings{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
user: cc.User,
password: cc.Password,
region: cc.Region,

View file

@ -31,12 +31,11 @@ func init() {
// NewCloudFromConfig creates a new vehicle
func NewCloudFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Token string
Title string
Capacity int64
Brand string
Other map[string]string `mapstructure:",remain"`
Cache time.Duration
Token string
embed `mapstructure:",squash"`
Brand string
Other map[string]string `mapstructure:",remain"`
Cache time.Duration
}{
Cache: interval,
}
@ -56,7 +55,7 @@ func NewCloudFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Cloud{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
token: cc.Token,
brand: cc.Brand,
config: cc.Other,

View file

@ -42,8 +42,7 @@ func init() {
// NewFordFromConfig creates a new vehicle
func NewFordFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -61,7 +60,7 @@ func NewFordFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("ford")
v := &Ford{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
log: log,
user: cc.User,

View file

@ -23,8 +23,7 @@ func init() {
// NewHyundaiFromConfig creates a new Vehicle
func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password string
VIN string
Cache time.Duration
@ -80,7 +79,7 @@ func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Hyundai{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
API: api,
}

View file

@ -27,8 +27,7 @@ func init() {
// NewIDFromConfig creates a new vehicle
func NewIDFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -40,7 +39,7 @@ func NewIDFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &ID{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
log := util.NewLogger("id")

View file

@ -23,8 +23,7 @@ func init() {
// NewKiaFromConfig creates a new Vehicle
func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password string
VIN string
Cache time.Duration
@ -80,7 +79,7 @@ func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Kia{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
API: api,
}

View file

@ -56,8 +56,7 @@ func init() {
// NewNissanFromConfig creates a new vehicle
func NewNissanFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, Region, VIN string
Cache time.Duration
}{
@ -72,7 +71,7 @@ func NewNissanFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("nissan")
v := &Nissan{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
log: log,
user: cc.User,

View file

@ -33,8 +33,7 @@ func init() {
// NewFordFromConfig creates a new vehicle
func NewNiuFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, Serial string
Cache time.Duration
}{
@ -52,7 +51,7 @@ func NewNiuFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("niu")
v := &Niu{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
user: cc.User,
password: cc.Password,

View file

@ -27,8 +27,7 @@ func init() {
// NewPorscheFromConfig creates a new vehicle
func NewPorscheFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -61,7 +60,7 @@ func NewPorscheFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Porsche{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
porscheProvider: provider,
}

View file

@ -45,8 +45,7 @@ type PSA struct {
// newPSA creates a new vehicle
func newPSA(log *util.Logger, brand, realm string, other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
ClientID, ClientSecret string
User, Password, VIN string
Cache time.Duration
@ -59,7 +58,7 @@ func newPSA(log *util.Logger, brand, realm string, other map[string]interface{})
}
v := &PSA{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
api := psa.NewAPI(log, brand, realm, cc.ClientID, cc.ClientSecret)

View file

@ -113,8 +113,7 @@ func init() {
// NewRenaultFromConfig creates a new vehicle
func NewRenaultFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, Region, VIN string
Cache time.Duration
}{
@ -129,7 +128,7 @@ func NewRenaultFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("renault")
v := &Renault{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
user: cc.User,
password: cc.Password,

View file

@ -26,8 +26,7 @@ func init() {
// NewSeatFromConfig creates a new vehicle
func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -39,7 +38,7 @@ func NewSeatFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Seat{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
log := util.NewLogger("seat")

View file

@ -27,8 +27,7 @@ func init() {
// NewSkodaFromConfig creates a new vehicle
func NewSkodaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -40,7 +39,7 @@ func NewSkodaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Skoda{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
log := util.NewLogger("skoda")

View file

@ -34,8 +34,7 @@ func init() {
// NewTeslaFromConfig creates a new Tesla vehicle
func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
ClientID, ClientSecret string
User, Password string
Tokens teslaTokens
@ -54,7 +53,7 @@ func NewTeslaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &Tesla{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
// authenticated http client with logging injected to the Tesla client

View file

@ -11,18 +11,26 @@ import (
)
type embed struct {
title string
capacity int64
Title_ string `mapstructure:"title"`
Capacity_ int64 `mapstructure:"capacity"`
Identifier_ string `mapstructure:"identifier"`
}
// Title implements the Vehicle.Title interface
func (m *embed) Title() string {
return m.title
return m.Title_
}
// Capacity implements the Vehicle.Capacity interface
func (m *embed) Capacity() int64 {
return m.capacity
return m.Capacity_
}
var _ api.Identifier = (*embed)(nil)
// Identify implements the api.Identifier interface
func (m *embed) Identify() (string, error) {
return m.Identifier_, nil
}
//go:generate go run ../../cmd/tools/decorate.go -p vehicle -f decorateVehicle -b api.Vehicle -o vehicle_decorators -t "api.ChargeState,Status,func() (api.ChargeStatus, error)" -t "api.VehicleRange,Range,func() (int64, error)"
@ -43,12 +51,11 @@ func init() {
// NewConfigurableFromConfig creates a new Vehicle
func NewConfigurableFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
Charge provider.Config
Status *provider.Config
Range *provider.Config
Cache time.Duration
embed `mapstructure:",squash"`
Charge provider.Config
Status *provider.Config
Range *provider.Config
Cache time.Duration
}{
Cache: interval,
}
@ -73,7 +80,7 @@ func NewConfigurableFromConfig(other map[string]interface{}) (api.Vehicle, error
}
v := &Vehicle{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
chargeG: getter,
}

View file

@ -97,8 +97,7 @@ func init() {
// NewVolvoFromConfig creates a new vehicle
func NewVolvoFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -112,7 +111,7 @@ func NewVolvoFromConfig(other map[string]interface{}) (api.Vehicle, error) {
log := util.NewLogger("volvo")
v := &Volvo{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
Helper: request.NewHelper(log),
user: cc.User,
password: cc.Password,

View file

@ -27,8 +27,7 @@ func init() {
// NewVWFromConfig creates a new vehicle
func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
Title string
Capacity int64
embed `mapstructure:",squash"`
User, Password, VIN string
Cache time.Duration
}{
@ -40,7 +39,7 @@ func NewVWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}
v := &VW{
embed: &embed{cc.Title, cc.Capacity},
embed: &cc.embed,
}
log := util.NewLogger("vw")

View file

@ -205,6 +205,21 @@ func (mr *MockVehicleMockRecorder) Capacity() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Capacity", reflect.TypeOf((*MockVehicle)(nil).Capacity))
}
// Identify mocks base method.
func (m *MockVehicle) Identify() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Identify")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Identify indicates an expected call of Identify.
func (mr *MockVehicleMockRecorder) Identify() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Identify", reflect.TypeOf((*MockVehicle)(nil).Identify))
}
// SoC mocks base method.
func (m *MockVehicle) SoC() (float64, error) {
m.ctrl.T.Helper()