Add status and climatisation apis for ID (#569)
This commit is contained in:
parent
c6a64d1d75
commit
8db09e8160
3 changed files with 100 additions and 26 deletions
|
|
@ -3,12 +3,16 @@ 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
|
||||
|
||||
// API is an api.Vehicle implementation for VW ID cars
|
||||
type API struct {
|
||||
*request.Helper
|
||||
|
|
@ -35,7 +39,8 @@ func (v *API) Vehicles() (res []string, err error) {
|
|||
|
||||
var vehicles struct {
|
||||
Data []struct {
|
||||
VIN string
|
||||
VIN string
|
||||
Nickname string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,10 +60,11 @@ type Status struct {
|
|||
Data struct {
|
||||
BatteryStatus BatteryStatus
|
||||
ChargingStatus ChargingStatus
|
||||
ChargingSettings ChargingSettings
|
||||
PlugStatus PlugStatus
|
||||
RangeStatus RangeStatus
|
||||
ClimatisationSettings ClimatisationSettings
|
||||
// ClimatisationStatus ClimatisationStatus // currently not available
|
||||
ClimatisationStatus ClimatisationStatus // may be currently not available
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,16 +78,16 @@ type BatteryStatus struct {
|
|||
// ChargingStatus is the /status.chargingStatus api
|
||||
type ChargingStatus struct {
|
||||
CarCapturedTimestamp string
|
||||
ChargingState string
|
||||
RemainingChargingTimeToCompleteMin int `json:"remainingChargingTimeToComplete_min"`
|
||||
ChargePowerKW int `json:"chargePower_kW"`
|
||||
ChargeRateKmph int `json:"chargeRate_kmph"`
|
||||
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
|
||||
MaxChargeCurrentAC string // reduced, maximum
|
||||
AutoUnlockPlugWhenCharged string
|
||||
TargetSOCPercent int `json:"targetSOC_pct"`
|
||||
}
|
||||
|
|
@ -89,17 +95,24 @@ type ChargingSettings struct {
|
|||
// PlugStatus is the /status.plugStatus api
|
||||
type PlugStatus struct {
|
||||
CarCapturedTimestamp string
|
||||
PlugConnectionState 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
|
||||
ClimatizationAtUnlock bool
|
||||
ClimatisationAtUnlock bool // ClimatizationAtUnlock?
|
||||
WindowHeatingEnabled bool
|
||||
ZoneFrontLeftEnabled bool
|
||||
ZoneFrontRightEnabled bool
|
||||
|
|
@ -134,3 +147,22 @@ func (v *API) Status(vin string) (res Status, err error) {
|
|||
|
||||
return res, 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package id
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/andig/evcc/api"
|
||||
"github.com/andig/evcc/provider"
|
||||
)
|
||||
|
||||
|
|
@ -31,6 +33,23 @@ func (v *Provider) ChargeState() (float64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
// Status implements the Vehicle.Status interface
|
||||
func (v *Provider) Status() (api.ChargeStatus, error) {
|
||||
status := api.StatusA // disconnected
|
||||
|
||||
res, err := v.statusG()
|
||||
if res, ok := res.(Status); err == nil && ok {
|
||||
if res.Data.PlugStatus.PlugConnectionState == "connected" {
|
||||
status = api.StatusB
|
||||
}
|
||||
if res.Data.ChargingStatus.ChargingState == "charging" {
|
||||
status = api.StatusC
|
||||
}
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
// FinishTime implements the Vehicle.ChargeFinishTimer interface
|
||||
func (v *Provider) FinishTime() (time.Time, error) {
|
||||
res, err := v.statusG()
|
||||
|
|
@ -52,3 +71,26 @@ func (v *Provider) Range() (int64, error) {
|
|||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Climater implements the Vehicle.Climater interface
|
||||
func (v *Provider) Climater() (active bool, outsideTemp float64, targetTemp float64, err error) {
|
||||
res, err := v.statusG()
|
||||
if res, ok := res.(Status); err == nil && ok {
|
||||
state := strings.ToLower(res.Data.ClimatisationStatus.ClimatisationState)
|
||||
|
||||
if state == "" {
|
||||
return false, 0, 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
active := state != "off" && state != "invalid" && state != "error"
|
||||
|
||||
targetTemp = res.Data.ClimatisationSettings.TargetTemperatureC
|
||||
|
||||
// TODO: not available; use target temp to avoid wrong heating/cooling display
|
||||
outsideTemp = targetTemp
|
||||
|
||||
return active, outsideTemp, targetTemp, nil
|
||||
}
|
||||
|
||||
return active, outsideTemp, targetTemp, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,23 @@ func (v *Provider) ChargeState() (float64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
// Status implements the Vehicle.Status interface
|
||||
func (v *Provider) Status() (api.ChargeStatus, error) {
|
||||
status := api.StatusA // disconnected
|
||||
|
||||
res, err := v.chargerG()
|
||||
if res, ok := res.(ChargerResponse); err == nil && ok {
|
||||
if res.Charger.Status.PlugStatusData.PlugState.Content == "connected" {
|
||||
status = api.StatusB
|
||||
}
|
||||
if res.Charger.Status.ChargingStatusData.ChargingState.Content == "charging" {
|
||||
status = api.StatusC
|
||||
}
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
// FinishTime implements the Vehicle.ChargeFinishTimer interface
|
||||
func (v *Provider) FinishTime() (time.Time, error) {
|
||||
res, err := v.chargerG()
|
||||
|
|
@ -57,23 +74,6 @@ func (v *Provider) FinishTime() (time.Time, error) {
|
|||
return time.Time{}, err
|
||||
}
|
||||
|
||||
// Status implements the Vehicle.Status interface
|
||||
func (v *Provider) Status() (api.ChargeStatus, error) {
|
||||
status := api.StatusA // disconnected
|
||||
|
||||
res, err := v.chargerG()
|
||||
if res, ok := res.(ChargerResponse); err == nil && ok {
|
||||
if res.Charger.Status.PlugStatusData.PlugState.Content == "connected" {
|
||||
status = api.StatusB
|
||||
}
|
||||
if res.Charger.Status.ChargingStatusData.ChargingState.Content == "charging" {
|
||||
status = api.StatusC
|
||||
}
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
|
||||
// Range implements the Vehicle.Range interface
|
||||
func (v *Provider) Range() (rng int64, err error) {
|
||||
res, err := v.chargerG()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue