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.
Absolutely not. These endpoints are a result of reverse engineering Porsche's web and mobile applications.
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:
Porsche Connect requires Swift 5.7 or higher. It uses the new async/await concurrency language features introduced in Swift 5.5.
Currently the library supports the following platforms:
- macOS (Version 12.0+)
- iOS (Version 15+)
- tvOS (Version 15+)
- watchOS (Version 8+)
This library is availble on the Swift Package Index at https://swiftpackageindex.com/driven-app/porsche-connect.
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.
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.
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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
}
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.
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.
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
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
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
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"),
]
)