Move MySkoda implementation into own package (#14349)
Some checks failed
Some checks failed
This commit is contained in:
parent
85b14d383b
commit
9ff704e763
12 changed files with 452 additions and 107 deletions
|
|
@ -6,8 +6,8 @@ import (
|
|||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda/service"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda/myskoda"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda/myskoda/service"
|
||||
)
|
||||
|
||||
// https://gitlab.com/prior99/skoda
|
||||
|
|
@ -15,7 +15,7 @@ import (
|
|||
// Enyaq is an api.Vehicle implementation for Skoda Enyaq cars
|
||||
type Enyaq struct {
|
||||
*embed
|
||||
*skoda.Provider // provides the api implementations
|
||||
*myskoda.Provider // provides the api implementations
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -50,17 +50,17 @@ func NewEnyaqFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
log := util.NewLogger("enyaq").Redact(cc.User, cc.Password, cc.VIN)
|
||||
|
||||
// use Skoda api to resolve list of vehicles
|
||||
ts, err := service.TokenRefreshServiceTokenSource(log, skoda.TRSParams, skoda.AuthParams, cc.User, cc.Password)
|
||||
ts, err := service.TokenRefreshServiceTokenSource(log, myskoda.TRSParams, myskoda.AuthParams, cc.User, cc.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
api := skoda.NewAPI(log, ts)
|
||||
api := myskoda.NewAPI(log, ts)
|
||||
api.Client.Timeout = cc.Timeout
|
||||
|
||||
vehicle, err := ensureVehicleEx(
|
||||
cc.VIN, api.Vehicles,
|
||||
func(v skoda.Vehicle) (string, error) {
|
||||
func(v myskoda.Vehicle) (string, error) {
|
||||
return v.VIN, nil
|
||||
},
|
||||
)
|
||||
|
|
@ -75,10 +75,10 @@ func NewEnyaqFromConfig(other map[string]interface{}) (api.Vehicle, error) {
|
|||
|
||||
// reuse tokenService to build provider
|
||||
if err == nil {
|
||||
api := skoda.NewAPI(log, ts)
|
||||
api := myskoda.NewAPI(log, ts)
|
||||
api.Client.Timeout = cc.Timeout
|
||||
|
||||
v.Provider = skoda.NewProvider(api, vehicle.VIN, cc.Cache)
|
||||
v.Provider = myskoda.NewProvider(api, vehicle.VIN, cc.Cache)
|
||||
}
|
||||
|
||||
return v, err
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const BaseURI = "https://mysmob.api.connect.skoda-auto.cz/api"
|
||||
const BaseURI = "https://api.connect.skoda-auto.cz/api"
|
||||
|
||||
// API is the Skoda api client
|
||||
type API struct {
|
||||
|
|
@ -30,35 +30,28 @@ func NewAPI(log *util.Logger, ts oauth2.TokenSource) *API {
|
|||
return v
|
||||
}
|
||||
|
||||
// Vehicles implements the /v2/garage response
|
||||
// Vehicles implements the /v3/garage response
|
||||
func (v *API) Vehicles() ([]Vehicle, error) {
|
||||
var res VehiclesResponse
|
||||
|
||||
uri := fmt.Sprintf("%s/v2/garage", BaseURI)
|
||||
uri := fmt.Sprintf("%s/v3/garage", BaseURI)
|
||||
err := v.GetJSON(uri, &res)
|
||||
|
||||
return res.Vehicles, err
|
||||
}
|
||||
|
||||
func (v *API) VehicleDetails(vin string) (Vehicle, error) {
|
||||
var res Vehicle
|
||||
uri := fmt.Sprintf("%s/v2/garage/vehicles/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Status implements the /v2/vehicle-status/<vin> response
|
||||
func (v *API) Status(vin string) (StatusResponse, error) {
|
||||
var res StatusResponse
|
||||
uri := fmt.Sprintf("%s/v1/vehicle-health-report/warning-lights/%s", BaseURI, vin)
|
||||
uri := fmt.Sprintf("%s/v2/vehicle-status/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Charger implements the /v1/charging/<vin> response
|
||||
// Charger implements the /v1/charging/<vin>/status response
|
||||
func (v *API) Charger(vin string) (ChargerResponse, error) {
|
||||
var res ChargerResponse
|
||||
uri := fmt.Sprintf("%s/v1/charging/%s", BaseURI, vin)
|
||||
uri := fmt.Sprintf("%s/v1/charging/%s/status", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
|
@ -66,48 +59,33 @@ func (v *API) Charger(vin string) (ChargerResponse, error) {
|
|||
// Settings implements the /v1/charging/<vin>/settings response
|
||||
func (v *API) Settings(vin string) (SettingsResponse, error) {
|
||||
var res SettingsResponse
|
||||
|
||||
chrgRes, err := v.Charger(vin)
|
||||
if err == nil {
|
||||
res = chrgRes.Settings
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Climater implements the /v2/air-conditioning/<vin> response
|
||||
func (v *API) Climater(vin string) (ClimaterResponse, error) {
|
||||
var res ClimaterResponse
|
||||
uri := fmt.Sprintf("%s/v2/air-conditioning/%s", BaseURI, vin)
|
||||
uri := fmt.Sprintf("%s/v1/charging/%s/settings", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
const (
|
||||
ActionCharge = "charging"
|
||||
ActionChargeStart = "start"
|
||||
ActionChargeStop = "stop"
|
||||
ActionChargeStart = "Start"
|
||||
ActionChargeStop = "Stop"
|
||||
)
|
||||
|
||||
// Action executes a vehicle action
|
||||
func (v *API) Action(vin, action, value string) error {
|
||||
// @POST("api/v1/charging/{vin}/start")
|
||||
// @POST("api/v1/charging/{vin}/stop")
|
||||
uri := fmt.Sprintf("%s/v1/%s/%s/%s", BaseURI, action, vin, value)
|
||||
var res map[string]interface{}
|
||||
uri := fmt.Sprintf("%s/v1/%s/operation-requests?vin=%s", BaseURI, action, vin)
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding)
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *API) WakeUp(vin string) error {
|
||||
// @POST("api/v1/vehicle-wakeup/{vin}")
|
||||
uri := fmt.Sprintf("%s/v1/vehicle-wakeup/%s", BaseURI, vin)
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding)
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, nil)
|
||||
data := struct {
|
||||
Typ string `json:"type"`
|
||||
}{
|
||||
Typ: value,
|
||||
}
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding)
|
||||
if err == nil {
|
||||
// {"id":"61991908906fa40af9a5cba4","status":"InProgress","deeplink":""}
|
||||
err = v.DoJSON(req, &res)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
13
vehicle/skoda/connect/params.go
Normal file
13
vehicle/skoda/connect/params.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package connect
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Skoda connect api
|
||||
var AuthParams = url.Values{
|
||||
"response_type": {"code id_token"},
|
||||
"redirect_uri": {"skodaconnect://oidc.login/"},
|
||||
"client_id": {"7f045eee-7003-4379-9968-9355ed2adb06@apps_vw-dilab_com"},
|
||||
"scope": {"openid profile mbb mileage"}, // phone address cars email birthdate badge dealers driversLicense
|
||||
}
|
||||
113
vehicle/skoda/myskoda/api.go
Normal file
113
vehicle/skoda/myskoda/api.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package myskoda
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const BaseURI = "https://mysmob.api.connect.skoda-auto.cz/api"
|
||||
|
||||
// API is the Skoda api client
|
||||
type API struct {
|
||||
*request.Helper
|
||||
}
|
||||
|
||||
// NewAPI creates a new api client
|
||||
func NewAPI(log *util.Logger, ts oauth2.TokenSource) *API {
|
||||
v := &API{
|
||||
Helper: request.NewHelper(log),
|
||||
}
|
||||
|
||||
v.Client.Transport = &oauth2.Transport{
|
||||
Source: ts,
|
||||
Base: v.Client.Transport,
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Vehicles implements the /v2/garage response
|
||||
func (v *API) Vehicles() ([]Vehicle, error) {
|
||||
var res VehiclesResponse
|
||||
|
||||
uri := fmt.Sprintf("%s/v2/garage", BaseURI)
|
||||
err := v.GetJSON(uri, &res)
|
||||
|
||||
return res.Vehicles, err
|
||||
}
|
||||
|
||||
func (v *API) VehicleDetails(vin string) (Vehicle, error) {
|
||||
var res Vehicle
|
||||
uri := fmt.Sprintf("%s/v2/garage/vehicles/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Status implements the /v2/vehicle-status/<vin> response
|
||||
func (v *API) Status(vin string) (StatusResponse, error) {
|
||||
var res StatusResponse
|
||||
uri := fmt.Sprintf("%s/v1/vehicle-health-report/warning-lights/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Charger implements the /v1/charging/<vin> response
|
||||
func (v *API) Charger(vin string) (ChargerResponse, error) {
|
||||
var res ChargerResponse
|
||||
uri := fmt.Sprintf("%s/v1/charging/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Settings implements the /v1/charging/<vin>/settings response
|
||||
func (v *API) Settings(vin string) (SettingsResponse, error) {
|
||||
var res SettingsResponse
|
||||
|
||||
chrgRes, err := v.Charger(vin)
|
||||
if err == nil {
|
||||
res = chrgRes.Settings
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Climater implements the /v2/air-conditioning/<vin> response
|
||||
func (v *API) Climater(vin string) (ClimaterResponse, error) {
|
||||
var res ClimaterResponse
|
||||
uri := fmt.Sprintf("%s/v2/air-conditioning/%s", BaseURI, vin)
|
||||
err := v.GetJSON(uri, &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
const (
|
||||
ActionCharge = "charging"
|
||||
ActionChargeStart = "start"
|
||||
ActionChargeStop = "stop"
|
||||
)
|
||||
|
||||
// Action executes a vehicle action
|
||||
func (v *API) Action(vin, action, value string) error {
|
||||
// @POST("api/v1/charging/{vin}/start")
|
||||
// @POST("api/v1/charging/{vin}/stop")
|
||||
uri := fmt.Sprintf("%s/v1/%s/%s/%s", BaseURI, action, vin, value)
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding)
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *API) WakeUp(vin string) error {
|
||||
// @POST("api/v1/vehicle-wakeup/{vin}")
|
||||
uri := fmt.Sprintf("%s/v1/vehicle-wakeup/%s", BaseURI, vin)
|
||||
|
||||
req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding)
|
||||
if err == nil {
|
||||
err = v.DoJSON(req, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
24
vehicle/skoda/myskoda/params.go
Normal file
24
vehicle/skoda/myskoda/params.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package myskoda
|
||||
|
||||
import "net/url"
|
||||
|
||||
const (
|
||||
Brand = "VW"
|
||||
Country = "CZ"
|
||||
|
||||
// Authorization ClientID
|
||||
AuthClientID = "afb0473b-6d82-42b8-bfea-cead338c46ef"
|
||||
)
|
||||
|
||||
// Skoda native api
|
||||
var AuthParams = url.Values{
|
||||
"response_type": {"code id_token"},
|
||||
"client_id": {"7f045eee-7003-4379-9968-9355ed2adb06@apps_vw-dilab_com"},
|
||||
"redirect_uri": {"myskoda://redirect/login/"},
|
||||
"scope": {"address badge birthdate cars driversLicense dealers email mileage mbb nationalIdentifier openid phone profession profile vin"},
|
||||
}
|
||||
|
||||
// TokenRefreshService parameters
|
||||
var TRSParams = url.Values{
|
||||
"brand": {"skoda"},
|
||||
}
|
||||
162
vehicle/skoda/myskoda/provider.go
Normal file
162
vehicle/skoda/myskoda/provider.go
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
package myskoda
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/provider"
|
||||
)
|
||||
|
||||
// Provider implements the vehicle api
|
||||
type Provider struct {
|
||||
statusG func() (StatusResponse, error)
|
||||
chargerG func() (ChargerResponse, error)
|
||||
settingsG func() (SettingsResponse, error)
|
||||
climateG func() (ClimaterResponse, error)
|
||||
action func(action, value string) error
|
||||
wakeup func() error
|
||||
}
|
||||
|
||||
// NewProvider creates a vehicle api provider
|
||||
func NewProvider(api *API, vin string, cache time.Duration) *Provider {
|
||||
impl := &Provider{
|
||||
statusG: provider.Cached(func() (StatusResponse, error) {
|
||||
return api.Status(vin)
|
||||
}, cache),
|
||||
chargerG: provider.Cached(func() (ChargerResponse, error) {
|
||||
return api.Charger(vin)
|
||||
}, cache),
|
||||
climateG: provider.Cached(func() (ClimaterResponse, error) {
|
||||
return api.Climater(vin)
|
||||
}, cache),
|
||||
settingsG: provider.Cached(func() (SettingsResponse, error) {
|
||||
return api.Settings(vin)
|
||||
}, cache),
|
||||
action: func(action, value string) error {
|
||||
return api.Action(vin, action, value)
|
||||
},
|
||||
wakeup: func() error {
|
||||
return api.WakeUp(vin)
|
||||
},
|
||||
}
|
||||
return impl
|
||||
}
|
||||
|
||||
var _ api.Battery = (*Provider)(nil)
|
||||
|
||||
// Soc implements the api.Vehicle interface
|
||||
func (v *Provider) Soc() (float64, error) {
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
return float64(res.Status.Battery.StateOfChargeInPercent), nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var _ api.ChargeState = (*Provider)(nil)
|
||||
|
||||
// Status implements the api.ChargeState interface
|
||||
func (v *Provider) Status() (api.ChargeStatus, error) {
|
||||
status := api.StatusA // disconnected
|
||||
|
||||
res, err := v.climateG()
|
||||
if err == nil {
|
||||
if res.ChargerConnectionState == "CONNECTED" {
|
||||
status = api.StatusB
|
||||
}
|
||||
}
|
||||
|
||||
resChrg, err := v.chargerG()
|
||||
if err == nil {
|
||||
if resChrg.Status.State == "CHARGING" {
|
||||
status = api.StatusC
|
||||
}
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
var _ api.VehicleFinishTimer = (*Provider)(nil)
|
||||
|
||||
// FinishTime implements the api.VehicleFinishTimer interface
|
||||
func (v *Provider) FinishTime() (time.Time, error) {
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
crg := res.Status
|
||||
|
||||
// estimate not available
|
||||
if crg.State == "Error" || crg.ChargeType == "Invalid" {
|
||||
return time.Time{}, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
remaining := time.Duration(crg.RemainingTimeToFullyChargedInMinutes) * time.Minute
|
||||
return time.Now().Add(remaining), err
|
||||
}
|
||||
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
var _ api.VehicleRange = (*Provider)(nil)
|
||||
|
||||
// Range implements the api.VehicleRange interface
|
||||
func (v *Provider) Range() (rng int64, err error) {
|
||||
res, err := v.chargerG()
|
||||
return res.Status.Battery.RemainingCruisingRangeInMeters / 1e3, err
|
||||
}
|
||||
|
||||
var _ api.VehicleOdometer = (*Provider)(nil)
|
||||
|
||||
// Odometer implements the api.VehicleOdometer interface
|
||||
func (v *Provider) Odometer() (odo float64, err error) {
|
||||
res, err := v.statusG()
|
||||
return res.MileageInKm, err
|
||||
}
|
||||
|
||||
// var _ api.VehicleClimater = (*Provider)(nil)
|
||||
|
||||
// // Climater implements the api.VehicleClimater interface
|
||||
// func (v *Provider) Climater() (active bool, outsideTemp float64, targetTemp float64, err error) {
|
||||
// res, err := v.climateG()
|
||||
// err == nil {
|
||||
// state := strings.ToLower(res.Climater.Status.ClimatisationStatusData.ClimatisationState.Content)
|
||||
// active := state != "off" && state != "invalid" && state != "error"
|
||||
|
||||
// targetTemp = res.Climater.Settings.TargetTemperature.Content
|
||||
// outsideTemp = res.Climater.Status.TemperatureStatusData.OutdoorTemperature.Content
|
||||
// if math.IsNaN(outsideTemp) {
|
||||
// outsideTemp = targetTemp // cover "invalid"
|
||||
// }
|
||||
|
||||
// return active, outsideTemp, targetTemp, nil
|
||||
// }
|
||||
|
||||
// return active, outsideTemp, targetTemp, err
|
||||
// }
|
||||
|
||||
var _ api.SocLimiter = (*Provider)(nil)
|
||||
|
||||
// GetLimitSoc implements the api.SocLimiter interface
|
||||
func (v *Provider) GetLimitSoc() (int64, error) {
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
return int64(res.Settings.TargetStateOfChargeInPercent), nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var _ api.ChargeController = (*Provider)(nil)
|
||||
|
||||
// ChargeEnable implements the api.ChargeController interface
|
||||
func (v *Provider) ChargeEnable(enable bool) error {
|
||||
action := map[bool]string{true: ActionChargeStart, false: ActionChargeStop}
|
||||
return v.action(ActionCharge, action[enable])
|
||||
}
|
||||
|
||||
var _ api.Resurrector = (*Provider)(nil)
|
||||
|
||||
// WakeUp implements the api.Resurrector interface
|
||||
func (v *Provider) WakeUp() error {
|
||||
return v.wakeup()
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda/tokenrefreshservice"
|
||||
"github.com/evcc-io/evcc/vehicle/skoda/myskoda/tokenrefreshservice"
|
||||
"github.com/evcc-io/evcc/vehicle/vag"
|
||||
"github.com/evcc-io/evcc/vehicle/vag/vwidentity"
|
||||
)
|
||||
73
vehicle/skoda/myskoda/types.go
Normal file
73
vehicle/skoda/myskoda/types.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package myskoda
|
||||
|
||||
// VehiclesResponse is the /v3/garage api
|
||||
type VehiclesResponse struct {
|
||||
Vehicles []Vehicle
|
||||
}
|
||||
|
||||
type Vehicle struct {
|
||||
ID, VIN string
|
||||
Name string // user-given name
|
||||
LastUpdatedAt string
|
||||
Specification Specification
|
||||
// Connectivities
|
||||
// Capabilities
|
||||
}
|
||||
|
||||
type Specification struct {
|
||||
Title string
|
||||
Model string
|
||||
ModelYear string
|
||||
Body string
|
||||
SystemCode string
|
||||
SystemModelId string
|
||||
Engine struct {
|
||||
Typ string `json:"type"`
|
||||
PowerInKW int
|
||||
}
|
||||
Battery struct {
|
||||
CapacityInKWh int
|
||||
}
|
||||
Gearbox struct {
|
||||
Typ string `json:"type"`
|
||||
}
|
||||
TrimLevel string
|
||||
ManufacturingDate string
|
||||
MaxChargingPowerInKW int
|
||||
}
|
||||
|
||||
// StatusResponse is the /v2/vehicle-status/<vin> api
|
||||
type StatusResponse struct {
|
||||
MileageInKm float64
|
||||
}
|
||||
|
||||
// ChargerResponse is the /v2/charging/<vin> api
|
||||
type ChargerResponse struct {
|
||||
IsVehicleInSaveLocation bool
|
||||
Status struct {
|
||||
ChargingRateInKilometersPerHour float64
|
||||
ChargePowerInKw float64
|
||||
RemainingTimeToFullyChargedInMinutes int64
|
||||
State string
|
||||
ChargeType string
|
||||
Battery struct {
|
||||
RemainingCruisingRangeInMeters int64
|
||||
StateOfChargeInPercent int
|
||||
}
|
||||
}
|
||||
Settings SettingsResponse
|
||||
}
|
||||
|
||||
// SettingsResponse is the /v1/charging/<vin>/settings api
|
||||
type SettingsResponse struct {
|
||||
AutoUnlockPlugWhenCharged string `json:"autoUnlockPlugWhenCharged"`
|
||||
MaxChargeCurrentAc string `json:"maxChargeCurrentAc"`
|
||||
TargetStateOfChargeInPercent int `json:"targetStateOfChargeInPercent"`
|
||||
}
|
||||
|
||||
// ChargerResponse is the /v2/air-conditioning/<vin> api
|
||||
type ClimaterResponse struct {
|
||||
State string `json:"state"`
|
||||
ChargerConnectionState string `json:"chargerConnectionState"`
|
||||
ChargerLockState string `json:"chargerLockState"`
|
||||
}
|
||||
|
|
@ -13,9 +13,9 @@ const (
|
|||
// Skoda native api
|
||||
var AuthParams = url.Values{
|
||||
"response_type": {"code id_token"},
|
||||
"client_id": {"7f045eee-7003-4379-9968-9355ed2adb06@apps_vw-dilab_com"},
|
||||
"redirect_uri": {"myskoda://redirect/login/"},
|
||||
"scope": {"address badge birthdate cars driversLicense dealers email mileage mbb nationalIdentifier openid phone profession profile vin"},
|
||||
"client_id": {"f9a2359a-b776-46d9-bd0c-db1904343117@apps_vw-dilab_com"},
|
||||
"redirect_uri": {"skodaconnect://oidc.login/"},
|
||||
"scope": {"openid mbb profile"},
|
||||
}
|
||||
|
||||
// TokenRefreshService parameters
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ type Provider struct {
|
|||
statusG func() (StatusResponse, error)
|
||||
chargerG func() (ChargerResponse, error)
|
||||
settingsG func() (SettingsResponse, error)
|
||||
climateG func() (ClimaterResponse, error)
|
||||
action func(action, value string) error
|
||||
wakeup func() error
|
||||
}
|
||||
|
||||
// NewProvider creates a vehicle api provider
|
||||
|
|
@ -26,18 +24,15 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider {
|
|||
chargerG: provider.Cached(func() (ChargerResponse, error) {
|
||||
return api.Charger(vin)
|
||||
}, cache),
|
||||
climateG: provider.Cached(func() (ClimaterResponse, error) {
|
||||
return api.Climater(vin)
|
||||
}, cache),
|
||||
// climateG: provider.Cached(func() (interface{}, error) {
|
||||
// return api.Climater(vin)
|
||||
// }, cache),
|
||||
settingsG: provider.Cached(func() (SettingsResponse, error) {
|
||||
return api.Settings(vin)
|
||||
}, cache),
|
||||
action: func(action, value string) error {
|
||||
return api.Action(vin, action, value)
|
||||
},
|
||||
wakeup: func() error {
|
||||
return api.WakeUp(vin)
|
||||
},
|
||||
}
|
||||
return impl
|
||||
}
|
||||
|
|
@ -48,7 +43,7 @@ var _ api.Battery = (*Provider)(nil)
|
|||
func (v *Provider) Soc() (float64, error) {
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
return float64(res.Status.Battery.StateOfChargeInPercent), nil
|
||||
return float64(res.Battery.StateOfChargeInPercent), nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
|
|
@ -60,16 +55,12 @@ var _ api.ChargeState = (*Provider)(nil)
|
|||
func (v *Provider) Status() (api.ChargeStatus, error) {
|
||||
status := api.StatusA // disconnected
|
||||
|
||||
res, err := v.climateG()
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
if res.ChargerConnectionState == "CONNECTED" {
|
||||
if res.Plug.ConnectionState == "Connected" {
|
||||
status = api.StatusB
|
||||
}
|
||||
}
|
||||
|
||||
resChrg, err := v.chargerG()
|
||||
if err == nil {
|
||||
if resChrg.Status.State == "CHARGING" {
|
||||
if res.Charging.State == "Charging" {
|
||||
status = api.StatusC
|
||||
}
|
||||
}
|
||||
|
|
@ -83,14 +74,14 @@ var _ api.VehicleFinishTimer = (*Provider)(nil)
|
|||
func (v *Provider) FinishTime() (time.Time, error) {
|
||||
res, err := v.chargerG()
|
||||
if err == nil {
|
||||
crg := res.Status
|
||||
crg := res.Charging
|
||||
|
||||
// estimate not available
|
||||
if crg.State == "Error" || crg.ChargeType == "Invalid" {
|
||||
if crg.State == "Error" || crg.ChargingType == "Invalid" {
|
||||
return time.Time{}, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
remaining := time.Duration(crg.RemainingTimeToFullyChargedInMinutes) * time.Minute
|
||||
remaining := time.Duration(crg.RemainingToCompleteInSeconds) * time.Second
|
||||
return time.Now().Add(remaining), err
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +93,7 @@ var _ api.VehicleRange = (*Provider)(nil)
|
|||
// Range implements the api.VehicleRange interface
|
||||
func (v *Provider) Range() (rng int64, err error) {
|
||||
res, err := v.chargerG()
|
||||
return res.Status.Battery.RemainingCruisingRangeInMeters / 1e3, err
|
||||
return res.Battery.CruisingRangeElectricInMeters / 1e3, err
|
||||
}
|
||||
|
||||
var _ api.VehicleOdometer = (*Provider)(nil)
|
||||
|
|
@ -110,7 +101,7 @@ var _ api.VehicleOdometer = (*Provider)(nil)
|
|||
// Odometer implements the api.VehicleOdometer interface
|
||||
func (v *Provider) Odometer() (odo float64, err error) {
|
||||
res, err := v.statusG()
|
||||
return res.MileageInKm, err
|
||||
return res.Remote.MileageInKm, err
|
||||
}
|
||||
|
||||
// var _ api.VehicleClimater = (*Provider)(nil)
|
||||
|
|
@ -138,9 +129,9 @@ var _ api.SocLimiter = (*Provider)(nil)
|
|||
|
||||
// GetLimitSoc implements the api.SocLimiter interface
|
||||
func (v *Provider) GetLimitSoc() (int64, error) {
|
||||
res, err := v.chargerG()
|
||||
res, err := v.settingsG()
|
||||
if err == nil {
|
||||
return int64(res.Settings.TargetStateOfChargeInPercent), nil
|
||||
return int64(res.TargetStateOfChargeInPercent), nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
|
|
@ -153,10 +144,3 @@ func (v *Provider) ChargeEnable(enable bool) error {
|
|||
action := map[bool]string{true: ActionChargeStart, false: ActionChargeStop}
|
||||
return v.action(ActionCharge, action[enable])
|
||||
}
|
||||
|
||||
var _ api.Resurrector = (*Provider)(nil)
|
||||
|
||||
// WakeUp implements the api.Resurrector interface
|
||||
func (v *Provider) WakeUp() error {
|
||||
return v.wakeup()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,24 +38,29 @@ type Specification struct {
|
|||
|
||||
// StatusResponse is the /v2/vehicle-status/<vin> api
|
||||
type StatusResponse struct {
|
||||
MileageInKm float64
|
||||
Remote struct {
|
||||
MileageInKm float64
|
||||
}
|
||||
}
|
||||
|
||||
// ChargerResponse is the /v2/charging/<vin> api
|
||||
// ChargerResponse is the /v1/charging/<vin>/status api
|
||||
type ChargerResponse struct {
|
||||
IsVehicleInSaveLocation bool
|
||||
Status struct {
|
||||
ChargingRateInKilometersPerHour float64
|
||||
ChargePowerInKw float64
|
||||
RemainingTimeToFullyChargedInMinutes int64
|
||||
State string
|
||||
ChargeType string
|
||||
Battery struct {
|
||||
RemainingCruisingRangeInMeters int64
|
||||
StateOfChargeInPercent int
|
||||
}
|
||||
Plug struct {
|
||||
ConnectionState string // Connected
|
||||
LockState string // Unlocked
|
||||
}
|
||||
Charging struct {
|
||||
State string // Error
|
||||
RemainingToCompleteInSeconds int64
|
||||
ChargingPowerInWatts float64
|
||||
ChargingRateInKilometersPerHour float64
|
||||
ChargingType string // Invalid
|
||||
ChargeMode string // MANUAL
|
||||
}
|
||||
Battery struct {
|
||||
CruisingRangeElectricInMeters int64
|
||||
StateOfChargeInPercent int
|
||||
}
|
||||
Settings SettingsResponse
|
||||
}
|
||||
|
||||
// SettingsResponse is the /v1/charging/<vin>/settings api
|
||||
|
|
@ -64,10 +69,3 @@ type SettingsResponse struct {
|
|||
MaxChargeCurrentAc string `json:"maxChargeCurrentAc"`
|
||||
TargetStateOfChargeInPercent int `json:"targetStateOfChargeInPercent"`
|
||||
}
|
||||
|
||||
// ChargerResponse is the /v2/air-conditioning/<vin> api
|
||||
type ClimaterResponse struct {
|
||||
State string `json:"state"`
|
||||
ChargerConnectionState string `json:"chargerConnectionState"`
|
||||
ChargerLockState string `json:"chargerLockState"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue