OCPP: how chargers and CSMS talk.
The Open Charge Point Protocol is the industry-standard messaging protocol between an EV charger and its central management system, running JSON over WebSocket. This reference covers the message lifecycle, the common implementation mistakes we've fixed in the field, and where 1.6J and 2.0.1 diverge.
What OCPP does, in one paragraph.
OCPP is the protocol a charger uses to tell its CSMS "a driver plugged in", ask "is this driver authorized?", report "the session delivered 12.4 kWh", and receive remote commands like "start a session for user X" or "update your firmware." It runs JSON messages over a persistent WebSocket connection, which the charger opens to the CSMS on boot and keeps alive with periodic heartbeats. Every OCPP message is either a Call (request expecting a response), a CallResult (success response) or a CallError (failure response), with a message ID correlating them.
One protocol, two neighbours.
OCPP sits between the charger's embedded firmware and the operator's cloud CSMS. Above OCPP: business logic (billing, tariffs, driver accounts). Below OCPP: WebSocket transport (TLS-secured in production), and beneath that, whatever connectivity the charger has, WiFi, Ethernet, or a cellular modem.
From boot to session, message by message.
A charger boots, connects, gets authorized, runs a session, and stops. The OCPP messages that carry each transition are named below. Every message not listed here is optional or event-driven.
First message on connect. Reports vendor, model, firmware version. CSMS returns heartbeat interval and, in 2.0.1, security-mode requirements.
Periodic keepalive at the interval set by BootNotification. Missing heartbeats indicate connectivity loss, not necessarily charger failure.
Sent whenever a connector's state or fault code changes. Reading these correctly is the difference between real fault detection and treating error codes as opaque strings.
Charger asks whether a presented ID token (RFID, app QR, driver ID) is allowed to charge. CSMS returns Accepted, Blocked, Expired or Invalid.
Opens a session with meter start reading, connector ID and driver ID. CSMS returns a unique transaction ID used in subsequent messages.
Periodic reports during the session: energy, current, voltage, temperature, SoC (if available). Sampling interval configured per network.
Closes the session with meter stop reading and a stop reason (Remote, Local, EV-Disconnected, HardReset, etc.).
Cloud-initiated session start, triggered by driver app or payment webhook. Charger responds with Accepted or Rejected.
Bugs we've fixed, so you don't have to ship them.
Every one of these has shipped in production somewhere. Nothing below is theoretical.
Treating heartbeat as a health check
Heartbeat only proves the WebSocket is alive. A charger can heartbeat happily while failing every session, or while its meter drifts by 20%. Session-success rate and MeterValue sanity are the real health signals.
Discarding MeterValues from offline queues
When a charger reconnects after network loss, its queued StartTransaction with an old timestamp gets rejected by naive CSMS implementations. Correct behaviour: accept the transaction as-is and reconcile at billing.
Ignoring StatusNotification errorCode
The error code carries the entire fault context, GroundFailure, OverCurrent, PowerMeterFailure, InternalError. Many CSMS platforms log only the state (Faulted) and miss the code, then can't route the ticket properly.
Firmware version reported inconsistently
The charger reports firmwareVersion in its BootNotification request, but some vendors also embed version info in vendorId or chargePointModel. Fleet-wide firmware inventory breaks when the payload isn't validated against a canonical field list.
Timestamp handling on transactions
OCPP timestamps are UTC ISO-8601. Chargers with unsynchronized RTCs report future or past-dated events. StopTransaction with a stop-time before start-time is not hypothetical; it happens. CSMS must guard against it.
Rejecting RemoteStartTransaction when charger is busy
If the charger is already in a session on the same connector, spec-compliant behaviour is to reject with 'Rejected', but some implementations report 'Accepted' then internally fail. Debug via a queued RemoteStart with no matching StatusNotification transition.
1.6J vs 2.0.1
| Feature | 1.6J | 2.0.1 |
|---|---|---|
| Transport | WebSocket + JSON | WebSocket + JSON |
| Device model | Ad hoc via vendorId | Formal (variables, components) |
| Security profile | Basic auth or TLS mutual | 3 profiles including secure firmware sig |
| ISO 15118 support | Add-on via extensions | Native (V2G Certificate messages) |
| Smart charging | Optional profile | Core, richer ChargingProfile |
| Firmware management | Optional profile | Core with signature verification |
| Adoption | Widely deployed installed base | Growing; often specified for new procurement |
Frequently asked
What is the difference between OCPP 1.6J and 2.0.1?
1.6J is JSON-over-WebSocket, widely deployed, with optional Smart Charging, Remote Trigger and Firmware Management profiles. 2.0.1 adds a formal device model (variables and components), richer security profiles (TLS + certificate management), ISO 15118 support and improved smart charging. Most new networks specify 2.0.1; the installed base is still primarily 1.6J.
How many chargers can one OCPP server handle?
A well-architected OCPP server handles 5,000-10,000 concurrent WebSocket connections on a modern node before requiring horizontal scaling. The bottleneck is rarely raw connections; it's the downstream processing of MeterValues and StatusNotifications. RIOD-built platforms shard by charger cohorts across nodes past this scale.
Should a new CMS support 1.6J, 2.0.1 or both?
Both, for the next few years. The installed base is 1.6J; new procurement often specifies 2.0.1. A single CMS supporting both, with version negotiated at WebSocket subprotocol setup before any OCPP message is exchanged, is the pragmatic answer.
How is OCPP compliance tested?
The Open Charge Alliance provides the OCPP Compliance Testing Tool (OCTT). Compliance testing exercises the full message space against your implementation. RIOD runs OCTT alongside interoperability testing with commercial CMS and charger vendors during firmware and platform releases.
Building on OCPP? Talk to the team that ships it.
We build OCPP-based CMS platforms and OCPP-compliant charger firmware. Real chargers, real testing, IP transferred to you.