Availability Flows - CSMS Developer Guide
Based on OCPP 2.1 Edition 2 Specification (Part 2), Section G (Availability). This guide covers all availability flows (G01–G05), including connector status reporting, heartbeat, change availability for EVSEs/Connectors and Charging Stations, and lock failure handling from the CSMS perspective using OCPP-J (JSON over WebSocket).
1. Overview
IntroductionThe Availability functional block governs how a Charging Station communicates its operational status to the CSMS and how the CSMS can control the availability of Charging Stations, EVSEs, and Connectors.
Messages Involved
| Message | Direction | CSMS Role |
|---|---|---|
NotifyEventRequest / NotifyEventResponse | CS → CSMS | Receive request, send response |
StatusNotificationRequest / StatusNotificationResponse | CS → CSMS | Receive request, send response (deprecated) |
HeartbeatRequest / HeartbeatResponse | CS → CSMS | Receive request, send response |
ChangeAvailabilityRequest / ChangeAvailabilityResponse | CSMS → CS | Send request, receive response |
Component Hierarchy
Charging Station
└── EVSE (id >= 1)
└── Connector (connectorId >= 1)Important: Each level (Charging Station, EVSE, Connector) has independent availability state. Setting a Connector to Inoperative and then setting its parent EVSE back to Operative does not override the Connector-level setting — the Connector remains Inoperative.
2. Shared Data Types & Schemas
ReferenceNotifyEventRequest Schema
Direction: Charging Station → CSMS (preferred method for reporting status changes)
{
"generatedAt": "date-time", // REQUIRED - when message was generated at CS
"tbc": false, // OPTIONAL - true = more messages follow
"seqNo": 0, // REQUIRED - sequence number (starts at 0)
"eventData": [ // REQUIRED - array of EventDataType
{ ... }
]
}EventDataType Schema
Nested object within the eventData array.
{
"eventId": 0, // REQUIRED - integer >= 0
"timestamp": "date-time", // REQUIRED
"trigger": "Alerting|Delta|Periodic", // REQUIRED
"cause": 0, // OPTIONAL - id of causal event
"actualValue": "string (max 2500)", // REQUIRED - the new value
"techCode": "string (max 50)", // OPTIONAL
"techInfo": "string (max 500)", // OPTIONAL
"cleared": false, // OPTIONAL - true = return to normal
"transactionId": "string (max 36)", // OPTIONAL
"component": { // REQUIRED - ComponentType
"name": "string (max 50)", // REQUIRED
"instance": "string (max 50)", // OPTIONAL
"evse": { // OPTIONAL - EVSEType
"id": 0, // REQUIRED - EVSE id (> 0)
"connectorId": 0 // OPTIONAL - connector index
}
},
"variableMonitoringId": 0, // OPTIONAL - integer >= 0
"eventNotificationType": "HardWiredNotification|HardWiredMonitor|PreconfiguredMonitor|CustomMonitor",
"variable": { // REQUIRED - VariableType
"name": "string (max 50)", // REQUIRED
"instance": "string (max 50)" // OPTIONAL
},
"severity": 0 // OPTIONAL - integer >= 0
}StatusNotificationRequest Schema
Direction: Charging Station → CSMS Deprecated
{
"timestamp": "date-time", // REQUIRED - time for which status is reported
"connectorStatus": "Available|Occupied|Reserved|Unavailable|Faulted", // REQUIRED
"evseId": 0, // REQUIRED - EVSE identifier
"connectorId": 0 // REQUIRED - connector index within EVSE
}HeartbeatRequest / HeartbeatResponse Schema
Direction: Charging Station → CSMS
{
// No required fields - empty payload
}{
"currentTime": "date-time" // REQUIRED - current time of the CSMS
}ChangeAvailabilityRequest Schema
Direction: CSMS → Charging Station
{
"evse": { // OPTIONAL - omit for station-wide change
"id": 0, // REQUIRED - EVSE identifier (> 0)
"connectorId": 0 // OPTIONAL - connector index (omit for entire EVSE)
},
"operationalStatus": "Inoperative|Operative" // REQUIRED - target state
}ChangeAvailabilityResponse Schema
Direction: Charging Station → CSMS
{
"status": "Accepted|Rejected|Scheduled", // REQUIRED
"statusInfo": { // OPTIONAL
"reasonCode": "string (max 20)", // REQUIRED
"additionalInfo": "string (max 1024)" // OPTIONAL
}
}Note: Both NotifyEventResponse and StatusNotificationResponse have no required fields. An empty JSON {} is a valid response for both.
3. G01 — Report Connector AvailabilityState
CS-Initiated| Use Case ID | G01 |
| Direction | CS → CSMS (CS initiates) |
| Trigger | Connector availability status changes (cable plug/unplug, fault, availability command) |
| OCPP Messages | NotifyEventRequest / NotifyEventResponse (preferred), StatusNotificationRequest / StatusNotificationResponse (deprecated) |
Triggering Events
The CSMS will receive notifications for the following events:
| Precondition | Expected Value | Trigger |
|---|---|---|
| Connector is Available, EV cable plugged in | Occupied | Delta |
| Connector is Occupied, EV disconnects, NOT scheduled to become Unavailable | Available | Delta |
| Connector is Occupied, EV disconnects, IS scheduled to become Unavailable | Unavailable | Delta |
| Connector is Reserved, EV connects with matching IdToken | Occupied | Delta |
| A ChangeAvailabilityRequest caused a status change | New value | Delta |
| Connector is Reserved, EV connects with non-matching or no IdToken | No change | — |
State Transition Table
| Initial State | Cable Plugin | Cable Unplug |
|---|---|---|
Available | → Occupied | — |
Occupied | — | → Available (or → Unavailable if scheduled) |
Reserved | — (no change unless IdToken matches) | — |
Unavailable | — | — |
Faulted | — | — |
How to Identify a G01 Availability Report
When processing an incoming NotifyEventRequest,
identify an availability state change event by checking:
eventData[].component.name == "Connector"
eventData[].variable.name == "AvailabilityState"
eventData[].trigger == "Delta"Extracting connector identity:
component.evse.ididentifies the EVSEcomponent.evse.connectorIdidentifies the specific ConnectoractualValuewill be one of:Available,Occupied,Reserved,Unavailable,Faulted
Optionally, the Charging Station may also include EVSE-level
(component.name = "EVSE")
and ChargingStation-level
(component.name = "ChargingStation")
state in additional eventData entries.
CSMS Implementation Steps
- Parse the incoming
NotifyEventRequest. - Validate the JSON payload against the schema.
- Iterate over
eventData[]array entries. - Filter for availability state changes:
component.name == "Connector"ANDvariable.name == "AvailabilityState". - Extract the connector identity:
component.evse.idandcomponent.evse.connectorId. - Extract the new status from
actualValue. - Update the internal connector status record in your database.
- Handle multi-part messages: if
tbc == true, expect additional messages. UseseqNofor ordering. - Respond with an empty
NotifyEventResponse({}). - Consider propagating the status to external systems (operator dashboard, mobile app, roaming platforms, etc.).
Alternative: StatusNotificationRequest Deprecated
Note: This message is deprecated. It is still supported but will be removed
in a future release. Prefer handling NotifyEventRequest.
{
"timestamp": "2025-06-15T10:30:00Z",
"connectorStatus": "Occupied",
"evseId": 2,
"connectorId": 1
}CSMS Implementation Steps (StatusNotification)
- Parse the incoming
StatusNotificationRequest. - Validate against schema.
- Extract
evseId,connectorId,connectorStatus, andtimestamp. - Update the connector status in your database.
- Respond with an empty
StatusNotificationResponse({}).
Important CSMS-Side Notes
- When one connector on a multi-connector EVSE becomes
OccupiedorReserved, the other connectors on that EVSE may no longer be usable — but the Charging Station SHOULD NOT send status changes for those other connectors. The CSMS must infer this from its knowledge of the EVSE's connector topology. - The
Unavailablestatus set byChangeAvailabilityRequestpersists across reboots. The CSMS should track this in its database. - A connector MUST always have one of the
ConnectorStatusenum values:Available,Occupied,Reserved,Unavailable,Faulted.
4. G02 — Heartbeat
CS-Initiated| Use Case ID | G02 |
| Direction | CS → CSMS (CS initiates) |
| Trigger | Charging Station periodically sends heartbeat |
| OCPP Messages | HeartbeatRequest / HeartbeatResponse |
| Purpose | Liveness tracking and time synchronization |
Inbound Message: HeartbeatRequest
The heartbeat request has no required fields — it is an empty payload.
{}CSMS Response: HeartbeatResponse
The CSMS SHALL respond with the current server time.
{
"currentTime": "2025-06-15T10:30:45.123Z"
}CSMS Implementation Steps
- Receive the
HeartbeatRequest. - Update the "last seen" timestamp for this Charging Station in your database/cache. This is the primary mechanism for liveness tracking.
- Generate the current CSMS server time in ISO 8601 / RFC 3339
date-timeformat (UTC recommended). - Respond with
HeartbeatResponsecontainingcurrentTime.
Liveness / Offline Detection Logic
The CSMS SHALL assume a Charging Station is available whenever any message is received from it (not just heartbeats — requirement G02.FR.04).
IF (now - lastMessageReceivedAt) > (heartbeatInterval + gracePeriod)
THEN mark Charging Station as Offline- The
heartbeatIntervalis set by the CSMS in theBootNotificationResponse(from the Provisioning section). - Choose an appropriate
gracePeriodto account for network latency (e.g., 30–60 seconds). - When JSON over WebSocket is used, the WebSocket ping/pong mechanism also provides liveness, so the heartbeat is mainly useful for time synchronization.
- At least one heartbeat every 24 hours is recommended for clock sync.
Requirements Summary
| Req ID | CSMS Responsibility |
|---|---|
G02.FR.03 | HeartbeatResponse SHALL contain the current time of the CSMS. |
G02.FR.04 | When any message is received from a Charging Station, assume it is available (reset offline timer). |
5. G03 — Change Availability EVSE/Connector
CSMS-Initiated| Use Case ID | G03 |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | CSMS wants to change availability of a specific EVSE or Connector |
| OCPP Messages | ChangeAvailabilityRequest / ChangeAvailabilityResponse |
| Use Cases | Maintenance, customer complaint about broken connector, restore availability |
Targeting Rules
| Target | How to Set evse |
|---|---|
| Specific Connector | { "id": <evseId>, "connectorId": <connectorId> } |
| Entire EVSE (all its connectors) | { "id": <evseId> } (omit connectorId) |
| Entire Charging Station | Omit the evse field entirely (see G04) |
Request Examples
{
"operationalStatus": "Inoperative",
"evse": {
"id": 2
}
}{
"operationalStatus": "Inoperative",
"evse": {
"id": 3,
"connectorId": 1
}
}{
"operationalStatus": "Operative",
"evse": {
"id": 2
}
}Response Status Values and CSMS Handling
| Status | Meaning | CSMS Action |
|---|---|---|
Accepted | The change was applied immediately. | Update internal state. Expect subsequent NotifyEventRequest with new connector statuses. |
Rejected | The change could not be performed. | Log failure. The EVSE/Connector state remains as before. Inspect statusInfo for the reason. |
Scheduled | A transaction is currently in progress. The change will be applied after the transaction finishes. | Mark the change as "pending" in your database. Wait for subsequent NotifyEventRequest messages to confirm the actual status change. |
Sequence Diagram
CSMS Charging Station
| |
| ChangeAvailabilityRequest(evse.id, type) |
|-------------------------------------------------->|
| |
| ChangeAvailabilityResponse(status) |
|<--------------------------------------------------|
| |
| [if availability changed] |
| [if transaction is ongoing: wait] |
| |
| NotifyEventRequest(Connector, AvailabilityState) |
|<--------------------------------------------------|
| NotifyEventResponse() |
|-------------------------------------------------->|
| |
| NotifyEventRequest(EVSE, AvailabilityState) |
|<--------------------------------------------------|
| NotifyEventResponse() |
|-------------------------------------------------->|Post-Response: Expect Follow-Up NotifyEventRequest Messages
- For each Connector of the affected EVSE:
NotifyEventRequestwithcomponent.name = "Connector",variable.name = "AvailabilityState" - For the EVSE itself:
NotifyEventRequestwithcomponent.name = "EVSE"
CSMS Implementation Steps
- Determine the target EVSE/Connector and desired
operationalStatus. - Construct the
ChangeAvailabilityRequestpayload with theevseobject andoperationalStatus. - Send the request over the WebSocket connection to the Charging Station.
- Process the
ChangeAvailabilityResponse:Accepted: update internal state immediately. Await confirmingNotifyEventRequestmessages.Scheduled: store a pending state change. Await confirming messages after the transaction completes.Rejected: log the failure. CheckstatusInfo.reasonCodeandstatusInfo.additionalInfofor details.
- Handle follow-up
NotifyEventRequestmessages (see G01) and update connector/EVSE state accordingly.
Requirements Summary
| Req ID | What Happens | CSMS Impact |
|---|---|---|
G03.FR.01 | CS responds with ChangeAvailabilityResponse. | Parse the response. |
G03.FR.02 | Response indicates whether change is possible. | Handle Accepted / Rejected / Scheduled. |
G03.FR.03 | If EVSE/Connector already in requested state → Accepted. | No state change needed. |
G03.FR.04 | CS notifies new connector status via NotifyEventRequest. | Handle the follow-up notification. |
G03.FR.05 | If a transaction is in progress → Scheduled. | Track the pending change; wait for transaction to end. |
G03.FR.06 | When EVSE becomes Inoperative, all non-faulted connectors → Unavailable. | Expect status updates for all connectors on the EVSE. |
G03.FR.07 | When EVSE becomes Operative, connectors revert to original status. | Expect status updates; update internal records. |
G03.FR.08 | Set availability persists across reboot/power loss. | Your database should reflect the persisted state. |
Important Notes
- Independent state levels: The Charging Station, each EVSE, and each Connector have separate availability states. Setting a Connector to Inoperative, then setting its parent EVSE to Inoperative, and then setting the EVSE back to Operative does not revert the Connector — it remains Inoperative.
- An EVSE/Connector is considered Operative in any status other than
FaultedandUnavailable.
6. G04 — Change Availability Charging Station
CSMS-Initiated| Use Case ID | G04 |
| Parent Use Case | G03 — Change Availability EVSE/Connector |
| Direction | CSMS → CS (CSMS initiates) |
| Trigger | CSMS wants to change availability of the entire Charging Station |
| OCPP Messages | ChangeAvailabilityRequest / ChangeAvailabilityResponse |
The CSMS changes the availability of the entire Charging Station — all EVSEs and all Connectors. Operative means the station is charging or ready for charging. Inoperative means the station does not allow any charging.
Request Format
To target the entire Charging Station, omit the evse field:
{
"operationalStatus": "Inoperative"
}{
"operationalStatus": "Operative"
}Response Handling
Same as G03 — the response is a ChangeAvailabilityResponse with status:
| Status | Meaning |
|---|---|
Accepted | All EVSEs/Connectors will change. Expect follow-up status notifications. |
Rejected | The station could not apply the change. |
Scheduled | At least one transaction is in progress. The change will apply after all transactions complete. |
Sequence Diagram
CSMS Charging Station
| |
| ChangeAvailabilityRequest(type) [no evse] |
|-------------------------------------------------->|
| |
| ChangeAvailabilityResponse(status) |
|<--------------------------------------------------|
| |
| [if availability changed] |
| [if transaction is ongoing: wait] |
| |
| NotifyEventRequest(Connector, AvailabilityState) | (loop for all connectors)
|<--------------------------------------------------|
| NotifyEventResponse() |
|-------------------------------------------------->|
| |
| NotifyEventRequest(ChargingStation, |
| AvailabilityState) |
|<--------------------------------------------------|
| NotifyEventResponse() |
|-------------------------------------------------->|Post-Response: Expect Follow-Up Messages
- For each Connector of each EVSE:
NotifyEventRequestwithcomponent.name = "Connector" - For the Charging Station itself:
NotifyEventRequestwithcomponent.name = "ChargingStation",variable.name = "AvailabilityState"
CSMS Implementation Steps
- Construct the request with only
operationalStatus(noevsefield). - Send the
ChangeAvailabilityRequest. - Process the
ChangeAvailabilityResponse(same as G03). - Handle follow-up
NotifyEventRequestmessages for every connector and the station-level component. - Update all EVSE and Connector records in your database.
Requirements Summary
| Req ID | What Happens | CSMS Impact |
|---|---|---|
G04.FR.01 | If evse field is omitted → applies to the whole Charging Station. | Ensure you omit evse when targeting the station. |
G04.FR.02 | CS responds with ChangeAvailabilityResponse. | Parse response. |
G04.FR.03 | Response indicates whether the change is possible. | Handle all 3 statuses. |
G04.FR.04 | If already in the requested state → Accepted. | No state change needed. |
G04.FR.05 | CS informs CSMS of each changed connector via NotifyEventRequest. | Process all follow-up notifications. |
G04.FR.06 | If transaction is in progress → Scheduled. | Track pending change. |
G04.FR.07 | When station becomes Inoperative, all non-faulted EVSEs and connectors → Unavailable. | Expect status updates for all components. |
G04.FR.08 | When station becomes Operative, EVSEs and connectors revert to original status. | Expect status restoration notifications. |
G04.FR.09 | Set availability persists across reboot/power loss. | Your database should reflect the persisted state. |
Important: Same independent-state-level rules apply as in G03.
Availability state set by ChangeAvailabilityRequest persists after reboot. If a Charging Station is set to Unavailable,
it remains unavailable after power loss.
7. G05 — Lock Failure
CS-Initiated| Use Case ID | G05 |
| Direction | CS → CSMS (CS initiates) |
| Trigger | Connector cable lock mechanism fails |
| OCPP Messages | NotifyEventRequest / NotifyEventResponse |
| Impact | Charging Station will NOT start charging |
When the Charging Station's connector cable lock mechanism fails, it notifies the CSMS. The Charging Station will NOT start charging in this case. The CSMS should log this event and optionally alert the operator.
Prerequisites
- A cable is plugged in (connector status =
Occupied). - The Charging Station has the
ConnectorPlugRetentionLockcomponent defined in its Device Model. - MonitoringLevel is set to a level that reports connector lock event failures.
How to Identify a Lock Failure Event
eventData[].component.name == "ConnectorPlugRetentionLock"
eventData[].variable.name == "Problem"
eventData[].actualValue == "true"{
"generatedAt": "2025-06-15T10:31:00Z",
"seqNo": 0,
"eventData": [
{
"eventId": 42,
"timestamp": "2025-06-15T10:30:58Z",
"trigger": "Delta",
"actualValue": "true",
"eventNotificationType": "HardWiredNotification",
"component": {
"name": "ConnectorPlugRetentionLock",
"evse": {
"id": 1,
"connectorId": 1
}
},
"variable": {
"name": "Problem"
}
}
]
}Sequence Diagram
User Charging Station CSMS
| | |
| Cable plugged in | |
|----------------->| |
| | User authorization |
| |------------------------------->|
| | |
| | lock connector attempt failed |
| |--x (internal) |
| | |
| | NotifyEventRequest( |
| | component=ConnectorPlug- |
| | RetentionLock, |
| | variable=Problem, |
| | value=true) |
| |------------------------------->|
| | |
| | NotifyEventResponse() |
| |<-------------------------------|
| | |
| optional notif. | |
|<-----------------| |CSMS Implementation Steps
- Receive the
NotifyEventRequest. - Check if any
eventDataentry hascomponent.name == "ConnectorPlugRetentionLock"andvariable.name == "Problem"withactualValue == "true". - If matched, this is a lock failure event:
- Log the failure with the
evse.idandevse.connectorId. - Alert the operator (dashboard notification, alert system, etc.).
- Record that the connector may be physically compromised — the transaction was NOT started.
- Note: A lock failure can also be reported when unlocking fails.
- Log the failure with the
- Respond with
NotifyEventResponse({}).
Requirements Summary
| Req ID | Requirement | CSMS Impact |
|---|---|---|
G05.FR.01 | Charging Station SHALL NOT start charging. | The CSMS will not receive a transaction start for this attempt. |
G05.FR.02 | CS SHALL send NotifyEventRequest for ConnectorPlugRetentionLock, Problem = true. | Handle this event type in your NotifyEventRequest handler. |
G05.FR.03 | CSMS SHALL respond with NotifyEventResponse. | Send the empty response. |
G05.FR.04 | CS MAY show notification to EV Driver. | No CSMS action required; informational only. |
8. Enumerations Reference
ReferenceConnectorStatusEnumType
Used in StatusNotificationRequest.connectorStatus and as values in NotifyEventRequest.eventData[].actualValue for AvailabilityState.
| Value | Description |
|---|---|
Available | Connector is available for a new session. |
Occupied | A cable is plugged in or an EV is connected. |
Reserved | Connector is reserved for a specific IdToken. |
Unavailable | Connector is not available (maintenance, Inoperative command, etc.). |
Faulted | A fault has been detected on the connector. |
OperationalStatusEnumType
Used in ChangeAvailabilityRequest.operationalStatus.
| Value | Description |
|---|---|
Operative | The target should be available for charging. Maps to connector statuses other than Unavailable/Faulted. |
Inoperative | The target should not be available for charging. Connectors will transition to Unavailable. |
ChangeAvailabilityStatusEnumType
Used in ChangeAvailabilityResponse.status.
| Value | Description |
|---|---|
Accepted | The change has been applied. |
Rejected | The change could not be applied. |
Scheduled | A transaction is in progress; the change will be applied after it completes. |
EventTriggerEnumType
Used in NotifyEventRequest.eventData[].trigger.
| Value | Description |
|---|---|
Alerting | Triggered by a threshold being exceeded. |
Delta | Triggered by a value change. This is the trigger for availability state changes. |
Periodic | Triggered by a periodic schedule. |
EventNotificationEnumType
Used in NotifyEventRequest.eventData[].eventNotificationType.
| Value | Description |
|---|---|
HardWiredNotification | Notification that is hardwired into the Charging Station. |
HardWiredMonitor | Triggered by a hardwired monitor. |
PreconfiguredMonitor | Triggered by a preconfigured monitor. |
CustomMonitor | Triggered by a custom monitor set via SetVariableMonitoring. |
9. CSMS State Management Notes
ArchitectureInternal Data Model
Your CSMS should maintain the following state per Charging Station:
ChargingStation
├── stationId: string
├── operationalStatus: "Operative" | "Inoperative"
├── lastSeenAt: datetime (updated on ANY received message)
├── isOnline: boolean (derived from lastSeenAt + heartbeatInterval)
│
└── evses[]
├── evseId: integer
├── operationalStatus: "Operative" | "Inoperative"
│
└── connectors[]
├── connectorId: integer
├── operationalStatus: "Operative" | "Inoperative"
├── connectorStatus: "Available" | "Occupied" | "Reserved" | "Unavailable" | "Faulted"
└── lastStatusUpdate: datetimeMessage Handler Routing
When a WebSocket message arrives from a Charging Station, route it by action name:
Inbound Messages (CS → CSMS)
| Action | Handler |
|---|---|
NotifyEvent | G01/G05 handler (check component.name and variable.name to distinguish) |
StatusNotification | G01 handler (deprecated path) |
Heartbeat | G02 handler |
Outbound Messages (CSMS → CS)
| Action | Use Case |
|---|---|
ChangeAvailability | G03/G04 (presence/absence of evse field distinguishes them) |
Multi-Connector EVSE Awareness
When an EVSE has multiple connectors (e.g., a dual-cable charger), and one connector
transitions to Occupied:
- The Charging Station SHOULD NOT send status changes for the sibling connectors.
- The CSMS must track which connectors share an EVSE and reflect in its user-facing systems that the sibling connectors are no longer usable, even though their reported status hasn't changed.
Persistence Across Reboots
Availability state set via ChangeAvailabilityRequest persists on the Charging Station across reboots. Your CSMS database should also persist
these settings so that the CSMS and Charging Station remain in sync after a restart on
either side.
10. Message Direction Summary
ReferenceIncoming to CSMS (Charging Station → CSMS)
| Message | CSMS Must Respond With | Use Cases |
|---|---|---|
NotifyEventRequest | NotifyEventResponse | G01, G05 |
StatusNotificationRequest | StatusNotificationResponse | G01 (deprecated) |
HeartbeatRequest | HeartbeatResponse | G02 |
ChangeAvailabilityResponse | (response to CSMS request) | G03, G04 |
Outgoing from CSMS (CSMS → Charging Station)
| Message | When to Send | Use Cases |
|---|---|---|
ChangeAvailabilityRequest | CSMS wants to change availability of an EVSE, Connector, or entire station | G03, G04 |