Almost nobody migrates a charging network from OCPP 1.6 to 2.0.1 in one step. New hardware arrives with 2.0.1 firmware, some existing models get a firmware upgrade, and a long tail stays on 1.6 for the rest of its life. So the real question is not "how do we switch" but "how does one CSMS run both properly". This article covers the mapping between the two and a plan that works with a mixed fleet. The higher-level business view is in OCPP 1.6 vs 2.0.
Message mapping
| OCPP 1.6 | OCPP 2.0.1 | What changes |
|---|---|---|
BootNotification | BootNotification | Station fields nested in chargingStation; new reason |
Heartbeat | Heartbeat | Unchanged |
StatusNotification | StatusNotification + NotifyEvent | Five states, per EVSE/connector; no error codes |
Authorize | Authorize | idTag string becomes IdTokenType object; IdTokenInfo richer |
StartTransaction | TransactionEvent (Started) | Station generates string transactionId |
StopTransaction | TransactionEvent (Ended) | stoppedReason in transactionInfo |
MeterValues (in transaction) | TransactionEvent (Updated) | Values are numbers; MeterValues remains for non-transaction data |
RemoteStartTransaction | RequestStartTransaction | remoteStartId for correlation; EVSE instead of connector |
RemoteStopTransaction | RequestStopTransaction | String transactionId |
GetConfiguration | GetVariables, GetBaseReport, GetReport | Device model addressing |
ChangeConfiguration | SetVariables | Batched, per-item status, RebootRequired |
Reset (Hard/Soft) | Reset (Immediate/OnIdle) | Optional evseId; Scheduled status |
ChangeAvailability | ChangeAvailability | operationalStatus and optional evse |
UnlockConnector | UnlockConnector | evseId plus connectorId |
SetChargingProfile, ClearChargingProfile, GetCompositeSchedule | Same names, plus GetChargingProfiles/ReportChargingProfiles | Schedule array, renamed purposes, external limits |
SendLocalList, GetLocalListVersion, ClearCache | Same names | IdTokenType entries |
ReserveNow, CancelReservation | Same names, plus ReservationStatusUpdate | Reserve per EVSE or by connector type |
TriggerMessage / ExtendedTriggerMessage | TriggerMessage | Merged; certificate triggers included |
GetDiagnostics, DiagnosticsStatusNotification | GetLog, LogStatusNotification | Diagnostics and security logs |
UpdateFirmware / SignedUpdateFirmware | UpdateFirmware | Always signed |
| Security whitepaper messages | Core block A messages | SignCertificate, CertificateSigned, InstallCertificate, SecurityEventNotification and others |
DataTransfer | DataTransfer | Prefer customData and device model where possible |
2.0.1 also has entire areas with no 1.6 equivalent: variable monitoring, display messages, tariff and cost, ISO 15118 certificate management, network connection profiles and customer information requests. Those are the reasons to migrate, and they are covered in parts 2, 8 and 9.
Configuration key mapping
Most standard 1.6 configuration keys have a device model counterpart. These are the ones a typical CSMS sets during provisioning; check names against the device model appendix of the spec edition you implement, since the mapping is not always one-to-one.
| 1.6 key | 2.0.1 component.variable |
|---|---|
HeartbeatInterval | OCPPCommCtrlr.HeartbeatInterval |
MeterValueSampleInterval | SampledDataCtrlr.TxUpdatedInterval |
MeterValuesSampledData | SampledDataCtrlr.TxUpdatedMeasurands (and TxStartedMeasurands) |
StopTxnSampledData | SampledDataCtrlr.TxEndedMeasurands |
ClockAlignedDataInterval | AlignedDataCtrlr.Interval |
MeterValuesAlignedData | AlignedDataCtrlr.Measurands |
ConnectionTimeOut | TxCtrlr.EVConnectionTimeOut |
StopTransactionOnInvalidId | TxCtrlr.StopTxOnInvalidId |
StopTransactionOnEVSideDisconnect | TxCtrlr.StopTxOnEVSideDisconnect |
AuthorizeRemoteTxRequests | AuthCtrlr.AuthorizeRemoteStart |
LocalAuthorizeOffline, LocalPreAuthorize | AuthCtrlr.LocalAuthorizeOffline, AuthCtrlr.LocalPreAuthorize |
AllowOfflineTxForUnknownId | AuthCtrlr.OfflineTxForUnknownIdEnabled |
AuthorizationCacheEnabled | AuthCacheCtrlr.Enabled |
LocalAuthListEnabled | LocalAuthListCtrlr.Enabled |
TransactionMessageAttempts, TransactionMessageRetryInterval | OCPPCommCtrlr.MessageAttempts / MessageAttemptInterval (instance TransactionEvent) |
WebSocketPingInterval | OCPPCommCtrlr.WebSocketPingInterval |
ChargeProfileMaxStackLevel | SmartChargingCtrlr.ProfileStackLevel |
ChargingScheduleAllowedChargingRateUnit | SmartChargingCtrlr.RateUnit |
SecurityProfile, AuthorizationKey | SecurityCtrlr.SecurityProfile, SecurityCtrlr.BasicAuthPassword |
There is no 1.6 equivalent of TxCtrlr.TxStartPoint and TxStopPoint. 1.6 stations had implicit, vendor-specific start and stop points. When the same hardware model moves from 1.6 to 2.0.1 firmware, compare its old behaviour with its new TxStartPoint before assuming session durations and idle times stay comparable in your reports. The 1.6 keys themselves are covered in 1.6 configuration keys.
Architecture for a mixed fleet
The approach that holds up is a version-specific adapter per connection and a version-neutral domain model behind it:
- Negotiate the version at the WebSocket handshake. Serve one endpoint that accepts both
ocpp1.6andocpp2.0.1subprotocols and pick per station, or separate paths per version. Record the negotiated version on the connection. - Adapters translate to domain events. A 1.6
StartTransactionand a 2.0.1TransactionEventStartedboth become "session started" in your domain. Billing, OCPI, analytics and support tools only see domain events. - Model the domain on 2.0.1, not 1.6. Station, EVSE, connector; string transaction ids; tokens with types. A 1.6 station maps cleanly into this model (each 1.6 connector becomes an EVSE with one connector, and the integer transaction id is stored as a string). Going the other way loses information.
- Commands go through the same adapters. "Start session on EVSE 2" becomes
RemoteStartTransactionwithconnectorId2 for 1.6 orRequestStartTransactionwithevseId2 for 2.0.1. - Configuration is per-version. Keep a logical configuration ("meter interval 60 s") and render it as 1.6 keys or 2.0.1 variables per station.
Migrating stations in the field
Moving an installed station from 1.6 to 2.0.1 is a firmware change, and 1.6 has no standard way to switch protocol or CSMS URL (2.0.1's network profiles are new). In practice the vendor's 2.0.1 firmware ships with a default or migrated connection configuration, or the vendor provides a 1.6 configuration key for it. Plan for:
- Keeping the same station identity and credentials, so the station reconnects to the same CSMS record on the new protocol.
- No transactions in flight during the switch. A transaction started under 1.6 and finished under 2.0.1 has no clean representation; schedule upgrades on idle stations.
- Re-provisioning after the first 2.0.1 boot: run
GetBaseReport, apply your configuration, set fallback messages, install certificates. UsePendingon the first boot for this (see part 3). - A rollback path. Keep the 1.6 endpoint running and know how to downgrade firmware if a model misbehaves.
- Updating OCPI EVSE ids if your identifiers depended on 1.6 connector numbering. See OCPP to OCPI mapping.
A migration plan that works
- Refactor the domain model to station/EVSE/connector and string transaction ids while still 1.6-only. This is most of the work, and it is risk-free to ship first.
- Build the 2.0.1 adapter for blocks B, C, E, F and G first: boot, authorization, transactions, remote control, availability. That is enough to charge and bill.
- Test against simulators and real hardware. Use a simulator for regression and edge cases, then at least one real station per model. See testing OCPP with a charge point simulator.
- Pilot one site with new 2.0.1 hardware. Watch transaction completeness (gaps in
seqNo), status accuracy and authorization latency. - Add security, device model tooling and monitoring, then smart charging, display messages and ISO 15118 as the business needs them.
- Upgrade existing models selectively, where the vendor's 2.0.1 firmware is mature and there is a feature you need. Leave the rest on 1.6.
Key takeaways
- Plan for permanent coexistence of 1.6 and 2.0.1, not a cutover.
- Model the domain on 2.0.1 concepts; adapt 1.6 into it.
- Map configuration deliberately, and check
TxStartPoint/TxStopPointon upgraded hardware. - Only upgrade field stations when idle, with re-provisioning and a rollback path.
Running both protocols on one platform is how HashTech builds CSMS platforms; see EV charging or get in touch if you are planning a migration.

