diff --git a/api/api.go b/api/api.go index 88db66e75..be19c58ca 100644 --- a/api/api.go +++ b/api/api.go @@ -107,6 +107,11 @@ type VehicleRange interface { Range() (int64, error) } +// VehicleStartCharge starts the charging session on the vehicle side +type VehicleStartCharge interface { + StartCharge() error +} + // Climater provides climatisation data type Climater interface { Climater() (active bool, outsideTemp float64, targetTemp float64, err error) diff --git a/core/loadpoint.go b/core/loadpoint.go index 71f9b2f7e..327e1e157 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -469,7 +469,16 @@ func (lp *LoadPoint) setLimit(chargeCurrent float64, force bool) (err error) { if err = lp.charger.Enable(enabled); err == nil { lp.enabled = enabled lp.guardUpdated = lp.clock.Now() + lp.bus.Publish(evChargeCurrent, chargeCurrent) + lp.log.DEBUG.Printf("charger %s", status[enabled]) + + // wake up vehicle + if car, ok := lp.vehicle.(api.VehicleStartCharge); enabled && ok { + if err := car.StartCharge(); err != nil { + lp.log.ERROR.Printf("vehicle remote charge start: %v", err) + } + } } else { lp.log.ERROR.Printf("charger %s: %v", status[enabled], err) } diff --git a/vehicle/id/api.go b/vehicle/id/api.go index 3c79a6e8c..31b5a245f 100644 --- a/vehicle/id/api.go +++ b/vehicle/id/api.go @@ -19,6 +19,18 @@ type API struct { 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{ @@ -148,6 +160,23 @@ func (v *API) Status(vin string) (res Status, err error) { return res, err } +// Action implements vehicle actions +func (v *API) Action(vin, action, value string) error { + uri := fmt.Sprintf("https://mobileapi.apps.emea.vwapps.io/vehicles/%s/%s/%s", 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") { diff --git a/vehicle/id/provider.go b/vehicle/id/provider.go index d8242ffc9..4ab75af1a 100644 --- a/vehicle/id/provider.go +++ b/vehicle/id/provider.go @@ -10,7 +10,8 @@ import ( // Provider is an api.Vehicle implementation for VW ID cars type Provider struct { - statusG func() (interface{}, error) + statusG func() (interface{}, error) + startChargeAction func() error } // NewProvider creates a new vehicle @@ -19,6 +20,9 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider { statusG: provider.NewCached(func() (interface{}, error) { return api.Status(vin) }, cache).InterfaceGetter(), + startChargeAction: func() error { + return api.Action(vin, ActionCharge, ActionChargeStart) + }, } return impl } @@ -94,3 +98,8 @@ func (v *Provider) Climater() (active bool, outsideTemp float64, targetTemp floa return active, outsideTemp, targetTemp, err } + +// StartCharge implements the VehicleStartCharge interface +func (v *Provider) StartCharge() error { + return v.startChargeAction() +}