# OCPP 1.6J

Salia charging stations connect to a backend (Central System) with OCPP
1.6J, that is OCPP 1.6 over WebSocket with JSON. This page describes which
parts of the protocol the station implements and where it deviates from what
a backend may expect. The fault codes the station sends are listed on
[OCPP Error Codes](/ocpp/error-codes).

Applies to firmware 2.5.0 and later on all charging stations with the Salia
controller. Each station has one connector (connector `1`); connector `0`
stands for the station as a whole.

## Connection

| Topic | Behaviour |
| --- | --- |
| Protocol | OCPP 1.6J, WebSocket subprotocol `ocpp1.6`. SOAP and OCPP 2.0.1 are not supported. |
| Backend URL | `ws://` or `wss://`. The URL is used exactly as entered, so it has to contain the charge point ID, for example `wss://backend.example.com/ocpp/CP-0001`. A changed `CentralSystemURI` takes effect after a restart. |
| TLS | `wss://` uses TLS 1.2. The server certificate, including the host name, is only checked when *Verify CERT* is enabled in the OCPP settings of the web UI. The option is off in the factory setting; without it any server certificate is accepted. |
| Authentication | HTTP Basic Auth with user name and password. The credentials are set in the station's web UI; they cannot be changed over OCPP (`AuthorizationKey` is not supported). Client certificates are not supported. |
| Response time | The backend has to answer every request within 60 seconds. Otherwise the station closes the connection and connects again. |
| Time | The station takes its time from `BootNotification` and `Heartbeat` (and NTP, if configured). Calibration-law (Eichrecht) stations refuse transactions until the clock is set. Other stations also start transactions with an unset clock (`allowTxWithInvalidTime`); their timestamps are then wrong. |
| BootNotification | `chargePointVendor` and `chargePointModel` (up to 20 characters each), `chargePointSerialNumber` and `chargeBoxSerialNumber` (if set; up to 25 characters each), `firmwareVersion`, `meterType`, `meterSerialNumber`; `iccid` and `imsi` on stations with a mobile modem. |
| Registration | The station starts transactions, online or offline, only after the backend in `CentralSystemURI` has accepted a `BootNotification` at least once. Changing `CentralSystemURI` discards transactions that were not yet sent to the previous backend. |

## Feature profiles

The configuration key `SupportedFeatureProfiles` reports
`Core,FirmwareManagement,LocalAuthListManagement`.

| Profile | Support |
| --- | --- |
| Core | Supported, limits below. |
| Firmware Management | Supported. |
| Local Auth List Management | Supported, full updates only. |
| Reservation | Not supported. `ReserveNow` is answered with `Rejected`. |
| Smart Charging | Not reported. `SetChargingProfile` is accepted in a limited form, see below. |
| Remote Trigger | Not reported. `TriggerMessage` works for some messages, see below. |

The extensions of the OCPP 1.6 Security Whitepaper (signed firmware update,
certificate management, security events, `GetLog`) are not implemented.

While a restart is pending (after `Reset` or a firmware installation) the
station answers most requests with a `CALLERROR` `GenericError`.

## Messages

### Core

| Message | Direction | Notes |
| --- | --- | --- |
| `Authorize` | Station → backend | Sent for cards that are not authorized locally, while online. |
| `BootNotification` | Station → backend | After `Pending` or `Rejected` the station retries after the `interval` from the answer. |
| `ChangeAvailability` | Backend → station | Connector `0` and `1`. `Inoperative` while the connector is `Preparing`, `Charging` or `Finishing` is answered with `Scheduled` and applied when the vehicle is unplugged. Kept across a restart. |
| `ChangeConfiguration` | Backend → station | Keys see [Configuration keys](#configuration-keys). Unknown keys: `NotSupported`; read-only keys: `Rejected`. |
| `ClearCache` | Backend → station | `Accepted` if the authorization cache is enabled, otherwise `Rejected` (factory setting). |
| `DataTransfer` | Both | Vendor-specific. A `DataTransfer` from the backend with an unknown `vendorId` is answered with `UnknownMessageId`. On calibration-law stations the station sends the meter's public key after `BootNotification` (`vendorId` `generalConfiguration`, `messageId` `setMeterConfiguration`); this can be switched off with `sendMeterPublicKeyOnBootNotification`. |
| `GetConfiguration` | Backend → station | All keys or the requested ones; unknown keys in `unknownKey`. |
| `Heartbeat` | Station → backend | When no other message was sent for `HeartbeatInterval` seconds. |
| `MeterValues` | Station → backend | Only during a transaction, always with `transactionId`. Not stored while offline. |
| `RemoteStartTransaction` | Backend → station | Connector `1`. A `chargingProfile` in the request is ignored. The vehicle has to be plugged in within `ConnectionTimeOut`. `Rejected` if the station is not registered, the connector is not `Available`, `Preparing` or `Finishing` (for example `Faulted`), the meter is not ready, a storage fault is active, 336 transactions are waiting to be sent, another authorization is pending, or the clock is unset on a calibration-law station. |
| `RemoteStopTransaction` | Backend → station | Stops with `reason` = `Remote`. `Rejected` if the `transactionId` is unknown or the station or connector is `Unavailable`. |
| `Reset` | Backend → station | `Soft` and `Hard` both stop a running transaction and restart the whole station after about 10 seconds. `Rejected` during a firmware update. |
| `StartTransaction` | Station → backend | Stored on the station before it is sent and sent again after a connection loss. |
| `StatusNotification` | Station → backend | `Available`, `Preparing`, `Charging`, `Finishing`, `Unavailable`, `Faulted`. `SuspendedEV` and `SuspendedEVSE` are not used: a paused session stays `Charging`. Notifications for connector 0 and 1 are sent at most once every 10 seconds together and carry the status at that moment, so a status that lasts shorter can be skipped. Identical notifications are not repeated, except after a reconnect. |
| `StopTransaction` | Station → backend | Reasons `EmergencyStop`, `EVDisconnected`, `HardReset`, `SoftReset`, `Local`, `PowerLoss`, `Remote`, `UnlockCommand`, `DeAuthorized`, `Other`. `idTag` is not sent. |
| `UnlockConnector` | Backend → station | Socket variants only; on stations with a fixed cable the answer is `NotSupported`. A running transaction is stopped (`reason` = `UnlockCommand`). The answer is sent once the lock has opened (`Unlocked`) or after 20 seconds (`UnlockFailed`); the backend's response timeout must be longer than 20 seconds. |

### Firmware Management

| Message | Direction | Notes |
| --- | --- | --- |
| `UpdateFirmware` | Backend → station | `location` (HTTP or HTTPS URL of the firmware file), `retrieveDate`, `retries` and `retryInterval`. The download starts at `retrieveDate` while the station is connected. The station installs the file and restarts. A second `UpdateFirmware` during a running update is acknowledged and ignored. |
| `FirmwareStatusNotification` | Station → backend | `Downloading`, `Downloaded`, `DownloadFailed`, `Installing`, `InstallationFailed`, `Installed` (after the restart). |
| `GetDiagnostics` | Backend → station | Uploads a log archive (`.tar.gz`) by FTP, FTPS, HTTP or HTTPS. With HTTP(S) the file is sent as `POST` to `<location>/<fileName>`. `startTime` and `stopTime` are ignored. |
| `DiagnosticsStatusNotification` | Station → backend | `Uploading`, `Uploaded`, `UploadFailed`. |

### Local Auth List Management

| Message | Direction | Notes |
| --- | --- | --- |
| `GetLocalListVersion` | Backend → station | `-1` while `LocalAuthListEnabled` is `false`. |
| `SendLocalList` | Backend → station | `updateType` `Full` only; `Differential` is answered with `NotSupported`, as is any update while `LocalAuthListEnabled` is `false`. Up to 10,000 entries. |

### Smart Charging (limited, not reported)

| Message | Direction | Notes |
| --- | --- | --- |
| `SetChargingProfile` | Backend → station | Accepted only with `chargingProfilePurpose` `ChargePointMaxProfile` (connector `0`) or `TxProfile`, `chargingProfileKind` `Relative`, `chargingRateUnit` `A`, `stackLevel` `0` and exactly one schedule period with `startPeriod` `0`, without `duration` and `minChargingRate`. Other profiles are answered with `NotSupported`. A `ChargePointMaxProfile` for connector `1` is `Rejected`, as is a `TxProfile` for a `transactionId` other than the running one. `ChargePointMaxProfile` is kept across a restart; `TxProfile` ends with the transaction. |
| `ClearChargingProfile` | Backend → station | By connector, profile ID or purpose. `Unknown` if no profile matches. |
| `GetCompositeSchedule` | Backend → station | Not supported (`Rejected`). |

### Remote Trigger (partial, not reported)

`TriggerMessage` is accepted for `BootNotification`, `Heartbeat` and
`StatusNotification`. `MeterValues`, `DiagnosticsStatusNotification` and
`FirmwareStatusNotification` are answered with `NotImplemented`.

## Configuration keys

The *Factory setting* column shows the values of a station on firmware 2.5.0
as delivered. Keys marked *restart* are stored at once and answered with
`RebootRequired`; they take effect after the next restart.

:::note
A firmware update sets `MeterValuesSampledData` back to the factory list.
Saving the settings in the web UI sets both `LocalAuthListEnabled` and
`LocalAuthorizeOffline` to the value of the *Offline Authentication*
option, including values set by the backend. Stations updated from older
firmware keep their previous values.
:::

| Key | Access | Factory setting | Takes effect |
| --- | --- | --- | --- |
| `AllowOfflineTxForUnknownId` | read/write | `false` | immediately |
| `AuthorizationCacheEnabled` | read/write | `false` | restart |
| `AuthorizeRemoteTxRequests` | read/write | `false` | immediately |
| `ClockAlignedDataInterval` | read/write | `0` | restart |
| `ConnectionTimeOut` | read/write | `60` | immediately |
| `HeartbeatInterval` | read/write | from `BootNotification` (600 before) | immediately, not stored; values up to `2` are rejected |
| `LocalAuthListEnabled` | read/write | `false` | restart |
| `LocalAuthorizeOffline` | read/write | `false` | immediately |
| `LocalPreAuthorize` | read/write | `false` | immediately |
| `MeterValuesAlignedData` | read/write | empty | restart |
| `MeterValuesSampledData` | read/write | `Energy.Active.Import.Register`, `Power.Active.Import`, `Power.Active.Import.L1`–`L3`, `Current.Import.L1`–`L3`, `Voltage.L1-N`–`L3-N` | next transaction |
| `MeterValueSampleInterval` | read/write | `60` | next transaction |
| `StopTransactionOnInvalidId` | read/write | `true` | immediately |
| `StopTxnAlignedData` | read/write | empty | next transaction |
| `StopTxnSampledData` | read/write | empty | next transaction |
| `TransactionMessageAttempts` | read/write | `3` | restart |
| `TransactionMessageRetryInterval` | read/write | `30` | restart |
| `WebSocketPingInterval` | read/write | `10` | immediately |
| `CentralSystemURI` | read/write | as configured | restart; rejected during a transaction |
| `ChargeProfileMaxStackLevel` | read only | `0` | |
| `ChargingScheduleAllowedChargingRateUnit` | read only | `Current` | |
| `ChargingScheduleMaxPeriods` | read only | `1` | |
| `ConnectorPhaseRotation` | read only | `Unknown` | |
| `GetConfigurationMaxKeys` | read only | `10` | |
| `LocalAuthListMaxLength` | read only | `10000` | |
| `MaxChargingProfilesInstalled` | read only | `2` | |
| `MeterValuesAlignedDataMaxLength` | read only | `27` | |
| `MeterValuesSampledDataMaxLength` | read only | `27` | |
| `NumberOfConnectors` | read only | `1` | |
| `ResetRetries` | read only | `0` | |
| `SendLocalListMaxLength` | read only | `10000` | |
| `StopTransactionOnEVSideDisconnect` | read only | `true` | |
| `StopTxnAlignedDataMaxLength` | read only | `27` | |
| `StopTxnSampledDataMaxLength` | read only | `27` | |
| `SupportedFeatureProfiles` | read only | see above | |
| `SupportedFileTransferProtocols` | read only | `FTP,FTPS,HTTP,HTTPS` | |
| `UnlockConnectorOnEVSideDisconnect` | read only | `true` | |

Vendor-specific keys:

| Key | Access | Factory setting | Meaning |
| --- | --- | --- | --- |
| `rfidStopTransaction` | read/write | `false` | `true`: the card that started a session can stop it at the station. Takes effect after a restart. |
| `rfidRequiresEvPresent` | read/write | `true` | `true`: cards are only read while a vehicle is plugged in. Takes effect after a restart. |
| `useAsTimeSource` | read/write | `true` | Set the clock from `BootNotification` and `Heartbeat`. |
| `allowTxWithInvalidTime` | read/write | `true` | Allow transactions before the clock is set (never on calibration-law stations). |
| `allowLocalChargingAlways` | read/write | `false` | `true`: every card is accepted locally, the answer to `StartTransaction` is ignored and `RemoteStartTransaction` is always `Rejected`. |
| `bootNotificationOnReconnect` | read/write | `false` | Send `BootNotification` after every reconnect. |
| `webSocketPingTimeout` | read/write | `120` | Seconds without a WebSocket pong before the connection is re-established. |
| `forwardCredentials` | read/write | empty | Host for which the Basic Auth credentials are also used for firmware and diagnostics URLs. |
| `ftpTryTLSUpgrade` | read/write | `false` | Try explicit FTPS for diagnostics uploads. |
| `calibrationLawFormat` | read/write | empty | Format of the signed meter values: empty, `OCMF,plain` or `OCMF,hex`. |
| `sendMeterPublicKeyOnBootNotification` | read/write | `true` | Send the meter's public key by `DataTransfer` after `BootNotification`. |
| `StopTransactionSignatureFormat` | read only | `MR` | Signed meter values: start and end in one OCMF data set. |
| `Meter1PublicKey` | read only | from the meter | Public key of the calibration-law meter. |
| `vendorId` | read only | `com.in-tech.smartcharging` | `vendorId` of the station for `DataTransfer` and `StatusNotification`. |

## Authorization

- While online, cards known locally (authorization cache or local list)
  start charging at once if `LocalPreAuthorize` is `true`; all other cards
  are checked with `Authorize`.
- Offline, cards from the cache or the local list are accepted only if
  `LocalAuthorizeOffline` is `true`. If it is `false`, every card counts as
  unknown, and unknown cards are accepted only if
  `AllowOfflineTxForUnknownId` is `true`.
- A card stops a running session at the station only if
  `rfidStopTransaction` is `true`, and only the card that started it.
- If the backend answers `StartTransaction` with a status other than
  `Accepted`, or with an `expiryDate` in the past, the station stops the
  session (`reason` = `DeAuthorized`). Keep `StopTransactionOnInvalidId` at
  `true`: with `false` charging is stopped as well, but no `StopTransaction`
  is sent, so the transaction stays open in the backend.

## Connection loss and power loss

- **Connection loss.** Charging continues. `StartTransaction` and
  `StopTransaction` are stored on the station and sent once the connection
  is back; a transaction started offline receives its `transactionId` then.
  Up to 336 transactions are stored; when that many are waiting, no new
  transaction starts until the connection is back. `MeterValues`,
  `StatusNotification`, `Heartbeat` and status notifications for firmware
  and diagnostics are not stored. After reconnecting the station sends the
  current status of connector 0 and 1.
- **Power loss.** A transaction that was running when the power failed is
  ended after the restart with `reason` = `PowerLoss`; `meterStop` and
  `timestamp` are taken after the restart. The vehicle has to be authorized
  again. The same applies to any restart that was not requested by `Reset`.
- **Firmware update.** After a successful installation the station restarts
  at once; a running transaction is then ended with `reason` = `PowerLoss`.
  Schedule updates outside charging sessions.

## Signed meter values

On calibration-law (Eichrecht) stations `StopTransaction` carries the
signed meter values in `transactionData`: a sampled value with context
`Transaction.End` and format `SignedData` holding the OCMF data set with
start and end of the transaction. The meter's public key is available in
`Meter1PublicKey`.

## Products

The OCPP implementation is the same on all charging stations with the Salia
controller.
