Back to blog
Tutorial8 min read

OCPP 2.1: What It Adds, and How to Test It Before You Have a 2.1 Charger

OCPP 2.1 is a superset of 2.0.1, which makes it easy to claim and hard to prove. Here is what it actually adds — settlement, grid control, event streams — and how to test each part before a 2.1 charger is on your bench.

I
Infinite Service Team

Every new OCPP version arrives with the same problem. Charger makers cannot test their firmware until a CSMS speaks the new version, and CSMS teams cannot test their backend until a charger does. OCPP 2.1 is no different — and because it is built on 2.0.1, it adds a second problem: it is very easy to say you support it without having tested a single thing it adds.

This post covers what 2.1 changes, where implementations go wrong first, and how to test both sides before real 2.1 hardware is on your bench.

2.1 is a superset of 2.0.1

The most important fact about OCPP 2.1 is what it keeps. The whole 2.0.1 model is still there: BootNotification, TransactionEvent, device model, security profiles. A 2.1 charger negotiates the ocpp2.1 WebSocket subprotocol instead of ocpp2.0.1, and from then on most of what it sends looks exactly like a 2.0.1 charger.

That is good news for implementers — a solid 2.0.1 stack is most of the way there — and a trap for testers. Run your 2.0.1 test plan against a charger that connects with ocpp2.1 and everything passes, yet you have not exercised one 2.1 message. A useful 2.1 test plan has two parts:

  • The full 2.0.1 flow, run on the ocpp2.1 connection, because 2.1 must still do all of it
  • The 2.1 additions, graded on their own, so that a pass means something

What 2.1 adds

The additions fall into a few families. These are the ones charger and CSMS teams meet first.

Payment and settlement

2.1 brings payment at the charger into the protocol. When a payment terminal on the unit takes money for a session, the charger reports it with NotifySettlement — the amount, the status and, crucially, pspRef, the payment provider's reference for that transaction.

pspRef looks like an optional detail and is the field that matters most. A settlement without it cannot be matched against the payment provider's records later, which means a disputed charge cannot be traced. Treat a settlement without pspRef as a failure, not a warning.

The same family covers VatNumberValidation: a driver who needs a company invoice enters a VAT number at the charger, and the charger asks the CSMS to validate it before the receipt is issued.

Grid control and dynamic charging

The largest part of 2.1 is about the grid. Chargers can now be managed as distributed energy resources (DER), including bidirectional charging:

  • GetDERControl and ReportDERControl let the CSMS read the DER controls a charger has in force
  • NotifyDERAlarm is the charger reporting that a grid condition triggered a DER control
  • PullDynamicScheduleUpdate lets a charger fetch a fresh schedule mid-session, rather than waiting for the CSMS to push one
  • UsePriorityCharging and NotifyPriorityCharging cover a driver opting into priority charging, and the charger confirming it is active

These messages are independent of each other. A charger may raise a DER alarm, pull a schedule and confirm priority charging in any order, so a test that expects a fixed sequence will fail good chargers.

Periodic event streams

Instead of the CSMS polling for values, a 2.1 charger can open a stream and push data on it: OpenPeriodicEventStream, then NotifyPeriodicEventStream as often as configured, then ClosePeriodicEventStream. The stream's id ties the three together — a notification or close that names a different stream from the one opened is a bug, and a common one when a charger restarts mid-stream.

Where 2.1 integrations break first

In our experience, the first failures are rarely the new messages themselves:

  1. Subprotocol negotiation. The charger offers ocpp2.1 and the CSMS only accepts ocpp2.0.1, or the reverse. Offer both, in order of preference, and log which one was chosen. Our WebSocket debugging guide covers what a failed negotiation looks like.
  2. Schema validation. 2.1 messages have their own JSON schemas. A CSMS that validates against the 2.0.1 schemas will reject valid 2.1 frames, and one that does not validate at all will accept broken ones.
  3. Settlements without `pspRef`. They pass a happy-path demo and fail the first reconciliation.
  4. Stream ids. A notification for a stream that was never opened, or a close for the wrong one.

Testing a 2.1 charger without a 2.1 CSMS

If you build chargers, you need a CSMS that speaks 2.1 and tells you precisely what your firmware got wrong. TestPilot has three suites that grade only what 2.1 adds, scored from the frames your charger actually sends:

  • Tariffs & Settlement — NotifySettlement with pspRef, status and amount; every settlement reconcilable; VatNumberValidation with a VAT number
  • DER & Dynamic Charging — PullDynamicScheduleUpdate, NotifyPriorityCharging, NotifyDERAlarm and ReportDERControl, in any order
  • Periodic Event Streams — open, notify and close, in order, for the same stream

Run them alongside the core 2.0.1 suite on the same ocpp2.1 connection — pick a 2.1 charger in the console and all of them are offered, or start them from CI through the API. Passing the 2.1 suites alone proves the additions work; passing both proves the charger is a 2.1 charger.

Testing a 2.1 CSMS without a 2.1 charger

If you build the backend, you need the opposite: a charger that sends real 2.1 traffic on demand. SimPilot runs simulated chargers on OCPP 1.6, 2.0.1 or 2.1. A 2.1 charger sends the 2.1 messages above, answers GetDERControl and UsePriorityCharging from your CSMS, and sends any of them when your CSMS asks with TriggerMessage.

For repeatable runs, SimPilot can replay each TestPilot 2.1 suite's sequence on its own — a settlement after every session, DER messages while idle, or an event stream during charging:

charger-sim --version 2.1 --scenario tariff21 \
  --url wss://your-test-csms.example/ocpp/ --id CP_21_01

Scenarios start a charging session every few seconds by themselves, so SimPilot only allows them against a test CSMS — never a production one.

A short checklist

  • Negotiate ocpp2.1, fall back to ocpp2.0.1, and log the result
  • Validate 2.1 frames against the 2.1 schemas, not the 2.0.1 ones
  • Re-run your whole 2.0.1 test plan on the 2.1 connection
  • Reject settlements without pspRef
  • Do not assume an order for DER and priority-charging messages
  • Check that every stream notification and close names the stream that was opened

2.1 is a large release, but most of it is additive. Test the base you already know on the new connection, test the additions one family at a time, and you can be confident in a 2.1 implementation well before the first 2.1 charger ships.

Related articles