Add Lexus vehicle support (#28836)

This commit is contained in:
Michael Heß 2026-04-05 18:21:58 +02:00 • committed by GitHub
parent e647eadf3f
commit 1c8387c978
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 52 additions and 16 deletions

View file

@ -0,0 +1,26 @@
template: lexus
products:
- brand: Lexus
requirements:
description:
de: |
Benötigt Lexus Link+ Connected Services Account.
en: |
Requires Lexus Link+ Connected Services Account.
params:
- preset: vehicle-common
- name: user
required: true
- name: password
required: true
- name: vin
example: JT...
- name: cache
default: 15m
render: |
type: lexus
{{ include "vehicle-common" . }}
user: {{ .user }}
password: {{ .password }}
vin: {{ .vin }}
cache: {{ .cache }}

View file

@ -9,18 +9,23 @@ import (
"github.com/evcc-io/evcc/vehicle/toyota"
)
// Toyota is an api.Vehicle implementation for Toyota cars
// Toyota is an api.Vehicle implementation for Toyota/Lexus cars
type Toyota struct {
*embed
*toyota.Provider
}
func init() {
registry.Add("toyota", NewToyotaFromConfig)
registry.Add("toyota", func(other map[string]any) (api.Vehicle, error) {
return newToyotaFromConfig("toyota", "T", other)
})
registry.Add("lexus", func(other map[string]any) (api.Vehicle, error) {
return newToyotaFromConfig("lexus", "L", other)
})
}
// NewToyotaFromConfig creates a new vehicle
func NewToyotaFromConfig(other map[string]any) (api.Vehicle, error) {
// newToyotaFromConfig creates a new vehicle
func newToyotaFromConfig(brand, brandCode string, other map[string]any) (api.Vehicle, error) {
cc := struct {
embed `mapstructure:",squash"`
User, Password, VIN string
@ -41,15 +46,15 @@ func NewToyotaFromConfig(other map[string]any) (api.Vehicle, error) {
embed: &cc.embed,
}
log := util.NewLogger("toyota").Redact(cc.User, cc.Password, cc.VIN)
identity := toyota.NewIdentity(log)
log := util.NewLogger(brand).Redact(cc.User, cc.Password, cc.VIN)
identity := toyota.NewIdentity(log, brandCode)
err := identity.Login(cc.User, cc.Password)
if err != nil {
return v, fmt.Errorf("login failed: %w", err)
}
api := toyota.NewAPI(log, identity)
api := toyota.NewAPI(log, identity, brandCode)
cc.VIN, err = ensureVehicle(cc.VIN, api.Vehicles)
if err == nil {

View file

@ -34,7 +34,7 @@ type API struct {
identity *Identity
}
func NewAPI(log *util.Logger, identity *Identity) *API {
func NewAPI(log *util.Logger, identity *Identity, brandCode string) *API {
v := &API{
Helper: request.NewHelper(log),
log: log,
@ -57,6 +57,7 @@ func NewAPI(log *util.Logger, identity *Identity) *API {
"x-client-ref": clientRef,
"x-appversion": clientRefKey,
"x-channel": channel,
"X-Appbrand": brandCode,
}),
Base: &oauth2.Transport{
Source: identity,

View file

@ -21,12 +21,12 @@ func TestAPI(t *testing.T) {
// Create and login identity
log := util.NewLogger("foo")
identity := NewIdentity(log)
identity := NewIdentity(log, "T")
err := identity.Login(user, password)
require.NoError(t, err)
// Create API client
api := NewAPI(log, identity)
api := NewAPI(log, identity, "T")
// Test Vehicles method
vehicles, err := api.Vehicles()

View file

@ -27,12 +27,14 @@ type Identity struct {
*request.Helper
oauth2.TokenSource
uuid string
brandCode string
}
func NewIdentity(log *util.Logger) *Identity {
func NewIdentity(log *util.Logger, brandCode string) *Identity {
return &Identity{
log: log,
Helper: request.NewHelper(log),
brandCode: brandCode,
}
}
@ -163,6 +165,8 @@ func (v *Identity) Login(user, password string) error {
uri := fmt.Sprintf("%s/%s", BaseUrl, AuthenticationPath)
req, err := request.New(http.MethodPost, uri, nil, map[string]string{
"Accept": "application/json",
"X-Brand": v.brandCode,
"X-Region": "EU",
})
if err != nil {
return fmt.Errorf("failed to create authentication request: %w", err)

View file

@ -20,7 +20,7 @@ func TestIdentityLogin(t *testing.T) {
util.LogLevel("trace", nil) // Enable trace logging
log := util.NewLogger("test")
identity := NewIdentity(log)
identity := NewIdentity(log, "T")
err := identity.Login(user, password)
require.NoError(t, err)