Functional block B (Provisioning) covers how a station introduces itself, how the CSMS decides whether to accept it, and how the CSMS configures it, including where it connects next. Block G (Availability) covers Heartbeat and connector status. Together they define the first minute of every connection, and they are where most onboarding issues show up.
BootNotification
After the WebSocket opens, the first message the station sends is BootNotification. Compared with 1.6, the station details move into a nested chargingStation object, and there is a new mandatory reason.
[2, "19223201", "BootNotification", {
"reason": "PowerUp",
"chargingStation": {
"model": "DC-150",
"vendorName": "ExampleVendor",
"serialNumber": "EV150-000123",
"firmwareVersion": "4.2.1",
"modem": {
"iccid": "8944500102198304826",
"imsi": "234500012345678"
}
}
}]reason is a BootReasonEnumType: ApplicationReset, FirmwareUpdate, LocalReset, PowerUp, RemoteReset, ScheduledReset, Triggered, Unknown or Watchdog. Store it. A station that keeps booting with Watchdog is crashing, and FirmwareUpdate after an UpdateFirmware confirms the install completed. This one field replaces a lot of guesswork from the 1.6 days.
[3, "19223201", {
"currentTime": "2026-10-26T09:00:00.000Z",
"interval": 300,
"status": "Accepted"
}]status is Accepted, Pending or Rejected. On Accepted, interval is the heartbeat interval in seconds and the station should sync its clock to currentTime. On Pending or Rejected, interval is how long the station waits before sending BootNotification again. An optional statusInfo (reasonCode plus additionalInfo) can explain the decision, which is useful for station logs.
Pending: provisioning before go-live
Pending is the CSMS saying "I know you, but I'm not ready to let you operate". While pending, the CSMS can send messages to configure the station, typically GetBaseReport, SetVariables, SetNetworkProfile, InstallCertificate or TriggerMessage, and the station should not send its own operational requests until accepted. This is the clean way to implement onboarding (use case B02): a new serial number boots, you return Pending, pull the full inventory, push your standard configuration, and only then return Accepted on the next boot attempt.
Use cases worth knowing
| Use case | Name |
|---|---|
| B01 | Cold Boot Charging Station |
| B02 | Cold Boot Charging Station - Pending |
| B03 | Cold Boot Charging Station - Rejected |
| B04 | Offline Behavior Idle Charging Station |
| B05 / B06 | Set Variables / Get Variables |
| B07 / B08 | Get Base Report / Get Custom Report |
| B09 | Setting a new NetworkConnectionProfile |
| B10 | Migrate to new CSMS |
| B11 / B12 | Reset without / with ongoing transaction |
After Accepted: StatusNotification
Once accepted, the station reports the state of every connector with StatusNotification. In 2.0.1 it is per connector, addressed by evseId plus connectorId, and connectorStatus has just five values: Available, Occupied, Reserved, Unavailable and Faulted.
[2, "d1e2f3a4-5b6c-4d7e-8f90-a1b2c3d4e5f6", "StatusNotification", {
"timestamp": "2026-10-26T09:00:02.000Z",
"connectorStatus": "Available",
"evseId": 1,
"connectorId": 1
}]
[3, "d1e2f3a4-5b6c-4d7e-8f90-a1b2c3d4e5f6", {}]If you are coming from 1.6 (see StatusNotification in 1.6), notice what is missing. There is no errorCode, and Preparing, Charging, SuspendedEV, SuspendedEVSE and Finishing are all collapsed into Occupied. The detailed charging state now lives in transactionInfo.chargingState inside TransactionEvent (Charging, EVConnected, SuspendedEV, SuspendedEVSE, Idle), and faults are reported through NotifyEvent. A CSMS that builds its live map from StatusNotification alone will show every in-use connector as just "occupied".
The connector status is also exposed in the device model as the AvailabilityState variable on the Connector component, which is handy when you want to poll it with GetVariables after a reconnect instead of waiting for notifications.
Heartbeat and time
[2, "hb-000187", "Heartbeat", {}]
[3, "hb-000187", {
"currentTime": "2026-10-26T09:05:00.000Z"
}]Heartbeat serves two purposes: liveness and clock sync. The interval comes from BootNotificationResponse.interval and is reflected in OCPPCommCtrlr.HeartbeatInterval. Many stations also rely on WebSocket ping/pong (OCPPCommCtrlr.WebSocketPingInterval) for connection liveness. For a CSMS, the reliable "is this station online" signal is the WebSocket connection state plus last-message-received time, not just the heartbeat.
Network connection profiles
2.0.1 formalises where and how a station connects. Connection settings are stored in numbered slots called network connection profiles. Each profile holds the CSMS URL, OCPP version and transport, the interface to use, the message timeout and the security profile. OCPPCommCtrlr.NetworkConfigurationPriority lists the slots in the order the station should try them.
[2, "np-0001", "SetNetworkProfile", {
"configurationSlot": 2,
"connectionData": {
"ocppVersion": "OCPP20",
"ocppTransport": "JSON",
"ocppCsmsUrl": "wss://csms-new.example.com/ocpp",
"messageTimeout": 30,
"securityProfile": 2,
"ocppInterface": "Wired0"
}
}]
[3, "np-0001", {
"status": "Accepted"
}]Note that ocppVersion uses OCPP20 for 2.0.1 (the enum values are OCPP12, OCPP15, OCPP16, OCPP20). ocppInterface is one of Wired0..Wired3 or Wireless0..Wireless3, and optional apn and vpn objects cover cellular and VPN settings. The response status is Accepted, Rejected or Failed.
Setting the profile does not switch the station over. To migrate to a new CSMS (B10) or upgrade the security profile, you store the new profile in a free slot, put that slot first in NetworkConfigurationPriority with SetVariables, and then Reset. If the station cannot connect using the new profile, it falls back to the next slot in the priority list, which is what prevents a bad URL from bricking a remote station.
Reset and availability
Reset in 2.0.1 takes type Immediate or OnIdle (replacing 1.6's Hard/Soft) and an optional evseId to reset a single EVSE where supported. OnIdle waits for transactions to end; Immediate stops them first. The response can be Accepted, Rejected or Scheduled; Scheduled means the station will reset once idle.
[2, "rst-42", "Reset", {
"type": "OnIdle"
}]
[3, "rst-42", {
"status": "Scheduled"
}]ChangeAvailability takes operationalStatus (Operative or Inoperative) and an optional evse object (with or without connectorId) to target the station, an EVSE, or a single connector. The response is Accepted, Rejected or Scheduled (when a transaction is in progress).
Field gotchas
- Pending loops. If the CSMS returns
Pendingbut never sends anything, some stations wait for the full interval before retrying. Make the provisioning workflow explicit and finish withAcceptedon the next boot or viaTriggerMessageforBootNotification. - Messages before Accepted. Some firmware sends
StatusNotificationor evenTransactionEventbefore boot is accepted. Do not crash; log it and respond. TheTxCtrlr.TxBeforeAcceptedEnabledvariable governs whether transactions may start before acceptance. - Identity mismatch. The identity in the URL, the Basic Auth username and
SecurityCtrlr.Identityshould agree. Reject mismatches at the WebSocket layer. - Reconnect storms. After a CSMS deploy, thousands of stations reconnect and send
BootNotificationat once. Keep the boot handler cheap and push heavy work (reports, configuration) into a queue.
Next
With the station accepted and reporting status, the next part covers the heart of 2.0.1: TransactionEvent. For the 1.6 version of this flow, see BootNotification and Heartbeat in 1.6.

