PorscheConnect

PorscheConnect License Reviewed by Hound

这是一个使用 Swift 编写的非官方 Porsche Connect API 库。该库的主要目的是作为构建移动、桌面和服务器端应用程序的基础模块,这些应用程序都围绕 Porsche Connect 服务构建。

您需要一个 My Porsche 帐户才能使用此库。

API 是官方的吗?

绝对不是。这些端点是通过逆向工程保时捷的 Web 和移动应用程序获得的。

CI/CD 状态

该库拥有一套全面的单元测试,可在 GitHub Actions 上运行。目前,测试套件在基于 Intel 的 macOS v13.x 上运行,并使用 XCode 14.3。

您可以在此处查看 main 分支的当前构建状态

PorscheConnect

要求

Swift

Porsche Connect 需要 Swift 5.7 或更高版本。 它使用 Swift 5.5 中引入的新的 async/await 并发语言特性。

支持的平台

目前,该库支持以下平台

Swift Package Index

此库可在 Swift Package Index 上找到:https://swiftpackageindex.cn/driven-app/porsche-connect

身份验证

自 2023 年第 12 周开始,保时捷已将其生产环境中的身份提供商 (iDP) 迁移到 Auth0。此库的 v0.1.37 及更高版本以透明的方式对外部客户端使用此新的 Auth0 服务。旧 iDP 的使用已停用。

用法

入门

创建库的一个实例

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

支持以下环境

要使用此库,需要有效的 MyPorsche 用户名(电子邮件)和密码。

列出车辆

获取与您的 My Porsche 帐户关联的车辆列表。此调用将返回一个 Vehicle 结构体数组,其中包含嵌套的 VehicleAttributeVehiclePicture(如果适用),以用于车辆配置。

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

例如,要获取帐户中第一辆车的外部 Color(一个 SwiftUI 结构体)

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 结构体。

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 结构体。

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 结构体。此结构体包含嵌套的 OnlineRemoteUpdateStatusHeatingCapabilities 结构体(如果适用于车辆)。

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

车辆的电动性能

如果车辆是插电式混合动力汽车 (PHEV) 或电池电动汽车 (BEV),这将返回车辆电动性能的状态和配置。 此调用需要车辆及其匹配的功能。 此调用将返回一个 Emobility 结构体。 传入车辆的 Capabilites 是可选的 - 如果未传入,则该库将假定该车辆基于 J1 (Taycan) 平台。

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 结构体。 此结构体包含嵌套的 ServiceIntervalsRemainingRanges 结构体(如果适用于车辆)。

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

车辆行程

获取车辆的行程。此调用将返回一个 Trip 结构体数组。您可以指定返回 shortTermlongTerm 行程。 如果未指定类型,则默认为 shortTerm

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 结构体,其中包含许多维护 items

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

鸣笛和闪灯

要求车辆闪烁指示灯并选择性地鸣喇叭。当请求被接受时,此调用将返回一个 RemoteCommandAccepted 结构体。 andHorn 参数是可选的,默认为 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
}

由于鸣笛和闪灯是一个远程命令,可能需要一段时间才能到达汽车并被执行,您可以检查命令的状态。您需要传入车辆和上面 flash() 调用的响应。

status 映射到一个强类型枚举,可以通过访问 remoteStatus 计算属性来检索。

无需传入 capabilites 参数即可确定鸣笛和闪灯命令的状态。

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
}

切换直接充电

将电池电动汽车 (BEV) 的直接充电模式切换为开启或关闭。当请求被接受时,此调用将返回一个 RemoteCommandAccepted 结构体。

enable 参数是可选的,默认为 true。

传入车辆的 Capabilites 是可选的 - 如果未传入,则该库将假定该车辆基于 J1 (Taycan) 平台。

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
}

由于切换直接充电是一个远程命令,可能需要一段时间才能到达汽车并被执行,您可以检查命令的状态。您需要传入车辆和上面 toggleDirectCharging() 调用的响应。

status 映射到一个强类型枚举,可以通过访问 remoteStatus 计算属性来检索。

传入车辆的 Capabilites 是可选的 - 如果未传入,则该库将假定该车辆基于 J1 (Taycan) 平台。

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
}

切换直接气候控制

将气候控制模式切换为开启或关闭。当请求被接受时,此调用将返回一个 RemoteCommandAccepted 结构体。

enable 参数是可选的,默认为 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
}

由于切换直接气候控制是一个远程命令,可能需要一段时间才能到达汽车并被执行,您可以检查命令的状态。您需要传入车辆和上面 toggleClimatisation() 调用的响应。

status 映射到一个强类型枚举,可以通过访问 remoteStatus 计算属性来检索。

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
}

锁定车辆

要求车辆远程锁定。当请求被接受时,此调用将返回一个 RemoteCommandAccepted 结构体。

确保车辆内没有车辆钥匙、人员或动物。

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
}

由于锁定车辆是一个远程命令,可能需要一段时间才能到达汽车并被执行,您可以检查命令的状态。您需要传入车辆,(可选)车辆功能和上面 lock() 调用的响应。

status 映射到一个强类型枚举,可以通过访问 remoteStatus 计算属性来检索。

无需传入 capabilites 参数即可确定锁定命令的状态。

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
}

解锁车辆

要求车辆远程解锁。 由于此操作会影响车辆的安全性(通过解锁),因此它还需要用户的四位数字安全(PIN)码。 当请求被接受时,此调用将返回一个 RemoteCommandAccepted 结构体。

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
}

由于解锁车辆是一个远程命令,可能需要一段时间才能到达汽车并被执行,您可以检查命令的状态。您需要传入车辆,(可选)车辆功能和上面 unlock() 调用的响应。

status 映射到一个强类型枚举,可以通过访问 remoteStatus 计算属性来检索。

无需传入 capabilites 参数即可确定解锁命令的状态。

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
}

测试

运行测试套件

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

这类似于在 CI 中运行的命令,用于在每次 git 提交时测试库。您可以将目标更改为库支持的任何平台。

命令行工具

该库与一个命令行实用程序打包在一起,以提供对该库包装的一组 Porsche Connect 服务的简单终端访问。

编译

在项目目录中,运行

swift build -c release

这会将可执行文件放置在 <project-dir>/.build/apple/Products/Release 文件夹中,并将其命名为 porsche。 如果您想在使用终端时更普遍地使用它,请将其从项目目录复制到 /usr/local/bin

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

通用二进制文件

如果您想为 Intel (x86) 和 Apple (ARC) 处理器(M 系列 Mac、iPhone、iPad、Watch)构建通用二进制文件,请使用以下命令运行编译器

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

使用

要获取有关可用各种命令的帮助,请在整个命令或任何子命令上使用 --help 调用

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

默认情况下,CLI 工具将尝试使用您的系统区域设置进行所有 API 请求。 这将影响 API 响应的本地化。 如果您的系统区域设置不受支持,则将改为使用德国。 您可以使用 --locale 标志并传递受支持的区域设置之一(例如 de_DEen_US)来选择受支持的区域设置之一。

获取与您的 My Porsche 帐户关联的所有车辆的列表

$ porsche list-vehicles <username> <password>

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

显示特定车辆的摘要 - 昵称通常设置为汽车的车牌,但可以是所有者设置的任何值

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

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

显示车辆的当前位置

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

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

显示车辆的当前状态

$ 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

显示车辆的功能

$ 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

显示车辆的电动性能

(注意:这仅显示电动性能服务返回的一小部分信息)

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

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

获取车辆所有行程的列表

您可以使用 --trip-type 选项指定 shortlong term 行程。 如果未指定选项,则默认显示 short term 行程。

$ 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

获取车辆的所有维护项目的列表

$ 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."

闪烁车辆的指示灯

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

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

闪烁车辆的指示灯并鸣喇叭

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

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

切换车辆的直接充电模式

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

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

切换车辆的气候控制模式

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

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

锁定车辆

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

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

解锁车辆

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

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

安装

包管理器

为此,请将存储库添加到 Package.swift,如下所示

import PackageDescription

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