Skip to content

psa-ng Specification


The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF BCP14 (RFC2119 & RFC8174)


psa-ng is a Rust reimplementation of the psa_car_controller project. It provides remote control and monitoring of PSA group vehicles (Peugeot, Citroën, Opel/Vauxhall, DS) via the PSA Connected Car v4 API, with a local web dashboard for visualization and control.

The project is split into two main modules: - psa-api: PSA API client library handling authentication, vehicle queries, and remote commands - psa-web: Web server providing REST endpoints and an interactive dashboard

Architecture requirements

Modular architecture

req~modular-architecture~1: The project MUST be organized as a Cargo workspace with separate crates for the PSA API client library and the web server application.

Needs: impl

Rust best practices

req~rust-best-practices~1: All crates MUST compile without warnings under #[deny(warnings)] and MUST pass clippy with default lints.

Needs: impl, utest

Stable dependencies

req~stable-dependencies~1: The project MUST only depend on stable, well-maintained crates that are widely adopted in the Rust ecosystem.

Needs: impl

PSA API authentication requirements

OAuth2 authentication

req~oauth2-authentication~1: The PSA API client MUST implement the OAuth2 authorization flow to obtain and manage access tokens for the PSA Connected Car v4 API.

Needs: impl, utest

Token refresh

req~token-refresh~1: The PSA API client MUST automatically refresh expired OAuth2 access tokens using the stored refresh token before making API requests.

Needs: impl, utest

Depends: - req~oauth2-authentication~1

Credential persistence

req~credential-persistence~1: The PSA API client MUST persist OAuth2 tokens and credentials to a local file so that re-authentication is not required on restart.

Needs: impl, utest

Depends: - req~oauth2-authentication~1

PSA API client requirements

Vehicle list retrieval

req~vehicle-list~1: The PSA API client MUST retrieve the list of vehicles associated with the authenticated user account.

Needs: impl, utest

Depends: - req~oauth2-authentication~1

Vehicle status retrieval

req~vehicle-status~1: The PSA API client MUST retrieve the current status of a vehicle, including battery level, charging state, odometer reading, and last-known position.

Needs: impl, utest

Depends: - req~vehicle-list~1

Vehicle wakeup

req~vehicle-wakeup~1: The PSA API client MUST support sending a wakeup request to force a vehicle to report its current status.

Needs: impl, utest

Charge control

req~charge-control~1: The PSA API client MUST support starting and stopping vehicle charging via remote commands.

Needs: impl, utest

Charge threshold

req~charge-threshold~1: The PSA API client MUST support setting a battery charge threshold percentage to limit charging.

Needs: impl, utest

Charge scheduling

req~charge-scheduling~1: The PSA API client MUST support setting a scheduled stop hour for charging to enable off-peak charging.

Needs: impl, utest

Preconditioning control

req~preconditioning-control~1: The PSA API client MUST support starting and stopping air conditioning preconditioning.

Needs: impl, utest

Door lock control

req~door-lock-control~1: The PSA API client MUST support locking and unlocking vehicle doors via remote commands.

Needs: impl, utest

Lights and horn control

req~lights-horn-control~1: The PSA API client MUST support flashing lights and honking the horn via remote commands.

Needs: impl, utest

Data persistence requirements

Status history storage

req~status-history~1: The application MUST persist vehicle status snapshots over time to enable historical analysis and dashboard visualization.

Needs: impl, utest

Trip recording

req~trip-recording~1: The application MUST record and persist trip data including start/end positions, distance, and energy consumption.

Needs: impl, utest

Charging session recording

req~charging-session-recording~1: The application MUST record and persist charging session data including start time, end time, energy charged, and battery level changes.

Needs: impl, utest

Web server requirements

HTTP server

req~http-server~1: The web module MUST provide an HTTP server using a lightweight, well-maintained Rust web framework.

Needs: impl

Vehicle status endpoint

req~vehicle-status-endpoint~1: The web server MUST expose an endpoint that returns the current vehicle status as JSON.

Needs: impl, utest

Depends: - req~vehicle-status~1

Charge control endpoint

req~charge-control-endpoint~1: The web server MUST expose endpoints for starting/stopping charging, setting charge threshold, and setting charge schedule.

Needs: impl, utest

Depends: - req~charge-control~1 - req~charge-threshold~1 - req~charge-scheduling~1

Preconditioning endpoint

req~preconditioning-endpoint~1: The web server MUST expose an endpoint for starting and stopping air conditioning preconditioning.

Needs: impl, utest

Depends: - req~preconditioning-control~1

Door lock endpoint

req~door-lock-endpoint~1: The web server MUST expose an endpoint for locking and unlocking vehicle doors.

Needs: impl, utest

Depends: - req~door-lock-control~1

Lights and horn endpoint

req~lights-horn-endpoint~1: The web server MUST expose an endpoint for flashing lights and honking the horn.

Needs: impl, utest

Depends: - req~lights-horn-control~1

Vehicle wakeup endpoint

req~wakeup-endpoint~1: The web server MUST expose an endpoint to trigger a vehicle wakeup.

Needs: impl, utest

Depends: - req~vehicle-wakeup~1

Settings endpoint

req~settings-endpoint~1: The web server MUST expose endpoints for reading and updating application configuration.

Needs: impl, utest

Trips endpoint

req~trips-endpoint~1: The web server MUST expose an endpoint that returns recorded trip data.

Needs: impl, utest

Depends: - req~trip-recording~1

Charging sessions endpoint

req~charging-sessions-endpoint~1: The web server MUST expose an endpoint that returns recorded charging session data.

Needs: impl, utest

Depends: - req~charging-session-recording~1

Dashboard requirements

Dashboard overview page

req~dashboard-overview~1: The web server MUST serve a dashboard page that displays a summary of vehicle status including battery level, charging state, and last-known position.

Needs: impl

Depends: - req~vehicle-status~1

Charge management page

req~charge-management-page~1: The web server MUST serve a page with forms to control charging: start/stop charge, set threshold percentage, and set charge schedule.

Needs: impl

Depends: - req~charge-control-endpoint~1

Trip display page

req~trip-display-page~1: The web server MUST serve a page that displays recorded trips in a tabular format.

Needs: impl

Depends: - req~trips-endpoint~1

Settings page

req~settings-page~1: The web server MUST serve a page with forms for managing application configuration including electricity pricing.

Needs: impl

Depends: - req~settings-endpoint~1

Clean web styling

req~clean-web-styling~1: The web dashboard MUST use a clean, simple, and responsive CSS styling that works well on both desktop and mobile browsers.

Needs: impl

Configuration requirements

Configuration file

req~configuration-file~1: The application MUST load configuration from a TOML file, including PSA API credentials, electricity pricing, and server settings.

Needs: impl, utest

Electricity pricing

req~electricity-pricing~1: The configuration MUST support setting an electricity price per kWh, with OPTIONAL support for separate day and night pricing with configurable time ranges.

Needs: impl, utest

Depends: - req~configuration-file~1

Security requirements

API bearer token authentication

req~api-bearer-auth~1: The web server MUST require a configurable bearer token on all /api/* endpoints, rejecting unauthenticated requests with HTTP 401.

Needs: impl, utest

HTML output escaping

req~html-output-escaping~1: The web server MUST escape all dynamic values inserted into HTML templates to prevent cross-site scripting (XSS) attacks.

Needs: impl, utest

Request body size limit

req~request-body-limit~1: The web server MUST enforce a maximum request body size to prevent denial-of-service via oversized payloads.

Needs: impl

Security response headers

req~security-headers~1: The web server MUST set security-related HTTP response headers including Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy.

Needs: impl, utest

Sanitized error responses

req~sanitized-errors~1: API error responses MUST NOT expose internal implementation details such as file paths, token states, or upstream API URLs to clients.

Needs: impl, utest

Dependency vulnerability scanning

req~dependency-audit~1: The CI pipeline MUST include automated dependency vulnerability scanning via cargo audit.

Needs: impl

Deployment requirements

Container image

req~container-image~1: The project MUST provide a multi-stage Dockerfile that builds the application from source using the stable Rust toolchain and produces a minimal runtime image containing only the compiled binary and its runtime dependencies.

Needs: impl

Container deployment

req~container-deployment~1: The project MUST provide a Docker Compose configuration that runs the application with a bind-mounted configuration file, a persistent named volume for data, and configurable port mapping.

Needs: impl

Depends: - req~container-image~1

API protocol conformance requirements

Callback registration

req~callback-registration~1: The PSA API client MUST register a callback with the PSA API before sending remote commands, and MUST use the returned callback ID in subsequent remote command requests.

Needs: impl, utest

Depends: - req~oauth2-authentication~1

Remote command schema

req~remote-command-schema~1: Remote command requests MUST use the PSA API v4 documented endpoint path (/user/vehicles/{id}/callbacks/{cbid}/remotes) and JSON payload schema with typed action fields (door, horn, charging, lights, wakeUp, preconditioning, navigation), and MUST send Content-Type: application/json.

Needs: impl, utest

Depends: - req~callback-registration~1

Rate limit handling

req~rate-limit-handling~1: The PSA API client MUST parse X-RateLimit-Remaining and Retry-After response headers and MUST delay subsequent requests when the API returns HTTP 429 (Too Many Requests).

Needs: impl, utest

API pagination

req~api-pagination~1: The PSA API client MUST support token-based pagination for collection endpoints by following pageToken values in responses until all pages have been retrieved.

Needs: impl, utest

OAuth2 scope management

req~oauth2-scope-management~1: The PSA API client SHOULD request the minimum required OAuth2 scopes during authorization and SHOULD validate that the token carries the scopes needed for a given operation before making the request.

Needs: impl, utest

Depends: - req~oauth2-authentication~1

API error response parsing

req~api-error-parsing~1: The PSA API client MUST parse structured error responses from the API (containing code, uuid, message, and timestamp fields) into a typed error variant.

Needs: impl, utest

Vehicle model completeness

req~vehicle-model-completeness~1: The Vehicle data model MUST include the motorization field (Electric, Hybrid, Thermic, Hydrogen) and timestamp fields (createdAt, updatedAt) as defined in the PSA Connected Car v4 API specification.

Needs: impl, utest

Future requirements

The following requirements are specified but not yet implemented. They document planned functionality.

Status polling

req~status-polling~1: The application SHOULD periodically poll vehicle status from the PSA API and persist snapshots, trips, and charging sessions to the database automatically.

Needs: impl, utest

Depends: - req~vehicle-status~1 - req~status-history~1 - req~trip-recording~1 - req~charging-session-recording~1