evcc-io/vehicle/id/api.go
andig d4f8d03cb9
Some checks failed
Build / Build (push) Failing after 5m22s
Build / Build UI (push) Failing after 1m45s
Build / Publish :latest (push) Has been skipped
Build / Publish :release (push) Has been skipped
Build / Release (push) Has been skipped
Add Peugeot/Opel/Citroen api (#692)
2021-02-28 14:06:05 +01:00

200 lines
5.3 KiB
Go

package id
import (
"fmt"
"net/http"
"strings"
"github.com/andig/evcc/util"
"github.com/andig/evcc/util/request"
"github.com/andig/evcc/vehicle/vw"
)
// https://identity-userinfo.vwgroup.io/oidc/userinfo
// https://customer-profile.apps.emea.vwapps.io/v1/customers/<userId>/realCarData
// BaseURL is the API base url
const BaseURL = "https://mobileapi.apps.emea.vwapps.io"
// API is an api.Vehicle implementation for VW ID cars
type API struct {
*request.Helper
identity *vw.Identity
}
// Actions and action values
const (
ActionCharge = "charging"
ActionChargeStart = "start"
ActionChargeStop = "stop"
ActionChargeSettings = "settings" // body: targetSOC_pct
ActionClimatisation = "climatisation"
ActionClimatisationStart = "start"
ActionClimatisationStop = "stop"
)
// NewAPI creates a new vehicle
func NewAPI(log *util.Logger, identity *vw.Identity) *API {
v := &API{
Helper: request.NewHelper(log),
identity: identity,
}
return v
}
// Vehicles implements the /vehicles response
func (v *API) Vehicles() (res []string, err error) {
uri := fmt.Sprintf("%s/vehicles", BaseURL)
req, err := request.New(http.MethodGet, uri, nil, map[string]string{
"Accept": "application/json",
"Authorization": "Bearer " + v.identity.Token(),
})
var vehicles struct {
Data []struct {
VIN string
Nickname string
}
}
if err == nil {
err = v.DoJSON(req, &vehicles)
for _, v := range vehicles.Data {
res = append(res, v.VIN)
}
}
return res, err
}
// Status is the /status api
type Status struct {
Data struct {
BatteryStatus BatteryStatus
ChargingStatus ChargingStatus
ChargingSettings ChargingSettings
PlugStatus PlugStatus
RangeStatus RangeStatus
ClimatisationSettings ClimatisationSettings
ClimatisationStatus ClimatisationStatus // may be currently not available
}
}
// BatteryStatus is the /status.batteryStatus api
type BatteryStatus struct {
CarCapturedTimestamp string
CurrentSOCPercent int `json:"currentSOC_pct"`
CruisingRangeElectricKm int `json:"cruisingRangeElectric_km"`
}
// ChargingStatus is the /status.chargingStatus api
type ChargingStatus struct {
CarCapturedTimestamp string
ChargingState string // readyForCharging
RemainingChargingTimeToCompleteMin int `json:"remainingChargingTimeToComplete_min"`
ChargePowerKW int `json:"chargePower_kW"`
ChargeRateKmph int `json:"chargeRate_kmph"`
}
// ChargingSettings is the /status.chargingSettings api
type ChargingSettings struct {
CarCapturedTimestamp string
MaxChargeCurrentAC string // reduced, maximum
AutoUnlockPlugWhenCharged string
TargetSOCPercent int `json:"targetSOC_pct"`
}
// PlugStatus is the /status.plugStatus api
type PlugStatus struct {
CarCapturedTimestamp string
PlugConnectionState string // connected, disconnected
PlugLockState string
}
// ClimatisationStatus is the /status.climatisationStatus api
type ClimatisationStatus struct {
CarCapturedTimestamp string
RemainingClimatisationTimeMin int `json:"remainingClimatisationTime_min"`
ClimatisationState string // off
}
// ClimatisationSettings is the /status.climatisationSettings api
type ClimatisationSettings struct {
CarCapturedTimestamp string
TargetTemperatureK float64 `json:"targetTemperature_K"`
TargetTemperatureC float64 `json:"targetTemperature_C"`
ClimatisationWithoutExternalPower bool
ClimatisationAtUnlock bool // ClimatizationAtUnlock?
WindowHeatingEnabled bool
ZoneFrontLeftEnabled bool
ZoneFrontRightEnabled bool
ZoneRearLeftEnabled bool
ZoneRearRightEnabled bool
}
// RangeStatus is the /status.rangeStatus api
type RangeStatus struct {
CarCapturedTimestamp string
CarType string
PrimaryEngine struct {
Type string
CurrentSOCPercent int `json:"currentSOC_pct"`
RemainingRangeKm int `json:"remainingRange_km"`
}
TotalRangeKm int `json:"totalRange_km"`
}
// Status implements the /status response
func (v *API) Status(vin string) (res Status, err error) {
uri := fmt.Sprintf("%s/vehicles/%s/status", BaseURL, vin)
req, err := request.New(http.MethodGet, uri, nil, map[string]string{
"Accept": "application/json",
"Authorization": "Bearer " + v.identity.Token(),
})
if err == nil {
err = v.DoJSON(req, &res)
}
return res, err
}
// Action implements vehicle actions
func (v *API) Action(vin, action, value string) error {
uri := fmt.Sprintf("%s/vehicles/%s/%s/%s", BaseURL, vin, action, value)
req, err := request.New(http.MethodPost, uri, nil, map[string]string{
"Accept": "application/json",
"Authorization": "Bearer " + v.identity.Token(),
})
if err == nil {
var res interface{}
err = v.DoJSON(req, &res)
}
return err
}
// Any implements any api response
func (v *API) Any(uri, vin string) (interface{}, error) {
if strings.Contains(uri, "%s") {
uri = fmt.Sprintf(uri, vin)
}
req, err := request.New(http.MethodGet, uri, nil, map[string]string{
"Accept": "application/json",
"Authorization": "Bearer " + v.identity.Token(),
})
var res interface{}
if err == nil {
err = v.DoJSON(req, &res)
}
return res, err
}