Skip to content

Latest commit

 

History

History
588 lines (418 loc) · 18.7 KB

README.md

File metadata and controls

588 lines (418 loc) · 18.7 KB

PorscheConnect

PorscheConnect License Reviewed by Hound

This is an unofficial Porsche Connect API library written in Swift. The primary purpose for this library is to act as a building block for both mobile, desktop and serverside applications built around the Porsche Connect service.

You will require a My Porsche account to be able to make use of this library.

Is the API official?

Absolutely not. These endpoints are a result of reverse engineering Porsche's web and mobile applications.

CI/CD Status

The library has a comprehensive suite of unit tests that run on GitHub Actions. Currently the test suite is run on a Intel based macOS v13..x running XCode 14.3.

You can see the current build status of the main branch here:

PorscheConnect

Requirements

Swift

Porsche Connect requires Swift 5.7 or higher. It uses the new async/await concurrency language features introduced in Swift 5.5.

Supported Platforms

Currently the library supports the following platforms:

  • macOS (Version 12.0+)
  • iOS (Version 15+)
  • tvOS (Version 15+)
  • watchOS (Version 8+)

Swift Package Index

This library is availble on the Swift Package Index at https://swiftpackageindex.com/driven-app/porsche-connect.

Auth

Since calendar week 12, 2023, Porsche has moved their identity provider (iDP) in production to Auth0. Release v0.1.37 and higher of this library uses this new Auth0 service in a transparent manner to external clients. Use of the old iDP has been retired.

Usage

Getting Started

Create an instance of the library:

 let porscheConnect = PorscheConnect(username: "homer.simpson@icloud.example", 
                                     password: "Duh!")

The following environments are supported:

  • Germany (default)
  • Test (used by the test suite against a mocked server)

A valid MyPorsche username (email) and password is required to use this library.

List Vehicles

To get a list of vehicles associated with your My Porsche account . This call will return an array of Vehicle structs, with nested VehicleAttribute's and VehiclePicture's as appropriate for the vehicles configuration.

do {
  let result = try await porscheConnect.vehicles()
  if let vehicles = result.vehicles {
    // Do something with vehicles
  }
} catch {
  // Handle the error
}

For example, to get the external Color (a SwiftUI struct) for the first car in your account:

do {
  let result = try await porscheConnect.vehicles()
  if let vehicles = result.vehicles {
    let firstVehicle = vehicles.first!
    let color: Color = firstVehicle.color
  }
} catch {
  // Handle the error
}

Summary of a vehicle

To get a summary for a vehicle. This call will return a Summary struct.

do {
  let result = try await porscheConnect.summary(vin: vehicle.vin)
  if let summary = result.summary {
    // Do something with the summary
  }
} catch {
  // Handle the error
}

Position of a vehicle

To get last reported position for a vehicle. This call will return a Position struct.

do {
  let result = try await porscheConnect.position(vin: vehicle.vin)
  if let position = result.position {
    // Do something with the position
  }
} catch {
  // Handle the error
}

Capabilities of a vehicle

To get capabilities for a vehicle. This call will return a Capabilities struct. This struct has nested OnlineRemoteUpdateStatus and HeatingCapabilities structs as appropriate for the vehicle.

do {
  let result = try await porscheConnect.capabilities(vin: vehicle.vin)
  if let capabilities = result.capabilities {
    // Do something with the capabilities
  }
} catch {
  // Handle the error
}

Emobility of a vehicle

If the vehicle is a plug-in hybrid (PHEV) or a battery electric vehicle (BEV) this will return the status and configuration of the e-mobility aspects of the vehicle. This call requires both a vehicle and its matching capabilities. This call will return a Emobility struct. Passing in a vehicles Capabilites is optional – if none is passed in, the library will assume the vehicle is based on the J1 (Taycan) platform.

do {
  let result = try await porscheConnect.emobility(vin: vehicle.vin, capabilities: capabilities)
  if let emobility = result.emobility {
    // Do something with the emobility
  }
} catch {
  // Handle the error
}

Status of a vehicle

To get the status for a vehicle. This call will return a Status struct. This struct has nested ServiceIntervals, and RemainingRanges structs as appropriate for the vehicle.

do {
  let result = try await porscheConnect.status(vin: vehicle.vin)
  if let status = result.status {
    // Do something with the status
  }
} catch {
  // Handle the error
}

Vehicle Trips

To get the trips for a vehicle. This call will return an array of Trip structs. You can specify either shortTerm or longTerm trips to be returned. shortTerm is the default if no type is specified.

do {
  let result = try await porscheConnect.trips(vin: vehicle.vin, type: .longTerm)
  if let trips = result.trips {
    // Do something with the trips
  }
} catch {
  // Handle the error
}

Maintenance

To get the maintenance status for a vehicle. This call will return a Maintenance struct which contains a number of maintenance items.

do {
  let result = try await porscheConnect.maintenance(vin: vehicle.vin)
  if let maintenance = result.maintenance {
    // Do something with maintenance
  }
} catch {
  // Handle the error
}

Honk and Flash

To ask the vehicle to flash its indicators and optionally honk the horn. This call will return a RemoteCommandAccepted struct when the request has been accepted. The andHorn paramater is optional and defaults to false.

do {
  let result = try await porscheConnect.flash(vin: vehicle.vin, andHorn: true)
  if let remoteCommandAccepted = result.remoteCommandAccepted {
    // Do something with the remote command
  }
} catch {
  // Handle the error
}

As Honk and Flash is a remote command that can take time to reach and be executed by the car, you can check the status of the command. You pass in both the vehicle and the response from the flash() call above.

The status is mapped to a strongly typed enum that can be retrieved by accessing the remoteStatus calculated property.

Passing in a capabilites paramater is not required to determine the status of a Honk and Flash command.

do {
  let result = try await porscheConnect.checkStatus(vin: vehicle.vin, remoteCommand: remoteCommandAccepted)
  if let remoteCommandStatus = result.remoteCommand {
    // Do something with the remote command status
  }
} catch {
  // Handle the error
}

Toggle Direct Charging

To toggle a battery electric vehicle (BEV) direct charging mode to on or off. This call will return a RemoteCommandAccepted struct when the request has been accepted.

The enable parameter is optional and defaults to true.

Passing in a vehicles Capabilites is optional – if none is passed in, the library will assume the vehicle is based on the J1 (Taycan) platform.

do {
  let result = try await porscheConnect.toggleDirectCharging(vin: vehicle.vin, capabilities: capabilities, enable: false)
  if let remoteCommandAccepted = result.remoteCommandAccepted {
    // Do something with the remote command
  }
} catch {
  // Handle the error
}

As Toggle Direct Charging is a remote command that can take time to reach and be executed by the car, you can check the status of the command. You pass in both the vehicle and the response from the toggleDirectCharging() call above.

The status is mapped to a strongly typed enum that can be retrieved by accessing the remoteStatus calculated property.

Passing in a vehicles Capabilites is optional – if none is passed in, the library will assume the vehicle is based on the J1 (Taycan) platform.

do {
  let result = try await porscheConnect.checkStatus(vin: vehicle.vin, capabilities: capabilities, remoteCommand: remoteCommandAccepted)
  if let remoteCommandStatus = result.remoteCommand {
    // Do something with the remote command status
  }
} catch {
  // Handle the error
}

Toggle Direct Climatisation

To toggle climatisation mode to on or off. This call will return a RemoteCommandAccepted struct when the request has been accepted.

The enable parameter is optional and defaults to true.

do {
  let result = try await porscheConnect.toggleClimatisation(vin: vehicle.vin, enable: false)
  if let remoteCommandAccepted = result.remoteCommandAccepted {
    // Do something with the remote command
  }
} catch {
  // Handle the error
}

As Toggle Direct Climatisation is a remote command that can take time to reach and be executed by the car, you can check the status of the command. You pass in both the vehicle and the response from the toggleClimatisation() call above.

The status is mapped to a strongly typed enum that can be retrieved by accessing the remoteStatus calculated property.

do {
  let result = try await porscheConnect.checkStatus(vin: vehicle.vin, remoteCommand: remoteCommandAccepted)
  if let remoteCommandStatus = result.remoteCommand {
    // Do something with the remote command status
  }
} catch {
  // Handle the error
}

Lock Vehicle

To ask the vehicle to remote lock. This call will return a RemoteCommandAccepted struct when the request has been accepted.

Make sure that there are no vehicle keys, persons or animals in the vehicle.

do {
  let result = try await porscheConnect.lock(vin: vehicle.vin)
  if let remoteCommandAccepted = result.remoteCommandAccepted {
    // Do something with the remote command
  }
} catch {
  // Handle the error
}

As Lock Vehicle is a remote command that can take time to reach and be executed by the car, you can check the status of the command. You pass in the vehicle, optionally the vehicles capabilities and the response from the lock() call above.

The status is mapped to a strongly typed enum that can be retrieved by accessing the remoteStatus calculated property.

Passing in a capabilites paramater is not required to determine the status of a Lock command.

do {
  let result = try await porscheConnect.checkStatus(vin: vehicle.vin, remoteCommand: remoteCommandAccepted)
  if let remoteCommandStatus = result.remoteCommand {
    // Do something with the remote command status
  }
} catch {
  // Handle the error
}

Unlock Vehicle

To ask the vehicle to remote unlock. As this action impacts the security of the vehicle (by unlocking it), it also requires the users four digit security (PIN) code. This call will return a RemoteCommandAccepted struct when the request has been accepted.

do {
  let result = try await porscheConnect.unlock(vin: vehicle.vin, pin: "1234")
  if let remoteCommandAccepted = result.remoteCommandAccepted {
    // Do something with the remote command
  }
} catch {
  // Handle the error
}

As Unlock Vehicle is a remote command that can take time to reach and be executed by the car, you can check the status of the command. You pass in the vehicle, optionally the vehicles capabilities and the response from the unlock() call above.

The status is mapped to a strongly typed enum that can be retrieved by accessing the remoteStatus calculated property.

Passing in a capabilites paramater is not required to determine the status of a Unlock command.

do {
  let result = try await porscheConnect.checkStatus(vin: vehicle.vin, remoteCommand: remoteCommandAccepted)
  if let remoteCommandStatus = result.remoteCommand {
    // Do something with the remote command status
  }
} catch {
  // Handle the error
}

Tests

To run the test suite:

xcodebuild test -destination "platform=iOS Simulator,name=iPhone 12 mini" -scheme "PorscheConnect"

This is similar to the commands that are run in CI to test the library on each git commit. You can change the destinations to any of the libraries supported platforms.

Command Line Tool

The library is packaged with a command line utility to give a simple terminal access to the set of Porsche Connect services wrapped by this library.

Compiling

From within the project directory, run:

swift build -c release

This will place the excutable in <project-dir>/.build/apple/Products/Release folder, where it will be named porsche. If you want to make it available more generally when using a terminal, copy it to /usr/local/bin from the project dir:

cp -f .build/apple/Products/Release/porsche /usr/local/bin

Universal binary

If you would like to build a universal binary for both Intel (x86) and Apple (ARC) processors (M-series Mac's, iPhones, iPads, Watches) then run the compiler with:

swift build -c release --arch arm64 --arch x86_64

Using

To get help on the various commands available, call with --help on either the overall command or any of the sub-commands:

$ porsche --help

OVERVIEW: A command-line tool to call and interact with Porsche Connect services

USAGE: porsche <subcommand>

OPTIONS:
  --version               Show the version.
  -h, --help              Show help information.

SUBCOMMANDS:
  list-vehicles
  show-summary
  show-position
  show-capabilities
  show-emobility
  show-trips
  show-maintenance
  flash
  honk-and-flash
  toggle-direct-charging
  toggle-direct-climatisation
  lock
  unlock
  
  See 'porsche help <subcommand>' for detailed help.

By default, the CLI tool will attempt to use your system locale for all API requests. This will affect the localization of the API responses. If your system locale is not supported, Germany will be used instead. You can choose one of the supported locales using the --locale flag and passing one of the supported locales, such as de_DE or en_US.

To get a list of all the vehicles associated with your My Porsche account:

$ porsche list-vehicles <username> <password>

#1 => Model: Taycan 4S; Year: 2021; Type: Y1ADB1; VIN: WP0ZZZXXXXXXXXXXX

To show the summary for a specific vehicle – the nickname is usually set to be the licenseplate of the car, but can be any value set by the owner:

$ porsche show-summary <username> <password> <vin>

Model Description: Taycan 4S; Nickname: 211-D-12345

To show the current position of a vehicle:

$ porsche show-position <username> <password> <vin>

Latitude: 53.395367; Longitude: -6.389296; Heading: 68

To show the current status of a vehicle:

$ porsche show-status <username> <password> <vin>

Overall lock status: Closed and locked
Battery level: 73.0%, Mileage: 2,206 kilometers
Remaining range is 292 kilometers
Next inspection in 27,842 kilometers or on Dec 10, 2024

To show the capabilties of a vehicle:

$ porsche show-capabilities <username> <password> <vin>

Display parking brake: yes; Needs SPIN: yes; Has RDK: yes; Engine Type: BEV; Car Model: J1; Front Seat Heating: yes; Rear Seat Heating: no; Steering Wheel Position: RIGHT; Honk & Flash: yes

To show the emobility of a vehicle:

(Note: this only displays a small subset of the information that the emobility service returns)

$ porsche show-emobility <username> <password> <vin>

Battery Level: 53%; Remaining Range: 180 KM; Charging Status: NOT_CHARGING; Plug Status: DISCONNECTED

To get a list of all trips taken by the vehicle:

You can specify either short or long term trips by using the --trip-type option. If no option is specified, it defaults to displaying short term trips.

$ porsche show-trips <username> <password> <vin> --trip-type <trip-type>

#1 => Trip ID: 1162572771; Timestamp: 8 Jan 2023 at 22:45:35; Distance: 6.0 km; Average speed: 11.0 km/h; EV consumption: 39.6 kWh/100km
#2 => Trip ID: 1161450482; Timestamp: 7 Jan 2023 at 09:11:00; Distance: 12.0 km; Average speed: 31.0 km/h; EV consumption: 34.9 kWh/100km

To get a list of all maintenance items for the vehicle:

$ porsche show-maintenance <username> <password> <vin>

#1 => Maintenance ID: 0003; Short Description: "Inspection"; Long Description: ""; Criticality: "No maintenance is due at the moment."
#2 => Maintenance ID: 0005; Short Description: "Brake pads"; Long Description: "Replace brake pads"; Criticality: "No maintenance is due at the moment."
#3 => Maintenance ID: 0007; Short Description: "Brake fluid"; Long Description: "Replace brake fluid"; Criticality: "No maintenance is due at the moment."

To flash the indicators of a vehicle:

$ porsche flash <username> <password> <vin>

Remote command \"Flash\" accepted by Porsche API with ID 123456

To flash and honk the indicators of a vehicle:

$ porsche honk-and-flash <username> <password> <vin>

Remote command \"Honk and Flash\" accepted by Porsche API with ID 123456

To toggle the direct charging mode of a vehicle:

$ porsche toggle-direct-charging <username> <password> <vin> <toggle-direct-charging-on>

Remote command \"Toggle Direct Charging\" accepted by Porsche API with ID 123456

To toggle climatisation mode of a vehicle:

$ porsche toggle-direct-climatisation <username> <password> <vin> <toggle-climatisation-on>

Remote command \"Toggle Direct Climatisation\" accepted by Porsche API with ID 123456

To lock a vehicle:

$ porsche lock <username> <password> <vin>

Remote command \"Lock\" accepted by Porsche API with ID 123456

To unlock a vehicle:

$ porsche unlock <username> <password> <vin> <pin>

Remote command \"Unlock\" accepted by Porsche API with ID 123456

Install

Package Manager

To do this, add the repo to Package.swift, like this:

import PackageDescription

let package = Package(
  name: "PorscheConnect",
  dependencies: [
    .package(url: "git@github.com:driven-app/porsche-connect.git", 
             from: "0.1"),
  ]
)