Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import (
"io"
"net/url"
"time"

"github.com/evcc-io/evcc/api/internal"
)

//go:generate go tool mockgen -package api -destination mock.go github.com/evcc-io/evcc/api Charger,ChargeState,CurrentLimiter,CurrentGetter,PhaseSwitcher,PhaseGetter,FeatureDescriber,Identifier,Meter,MeterEnergy,PhaseCurrents,Vehicle,ChargeRater,Battery,BatteryController,BatterySocLimiter,Circuit,Tariff

var ContextTitle internal.ContextKey

// Meter provides total active power in W
type Meter interface {
CurrentPower() (float64, error)
Expand Down Expand Up @@ -140,11 +144,9 @@ type PhaseDescriber interface {
type Vehicle interface {
Battery
BatteryCapacity
IconDescriber
FeatureDescriber
PhaseDescriber
TitleDescriber
SetTitle(string)
Identifiers() []string
OnIdentified() ActionConfig
}
Expand Down
6 changes: 6 additions & 0 deletions api/internal/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package internal

// ContextKey is just an empty struct. It exists so context keys can be
// an immutable public variable with a unique type. It's immutable
// because nobody else can create a ContextKey, being unexported.
type ContextKey struct{}
26 changes: 15 additions & 11 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,9 @@ func configureChargers(static []config.Named, names ...string) error {
return eg.Wait()
}

func vehicleInstance(cc config.Named) (api.Vehicle, error) {
ctx := util.WithLogger(context.TODO(), util.NewLogger(cc.Name))
func vehicleInstance(ctx context.Context, cc config.Named) (api.Vehicle, error) {
// TODO move key
ctx = util.WithLogger(ctx, util.NewLogger(cc.Name))

props, err := customDevice(cc.Other)

Expand All @@ -384,13 +385,7 @@ func vehicleInstance(cc config.Named) (api.Vehicle, error) {

// wrap non-config vehicle errors to prevent fatals
log.ERROR.Printf("creating vehicle %s failed: %v", cc.Name, err)
instance = vehicle.NewWrapper(cc.Name, cc.Type, cc.Other, err)
}

// ensure vehicle config has title
if instance.GetTitle() == "" {
//lint:ignore SA1019 as Title is safe on ascii
instance.SetTitle(strings.Title(cc.Name))
instance = vehicle.NewWrapper(ctx, cc.Name, cc.Type, cc.Other, err)
}

return instance, nil
Expand All @@ -417,7 +412,9 @@ func configureVehicles(static []config.Named, names ...string) error {
}

eg.Go(func() error {
instance, err := vehicleInstance(cc)
ctx := context.WithValue(context.Background(), api.ContextTitle, cc.Name)

instance, err := vehicleInstance(ctx, cc)
if err != nil {
return fmt.Errorf("cannot create vehicle '%s': %w", cc.Name, err)
}
Expand Down Expand Up @@ -447,7 +444,14 @@ func configureVehicles(static []config.Named, names ...string) error {
return nil
}

instance, err := vehicleInstance(cc)
title := conf.Properties.Title
if title == "" {
title = cc.Name
}

ctx := context.WithValue(context.Background(), api.ContextTitle, title)

instance, err := vehicleInstance(ctx, cc)
if err != nil {
return fmt.Errorf("cannot create vehicle '%s': %w", cc.Name, err)
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/soc/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"log"
"math"
Expand Down Expand Up @@ -34,7 +35,7 @@ func main() {
log.Fatal("not enough arguments")
}

params := make(map[string]interface{})
params := make(map[string]any)
params["brand"] = strings.ToLower(os.Args[1])

action := "soc"
Expand Down Expand Up @@ -65,7 +66,7 @@ func main() {
log.Fatal("unexpected number of parameters")
}

v, err := vehicle.NewCloudFromConfig(params)
v, err := vehicle.NewCloudFromConfig(context.Background(), params)
if err != nil {
log.Fatal(err)
}
Expand Down
5 changes: 3 additions & 2 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,9 @@ func meterCapabilities(name string, meter any) string {
// DumpConfig site configuration
func (site *Site) DumpConfig() {
// verify vehicle detection
if vehicles := site.Vehicles().Instances(); len(vehicles) > 1 {
for _, v := range vehicles {
if devs := config.Vehicles().Devices(); len(devs) > 1 {
for _, dev := range devs {
v := dev.Instance()
if _, ok := v.(api.ChargeState); !ok && len(v.Identifiers()) == 0 {
site.log.WARN.Printf("vehicle '%s' does not support automatic detection", v.GetTitle())
}
Expand Down
2 changes: 1 addition & 1 deletion core/site/vehicles.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ type Vehicles interface {
// ByName returns a single vehicle adapter by name
ByName(string) (vehicle.API, error)

// All returns the list of vehicle instances
// Instance returns the list of vehicle instances
Instances() []api.Vehicle
}
17 changes: 9 additions & 8 deletions core/site_vehicles.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,25 @@ type vehicleStruct struct {

// publishVehicles returns a list of vehicle titles
func (site *Site) publishVehicles() {
vv := site.Vehicles().Settings()
res := make(map[string]vehicleStruct, len(vv))
devs := config.Vehicles().Devices()
res := make(map[string]vehicleStruct, len(devs))

for _, v := range vv {
var plan *planStruct
for _, dev := range devs {
v := vehicle.Adapter(site.log, dev)

instance := v.Instance()
ac := instance.OnIdentified()

var plan *planStruct
if time, precondition, soc := v.GetPlanSoc(); !time.IsZero() {
plan = &planStruct{Soc: soc, Precondition: int64(precondition.Seconds()), Time: time}
}

instance := v.Instance()
ac := instance.OnIdentified()

res[v.Name()] = vehicleStruct{
Title: instance.GetTitle(),
Icon: instance.Icon(),
Capacity: instance.Capacity(),
Phases: instance.Phases(),
Icon: deviceProperties(dev).Icon, // device meta data
MinSoc: v.GetMinSoc(),
LimitSoc: v.GetLimitSoc(),
MinCurrent: ac.MinCurrent,
Expand Down
1 change: 0 additions & 1 deletion push/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ func (h *Hub) apply(ev Event, tmpl string) (string, error) {

instance := v.Instance()
attr["vehicleTitle"] = instance.GetTitle()
attr["vehicleIcon"] = instance.Icon()
attr["vehicleCapacity"] = instance.Capacity()
}
}
Expand Down
4 changes: 2 additions & 2 deletions util/templates/defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,9 @@ presets:
vehicle-common:
params:
- name: title
deprecated: true
- name: icon
default: car
advanced: true
deprecated: true
- name: capacity
- name: phases
advanced: true
Expand Down
6 changes: 0 additions & 6 deletions util/templates/includes/vehicle-common.tpl
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
{{ define "vehicle-common" }}
{{- if .title }}
title: {{ .title }}
{{- end }}
{{- if .icon }}
icon: {{ .icon }}
{{- end }}
{{- if .capacity }}
capacity: {{ .capacity }}
{{- end }}
Expand Down
7 changes: 4 additions & 3 deletions vehicle/aiways.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vehicle

import (
"context"
"strconv"
"time"

Expand All @@ -20,11 +21,11 @@ type Aiways struct {
}

func init() {
registry.Add("aiways", NewAiwaysFromConfig)
registry.AddCtx("aiways", NewAiwaysFromConfig)
}

// NewAiwaysFromConfig creates a new vehicle
func NewAiwaysFromConfig(other map[string]interface{}) (api.Vehicle, error) {
func NewAiwaysFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
User, Password, VIN string
Expand All @@ -44,7 +45,7 @@ func NewAiwaysFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}

v := &Aiways{
embed: &cc.embed,
embed: cc.embed.withContext(ctx),
}

log := util.NewLogger("aiways").Redact(cc.User, cc.Password, cc.VIN)
Expand Down
8 changes: 3 additions & 5 deletions vehicle/audi.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ type Audi struct {
}

func init() {
registry.Add("audi", NewAudiFromConfig)
registry.Add("etron", NewAudiFromConfig)
registry.AddCtx("audi", NewAudiFromConfig)
}

// NewAudiFromConfig creates a new vehicle
func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
func NewAudiFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
User, Password, VIN string
Expand All @@ -49,7 +48,7 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
}

v := &Audi{
embed: &cc.embed,
embed: cc.embed.withContext(ctx),
}

log := util.NewLogger("audi").Redact(cc.User, cc.Password, cc.VIN)
Expand Down Expand Up @@ -85,7 +84,6 @@ func NewAudiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
api := id.NewAPI(log, its)
api.Client.Timeout = cc.Timeout

v.fromVehicle(vehicle.Nickname, 0)
v.Provider = id.NewProvider(api, vehicle.VIN, cc.Cache)
}

Expand Down
17 changes: 9 additions & 8 deletions vehicle/bluelink.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vehicle

import (
"context"
"time"

"github.com/evcc-io/evcc/api"
Expand All @@ -18,12 +19,12 @@ type Bluelink struct {
}

func init() {
registry.Add("kia", NewKiaFromConfig)
registry.Add("hyundai", NewHyundaiFromConfig)
registry.AddCtx("kia", NewKiaFromConfig)
registry.AddCtx("hyundai", NewHyundaiFromConfig)
}

// NewHyundaiFromConfig creates a new vehicle
func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
func NewHyundaiFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
settings := bluelink.Config{
URI: "https://prd.eu-ccapi.hyundai.com:8080",
BasicToken: "NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==",
Expand All @@ -40,11 +41,11 @@ func NewHyundaiFromConfig(other map[string]interface{}) (api.Vehicle, error) {
// BrandAuthUrl: "%s/auth/api/v2/user/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s/api/v1/user/oauth2/redirect&lang=%s&state=ccsp",
}

return newBluelinkFromConfig("hyundai", other, settings)
return newBluelinkFromConfig(ctx, "hyundai", other, settings)
}

// NewKiaFromConfig creates a new vehicle
func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
func NewKiaFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
settings := bluelink.Config{
URI: "https://prd.eu-ccapi.kia.com:8080",
BasicToken: "ZmRjODVjMDAtMGEyZi00YzY0LWJjYjQtMmNmYjE1MDA3MzBhOnNlY3JldA==",
Expand All @@ -58,11 +59,11 @@ func NewKiaFromConfig(other map[string]interface{}) (api.Vehicle, error) {
Brand: "kia",
}

return newBluelinkFromConfig("kia", other, settings)
return newBluelinkFromConfig(ctx, "kia", other, settings)
}

// newBluelinkFromConfig creates a new Vehicle
func newBluelinkFromConfig(brand string, other map[string]interface{}, settings bluelink.Config) (api.Vehicle, error) {
func newBluelinkFromConfig(ctx context.Context, brand string, other map[string]interface{}, settings bluelink.Config) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
User, Password string
Expand Down Expand Up @@ -100,7 +101,7 @@ func newBluelinkFromConfig(brand string, other map[string]interface{}, settings
}

v := &Bluelink{
embed: &cc.embed,
embed: cc.embed.withContext(ctx),
Provider: bluelink.NewProvider(api, vehicle, cc.Expiry, cc.Cache),
}

Expand Down
17 changes: 9 additions & 8 deletions vehicle/bmw.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vehicle

import (
"context"
"time"

"github.com/evcc-io/evcc/api"
Expand All @@ -15,22 +16,22 @@ type BMW struct {
}

func init() {
registry.Add("bmw", NewBMWFromConfig)
registry.Add("mini", NewMiniFromConfig)
registry.AddCtx("bmw", NewBMWFromConfig)
registry.AddCtx("mini", NewMiniFromConfig)
}

// NewBMWFromConfig creates a new vehicle
func NewBMWFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return NewBMWMiniFromConfig("bmw", other)
func NewBMWFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
return NewBMWMiniFromConfig(ctx, "bmw", other)
}

// NewMiniFromConfig creates a new vehicle
func NewMiniFromConfig(other map[string]interface{}) (api.Vehicle, error) {
return NewBMWMiniFromConfig("mini", other)
func NewMiniFromConfig(ctx context.Context, other map[string]interface{}) (api.Vehicle, error) {
return NewBMWMiniFromConfig(ctx, "mini", other)
}

// NewBMWMiniFromConfig creates a new vehicle
func NewBMWMiniFromConfig(brand string, other map[string]interface{}) (api.Vehicle, error) {
func NewBMWMiniFromConfig(ctx context.Context, brand string, other map[string]interface{}) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
User, Password, VIN string
Expand All @@ -51,7 +52,7 @@ func NewBMWMiniFromConfig(brand string, other map[string]interface{}) (api.Vehic
}

v := &BMW{
embed: &cc.embed,
embed: cc.embed.withContext(ctx),
}

log := util.NewLogger(brand).Redact(cc.User, cc.Password, cc.VIN)
Expand Down
2 changes: 1 addition & 1 deletion vehicle/cardata.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewCardataFromConfig(ctx context.Context, other map[string]interface{}) (ap
}

v := &Cardata{
embed: &cc.embed,
embed: cc.embed.withContext(ctx),
}

oc := cardata.Config
Expand Down
Loading
Loading