Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Dec 17, 2023
1 parent a35f950 commit 1113b10
Show file tree
Hide file tree
Showing 5 changed files with 430 additions and 84 deletions.
86 changes: 59 additions & 27 deletions vehicle/polestar/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ package polestar

import (
"context"
"fmt"
"net/http"

"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/evcc-io/evcc/util/transport"
"github.com/samber/lo"
"github.com/shurcooL/graphql"
"golang.org/x/oauth2"
)

// https://github.com/TA2k/ioBroker.polestar

const ApiURI = "https://pc-api.polestar.com/eu-north-1/mesh/"
const ApiURI = "https://pc-api.polestar.com/eu-north-1/mesh"

type API struct {
*request.Helper
client *graphql.Client
}

Expand All @@ -35,53 +38,82 @@ func NewAPI(log *util.Logger, identity oauth2.TokenSource) *API {
}

v := &API{
Helper: request.NewHelper(log),
client: graphql.NewClient(ApiURI, httpClient),
}

v.Client.Transport = httpClient.Transport

return v
}

func (v *API) Vehicles(ctx context.Context) ([]string, error) {
type vehicle struct {
VIN, Type, Nickname string
}

var res struct {
GetConsumerInformation struct {
MyStar struct {
Type string `graphql:"__typename"`
GetConsumer struct {
Type string `graphql:"__typename"`
MyStarConsumerDetails string `graphql:"... MyStarConsumerDetails"`
} `graphql:"getConsumer"`
} `graphql:"myStar"`
} `graphql:"GetConsumerInformation"`
MyStar struct {
// Type string `graphql:"__typename"`
GetConsumer Consumer
GetConsumerCars []ConsumerCar
}
}

var vins []string
err := v.client.Query(ctx, &res, nil)
// if err == nil {
// vins = lo.Map(res.UserVehicles, func(v vehicle, _ int) string {
// return v.VIN
// })
// }
if err == nil {
vins = lo.Map(res.MyStar.GetConsumerCars, func(v ConsumerCar, _ int) string {
return v.Vin
})
}

v.Status(ctx, vins[0])

return vins, err
}

// func (v *API) Status(vin string) (StatusResponse, error) {
// var res StatusResponse
type VehicleInformation struct {
VdmsExtendedCarDetails `graphql:"... on VehicleInformation"`
}

// uri := fmt.Sprintf("%s/vehicles/%s/init-data?requestedData=BOTH&countryCode=DE&locale=de-DE", ApiURI, vin)
// err := v.GetJSON(uri, &res)
type VdmsExtendedCarDetails struct {
Type string `graphql:"__typename"`
}

// if err != nil && res.Error != "" {
// err = fmt.Errorf("%s (%s): %w", res.Error, res.ErrorDescription, err)
// {
// "query": "query($locale:String!$vin:String!){
// vdms{
// vehicleInformation(vin: $vin, locale: $locale){
// ... on VehicleInformation{
// __typename
// }
// }
// }
// }",
// "variables": {
// "locale": "de_DE",
// "vin": "LPSVSEDEEML002398"
// }

// return res, err
// }

func (v *API) Status(ctx context.Context, vin string) error {
// var res struct {
// // GetVDMSCarDetails struct {
// Vdms struct {
// VehicleInformation `graphql:"vehicleInformation(vin: $vin, locale: $locale)"`
// } //`graphql:"GetVDMSCarDetails($vin: String!, $locale: String!)"`
// // }
// }

// err := v.client.Query(ctx, &res, map[string]interface{}{
// "vin": graphql.String(vin),
// "locale": graphql.String("de_DE"),
// })
// if err == nil {

// }

err := v.GetJSON(fmt.Sprintf("%s/status/%s", ApiURI, vin), nil)
return err
}

// func (v *API) Refresh(vin string) (StatusResponse, error) {
// var res StatusResponse

Expand Down
8 changes: 4 additions & 4 deletions vehicle/polestar/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
// https://github.com/TA2k/ioBroker.polestar

type Provider struct {
statusG func() (StatusResponse, error)
expiry time.Duration
// statusG func() (StatusResponse, error)
expiry time.Duration
}

func NewProvider(log *util.Logger, api *API, vin string, expiry, cache time.Duration) *Provider {
Expand All @@ -36,8 +36,8 @@ func NewProvider(log *util.Logger, api *API, vin string, expiry, cache time.Dura

// SoC implements the api.Vehicle interface
func (v *Provider) SoC() (float64, error) {
res, err := v.statusG()
return res.Status.Data.Soc.Value, err
// res, err := v.statusG()
return 0, nil
}

// var _ api.ChargeState = (*Provider)(nil)
Expand Down
100 changes: 100 additions & 0 deletions vehicle/polestar/query.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
query GetConsumerInformation {
myStar {
__typename
getConsumer {
__typename
...MyStarConsumerDetails
}
getOrders {
__typename
...MyStarOrderDetails
}
getConsumerCars {
__typename
...MyStarCarDetails
}
}
}
fragment MyStarConsumerDetails on MyStarConsumer {
__typename
birthdate
city
country
countryCode
email
firstName
lastName
mobilePhone
salesforceId
streetAddress
zipCode
additionalCustomerIds {
__typename
code
id
}
}
fragment MyStarOrderDetails on MyStarOrder {
__typename
type
address
city
configurationId
consumerId
country
countryCode
deposit
district
downPayment
externalOrderId
orderId
orderState
packageId
placedAt
province
redirectUrl
totalPrice
zipCode
car {
__typename
...MyStarCarDetails
}
items {
__typename
...MyStarOrderItemDetails
}
}
fragment MyStarCarDetails on MyStarCar {
__typename
id
consumerId
engine
exterior
exteriorCode
exteriorImageUrl
gearbox
interior
interiorCode
interiorImageUrl
model
modelYear
package
packageCode
pdfUrl
status
steering
vin
wheels
wheelsCode
}
fragment MyStarOrderItemDetails on MyStarOrderItem {
__typename
id
currency
deposit
downPayment
price
quantity
title
type
}
85 changes: 32 additions & 53 deletions vehicle/polestar/types.go
Original file line number Diff line number Diff line change
@@ -1,62 +1,41 @@
package polestar

import (
"strconv"
"time"
)

type StatusResponse struct {
PreCond struct {
Data struct {
ChargingPower FloatValue
ChargingActive BoolValue
ChargingStatus IntValue
} `json:"data"`
}
ChargeOpt struct{}
Status struct {
Data struct {
Odo FloatValue
RangeElectric FloatValue
Soc FloatValue
} `json:"data"`
}
Images []string
Error string
ErrorDescription string `json:"error_description"`
}

type BoolValue struct {
Status int
Value bool
Ts TimeSecs
type Consumer struct {
// Type string `graphql:"__typename"`
MyStarConsumerDetails `graphql:"... on MyStarConsumer"`
}

type IntValue struct {
Status int
Value int
Ts TimeSecs
type MyStarConsumerDetails struct {
// Type string `graphql:"__typename"`
Email string
FirstName string
LastName string
}

type FloatValue struct {
Status int
Value float64
Ts TimeSecs
type ConsumerCar struct {
// Type string `graphql:"__typename"`
MyStarCarDetails `graphql:"... on MyStarCar"`
}

// TimeSecs implements JSON unmarshal for Unix timestamps in seconds
type TimeSecs struct {
time.Time
}

// UnmarshalJSON decodes unix timestamps in ms into time.Time
func (ct *TimeSecs) UnmarshalJSON(data []byte) error {
i, err := strconv.ParseInt(string(data), 10, 64)

if err == nil {
t := time.Unix(i, 0)
(*ct).Time = t
}

return err
type MyStarCarDetails struct {
Id int
// ConsumerId string
// Engine string
// Exterior string
// ExteriorCode string
// ExteriorImageUrl string
// Gearbox string
// Interior string
// InteriorCode string
// InteriorImageUrl string
Model string
ModelYear int
// Package string
// PackageCode string
// PdfUrl string
// Status string
// Steering string
Vin string
// Wheels string
// WheelsCode string
}
Loading

0 comments on commit 1113b10

Please sign in to comment.