Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/driven-app/porsche-connect

An unofficial Porsche Connect API library written in Swift
https://github.com/driven-app/porsche-connect

electric-vehicles macos porsche swift

Last synced: 11 days ago
JSON representation

An unofficial Porsche Connect API library written in Swift

Awesome Lists containing this project

README

        

# PorscheConnect

![PorscheConnect](https://github.com/driven-app/porsche-connect/workflows/PorscheConnect/badge.svg)
[![License](https://img.shields.io/github/license/driven-app/porsche-connect)](https://github.com/driven-app/porsche-connect/blob/main/LICENSE)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fdriven-app%2Fporsche-connect%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/driven-app/porsche-connect)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fdriven-app%2Fporsche-connect%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/driven-app/porsche-connect)

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](https://github.com/driven-app/porsche-connect/workflows/PorscheConnect/badge.svg)

## 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](https://swiftpackageindex.com/driven-app/porsche-connect).

### Auth

Since calendar week 12, 2023, Porsche has moved their identity provider (iDP) in production to [Auth0](https://auth0.com). 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:

```swift
let porscheConnect = PorscheConnect(username: "[email protected]",
password: "Duh!")
```

The following environments are supported:

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

A valid [MyPorsche](https://my.porsche.com) 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.

```swift
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](https://developer.apple.com/documentation/swiftui/color) (a SwiftUI struct) for the first car in your account:

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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`.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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.

```swift
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:

```bash
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:

```bash
swift build -c release
```

This will place the excutable in `/.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:

```bash
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:

```bash
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:

```bash
$ porsche --help

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

USAGE: porsche

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 ' 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:

```bash
$ porsche list-vehicles

#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:

```bash
$ porsche show-summary

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

To show the current position of a vehicle:

```bash
$ porsche show-position

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

To show the current status of a vehicle:

```bash
$ porsche show-status

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:

```bash
$ porsche show-capabilities

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)*

```bash
$ porsche show-emobility

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.*

```bash
$ porsche show-trips --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:

```bash
$ porsche show-maintenance

#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:

```bash
$ porsche flash

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

To flash and honk the indicators of a vehicle:

```bash
$ porsche honk-and-flash

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

To toggle the direct charging mode of a vehicle:

```bash
$ porsche toggle-direct-charging

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

To toggle climatisation mode of a vehicle:

```bash
$ porsche toggle-direct-climatisation

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

To lock a vehicle:

```bash
$ porsche lock

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

To unlock a vehicle:

```bash
$ porsche unlock

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

# Install

### Package Manager

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

```swift
import PackageDescription

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