Remote Control Flows - CSMS Developer Guide
Based on OCPP 2.1 Edition 2 Specification (Part 2), Section F (Remote Control). This guide covers all remote control flows (F01–F07), including remote start/stop transactions, unlock connector, trigger messages, and transaction limits from the CSMS perspective using OCPP-J (JSON over WebSocket).
1. Overview
IntroductionThe Remote Control functional block covers three categories of CSMS-initiated operations. These allow the CSMS to remotely start and stop charging transactions, unlock connectors, and trigger specific messages from Charging Stations.
Remote Transaction Control
F01 — Cable Plugin First
Remote start when the cable is already plugged in. CSMS sends RequestStartTransactionRequest after the CS reports a cable connection.
F02 — Remote Start First
Remote start sent before the cable is plugged in. The CS creates a transaction and waits
for the EV driver to connect within EVConnectionTimeOut.
F03 — Remote Stop
Stop an active transaction remotely via RequestStopTransactionRequest. The CS stops energy transfer and ends the transaction.
F07 — Start with Limits
Remote start with fixed cost, energy, SoC, or time limits. The CSMS includes transactionLimit in the TransactionEventResponse.
Unlock Connector
F05 — Remotely Unlock Connector
Remotely unlock a connector to help EV drivers unplug cables. CSMS sends UnlockConnectorRequest. Only unlocks the cable retention lock, NOT connector access doors.
Remote Trigger
F06 — Trigger Message
Request a Charging Station to send a specific CS-initiated message on demand via TriggerMessageRequest. Supports triggering heartbeats, meter values, status notifications, transaction events,
and more.
Message Direction Summary
| Flow | CSMS Sends (to CS) | CSMS Receives (from CS) |
|---|---|---|
F01/F02 | RequestStartTransactionRequest | RequestStartTransactionResponse |
F01/F02 | — | TransactionEventRequest (multiple) |
F01/F02 | TransactionEventResponse | — |
F03/F04 | RequestStopTransactionRequest | RequestStopTransactionResponse |
F03/F04 | — | TransactionEventRequest (multiple) |
F03/F04 | TransactionEventResponse | — |
F05 | UnlockConnectorRequest | UnlockConnectorResponse |
F06 | TriggerMessageRequest | TriggerMessageResponse |
F07 | RequestStartTransactionRequest | RequestStartTransactionResponse |
F07 | TransactionEventResponse (with limits) | TransactionEventRequest |
2. Common Data Types & Schemas
ReferenceIdTokenType
{
"idToken": "string (max 255, case-insensitive)",
"type": "string (max 20)",
"additionalInfo": [
{
"additionalIdToken": "string (max 255)",
"type": "string (max 50)"
}
]
}Common type values (IdTokenEnumStringType):
| Type | Description |
|---|---|
Central | Server-generated token for CSMS-initiated transactions. CS will skip local authorization. |
eMAID | Electro-Mobility Account Identifier (ISO 15118 Plug & Charge) |
ISO14443 | RFID UID per ISO 14443 (most common physical RFID) |
ISO15693 | RFID UID per ISO 15693 |
KeyCode | PIN-code entered by user |
Local | Locally generated identifier (e.g., parking ticket) |
MacAddress | MAC address based identifier |
NoAuthorization | No authorization needed — anyone can stop the transaction if CS supports local stop |
OCPP2WhiteList | OCPP 2.0 whitelist token |
StatusInfoType
{
"reasonCode": "string (max 20, case-insensitive, REQUIRED)",
"additionalInfo": "string (max 1024)"
}EVSEType
{
"id": "integer (>= 0, REQUIRED)",
"connectorId": "integer (>= 0)"
}ChargingProfileType (for RequestStartTransaction)
When including a ChargingProfile in RequestStartTransactionRequest:
{
"id": 1,
"stackLevel": 0,
"chargingProfilePurpose": "TxProfile",
"chargingProfileKind": "Relative",
"chargingSchedule": [
{
"id": 1,
"chargingRateUnit": "W",
"chargingSchedulePeriod": [
{
"startPeriod": 0,
"limit": 11000,
"numberPhases": 3
}
]
}
]
}Constraints for Remote Start:
chargingProfilePurposeMUST be"TxProfile"transactionIdMUST NOT be set (unknown at request time)chargingProfileKind:"Absolute","Recurring","Relative", or"Dynamic"chargingRateUnit:"W"(Watts) or"A"(Amps)
| Field | Type | Required | Description |
|---|---|---|---|
startPeriod | integer | Yes | Start in seconds from schedule start |
limit | number | Conditional | Charging rate limit in the applicable unit |
numberPhases | integer (0-3) | No | Number of phases. Default 3 for AC, omit for DC. |
phaseToUse | integer (1-3) | No | Specific phase, only when numberPhases=1 |
TransactionEventRequest Key Fields (Incoming to CSMS)
Direction: Charging Station → CSMS
| Field | Type | Required | Description |
|---|---|---|---|
eventType | enum | Yes | "Started", "Updated", or "Ended" |
timestamp | dateTime | Yes | When the event occurred |
triggerReason | TriggerReasonEnum | Yes | Why the event was triggered |
seqNo | integer (>= 0) | Yes | Sequence number for ordering |
transactionInfo | TransactionType | Yes | Transaction details |
meterValue | MeterValueType[] | No | Meter readings |
evse | EVSEType | No | EVSE where transaction is happening |
idToken | IdTokenType | No | The token associated with the transaction |
offline | boolean | No | true if event occurred while CS was offline. Default: false |
numberOfPhasesUsed | integer (0-3) | No | Phases used |
cableMaxCurrent | integer | No | Max current of connected cable in Amps |
reservationId | integer | No | Reservation ID if transaction ends a reservation |
costDetails | CostDetailsType | No | Cost breakdown calculated by CS |
TransactionType (inside TransactionEventRequest)
| Field | Type | Required | Description |
|---|---|---|---|
transactionId | string (max 36) | Yes | Unique transaction identifier |
chargingState | enum | No | "EVConnected", "Charging", "SuspendedEV", "SuspendedEVSE", "Idle" |
timeSpentCharging | integer | No | Seconds of actual energy transfer |
stoppedReason | ReasonEnumType | No | Why the transaction stopped (only on Ended) |
remoteStartId | integer | No | Matches the remoteStartId from RequestStartTransactionRequest |
operationMode | OperationModeEnum | No | Current operation mode |
transactionLimit | TransactionLimitType | No | Echoed-back transaction limit from CSMS |
TriggerReasonEnumType Values (Relevant to Remote Control)
| Value | When Used |
|---|---|
RemoteStart | Transaction event triggered by a RequestStartTransactionRequest |
RemoteStop | Energy transfer stopped by RequestStopTransactionRequest |
Trigger | Message triggered by TriggerMessageRequest |
CablePluggedIn | Cable was plugged in |
ChargingStateChanged | Charging state changed |
EVConnectTimeout | EV didn't connect within timeout (F02) |
Authorized | Authorization was obtained |
Deauthorized | Authorization was revoked |
ReasonEnumType (stoppedReason) Values
| Value | When Used |
|---|---|
Remote | Transaction stopped by CSMS via RequestStopTransactionRequest |
Timeout | EV connection timeout (F02 scenario) |
DeAuthorized | CSMS revoked authorization |
Local | Local stop by user |
EnergyLimitReached | Energy limit from transactionLimit reached (F07) |
TimeLimitReached | Time limit reached (F07) |
SOCLimitReached | SoC limit reached (F07) |
LocalOutOfCredit | Local cost limit reached (F07) |
3. F01 — Remote Start Transaction (Cable Plugin First)
CSMS-Initiated| Use Case ID | F01 |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | External trigger (e.g. mobile app, CSO operator panel, EV Driver app) |
| Precondition | Charging cable is already plugged in at the Charging Station |
| OCPP Messages | RequestStartTransactionRequest / RequestStartTransactionResponse, TransactionEventRequest / TransactionEventResponse |
Sequence Flow (CSMS Perspective)
EV Driver Charging Station CSMS
| | |
|--- Plugin cable ------>| |
| |-- NotifyEventRequest -------->| (1)
| |<- NotifyEventResponse --------| (2)
| |-- TransactionEventRequest --->| (3) eventType=Started
| |<- TransactionEventResponse ---| (4)
| | |
| | remote start trigger
| |<- RequestStartTransactionReq -| (5) CSMS SENDS
| |-- RequestStartTransactionRes->| (6) CSMS RECEIVES
| | |
| | Match remoteStartId
| | with transactionId
| | |
| |-- TransactionEventRequest --->| (7) eventType=Updated,
| |<- TransactionEventResponse ---| (8) chargingState=ChargingStep-by-Step CSMS Implementation
Step 1: Handle incoming NotifyEventRequest
The Charging Station notifies that a connector became Occupied (cable plugged in).
CSMS Action: Respond with NotifyEventResponse (empty acknowledgment). Track the connector state internally.
Step 2: Handle incoming TransactionEventRequest (eventType = Started)
The Charging Station reports a new transaction has started (even before driver is known).
Incoming payload key fields:
eventType | "Started" |
triggerReason | "CablePluggedIn" |
transactionInfo.transactionId | The CS-generated transaction ID (string, max 36 chars) |
transactionInfo.chargingState | "EVConnected" |
evse.id | EVSE identifier |
evse.connectorId | Connector identifier |
CSMS Action: Respond with TransactionEventResponse. Store the transactionId for later matching.
Step 3: Send RequestStartTransactionRequest
When an external trigger initiates a remote start, the CSMS sends this message to the Charging Station.
{
"remoteStartId": 123,
"idToken": {
"idToken": "ABCD1234",
"type": "ISO14443"
},
"evseId": 1,
"groupIdToken": { ... },
"chargingProfile": { ... }
}| Field | Type | Required | Description |
|---|---|---|---|
remoteStartId | integer | Yes | Unique ID assigned by CSMS. Used to correlate with subsequent TransactionEventRequest messages. |
idToken | IdTokenType | Yes | The token to use for this transaction. |
evseId | integer (>= 1) | No | Target EVSE. If omitted, the Charging Station selects one. |
groupIdToken | IdTokenType | No | Group token for group reservation matching. |
chargingProfile | ChargingProfileType | No | Optional charging profile for smart charging. chargingProfilePurpose MUST be TxProfile and transactionId MUST NOT be set. |
Important Rules for CSMS
idToken.type = "NoAuthorization"is allowed — but anyone can stop the transaction if CS supports local stopidToken.type = "Central"is allowed — CS will skip local authorization- When
AuthorizeRemoteStart = falseORidToken.typeisCentralorNoAuthorization, the CS will start without checking authorization - If a
chargingProfileis included,chargingProfilePurposeMUST be"TxProfile" transactionIdin the ChargingProfile MUST NOT be set (the CS doesn't know it yet)
Step 5: Handle subsequent TransactionEventRequest messages
After accepting the remote start, the CS will send TransactionEventRequest with:
triggerReason:"RemoteStart"transactionInfo.remoteStartId: matching theremoteStartIdyou senteventType:"Updated"transactionInfo.chargingState:"Charging"(when energy transfer begins)
CSMS Action: Match remoteStartId to correlate this transaction event with your original request. Respond with TransactionEventResponse.
Step 6: Handle AuthorizeRequest (if AuthorizeRemoteStart = true)
If the CS is configured with AuthorizeRemoteStart = true, it will send an AuthorizeRequest with the idToken you provided.
CSMS Action: Validate the token and respond with AuthorizeResponse containing idTokenInfo.status = "Accepted" (or reject).
Handle RequestStartTransactionResponse
{
"status": "Accepted",
"transactionId": "AB1234",
"statusInfo": {
"reasonCode": "...",
"additionalInfo": "..."
}
}| Field | Type | Required | Description |
|---|---|---|---|
status | enum | Yes | "Accepted" or "Rejected" |
transactionId | string (max 36) | No | Present when a transaction was already started before this request (cable-plugin-first scenario). |
statusInfo | StatusInfoType | No | Additional info about rejection. |
IF status == "Accepted":
IF transactionId is present:
// Cable was plugged in first - transaction already exists
// Match this remoteStartId with the returned transactionId
store_mapping(remoteStartId, transactionId)
ELSE:
// Wait for TransactionEventRequest(Started) with this remoteStartId
mark_pending(remoteStartId)
IF status == "Rejected":
// Start was rejected
IF statusInfo.reasonCode == "InvalidProfile":
log("ChargingProfile was invalid")
ELSE IF statusInfo.reasonCode == "InvalidSchedule":
log("ChargingSchedule was invalid")
notify_external_trigger(FAILED)Rejection Reasons (per requirements)
- EVSE reserved for a different idToken (F01.FR.21, F01.FR.22)
- EVSE is
UnavailableorFaulted(F01.FR.23) - EVSE is
Occupiedwith an authorized transaction (F01.FR.24) - Invalid ChargingProfile on a smart-charging-capable CS (F01.FR.26) —
reasonCode = "InvalidProfile"or"InvalidSchedule"
TransactionEventResponse Schema (CSMS sends)
All fields are optional. The CSMS responds to every TransactionEventRequest:
{
"totalCost": 12.50,
"chargingPriority": 0,
"idTokenInfo": {
"status": "Accepted",
"cacheExpiryDateTime": "2025-12-31T23:59:59Z",
"chargingPriority": 0,
"groupIdToken": { ... },
"language1": "en",
"evseId": [1, 2],
"personalMessage": {
"format": "UTF8",
"content": "Welcome!"
}
},
"transactionLimit": {
"maxCost": 50.00,
"maxEnergy": 30000,
"maxTime": 7200,
"maxSoC": 80
},
"updatedPersonalMessage": {
"format": "UTF8",
"content": "Updated message"
}
}| Field | Type | Description |
|---|---|---|
totalCost | number | Running cost (for Updated) or final cost (for Ended). Send 0.00 to indicate free. Absence does NOT mean free. |
chargingPriority | integer (-9 to 9) | Temporary priority override. Higher = higher priority. Default 0. |
idTokenInfo | IdTokenInfoType | Authorization status of the idToken. |
transactionLimit | TransactionLimitType | Cost/energy/time/SoC limits for the transaction. |
updatedPersonalMessage | MessageContentType | Updated message for display. |
| IdTokenInfo Status | Meaning |
|---|---|
Accepted | Token is valid, allow charging |
Blocked | Token is blocked |
ConcurrentTx | Token already has active transaction |
Expired | Token has expired |
Invalid | Token is unknown/invalid |
NoCredit | No credit remaining |
NotAllowedTypeEVSE | Token not allowed on this EVSE type |
NotAtThisLocation | Token not valid at this location |
NotAtThisTime | Token not valid at this time |
Unknown | Token status unknown (offline) |
4. F02 — Remote Start Transaction (Remote Start First)
CSMS-Initiated| Use Case ID | F02 |
| Parent | F01 (same RequestStartTransactionRequest message) |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | External trigger — remote start is sent BEFORE the cable is plugged in |
| Precondition | Charging cable NOT plugged in. Remote start is sent first. |
Sequence Flow (CSMS Perspective) — TxStartPoint=Authorized
External Trigger CSMS Charging Station
| | |
|-- remote start ---->| |
| |-- RequestStartTransactionReq ->| (1) CSMS SENDS
| |<- RequestStartTransactionRes --| (2) status=Accepted
| [opt: notification]| |
| | |
| | [opt: AuthorizeRequest if AuthorizeRemoteStart=true]
| |<- AuthorizeRequest ------------| (3)
| |-- AuthorizeResponse ---------->| (4)
| | |
| |<- TransactionEventRequest -----| (5) eventType=Started
| | triggerReason=RemoteStart | remoteStartId=123
| |-- TransactionEventResponse --->| (6)
| | |
| | [alt: within ConnectionTimeOut]
| | EV Driver plugs in cable |
| |<- NotifyEventRequest ----------| (7)
| |-- NotifyEventResponse -------->| (8)
| |<- TransactionEventRequest -----| (9) Updated, EVConnected
| |-- TransactionEventResponse --->| (10)
| |<- TransactionEventRequest -----| (11) Updated, Charging
| |-- TransactionEventResponse --->| (12)
| | |
| | [alt: NOT within ConnectionTimeOut]
| |<- TransactionEventRequest -----| (13) Ended, Timeout
| |-- TransactionEventResponse --->| (14)Key Differences from F01
No Pre-existing Transaction
The RequestStartTransactionResponse will NOT contain a transactionId (since no cable was plugged in yet).
Transaction Starts After Remote Command
The CS creates the transaction upon accepting the RequestStartTransactionRequest.
Connection Timeout
If the EV driver doesn't plug in within EVConnectionTimeOut, the transaction ends with stoppedReason = "Timeout" and triggerReason = "EVConnectTimeout".
Trigger Reason
triggerReason in TransactionEventRequest will be "RemoteStart" (NOT "CablePluggedIn" or "Authorized"), even if TxStartPoint = EVConnected.
CSMS Implementation Details
The RequestStartTransactionRequest payload is identical to F01. The key difference is in how you handle responses:
SEND RequestStartTransactionRequest(remoteStartId, idToken, [evseId], [chargingProfile])
ON RequestStartTransactionResponse:
IF status == "Accepted":
// Transaction will be created by CS
// Wait for TransactionEventRequest with remoteStartId matching
start_timeout_timer(EVConnectionTimeOut)
IF status == "Rejected":
handle_rejection()
ON TransactionEventRequest(eventType=Started, remoteStartId=123):
// Transaction has been created
store_transaction(transactionInfo.transactionId, remoteStartId)
// Respond with TransactionEventResponse
ON TransactionEventRequest(eventType=Updated, chargingState=EVConnected):
// Cable plugged in - charging will start soon
cancel_timeout_timer()
ON TransactionEventRequest(eventType=Updated, chargingState=Charging):
// Energy transfer started
ON TransactionEventRequest(eventType=Ended, stoppedReason=Timeout):
// EV was not connected in time
clean_up_transaction()Connection Timeout Behavior
| TxStopPoint Configuration | Timeout Behavior |
|---|---|
Does NOT contain ParkingBayOccupancy | CS ends transaction, sends TransactionEventRequest(Ended, stoppedReason=Timeout, triggerReason=EVConnectTimeout) |
Contains ParkingBayOccupancy | CS deauthorizes transaction, sends TransactionEventRequest(triggerReason=EVConnectionTimeout) — transaction ends normally when driver leaves |
Recommendations for Remote Start First
- It is advised to include
evseIdto avoid uncertainty about which EVSE is activated (especially for Logic Controllers with many EVSEs) - Always track
remoteStartIdto correlate with subsequentTransactionEventRequestmessages - Implement a timeout mechanism matching the CS's
EVConnectionTimeOutsetting
5. F03 — Remote Stop Transaction
CSMS-Initiated| Use Case ID | F03 |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | External trigger (e.g. mobile app termination, prepaid credit exceeded, CSO action) |
| Precondition | An active transaction exists |
| OCPP Messages | RequestStopTransactionRequest / RequestStopTransactionResponse, TransactionEventRequest / TransactionEventResponse |
Sequence Flow (CSMS Perspective)
External Trigger CSMS Charging Station
| | |
|-- remote stop ----->| |
| |-- RequestStopTransactionReq -->| (1) CSMS SENDS
| |<- RequestStopTransactionRes ---| (2) CSMS RECEIVES
| [opt: notification]| |
| | | stop energy offer
| | | unlock connector
| | |
| |<- TransactionEventRequest -----| (3) Updated,
| | triggerReason=RemoteStop | chargingState=EVConnected
| |-- TransactionEventResponse --->| (4)
| | |
| [opt: notification]| |
| | | EV Driver unplugs cable
| |<- NotifyEventRequest ----------| (5)
| |-- NotifyEventResponse -------->| (6)
| |<- TransactionEventRequest -----| (7) Ended,
| | stoppedReason=Remote |
| |-- TransactionEventResponse --->| (8)Sending RequestStopTransactionRequest
Direction: CSMS → Charging Station
{
"transactionId": "AB1234-5678-90EF"
}| Field | Type | Required | Max Length | Description |
|---|---|---|---|---|
transactionId | string | Yes | 36 | The ID of the transaction to stop. Must match a currently active transaction on the CS. |
Handling RequestStopTransactionResponse
Direction: Charging Station → CSMS
{
"status": "Accepted",
"statusInfo": {
"reasonCode": "...",
"additionalInfo": "..."
}
}| Field | Type | Required | Description |
|---|---|---|---|
status | enum | Yes | "Accepted" or "Rejected" |
statusInfo | StatusInfoType | No | Additional details about rejection |
IF status == "Accepted":
// Transaction will be stopped
// Wait for TransactionEventRequest(eventType=Updated, triggerReason=RemoteStop)
// Then wait for TransactionEventRequest(eventType=Ended, stoppedReason=Remote)
IF status == "Rejected":
// TransactionId could not be matched to an active transaction (F03.FR.08)
log_error("Transaction not found or cannot be stopped")
notify_external_trigger(FAILED)Handling Subsequent TransactionEventRequest Messages
After accepting the stop, the CS sends the following events:
Event 1 — Energy Stopped (Updated)
eventType | "Updated" |
triggerReason | "RemoteStop" |
transactionInfo.chargingState | "EVConnected" (energy stopped, cable still connected) |
Event 2 — Transaction Ended (Ended)
eventType | "Ended" |
stoppedReason | "Remote" |
meterValue | Includes final meter values |
CSMS must respond to each TransactionEventRequest with TransactionEventResponse. For the Ended event, include totalCost with the final cost.
TxStopPoint Impact on Behavior
| TxStopPoint | Effect on Remote Stop |
|---|---|
NOT Authorized or PowerPathClosed (e.g. EVConnected) | CS stops energy offer, sends Updated with triggerReason=RemoteStop. Transaction does NOT end until EV disconnects. |
Authorized or PowerPathClosed | CS sends TransactionEventRequest(Ended, triggerReason=RemoteStop, stoppedReason=Remote) immediately. |
Meter Data in Final TransactionEventRequest
When the transaction ends, the CS should include final meter values. The CSMS should validate the final meter readings, calculate final cost, and send totalCost in the TransactionEventResponse for the Ended event.
6. F04 — Remote Stop ISO 15118 Charging from CSMS
CSMS-Initiated| Use Case ID | F04 |
| Direction | CSMS → CS (same as F03) |
| Trigger | Same as F03 — external trigger for remote stop |
| Difference | The Charging Station is using ISO 15118-2 or ISO 15118-20 for communication with the EV |
CSMS Implementation
From the CSMS perspective, F04 is identical to F03. The CSMS sends the same RequestStopTransactionRequest and handles the same responses. No additional ISO 15118-specific handling is needed at the CSMS level.
The differences are internal to the Charging Station:
ISO 15118-2
CS sends EVSENotification = StopCharging via ChargingStatusRes (AC) or CurrentDemandRes (DC)
ISO 15118-20
CS sends EVSENotification = Terminate via AC_ChargeLoopRes or DC_ChargeLoopRes
Sequence (CSMS sees the same as F03)
CSMS Charging Station EV
| | |
|-- RequestStopTransactionReq ------->| |
|<- RequestStopTransactionRes(Accepted)| |
| |-- [ISO 15118 stop] -->|
| | |
|<- TransactionEventReq(Updated) -----| (energy stopped) |
|-- TransactionEventRes ------------>| |
|<- TransactionEventReq(Ended) ------| (cable unplugged) |
|-- TransactionEventRes ------------>| |CSMS Action: Implement exactly as F03. No additional ISO 15118-specific handling is needed at the CSMS level.
7. F05 — Remotely Unlock Connector
CSMS-Initiated| Use Case ID | F05 |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | External trigger (e.g. driver reports stuck cable via app, CSO support action) |
| Precondition | No ongoing authorized transaction on the connector. The connector has a lock mechanism. |
| OCPP Messages | UnlockConnectorRequest / UnlockConnectorResponse |
Sequence Flow
External Trigger CSMS Charging Station
| | |
|-- unlock request -->| |
| |-- UnlockConnectorRequest ----->| (1) CSMS SENDS
| | | [attempts unlock]
| |<- UnlockConnectorResponse -----| (2) CSMS RECEIVES
| [opt: notification]| |Sending UnlockConnectorRequest
Direction: CSMS → Charging Station
{
"evseId": 1,
"connectorId": 1
}| Field | Type | Required | Description |
|---|---|---|---|
evseId | integer (>= 0) | Yes | EVSE identifier |
connectorId | integer (>= 0) | Yes | Connector identifier on the EVSE |
Note: UnlockConnectorRequest is intended ONLY for unlocking the cable retention lock on the connector, NOT for unlocking a connector access door.
Handling UnlockConnectorResponse
Direction: Charging Station → CSMS
{
"status": "Unlocked",
"statusInfo": {
"reasonCode": "...",
"additionalInfo": "..."
}
}| Status | Meaning | CSMS Action |
|---|---|---|
Unlocked | Connector was successfully unlocked | Notify trigger that unlock succeeded |
UnlockFailed | CS attempted but failed to unlock | Notify trigger of failure. May suggest manual intervention. |
OngoingAuthorizedTransaction | Cannot unlock — there's an authorized transaction on this connector | The CS will NOT unlock and will NOT stop the transaction. CSMS should stop the transaction first (F03), then retry unlock. |
UnknownConnector | The specified connector is not known to the CS | Check evseId/connectorId values and retry with correct values. |
Error Handling
- If the connector has no lock mechanism or has a manual lock (e.g. Type 1), the CS SHOULD respond with RPC Framework
CALLERROR: NotSupported - The CS will attempt to unlock even if no cable is connected, and returns the result of the attempt
Implementation Logic
FUNCTION unlock_connector(evseId, connectorId):
// Check if there's an active authorized transaction
IF has_active_authorized_transaction(evseId, connectorId):
// Must stop transaction first
send RequestStopTransactionRequest(transactionId)
wait_for_transaction_end()
send UnlockConnectorRequest(evseId, connectorId)
ON UnlockConnectorResponse:
SWITCH status:
CASE "Unlocked":
return SUCCESS
CASE "UnlockFailed":
return FAILURE("Mechanical unlock failed")
CASE "OngoingAuthorizedTransaction":
return FAILURE("Stop transaction first")
CASE "UnknownConnector":
return FAILURE("Invalid connector")8. F06 — Trigger Message
CSMS-Initiated| Use Case ID | F06 |
| Direction | CSMS → CS (CSMS initiates) |
| Objective | Request a Charging Station to send a specific CS-initiated message on demand |
| Precondition | The Functional Block "Remote Trigger" is installed on the CS |
| OCPP Messages | TriggerMessageRequest / TriggerMessageResponse |
Sequence Flow
CSMS Charging Station
| |
|-- TriggerMessageRequest ----------->| (1) CSMS SENDS
|<- TriggerMessageResponse -----------| (2) CSMS RECEIVES
| |
|<- [Requested Message] --------------| (3) CS sends the triggered message
|-- [Response to Requested Message] ->| (4) CSMS responds normallySending TriggerMessageRequest
Direction: CSMS → Charging Station
{
"requestedMessage": "TransactionEvent",
"evse": {
"id": 1,
"connectorId": 1
},
"customTrigger": "SomeCustomMessage"
}| Field | Type | Required | Description |
|---|---|---|---|
requestedMessage | MessageTriggerEnumType | Yes | The type of message to trigger |
evse | EVSEType | No | Target EVSE. If absent, interpreted as "all EVSEs". |
customTrigger | string (max 50) | No | Custom trigger name. Only used when requestedMessage = "CustomTrigger". |
EVSE Field Rules
- If
evseis omitted, the CS interprets it as "all applicable EVSEs" (F06.FR.11) - For
StatusNotification: CSMS MUST setconnectorIdin the EVSE field (F06.FR.13) — StatusNotification can only be requested at connector level - If the specified
evseIdis not relevant to the message type, the CS ignores it but still sends the message (F06.FR.03)
requestedMessage Enum Values
| Value | Triggered Message | Notes |
|---|---|---|
BootNotification | BootNotificationRequest | Only useful when the last BootNotification was NOT yet Accepted (F06.FR.17). CS will reject if already accepted. |
LogStatusNotification | LogStatusNotificationRequest | Returns current upload status: Uploading if uploading, Idle otherwise. |
FirmwareStatusNotification | FirmwareStatusNotificationRequest | Returns Idle if not performing firmware tasks. |
Heartbeat | HeartbeatRequest | Triggers an immediate heartbeat. |
MeterValues | MeterValuesRequest | Returns most recent measurements for measurands in AlignedDataMeasurands. |
SignChargingStationCertificate | SignCertificateRequest | Triggers CSR for Charging Station certificate. |
SignV2GCertificate | SignCertificateRequest | Triggers CSR for V2G certificate (ISO 15118-2). |
SignV2G20Certificate | SignCertificateRequest | Triggers CSR for V2G certificate (ISO 15118-20). |
StatusNotification | StatusNotificationRequest | Must include evse with connectorId. CS MAY reject if evse or connectorId is omitted (F06.FR.12). |
TransactionEvent | TransactionEventRequest | Sends with triggerReason=Trigger, includes transactionInfo, chargingState, and meter values per SampledDataTxUpdatedMeasurands. |
SignCombinedCertificate | SignCertificateRequest | Triggers CSR for combined certificate. |
PublishFirmwareStatusNotification | PublishFirmwareStatusNotificationRequest | Returns current publish firmware status. |
CustomTrigger | Custom message | Requires customTrigger field. Check CS's CustomizationCtrlr.CustomTriggers for supported values. |
Handling TriggerMessageResponse
Direction: Charging Station → CSMS
{
"status": "Accepted",
"statusInfo": {
"reasonCode": "...",
"additionalInfo": "..."
}
}| Status | Meaning | CSMS Action |
|---|---|---|
Accepted | CS will send the requested message | Wait for the triggered message to arrive. Note: the CS sends the TriggerMessageResponse FIRST, then the requested message. |
Rejected | CS refuses to send the message | Log and handle. Possible reasons: BootNotification already accepted, StatusNotification without connector, etc. |
NotImplemented | CS does not support this message type | The CS has not implemented this specific message. Do not retry. |
FUNCTION trigger_message(requestedMessage, evseId=None, connectorId=None, customTrigger=None):
request = { "requestedMessage": requestedMessage }
IF evseId is not None:
request["evse"] = { "id": evseId }
IF connectorId is not None:
request["evse"]["connectorId"] = connectorId
IF requestedMessage == "StatusNotification":
// MUST include connectorId
ASSERT connectorId is not None
IF requestedMessage == "CustomTrigger":
ASSERT customTrigger is not None
request["customTrigger"] = customTrigger
send TriggerMessageRequest(request)
ON TriggerMessageResponse:
IF status == "Accepted":
// Message will arrive shortly - handle it via normal message handlers
start_timeout(TRIGGER_RESPONSE_TIMEOUT)
ELSE IF status == "Rejected":
log("Trigger rejected")
ELSE IF status == "NotImplemented":
log("Message type not supported by this CS")Handling the Triggered Message
After receiving Accepted, the CSMS should expect the corresponding message via the normal message handler. The triggered messages are handled with the same response logic as when they arrive spontaneously.
Key Notes
- Triggered messages only provide current information, not historical data (F06.FR.09)
- If the same message arrives via normal operations between acceptance and the triggered send, it MAY count as fulfilling the trigger (F06.FR.10)
- For
TransactionEventtriggers: thetriggerReasonwill be"Trigger"in the incomingTransactionEventRequest
9. F07 — Remote Start with Fixed Cost, Energy, SoC or Time
CSMS-Initiated New in OCPP 2.1| Use Case ID | F07 |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | EV Driver or CSMS specifies a limit (cost, energy, SoC, or time) for the transaction |
| Use Case | Prepaid balance, ad-hoc payment reservation amount, energy/time limits |
| OCPP Messages | RequestStartTransactionRequest / RequestStartTransactionResponse, TransactionEventRequest / TransactionEventResponse (with transactionLimit) |
Sequence Flow
EV Driver CSMS Charging Station
| | |
|-- request start --->| |
| (with limits) | |
| |-- RequestStartTransactionReq ->| (1)
| |<- RequestStartTransactionRes --| (2) Accepted
| | |
| | [opt: AuthorizeRequest/Response]
| | |
| |<- TransactionEventReq ---------| (3) Started, remoteStartId=123
| |-- TransactionEventRes -------->| (4) WITH transactionLimit
| | |
| |<- TransactionEventReq ---------| (5) Updated,
| | transactionInfo | transactionLimit echoed back
| |-- TransactionEventRes -------->| (6)
| | |
| | [When limit reached] |
| |<- TransactionEventReq ---------| (7) Updated,
| | chargingState=SuspendedEVSE |
| |-- TransactionEventRes -------->| (8)Transaction Limits
When the CS sends the first TransactionEventRequest with eventType = "Started", the CSMS responds with a TransactionEventResponse that includes the transactionLimit:
{
"transactionLimit": {
"maxCost": 25.00,
"maxEnergy": 20000,
"maxTime": 3600,
"maxSoC": 80
}
}| Field | Type | Required | Description |
|---|---|---|---|
maxCost | number | No | Maximum cost in the currency of the tariff |
maxEnergy | number | No | Maximum energy in Wh |
maxTime | integer | No | Maximum duration in seconds (start to end) |
maxSoC | integer (0-100) | No | Maximum State of Charge percentage |
Rules
- At least one limit should be provided
- If multiple limits are given (e.g. both
maxTimeandmaxEnergy), whichever is reached first determines the end of energy transfer - For
maxCost, the CS must calculate cost locally to stop exactly on time
CSMS Implementation
Step 1: Send RequestStartTransactionRequest
Same as F01/F02. The request payload is identical — limits are NOT included in the start request.
Step 2: Include transactionLimit in TransactionEventResponse
When the CS sends the first TransactionEventRequest with eventType = "Started", include the transactionLimit in your response.
Step 3: CS echoes back the limit
The Charging Station will include the limit in the transactionInfo.transactionLimit field of the next TransactionEventRequest, confirming it received and applied the limit.
Step 4: When the limit is reached
The CS stops energy transfer and sends a TransactionEventRequest with chargingState = "SuspendedEVSE".
ON TransactionEventRequest(eventType=Started, remoteStartId=matching):
respond with TransactionEventResponse:
transactionLimit = {
maxCost: user_requested_cost_limit,
maxEnergy: user_requested_energy_limit,
maxTime: user_requested_time_limit,
maxSoC: user_requested_soc_limit
}
ON TransactionEventRequest(transactionInfo.transactionLimit is present):
// CS confirmed it received the limit
verify_limit_matches(expected_limit)
ON TransactionEventRequest(chargingState=SuspendedEVSE):
// Limit was reached - charging suspended
notify_user("Charging limit reached")10. Message Schema Quick Reference
ReferenceOutgoing from CSMS (CSMS → Charging Station)
| Message | Required Fields | Optional Fields | Use Cases |
|---|---|---|---|
RequestStartTransactionRequest | remoteStartId (int), idToken (IdTokenType) | evseId (int >=1), groupIdToken (IdTokenType), chargingProfile (ChargingProfileType) | F01, F02, F07 |
RequestStopTransactionRequest | transactionId (string max 36) | — | F03, F04 |
UnlockConnectorRequest | evseId (int >=0), connectorId (int >=0) | — | F05 |
TriggerMessageRequest | requestedMessage (MessageTriggerEnumType) | evse (EVSEType), customTrigger (string max 50) | F06 |
TransactionEventResponse | — (all fields optional) | totalCost, chargingPriority, idTokenInfo, transactionLimit, updatedPersonalMessage | F01–F07 |
Incoming to CSMS (Charging Station → CSMS)
| Message | Required Fields | Optional Fields | Use Cases |
|---|---|---|---|
RequestStartTransactionResponse | status (Accepted|Rejected) | transactionId (string max 36), statusInfo (StatusInfoType) | F01, F02, F07 |
RequestStopTransactionResponse | status (Accepted|Rejected) | statusInfo (StatusInfoType) | F03, F04 |
UnlockConnectorResponse | status (Unlocked|UnlockFailed|OngoingAuthorizedTransaction|UnknownConnector) | statusInfo (StatusInfoType) | F05 |
TriggerMessageResponse | status (Accepted|Rejected|NotImplemented) | statusInfo (StatusInfoType) | F06 |
TransactionEventRequest | eventType, timestamp, triggerReason, seqNo, transactionInfo | meterValue[], evse, idToken, offline, numberOfPhasesUsed, cableMaxCurrent, reservationId, costDetails | F01–F07 |