leeyuentuen / polestar_api

Polestar Api - Home Assistant Component
MIT License
131 stars 23 forks source link

IMPORTANT! Volvo Energy API is down #10

Closed leeyuentuen closed 9 months ago

leeyuentuen commented 10 months ago

Seems volvo block this way?

i did a call on https://developer.volvocars.com/apis/energy/v1/specification/ and seems it got a 404 back for the call.

image

leeyuentuen commented 10 months ago

seems api.volvocars.com is down atm

{ "statusCode": 404, "message": "Resource not found" }

ClementBuurman commented 10 months ago

Just when I wanted to start to checkout this API 🤣 : image

leeyuentuen commented 10 months ago

ow nice! didn't saw that bar xD

leeyuentuen commented 10 months ago

API Down status 😂 image

ccantill commented 10 months ago

Well... the bar is gone but it's still not working with my PS2 VIN. I guess they patched the hole 🙈 Kinda regret posting about the API on the forum now 😆

leeyuentuen commented 10 months ago

I suppose they check that the VIN belongs to one of the accounts. but I don't see any way to link a non-volvo Vin to a Volvo account. Yesterday I also sent a mail to polestar developer. let's see if they want to reply on my mail

leeyuentuen commented 10 months ago

the only thing that i see what we can do is finding documentation about this URL:

https://pc-api.polestar.com/eu-north-1/mesh/

that URL is normally used on the polestar app (after reverse engineering)

jbereuter commented 10 months ago

that URL is normally used on the polestar app (after reverse engineering)

i know, thats not part of this discussion - but did you manage to get around the cert pinning of the app?

leeyuentuen commented 10 months ago

not from the app, but somewhere else i found a the cert.. i'm try now to check if i can connect on it.

leeyuentuen commented 10 months ago

so far what i got

it uwe graphql i got the url where we api call will be done https://pc-api.polestar.com/eu-north-1/mesh/

content should be Query, but what the graphql should be is now guessing cars and spaces are already valid keywords , but there are subfields

image

jyrkih commented 10 months ago

Do you get anything with query

query Cars {
  cars {
    carModels {
      id
    }
  }
}

this should be valid full query, but I get invalid JSON error, which may be authorization or some other issue

query CarModels {
  cars {
    __typename
    carModels {
      __typename
      ...CarModelDetails
    }
  }
}
fragment CarModelDetails on CarModel {
  __typename
  id
  title
  tagline
  headerImageInEnvironmentAsset {
    __typename
    url
  }
  defaultConfiguration {
    __typename
    ...CarConfigurationDetails
  }
  themes {
    __typename
    ...CarConfigurationDetails
  }
}
fragment CarConfigurationDetails on CarConfiguration {
  __typename
  id
  imageAsset {
    __typename
    url
  }
  gallery {
    __typename
    url
  }
  title
  subTitle
  body
  isBaseModel
  configuratorUrl
  visible
  enabled
  configurationCtaText
}
leeyuentuen commented 10 months ago

authentication information from polestar app that i reverse engineered:

client_secret: XaiKooHeireisoosah0Ev6quohs8cohFeKohwie1ae7kiewohdooyei9AeYeiWoh
client_id: polxplore
access_token_manager_id: JWTpolxplore
scope: "openid", "profile", "email", "customer:attributes", "customer:attributes:write"

some data that are useful:

polestar-explore://explore.polestar.com
ITJamie commented 9 months ago

Ive seen the following when pairing the google home app to polestar

Some of these scopes might help

https://polestarid.eu.polestar.com/PolestarLogin/approval?resumePath=<>&cSRFToken=8WG0U7sK9goIkekHytNa&userName=<>@gmail.com&scopes=%5B%22vehicle:unlock%22,%22vehicle:climatization%22,%22vehicle:engine_start%22,%22vehicle:engine%22,%22vehicle:doors_status%22,%22vehicle:lock_status%22,%22vehicle:engine_status%22,%22vehicle:fuel_status%22,%22vehicle:climatization_status%22,%22vehicle:lock%22%5D&client_id=polGoogleAssistantRVA&client_name=Google%20Assistant%20for%20Polestar
loebse commented 9 months ago

You can now see SoC and odometer on the polestar website. Maybe this is another option?!

image

dickdahm commented 9 months ago

You can now see SoC and odometer on the polestar website. Maybe this is another option?!

image

URL for this?

BeauGiles commented 9 months ago

Log in and head to the 'Cars' page in your profile - https://www.polestar.com/au/login/cars - select your car and it'll be shown there.

On 16 Dec 2023, at 08:37, Peter @.***> wrote:



You can now see SoC and odometer on the polestar website. Maybe this is another option?!

[image]https://private-user-images.githubusercontent.com/39953358/290939283-ff281607-1742-4291-9f9b-0cef0d837d88.jpeg?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTEiLCJleHAiOjE3MDI2NzY0NTcsIm5iZiI6MTcwMjY3NjE1NywicGF0aCI6Ii8zOTk1MzM1OC8yOTA5MzkyODMtZmYyODE2MDctMTc0Mi00MjkxLTlmOWItMGNlZjBkODM3ZDg4LmpwZWc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMxMjE1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMTIxNVQyMTM1NTdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT03OGIwN2FiZTI1YzhjNzIxYWY0NjEwOTVkYjlkNjI0OGMzYTdkNzg0MmNlMzE2MzE0ZmI4YTJhMDk5MGRkNjk2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZhY3Rvcl9pZD0wJmtleV9pZD0wJnJlcG9faWQ9MCJ9.MPibk3-LX12cAvOrez46MgxMYZLq56q9A56F_eQK5Qk

URL for this?

— Reply to this email directly, view it on GitHubhttps://github.com/leeyuentuen/polestar_api/issues/10#issuecomment-1858518199, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AABTXMOUODN4KG7RC6YYBRTYJS7I3AVCNFSM6AAAAAA7TCO35KVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNJYGUYTQMJZHE. You are receiving this because you are subscribed to this thread.Message ID: @.***>

BeauGiles commented 9 months ago

Log in at https://www.polestar.com/au/auth/login?to=/au/login/profile

Head to 'Cars' tab - https://www.polestar.com/au/login/cars

Select your car - https://www.polestar.com/au/login/explore-car/***UUID***

Screenshot 2023-12-16 at 09 48 17

Page makes a bunch of API calls;

Battery - https://pc-api.polestar.com/eu-north-1/my-star/?query=query%20GetBatteryData(%24vin%3A%20String!)%20%7B%0A%20%20getBatteryData(vin%3A%20%24vin)%20%7B%0A%20%20%20%20averageEnergyConsumptionKwhPer100Km%0A%20%20%20%20batteryChargeLevelPercentage%0A%20%20%20%20chargerConnectionStatus%0A%20%20%20%20chargingCurrentAmps%0A%20%20%20%20chargingPowerWatts%0A%20%20%20%20chargingStatus%0A%20%20%20%20estimatedChargingTimeMinutesToTargetDistance%0A%20%20%20%20estimatedChargingTimeToFullMinutes%0A%20%20%20%20estimatedDistanceToEmptyKm%0A%20%20%20%20estimatedDistanceToEmptyMiles%0A%20%20%20%20eventUpdatedTimestamp%20%7B%0A%20%20%20%20%20%20iso%0A%20%20%20%20%20%20unix%0A%20%20%20%20%20%20__typename%0A%20%20%20%20%7D%0A%20%20%20%20__typename%0A%20%20%7D%0A%7D&operationName=GetBatteryData&variables=%7B%22vin%22%3A%22****VIN*****%22%7D

Odometer - https://pc-api.polestar.com/eu-north-1/my-star/?query=query%20GetOdometerData(%24vin%3A%20String!)%20%7B%0A%20%20getOdometerData(vin%3A%20%24vin)%20%7B%0A%20%20%20%20averageSpeedKmPerHour%0A%20%20%20%20eventUpdatedTimestamp%20%7B%0A%20%20%20%20%20%20iso%0A%20%20%20%20%20%20unix%0A%20%20%20%20%20%20__typename%0A%20%20%20%20%7D%0A%20%20%20%20odometerMeters%0A%20%20%20%20tripMeterAutomaticKm%0A%20%20%20%20tripMeterManualKm%0A%20%20%20%20__typename%0A%20%20%7D%0A%7D&operationName=GetOdometerData&variables=%7B%22vin%22%3A%22****VIN*****%22%7D

Example of the battery query result


    "data": {
        "getBatteryData": {
            "averageEnergyConsumptionKwhPer100Km": 16,
            "batteryChargeLevelPercentage": 90,
            "chargerConnectionStatus": "CHARGER_CONNECTION_STATUS_DISCONNECTED",
            "chargingCurrentAmps": null,
            "chargingPowerWatts": null,
            "chargingStatus": "CHARGING_STATUS_IDLE",
            "estimatedChargingTimeMinutesToTargetDistance": null,
            "estimatedChargingTimeToFullMinutes": 0,
            "estimatedDistanceToEmptyKm": 340,
            "estimatedDistanceToEmptyMiles": 210,
            "eventUpdatedTimestamp": {
                "iso": "2023-12-15T22:32:14.000Z",
                "unix": "1702679534",
                "__typename": "EventUpdatedTimestamp"
            },
            "__typename": "Battery"
        }
    }
}
leeyuentuen commented 9 months ago

nice, maybe need to investigate

jyrkih commented 9 months ago

good catch! This query seems to return SOC just fine from https://pc-api.polestar.com/eu-north-1/my-star/

query GetBatteryData($vin: String!) {
  getBatteryData(vin: $vin) {
    averageEnergyConsumptionKwhPer100Km
    batteryChargeLevelPercentage
    chargerConnectionStatus
    chargingCurrentAmps
    chargingPowerWatts
    chargingStatus
    estimatedChargingTimeMinutesToTargetDistance
    estimatedChargingTimeToFullMinutes
    estimatedDistanceToEmptyKm
    estimatedDistanceToEmptyMiles
    eventUpdatedTimestamp {
      iso
      unix
      __typename
    }
    __typename
  }
}

with variables

{
  "vin": "XXXX"
}

All it needs is Authorization header with Bearer token

leeyuentuen commented 9 months ago

the whole graphql schema:

type Acceleration {
  value: Float!
  unit: String!
  description: String!
}

type AcceptedHandoverTime {
  start: String
  end: String
  timezone: String
}

type AdditionalCustomerId {
  id: String
  code: String
}

type App {
  name: String
  host(tld: String): String
  patterns: [String]
  environment: String
  domain: String
}

input Attachment {
  name: String
  body: String
}

input Attachments {
  name: String
  body: String
}

type AuthTokens {
  access_token: String
  refresh_token: String
  id_token: String
  expires_in: Int
}

type Battery {
  averageEnergyConsumptionKwhPer100Km: Float
  batteryChargeLevelPercentage: Float
  chargerConnectionStatus: String
  chargingCurrentAmps: Int
  chargingPowerWatts: Int
  chargingStatus: String
  estimatedChargingTimeMinutesToTargetDistance: Int
  estimatedChargingTimeToFullMinutes: Int
  estimatedDistanceToEmptyKm: Int
  estimatedDistanceToEmptyMiles: Int
  eventUpdatedTimestamp: EventUpdatedTimestamp
}

type BrandStatus {
  code: String
  timestamp: String
  description: String
}

input CancellationCase {
  caseId: String!
  caseNumber: String!
  paymentMethod: PaymentMethod!
  bankName: String
  bankAccountHolder: String
  bankAccountNumber: String
  bankSortCode: String
  iban: String
  bic: String
  attachment: [Attachment]
  returnReason: String
  currentOdometerReading: Int
  returnOdometerReading: Int
  returnLocation: String
  returnTimeSlots: String
  extrasOrdered: String
  damagedCar: Boolean
  otherInformation: String
}

type Car {
  id: Int @deprecated(reason: "id is deprecated. Use vin instead.")
  vin: String
  model: String
  modelYear: String
  modelCode: String
  package: String
  exteriorImageUrl: String
  imageAngles: [String!]
}

type CarImage {
  imageUrl: String
}

type CarImages {
  studio: VDMSImage
  location: VDMSImage
  interior: VDMSImage
}

type CarInformation {
  id: Int
  consumerId: String
  status: String
  orderStatus: String
  vin: String
}

enum CaseRecordType {
  CUSTOMERSUPPORT
  DAMAGEREPAIR
  SALESTOORDER
  SERVICEORDER
}

type Claim {
  type: String
  validFromDate: String
  validUntilDate: String
  validUntilMileage: String
  performedJobs: [PerformedClaimJob]
}

type ClaimOperation {
  code: String
}

type ClaimPart {
  code: String
}

type CommonStatusPoint {
  code: Int
  timestamp: String
  description: String
}

type Consent {
  termsAndConditionVersion: String
  consent: Boolean!
}

type Consumer {
  salesforceId: String
  firstName: String
  lastName: String
  email: String
  birthdate: String
  mobilePhone: String
  language: String
  preferredLanguage: String
  countryCode: String
  country: String
  city: String
  zipCode: String
  streetAddress: String
  state: String
  additionalCustomerIds: [AdditionalCustomerId]
  hasOptedOutOfEmail: Boolean
  optInDate: String
  optOutDate: String
  customerType: String
  username: String
  gtmId: String
  isPolestarOrVolvoEmployee: Boolean
  linkToken: String
}

type ConsumerUpdateResponse {
  salesforceId: String
  error: String
  message: String
}

type Content {
  exterior: Property
  exteriorDetails: Property
  interior: Property
  performancePackage: Property
  performanceOptimizationSpecification: performanceOptimizationSpecification
  wheels: Property
  plusPackage: Property
  pilotPackage: Property
  motor: Property
  model: Model
  images: CarImages
  specification: Specification
  dimensions: Dimensions
  towbar: Property
}

enum ContentDisposition {
  Attachment
  Inline
  Formdata
  Signal
}

enum CountryFilter {
  Alltime
  Year
}

type CountryLeaderboard {
  scores: [LeaderboardCountry]!
  country: LeaderboardCountry
}

type CreateCaseResponse {
  message: String
  error: String
}

type CreateFleetResponse {
  message: String
  error: String
}

type CreateLeadResponse {
  message: String
  error: String
}

type Dimensions {
  wheelbase: ValueLabel
  groundClearanceWithPerformance: ValueLabel
  groundClearanceWithoutPerformance: ValueLabel
  dimensions: ValueLabel
}

type DocumentData {
  documentType: String
  subType: String
  documentId: String
  dateCreated: String
  size: Int
  contentType: String
}

type DocumentDataV2 {
  documentId: String
  link: String
  name: String
  expirationDate: String
  documentType: String
  dateCreated: String
  version: String
  contentType: String
  extension: String
  subType: String
  size: Int
  linkedEntity: LinkedEntity
}

type DocumentMetadata {
  link: String
}

enum DocumentSearchType {
  VIN
}

enum DocumentSearchTypeV2 {
  Vin
  PolestarId
  PomsId
}

type ElectricalEngineNumber {
  number: String!
  placement: String!
}

type Energy {
  elecRange: String
  elecRangeUnit: String
  elecEnergyConsumption: String
  elecEnergyUnit: String
  weightedCombinedCO2: String
  weightedCombinedCO2Unit: String
  weightedCombinedFuelConsumption: String
  weightedCombinedFuelConsumptionUnit: String
}

type Event {
  name: String
  date: String
  location: String
  text: String
  image: Image
  times: String
  link: String
}

type EventUpdatedTimestamp {
  iso: String
  unix: String
}

type Extras {
  id: Int
  articleNumber: String
  title: String
  description: String
  sortorder: Int
  requires: [ItemOption]
  incompatible: [ItemOption]
}

type FeatureImage {
  url: String!
  alt: String
}

type FeatureProperty {
  type: String!
  code: String!
  name: String
  description: String
  excluded: Boolean
  galleryImage: [FeatureImage]!
  thumbnail: FeatureImage
}

input FleetCase {
  country: String
  subject: String!
  description: String
  caseType: String
  caseSubType: String
  caseStatus: String
  externalFspId: String
  model: String
  attachment: [Attachments]
}

type GetCartResult {
  Item: OutputCart
}

input GetDocumentMetadataRequest {
  id: String!
  contentDisposition: ContentDisposition
  downloadFileName: String
}

type HandoverBooking {
  acceptedHandoverTime: AcceptedHandoverTime
}

type Hardware {
  nodeAddress: String!
  partNo: String
  description: HardwareDescription
  software: [Software]
}

type HardwareDescription {
  text: String
  short: String
}

type Image {
  alt: String
  url: String
}

input InputCart {
  cart: [InputCartItem]!
  finance: InputFinance!
  itemsCount: Int!
  consumer: InputCartConsumer!
  orderStatus: Int!
  market: InputMarket!
  deliveryMethod: String!
  connectId: String
  transactions: [InputTransaction]
}

input InputCartConsumer {
  firstName: String
  lastName: String
  email: String
  mobilePhone: String
  birthdate: String
  language: String
  streetAddress: String
  zipCode: String
  city: String
  country: String
  countryCode: String
  companyName: String
  vatNo: String
  orgNo: String
  careOf: String
  customerType: String
}

input InputCartItem {
  id: Int
  title: String
  description: String
  featuredImageUrl: String
  marketPrice: Float
  marketVat: Float
  quantity: Int
  maxQuantity: Int
  minQuantity: Int
  extras: [InputExtras]
  currency: String
}

input InputExtras {
  id: Int
  articleNumber: String
  title: String
  description: String
  sortorder: Int
  requires: [InputItemOption]
  incompatible: [InputItemOption]
}

input InputFinance {
  totalPrice: Float!
  totalVat: Float!
  currency: String
}

input InputItemOption {
  type: String
  code: String
}

input InputMarket {
  country: String
  language: String
}

input InputTransaction {
  createdAt: String
  id: String
  transactionStatus: Int
}

type InternalCar {
  origin: String!
  registeredAt: String!
}

type IntrospectResponse {
  active: Boolean
}

type ItemOption {
  type: String
  code: String
}

type LatestClaimStatus {
  mileage: String
  mileageUnit: String
  registeredDate: String
  vehicleAge: String
}

input LeadCase {
  firstName: String
  lastName: String
  email: String
  mobilePhone: String
  source: String
  emailOptOut: Boolean
  doubleOptInDate: String
  newsletterSubscribed: String
  polestarId: String
  market: String
  country: String
  preferredLanguage: String
  consentName: String
  consentType: String
  consentDate: String
  privacyPolicy: String
  campaignSourceCode: String
  role: String
  description: String
  leadRecordType: String
  postalCode: String
  type: String
  leasingCompanyName: String
  companyName: String
  bringAFriend: Int
  clothingSize: String
  foodPreferences: String
  parkingSpotNeeded: Boolean
  rideAlong: Boolean
  ticketNeeded: Boolean
  vehicle: String
  birthday: String
  street: String
  city: String
  state: String
}

type LeaderboardCountry {
  code: String!
  score: Int!
  rank: Int!
  trend: String!
}

type LeaderboardUser {
  displayName: String!
  score: Int!
  rank: Int!
  trend: String!
  psid: String!
  country: String!
  favorite: Boolean
  locatedOnPage: Int
  scoreToMoveUp: Int
}

union LinkedEntity = Car | Order

type LoadResponse {
  returnUrl: String
  orderId: String
  configuration: String
}

type LoginConfig {
  loginUrl: String
  logoutUrl: String
  baseUrl: String
}

type Market {
  locale: String
  marketName: String
  marketType: String
  countryCode: String
  cmsLocale: String
  languageCode: String
  languageName: String
  region: String
  apiRegion: String
  dateFormat: String
  features: [String]
}

type Model {
  name: String
  code: String
}

type Motor {
  description: String
  code: String
}

type Mutation {
  revokeToken(token: String!): TokenRevokeResponse
  setConsent(consent: Boolean!, displayName: String, termsAndConditionVersion: String, market: String!): Boolean
  addFavorite(psid: String!): Boolean
  removeFavorite(psid: String!): Boolean
  saveCart(orderId: String, cart: InputCart!): SaveCartResponse
  updateConsumer(body: MutationableConsumer!): ConsumerUpdateResponse
  createFleetRequest(body: FleetCase!): CreateFleetResponse
  createLeadRequest(body: LeadCase!): CreateLeadResponse
  createCaseRequest(body: SupportCase!): CreateCaseResponse
  createGDPRRequest(body: SupportCase!): CreateCaseResponse
  createCancellationRequest(body: CancellationCase!): CreateCaseResponse
}

input MutationableConsumer {
  firstName: String
  lastName: String
  email: String
  birthdate: String
  mobilePhone: String
  language: String
  countryCode: String
  country: String
  city: String
  zipCode: String
  streetAddress: String
  state: String
  stateCode: String
  hasOptedOutOfEmail: Boolean
}

type Odometer {
  averageSpeedKmPerHour: Int
  eventUpdatedTimestamp: EventUpdatedTimestamp
  odometerMeters: Int
  tripMeterAutomaticKm: Float
  tripMeterManualKm: Float
}

type Operation {
  id: String!
  code: String!
  description: String
  quantity: Float
  performedDate: String!
}

type Order {
  orderId: String
  type: String
  consumerId: Int
  packageId: Int
  configurationId: String
  source: String
  externalOrderId: String
  placedAt: String
  placeAtIso: String
  termsAndConditionsUrl: String
  redirectUrl: String
  totalPrice: Float
  deposit: Float
  depositUsed: Boolean
  orderState: String
  lockState: String
  downPayment: Float
  addressLine1: String
  address: String @deprecated(reason: "Use 'addressLine1'.")
  addressLine2: String
  zipCode: String
  city: String
  district: String
  province: String
  countryCode: String
  country: String
  car: Car
  lines: [OrderItem]
  items: [OrderItem] @deprecated(reason: "Use 'lines'.")
  roles: [String]
  handoverBooking: HandoverBooking
}

type OrderItem {
  id: Int
  title: String
  price: Float
  total: Float
  deposit: Float
  downPayment: Float
  currency: String
  quantity: Int
  type: String
}

enum Origin {
  EMAIL
  PHONE
  WEB
  FACEBOOK
  TWITTER
  CONTACTFORM
}

type OutputCart {
  orderId: String
  cart: [OutputCartItem]
  finance: OutputFinance
  itemsCount: Int
  consumer: OutputCartConsumer
  orderStatus: Int
  market: OutputMarket
  deliveryMethod: String
  connectId: String
  transactions: [OutputTransaction]
}

type OutputCartConsumer {
  firstName: String
  lastName: String
  email: String
  mobilePhone: String
  birthdate: String
  language: String
  streetAddress: String
  zipCode: String
  city: String
  country: String
  countryCode: String
  companyName: String
  vatNo: String
  orgNo: String
  careOf: String
  customerType: String
}

type OutputCartItem {
  id: Int
  title: String
  description: String
  featuredImageUrl: String
  marketPrice: Float
  marketVat: Float
  quantity: Int
  maxQuantity: Int
  minQuantity: Int
  extras: [Extras]
  currency: String
}

type OutputFinance {
  totalPrice: Float!
  totalVat: Float!
  currency: String
}

type OutputMarket {
  country: String
  language: String
}

type OutputTransaction {
  createdAt: String
  id: String
  transactionStatus: Int
}

type Owner {
  id: String!
  registeredAt: String!
  information: OwnerInformation
}

type OwnerInformation {
  polestarId: String
  ownerType: String
}

type Part {
  id: String!
  code: String!
  description: String
  quantity: Float
  performedDate: String!
}

enum PaymentMethod {
  BANKTRANSACTION
  CREDITCARD
  OTHER
}

type PerformanceOptimization {
  value: Boolean!
  description: String
  timestamp: String
}

type performanceOptimizationSpecification {
  power: [Power]
  torqueMax: [TorqueMax]
  acceleration: [Acceleration]
}

type PerformedClaimJob {
  repairDate: String
}

type PerformedClaims {
  claimType: String
  workshopId: String
  market: String
  orderNumber: String
  claimPerformedManually: Boolean
  orderEndDate: String
  mileage: String
  mileageUnit: String
  vehicleAge: String
  symptomCode: String
  parts: [ClaimPart]
  operations: [ClaimOperation]
}

type Power {
  value: Int!
  unit: String!
}

type Property {
  code: String!
  name: String
  description: String
  excluded: Boolean
  galleryImage: [FeatureImage]!
  thumbnail: FeatureImage
}

type Query {
  applications(env: String): [App]
  getApplications(env: String): [App]
  application(name: String!, env: String): App
  getAuthToken(code: String): AuthTokens
  getAuthConfig(market: String): LoginConfig
  refreshAuthToken(token: String!): Token
  getConsumer(id: String): Consumer
  introspectToken(token: String!): IntrospectResponse
  hello(message: String): String
  getUserLeaderboard(market: String!, filter: UserFilter!, limit: Int, skip: Int, name: String, onlyFavorites: Boolean): UserLeaderboard!
  getConsent: Consent
  getCountryLeaderboard(market: String!, filter: CountryFilter!, searchValue: String): CountryLeaderboard!
  getMarkets(marketNames: [String]): [Market]
  markets(marketNames: [String]): [Market]
  market(marketName: String, locale: String, cmsLocale: String): Market
  getBatteryData(vin: String!): Battery
  getOdometerData(vin: String!): Odometer
  getConsumerCars: [Car]!
  getConsumerCarsV2(locale: String): [VehicleInformation!]!
  getConsumerCarsByVin(vin: [String]!): [CarInformation]
  getCart(market: String): GetCartResult
  getConfiguration(orderId: String!): LoadResponse
  getDocumentMetadata(input: GetDocumentMetadataRequest!): DocumentMetadata
  searchDocuments(input: SearchDocumentsRequest!): [DocumentData]
  getEvents: [Event]
  getOrders: [Order]!
  searchDocumentsV2(input: SearchDocumentsRequestV2!): [DocumentDataV2]!
  getUserDocuments: [DocumentDataV2]!
}

type RemoveCartResponse {
  message: String
  error: String
}

type SaveCartResponse {
  orderId: String
  status: Int
  message: String
}

input SearchDocumentsRequest {
  searchVal: String!
  searchType: DocumentSearchType
  documentType: String
}

input SearchDocumentsRequestV2 {
  searchVal: String!
  entityType: DocumentSearchTypeV2!
}

type Software {
  partNo: String!
}

type Specification {
  battery: String
  bodyType: String
  brakes: String
  combustionEngine: String
  electricMotors: String
  performance: String
  suspension: String
  tireSizes: String
  torque: String
  totalHp: String
  totalKw: String
  trunkCapacity: ValueLabel
}

input SupportCase {
  caseRecordType: CaseRecordType
  origin: Origin
  firstName: String
  lastName: String
  email: String
  market: String
  country: String
  preferredLanguage: String
  subject: String
  description: String
  streetAddress: String
  salesforceId: String
  reason: String
  mobilePhone: String
  caseType: String
  caseSubType: String
  additionalCountry: String
  requestSource: String
  region: String
  zipCode: String
  city: String
  privacyPolicy: String
  isEscalated: String
  caseStatus: String
}

type Token {
  access_token: String
  refresh_token: String
  id_token: String
  expires_in: Int
}

type TokenRevokeResponse {
  success: Boolean
}

type TorqueMax {
  value: Int!
  unit: String!
}

type TransactionReponse {
  id: String
  transactionStatus: Int
  createdAt: String
}

enum UserFilter {
  GlobalAlltime
  GlobalYear
  CountryAlltime
  CountryYear
}

type UserLeaderboard {
  top: [LeaderboardUser]!
  before: LeaderboardUser
  user: LeaderboardUser
  after: LeaderboardUser
  totalUsersCount: Int
}

type ValueLabel {
  label: String
  value: String
}

type VDMSImage {
  url: String!
  angles: [String]
  resolutions: [String]
}

type VehicleInformation {
  vin: String!
  internalVehicleIdentifier: String!
  salesType: String
  currentPlannedDeliveryDate: String
  market: String!
  originalMarket: String!
  pno34: String!
  modelYear: String!
  belongsToFleet: Boolean!
  registrationNo: String
  metaOrderNumber: String!
  factoryCompleteDate: String
  registrationDate: String
  deliveryDate: String
  serviceHistory: [WorkOrder]
  content: Content
  primaryDriver: String
  primaryDriverRegistrationTimestamp: String
  owners: [Owner]
  wltpNedcData: WltpNedcData
  energy: Energy
  fuelType: String
  drivetrain: String
  numberOfDoors: Int
  numberOfSeats: Int
  motor: Motor
  maxTrailerWeight: Weight
  curbWeight: Weight
  hasPerformancePackage: Boolean
  numberOfCylinders: Int
  cylinderVolume: Int
  cylinderVolumeUnit: String
  transmission: String
  numberOfGears: Int
  structureWeek: String
  hardware: [Hardware]
  software: VehicleSoftware
  claims: [Claim]
  performedClaims: [PerformedClaims]
  latestClaimStatus: LatestClaimStatus
  internalCar: InternalCar
  edition: String
  commonStatusPoint: CommonStatusPoint
  brandStatus: BrandStatus
  intermediateDestinationCode: String
  partnerDestinationCode: String
  features: [FeatureProperty]
  electricalEngineNumbers: [ElectricalEngineNumber]
}

type VehicleInformationByLocale {
  locale: String!
  result: VehicleInformation
}

type VehiclesInformationByLocale {
  locale: String!
  result: [VehicleInformation]
}

type VehicleSoftware {
  version: String
  versionTimestamp: String
  performanceOptimization: PerformanceOptimization
}

type Weight {
  value: Int
  unit: String
}

type WltpNedcData {
  wltpCO2Unit: String
  wltpElecEnergyConsumption: String
  wltpElecEnergyUnit: String
  wltpElecRange: String
  wltpElecRangeUnit: String
  wltpWeightedCombinedCO2: String
  wltpWeightedCombinedFuelConsumption: String
  wltpWeightedCombinedFuelConsumptionUnit: String
}

type WorkOrder {
  claimType: String
  market: String!
  mileage: String
  mileageUnit: String
  operations: [Operation]
  orderEndDate: String
  orderNumber: String!
  orderStartDate: String!
  parts: [Part]
  status: String!
  statusDMS: String!
  symptomCode: String
  vehicleAge: String
  workshopId: String!
}
leeyuentuen commented 9 months ago

using correct authorization you can get the data, but still finding a way to get this authorization key

image

leeyuentuen commented 9 months ago

good news seems i found a way to fetch the data: image

spockfish commented 9 months ago

Love your work!

jyrkih commented 9 months ago

Looks very promising.

kaohlive commented 9 months ago

So did you solve the authorization challange?

leeyuentuen commented 9 months ago

So did you solve the authorization challange?

yes, found a way to get the access_token

i'll release over few days a dirty alpha version.

leeyuentuen commented 9 months ago

just a quick question, since today, the odo meter became 0, yesterday it was still the KM, can someone else also confirm? image

jbereuter commented 9 months ago

there is no change or reset in my account

ITJamie commented 9 months ago

Shows fine on mine too.

niklasvieth commented 9 months ago

https://github.com/andysmithfal/polestar.js

Checkout this. I tested it, and it works without any client creds and just personal user/pw.

leeyuentuen commented 9 months ago

let's start with a dirty release

there should be some issues, but let's see if it works with the authentication

this are the known issues atm

  • Change readme file
  • cleanup old code
  • current/amps issue
  • trip meter doesn't give correct value
  • use refresh token

https://github.com/leeyuentuen/polestar_api/releases/tag/1.0.0-alpha

spockfish commented 9 months ago

Works like a charm!

leeyuentuen commented 9 months ago

Works like a charm!

do you have correct "trip meter" value and "odometer" value? for me, yesterday it work, but today it showed strange values (maybe I fetch too much?)

Screenshot 2023-12-19 at 13 55 48

spockfish commented 9 months ago

Yes,

Both are looking good:

image

leeyuentuen commented 9 months ago

Yes,

Both are looking good:

image

let me know tomorrow if the value is still like that,

m0wlheld commented 9 months ago

https://github.com/andysmithfal/polestar.js

Checkout this. I tested it, and it works without any client creds and just personal user/pw.

Looking at that solution, I don't see a need to generate a Volvo Developer Account any longer. The app seems to mimic the Polestar web-site acting as client.

Do you agree?

leeyuentuen commented 9 months ago

https://github.com/andysmithfal/polestar.js Checkout this. I tested it, and it works without any client creds and just personal user/pw.

Looking at that solution, I don't see a need to generate a Volvo Developer Account any longer. The app seems to mimic the Polestar web-site acting as client.

Do you agree?

my current one is just using polestar username and password and vin. It is not using volvo developer account. (readme at frontpage need to be updated)

dgomes commented 9 months ago

Can I advise we split the API file into it's own separate library for future integration into HA as official integration :) ?

m0wlheld commented 9 months ago

Can I advise we split the API file into it's own separate library for future integration into HA as official integration :) ?

I'd love to see an official integration, as I don't use HA OS or HACS (just the plain container image). But that should be a dedicated ticket / feature request.

leeyuentuen commented 9 months ago

Can I advise we split the API file into its own separate library for future integration into HA as official integration :)?

most of the code is in a separate polestar_api.py file. but let me see how to cleanup the code for further integration with the core

dgomes commented 9 months ago

I support several official integrations, if you would like my help, I can refactor the current file into a separate library and work with you all on an official integration.

Answering @m0wlheld official integration means it gets distributed in the core of the project (we don't need any add-on)

m0wlheld commented 9 months ago

Answering @m0wlheld official integration means it gets distributed in the core of the project (we don't need any add-on)

Correct. I can contribute German translation and have a Polestar on my own, so I can do testing as well.

loebse commented 9 months ago

https://github.com/andysmithfal/polestar.js Checkout this. I tested it, and it works without any client creds and just personal user/pw.

Looking at that solution, I don't see a need to generate a Volvo Developer Account any longer. The app seems to mimic the Polestar web-site acting as client. Do you agree?

my current one is just using polestar username and password and vin. It is not using volvo developer account. (readme at frontpage need to be updated)

That is great to hear! My question would be if you can still query every VIN or just the VIN in your Polestar account? I guess this was the reason for Polestar to shutdown the previous way.

leeyuentuen commented 9 months ago

https://github.com/andysmithfal/polestar.js Checkout this. I tested it, and it works without any client creds and just personal user/pw.

Looking at that solution, I don't see a need to generate a Volvo Developer Account any longer. The app seems to mimic the Polestar web-site acting as client. Do you agree?

my current one is just using polestar username and password and vin. It is not using volvo developer account. (readme at frontpage need to be updated)

That is great to hear! My question would be if you can still query every VIN or just the VIN in your Polestar account? I guess this was the reason for Polestar to shutdown the previous way.

you can only query the vin that is linked to your Polestar account.

in theory, I can use it without config flow, and let the integration search for the VIN in the polestar account (maybe a feature for the next release)

leeyuentuen commented 9 months ago

I support several official integrations, if you would like my help, I can refactor the current file into a separate library and work with you all on an official integration.

Answering @m0wlheld official integration means it gets distributed in the core of the project (we don't need any add-on)

this is a good opportunity, maybe let me first make sure that this run stable before we refactor them?

ITJamie commented 9 months ago

just installed. its working well!

jyrkih commented 9 months ago

confirmed, works. did anybody else notice this yet? do you have correct "trip meter" value and "odometer" value? for me, yesterday it work, but today it showed strange values (maybe I fetch too much?)

leeyuentuen commented 9 months ago

confirmed, works. did anybody else notice this yet? do you have correct "trip meter" value and "odometer" value? for me, yesterday it work, but today it showed strange values (maybe I fetch too much?)

solved the problem, just do 3 times the reset in the car (middle console reset them 3 times) and it the value came back as normal

leeyuentuen commented 9 months ago

I'll close this ticket, the code has been merged to master because the current master version doesn't work. for issue, open new issue to get better overview

https://github.com/leeyuentuen/polestar_api/releases/tag/1.0.1

Know issue: