PHP2Shell alert: critical PHP flaws CVE-2026-109618 / 109619 — check your servers and get patched fast
HashTech Systems
EV Charging
Part 3 of 11

OCPP 2.0.1 BootNotification, Network Profiles and Heartbeat

Bringing an OCPP 2.0.1 station online: BootNotification reasons, Pending provisioning, SetNetworkProfile, Heartbeat, StatusNotification and Reset.

HashTech Engineering · October 26, 2026 · 5 min read

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.

json
[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.

json
[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 caseName
B01Cold Boot Charging Station
B02Cold Boot Charging Station - Pending
B03Cold Boot Charging Station - Rejected
B04Offline Behavior Idle Charging Station
B05 / B06Set Variables / Get Variables
B07 / B08Get Base Report / Get Custom Report
B09Setting a new NetworkConnectionProfile
B10Migrate to new CSMS
B11 / B12Reset 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.

json
[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

json
[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.

json
[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.

json
[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 Pending but never sends anything, some stations wait for the full interval before retrying. Make the provisioning workflow explicit and finish with Accepted on the next boot or via TriggerMessage for BootNotification.
  • Messages before Accepted. Some firmware sends StatusNotification or even TransactionEvent before boot is accepted. Do not crash; log it and respond. The TxCtrlr.TxBeforeAcceptedEnabled variable governs whether transactions may start before acceptance.
  • Identity mismatch. The identity in the URL, the Basic Auth username and SecurityCtrlr.Identity should agree. Reject mismatches at the WebSocket layer.
  • Reconnect storms. After a CSMS deploy, thousands of stations reconnect and send BootNotification at 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.

Let's Talk

Ready to build something that lasts?

Whether it's a charging network, an AI rollout, or a core enterprise system — let's talk about what you're building.