wtpalexander/volvo-cars-api
A Swift package for accessing the Volvo Connected Car API.
Features
- OAuth2 authentication with PKCE
- List vehicles in your account
- Get vehicle details
- Get odometer readings
- Get tyre pressure status
Requirements
- iOS 16.0+ / macOS 13.0+ / watchOS 9.0+ / tvOS 16.0+
- Swift 6.0+
- Volvo Developer Portal credentials (Client ID, Client Secret, and API Key)
Installation
Swift Package Manager
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/yourusername/volvo-cars-api.git", from: "1.0.0")
]Or in Xcode, go to File > Add Package Dependencies and enter the repository URL.
Setup
- Register for a Volvo Developer account at https://developer.volvocars.com/
- Create a new application in the Volvo Developer Portal
- Note your Client ID, Client Secret, and VCC API Key
- Configure your OAuth redirect URI (e.g.,
volvocars://oauth-callback)
Command Line Tool
The package includes a command-line tool for easy testing and interaction with the Volvo API.
Build the CLI
swift build
.build/debug/VolvoCarsAPICLT --helpAuthentication
- Start the OAuth flow to get an authorization URL:
.build/debug/VolvoCarsAPICLT authorize \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEY- Open the displayed URL in your browser and log in with your Volvo account
- After authorization, you'll be redirected to a URL like:
volvocars://oauth-callback?code=AUTHORIZATION_CODE
- Exchange the authorization code for an access token:
.build/debug/VolvoCarsAPICLT authenticate \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEY \
--code AUTHORIZATION_CODEThe token will be saved to ~/.volvo-cars-api-token.json and automatically used for subsequent commands.
CLI Commands
List all vehicles:
.build/debug/VolvoCarsAPICLT list-vehicles \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEYGet vehicle details:
.build/debug/VolvoCarsAPICLT vehicle-details YOUR_VIN \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEYGet odometer reading:
.build/debug/VolvoCarsAPICLT odometer YOUR_VIN \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEYGet tyre status:
.build/debug/VolvoCarsAPICLT tyres YOUR_VIN \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEYEnable verbose logging:
Add the --verbose flag to any command:
.build/debug/VolvoCarsAPICLT list-vehicles \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--api-key YOUR_API_KEY \
--verboseLogout (remove saved token):
.build/debug/VolvoCarsAPICLT logoutUsage as a Library
Initialize VolvoCarsAPI
import VolvoCarsAPI
let volvo = VolvoCarsAPI(
clientID: "your-client-id",
clientSecret: "your-client-secret",
apiKey: "your-vcc-api-key"
)Authentication Flow
Volvo uses OAuth2 with PKCE for authentication. The authentication flow requires user interaction:
// 1. Generate the authorization URL
let authURL = try volvo.getAuthorizationURL()
// 2. Open this URL in a browser for the user to authenticate
// The user will be redirected to your redirect URI with an authorization code
// 3. Extract the code from the redirect URL and exchange it for tokens
try await volvo.authenticate(code: authorizationCode)Persist Tokens
You can save and restore tokens to avoid requiring the user to authenticate each time:
// Save the token after authentication
if let token = await volvo.getToken() {
// Save token to keychain or secure storage
saveToken(token)
}
// Restore the token on next launch
if let savedToken = loadToken() {
await volvo.setToken(savedToken)
}Get Vehicles
let vins = try await volvo.getVehicles()
print("Found \(vins.count) vehicles")Get Vehicle Details
let details = try await volvo.getVehicleDetails(vin: "YV1ABC123DEF45678")
print("Model: \(details.descriptions?.model ?? "Unknown")")
print("Year: \(details.modelYear ?? 0)")Get Odometer Reading
if let odometer = try await volvo.getOdometer(vin: "YV1ABC123DEF45678") {
print("Odometer: \(odometer.value) \(odometer.unit)")
}Get Tyre Status
let tyres = try await volvo.getTyres(vin: "YV1ABC123DEF45678")
print("Front Left: \(tyres.frontLeft.value)")
print("Front Right: \(tyres.frontRight.value)")
print("Rear Left: \(tyres.rearLeft.value)")
print("Rear Right: \(tyres.rearRight.value)")OAuth Scopes
The package requests the following default scopes:
openid- Required for authenticationconve:vehicle_relation- List vehicles and get vehicle detailsconve:odometer_status- Read odometer valuesconve:tyre_status- Read tyre pressure status
You can customize the scopes when initializing VolvoCarsAPI:
let volvo = VolvoCarsAPI(
clientID: "your-client-id",
clientSecret: "your-client-secret",
apiKey: "your-vcc-api-key",
scopes: [
"openid",
"conve:vehicle_relation",
"conve:odometer_status",
"conve:tyre_status",
"conve:fuel_status"
]
)Available scopes can be found in the Volvo API documentation.
Error Handling
The package throws errors for authentication failures and API errors:
do {
let vehicles = try await volvo.getVehicles()
print(vehicles)
} catch let error as VolvoAuthError {
print("Authentication error: \(error)")
} catch {
print("API error: \(error)")
}Debug Logging
Enable debug logging to see network requests and responses:
let volvo = VolvoCarsAPI(
clientID: "your-client-id",
clientSecret: "your-client-secret",
apiKey: "your-vcc-api-key",
isDebugLoggingEnabled: true
)License
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Acknowledgments
- Based on the volvocars-api Python library
- Uses the official Volvo Cars API
Package Metadata
Repository: wtpalexander/volvo-cars-api
Default branch: main
README: README.md