Jaguar/Landrover: add more apis (#2480)

This commit is contained in:
andig 2022-02-03 18:05:15 +01:00 • committed by GitHub
parent dcb6b65002
commit fb75ec8f63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 5 deletions

View file

@ -82,7 +82,7 @@ func NewJLRFromConfig(other map[string]interface{}) (api.Vehicle, error) {
})
if err == nil {
v.Provider = jlr.NewProvider(api, cc.VIN, cc.Cache)
v.Provider = jlr.NewProvider(api, cc.VIN, user.UserId, cc.Cache)
}
return v, err

View file

@ -1,6 +1,7 @@
package jlr
import (
"errors"
"fmt"
"net/http"
"net/url"
@ -33,7 +34,6 @@ func NewAPI(log *util.Logger, device string, ts oauth2.TokenSource) *API {
if err == nil {
for k, v := range map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", token.AccessToken),
"Content-Type": request.JSONContent,
"X-Device-Id": device,
"x-telematicsprogramtype": "jlrpy",
} {
@ -96,3 +96,67 @@ func (v *API) Status(vin string) (StatusResponse, error) {
return status, err
}
// Position returns the vehicle position
func (v *API) Position(vin string) (PositionResponse, error) {
var status PositionResponse
uri := fmt.Sprintf("%s/vehicles/%s/position", IF9_BASE_URL, vin)
req, err := request.New(http.MethodGet, uri, nil, map[string]string{
"Content-Type": "application/json",
})
if err == nil {
err = v.DoJSON(req, &status)
}
return status, err
}
func (v *API) AuthenticateVinService(vin, user, service string) (PinResponse, error) {
pin := vin[len(vin)-4:]
data := map[string]string{
"serviceName": service,
"pin": pin}
uri := fmt.Sprintf("%s/vehicles/%s/users/%s/authenticate", IF9_BASE_URL, vin, user)
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), map[string]string{
"Content-Type": "application/vnd.wirelesscar.ngtp.if9.AuthenticateRequest-v2+json",
})
var res PinResponse
if err == nil {
err = v.DoJSON(req, &res)
}
return res, err
}
func (v *API) ChargeAction(vin, user string, start bool) error {
var data map[string]interface{}
pin, err := v.AuthenticateVinService(vin, user, "CP")
if err == nil {
onoff := map[bool]string{false: "FORCE_OFF", true: "FORCE_ON"}
data = map[string]interface{}{
"token": pin.Token,
"serviceParameters": []KeyValue{{"CHARGE_NOW_SETTING", onoff[start]}},
}
}
uri := fmt.Sprintf("%s/vehicles/%s/chargeProfile", IF9_BASE_URL, vin)
req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), map[string]string{
"Content-Type": "application/vnd.wirelesscar.ngtp.if9.PhevService-v1+json",
"Accept": "application/vnd.wirelesscar.ngtp.if9.ServiceStatus-v5+json",
})
var res ActionResponse
if err == nil {
if err = v.DoJSON(req, &res); err == nil && res.FailureDescription != "" {
err = errors.New(res.FailureDescription)
}
}
return err
}

View file

@ -8,14 +8,22 @@ import (
)
type Provider struct {
statusG func() (interface{}, error)
statusG func() (interface{}, error)
positionG func() (interface{}, error)
actionS func(bool) error
}
func NewProvider(api *API, vin string, cache time.Duration) *Provider {
func NewProvider(api *API, vin, user string, cache time.Duration) *Provider {
impl := &Provider{
statusG: provider.NewCached(func() (interface{}, error) {
return api.Status(vin)
}, cache).InterfaceGetter(),
positionG: provider.NewCached(func() (interface{}, error) {
return api.Position(vin)
}, cache).InterfaceGetter(),
actionS: func(start bool) error {
return api.ChargeAction(vin, user, start)
},
}
return impl
@ -95,3 +103,29 @@ func (v *Provider) Odometer() (float64, error) {
return val / 1e3, err
}
var _ api.VehiclePosition = (*Provider)(nil)
// Position implements the api.VehiclePosition interface
func (v *Provider) Position() (float64, float64, error) {
res, err := v.positionG()
if res, ok := res.(PositionResponse); err == nil && ok {
return res.Position.Latitude, res.Position.Longitude, nil
}
return 0, 0, err
}
var _ api.VehicleStartCharge = (*Provider)(nil)
// StartCharge implements the api.VehicleStartCharge interface
func (v *Provider) StartCharge() error {
return v.actionS(true)
}
var _ api.VehicleStopCharge = (*Provider)(nil)
// StopCharge implements the api.VehicleStopCharge interface
func (v *Provider) StopCharge() error {
return v.actionS(false)
}

View file

@ -29,7 +29,8 @@ type VehiclesResponse struct {
}
type KeyValue struct {
Key, Value string
Key string `json:"key"`
Value string `json:"value"`
}
type KeyValueList []KeyValue
@ -41,6 +42,25 @@ type StatusResponse struct {
}
}
type PositionResponse struct {
Position struct {
Latitude float64
Longitude float64
Timestamp string
Speed float64
Heading float64
PositionQuality interface{}
}
}
type PinResponse struct {
Token string
}
type ActionResponse struct {
FailureDescription string
}
func (l KeyValueList) StringVal(key string) (string, error) {
for _, el := range l {
if el.Key == key {