OCPP 1.6 vs 2.0.1

2.0.1 is not 1.6 with more messages. It restructures configuration, transactions and security, and the two are not wire-compatible in either direction.

The two versions share a transport — OCPP-J over WebSocket — and a subprotocol negotiation mechanism, and that is roughly where the similarity ends. A charger announces ocpp1.6 or ocpp2.0.1 in Sec-WebSocket-Protocol, and a CSMS that supports both runs two separate implementations behind that choice.

OCPP 1.6 remains the version most deployed hardware speaks. 2.0.1 is what new procurement increasingly requires. Most operators run both for years, which is the practical reason this comparison matters.

Message equivalents

Where a 1.6 message went in 2.0.1. Not a migration path — the payloads differ even where the name survives.

OCPP 1.6OCPP 2.0.1What changed
AuthorizeAuthorizeSame purpose. `idTag` becomes the structured `idToken` object.
BootNotificationBootNotification`chargePointVendor`/`chargePointModel` move into a `chargingStation` object.
HeartbeatHeartbeatUnchanged in purpose.
StartTransactionTransactionEventStart, stop and updates collapse into one message with an `eventType`.
StopTransactionTransactionEventSame — `eventType: "Ended"`.
MeterValuesTransactionEventMeter data rides inside TransactionEvent during a session.
StatusNotificationStatusNotificationNow reports per EVSE and connector rather than a flat connector id.
ChangeConfigurationSetVariablesFlat string keys become addressed variables in the device model.
GetConfigurationGetVariablesSame change, reading rather than writing.
GetDiagnosticsGetLogGeneralised: diagnostics logs and security logs.
ReserveNowReserveNowReservation is now part of the core rather than an optional profile.

The device model

This is the change everything else follows from. OCPP 1.6 configuration is a flat map of string keys — HeartbeatInterval, MeterValueSampleInterval — and a charger's capabilities are whatever keys it happens to have.

2.0.1 replaces that with a structured device model: components, variables, and attributes with types and constraints. A CSMS can ask a charger to describe itself rather than probing for keys and hoping.

It is a genuine improvement and it is also the single biggest source of migration work, because nothing about the 1.6 configuration surface carries across.

Transactions became one message

In 1.6, a session is StartTransaction, then MeterValues, then StopTransaction — three message types with separate correlation rules and a transactionId the server assigns.

In 2.0.1 all three are TransactionEvent with an eventType of Started, Updated or Ended, and the charger generates the transaction id itself. Offline handling gets substantially simpler as a result, because the charger never has to wait for the server to name a session it has already begun.

Security is specified, not assumed

OCPP 1.6 says essentially nothing about security. TLS is a recommendation, authentication is out of scope, and in practice deployments run anything from plain ws:// to mutual TLS.

2.0.1 defines three security profiles: HTTP Basic over TLS, TLS with a client certificate, and TLS with mutual certificate authentication, plus certificate management messages to rotate them. For anyone who has had to answer a security questionnaire about a charging network, this is the most valuable part of the upgrade.

EVSE and connector are now distinct

1.6 has connectors numbered from 1, with 0 meaning the whole charge point. That flat model cannot express a station where two connectors share one power module and cannot charge simultaneously at full power.

2.0.1 introduces the EVSE as an explicit level between station and connector, which is what makes correct load allocation on multi-outlet hardware possible.

Smart charging got more capable and more complex

Charging profiles exist in both. 2.0.1 adds charging limits sourced from the local energy management system, ISO 15118 support for plug-and-charge and bidirectional flows, and a much richer notion of what may constrain a session.

If your 1.6 smart charging works, the concepts transfer. The payloads do not.

Which one should you implement?

If you are building firmware for hardware that ships this year, 1.6 is still what most networks will connect it to, and 2.0.1 is what an increasing share of tenders ask for. Building the protocol layer behind an abstraction — rather than threading OCPP message types through your business logic — is what makes supporting both affordable.

If you are building a CSMS, you will need both, because your customers' fleets will contain both for the foreseeable future.

Either way the migration cost is concentrated in configuration and transactions, not in the transport. Budget for the device model.

The full 1.6 message set is documented in our OCPP 1.6 reference, and OcppPilot implements both versions behind one Go interface.