Skip to content

Commit

Permalink
Refactor status api
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Sep 7, 2021
1 parent 6f483cb commit 274896d
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 42 deletions.
8 changes: 4 additions & 4 deletions vehicle/audi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import (

"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/vehicle/vw"
"golang.org/x/oauth2"
)

// DefaultBaseURI is the Audi api base URI
const DefaultBaseURI = "https://msg.audi.de/fs-car"

const StatusOdometer = "0x0101010002"

// API is the VW api client
type API struct {
*request.Helper
Expand Down Expand Up @@ -55,10 +54,11 @@ func (v *API) getJSON(uri string, res interface{}) error {
}

// Status returns the /vehicles/<vin>/status response
func (v *API) Status(vin string) (StatusResponse, error) {
var res StatusResponse
func (v *API) Status(vin string) (vw.StatusResponse, error) {
var res vw.StatusResponse

uri := fmt.Sprintf("%s/bs/vsr/v1/Audi/DE/vehicles/%s/status", DefaultBaseURI, vin)
// uri := fmt.Sprintf("https://mal-3a.prd.eu.dp.vwg-connect.com/api/bs/vsr/v1/vehicles/%s/status", vin)
err := v.getJSON(uri, &res)

if err != nil && res.Error.ErrorCode != "" {
Expand Down
5 changes: 3 additions & 2 deletions vehicle/audi/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/provider"
"github.com/evcc-io/evcc/vehicle/vw"
)

// Provider implements the evcc vehicle api
Expand All @@ -28,8 +29,8 @@ var _ api.VehicleOdometer = (*Provider)(nil)
// Odometer implements the api.VehicleOdometer interface
func (v *Provider) Odometer() (float64, error) {
res, err := v.statusG()
if res, ok := res.(StatusResponse); err == nil && ok {
fd := res.ServiceByID(StatusOdometer).FieldByID(StatusOdometer)
if res, ok := res.(vw.StatusResponse); err == nil && ok {
fd := res.ServiceByID(vw.ServiceOdometer).FieldByID(vw.ServiceOdometer)
if fd != nil {
return strconv.ParseFloat(fd.Value, 64)
}
Expand Down
File renamed without changes.
56 changes: 48 additions & 8 deletions vehicle/vw/api.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package vw

import (
"encoding/json"
"fmt"
"net/http"
"strings"
Expand All @@ -22,6 +21,7 @@ type API struct {
*request.Helper
brand, country string
baseURI string
statusURI string
}

// NewAPI creates a new api client
Expand All @@ -41,8 +41,13 @@ func NewAPI(log *util.Logger, identity oauth2.TokenSource, brand, country string
return v
}

func (v *API) getJSON(uri string, res interface{}) error {
req, err := request.New(http.MethodGet, uri, nil, request.AcceptJSON)
func (v *API) getJSON(uri string, res interface{}, headers ...map[string]string) error {
header := request.AcceptJSON
if len(headers) == 1 {
header = headers[0]
}

req, err := request.New(http.MethodGet, uri, nil, header)

if err == nil {
err = v.DoJSON(req, &res)
Expand Down Expand Up @@ -73,6 +78,15 @@ func (v *API) HomeRegion(vin string) error {
}
}

_, _ = v.Status(vin, map[string]string{
"Accept": request.JSONContent,
"X-App-Name": "myAudi",
"X-Country-Id": "DE",
"X-Language-Id": "de",
"X-App-Version": "3.22.0",
})
panic(1)

return err
}

Expand All @@ -85,11 +99,37 @@ func (v *API) RolesRights(vin string) (RolesRights, error) {
}

// Status implements the /status response
func (v *API) Status(vin string) (string, error) {
var res json.RawMessage
uri := fmt.Sprintf("%s/bs/vsr/v1/vehicles/%s", RegionAPI, vin)
err := v.getJSON(uri, &res)
return string(res), err
func (v *API) Status(vin string, headers map[string]string) (StatusResponse, error) {
var res StatusResponse
uri := fmt.Sprintf("%s/bs/vsr/v1/vehicles/%s/status", RegionAPI, vin)
err := v.getJSON(uri, &res, headers)

if _, ok := err.(request.StatusError); ok {
var rr RolesRights
rr, err = v.RolesRights(vin)

var si *ServiceInfo
if err == nil {
if si = rr.ServiceByID(StatusService); si == nil {
err = fmt.Errorf("%s not found", StatusService)
}
}

if err == nil {
uri := si.InvocationUrl.Content
uri = strings.ReplaceAll(uri, "{vin}", vin)
uri = strings.ReplaceAll(uri, "{brand}", v.brand)
uri = strings.ReplaceAll(uri, "{country}", v.country)

if strings.HasSuffix(uri, fmt.Sprintf("%s/", vin)) {
uri += "status"
}

err = v.getJSON(uri, &res, headers)
}
}

return res, err
}

// Charger implements the /charger response
Expand Down
2 changes: 1 addition & 1 deletion vehicle/vw/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (v *Provider) StopCharge() error {
// var _ api.Diagnosis = (*Provider)(nil)

// Diagnose implements the api.Diagnosis interface
func (v *Provider) Diagnose2() {
func (v *Provider) Diagnose() {
rr, err := v.rr()
if err != nil {
return
Expand Down
27 changes: 0 additions & 27 deletions vehicle/vw/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,3 @@ type ClimaterResponse struct {
}
}
}

// RolesRights is the /rolesrights/operationlist response
type RolesRights struct {
OperationList struct {
VIN, UserId, Role, Status string
ServiceInfo []ServiceInfo
}
}

// ServiceInfo is the rolesrights service information
type ServiceInfo struct {
ServiceId string
ServiceType string
ServiceStatus struct {
Status string
}
LicenseRequired bool
CumulatedLicense map[string]interface{}
PrimaryUserRequired bool
TermsAndConditionsRequired bool
ServiceEol string
RolesAndRightsRequired bool
InvocationUrl struct {
Content string
}
Operation []map[string]interface{}
}
39 changes: 39 additions & 0 deletions vehicle/vw/types_rolesrights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package vw

const StatusService = "statusreport_v1"

// RolesRights is the /rolesrights/operationlist response
type RolesRights struct {
OperationList struct {
VIN, UserId, Role, Status string
ServiceInfo []ServiceInfo
}
}

func (rr RolesRights) ServiceByID(id string) *ServiceInfo {
for _, s := range rr.OperationList.ServiceInfo {
if s.ServiceId == id {
return &s
}
}
return nil
}

// ServiceInfo is the rolesrights service information
type ServiceInfo struct {
ServiceId string
ServiceType string
ServiceStatus struct {
Status string
}
LicenseRequired bool
CumulatedLicense map[string]interface{}
PrimaryUserRequired bool
TermsAndConditionsRequired bool
ServiceEol string
RolesAndRightsRequired bool
InvocationUrl struct {
Content string
}
Operation []map[string]interface{}
}
58 changes: 58 additions & 0 deletions vehicle/vw/types_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package vw

const ServiceOdometer = "0x0101010002"

type StatusResponse struct {
StoredVehicleDataResponse struct {
VIN string
VehicleData struct {
Data []ServiceDefinition
}
}
Error Error
}

type Error struct {
ErrorCode string
Description string
}

func (s *StatusResponse) ServiceByID(id string) *ServiceDefinition {
for _, d := range s.StoredVehicleDataResponse.VehicleData.Data {
if d.ID == id {
return &d
}
}

return nil
}

type ServiceDefinition struct {
ID string
Field []FieldDefinition
}

func (s *ServiceDefinition) FieldByID(id string) *FieldDefinition {
if s == nil {
return nil
}

for _, f := range s.Field {
if f.ID == id {
return &f
}
}

return nil
}

type FieldDefinition struct {
ID string // "0x0101010001",
TsCarSentUtc string // "2021-09-05T07:54:20Z",
TsCarSent string // "2021-09-05T07:54:19",
TsCarCaptured string // "2021-09-05T07:54:19",
TsTssReceivedUtc string // "2021-09-05T07:54:23Z",
MilCarCaptured int // 25009,
MilCarSent int // 25009,
Value string // "echo"
}

0 comments on commit 274896d

Please sign in to comment.