Coordinated with Fredrik

Special Deep Dive for David: OCPP Without the Marketing Fluff


Listen Later

It wasn’t for a broad audience.It wasn’t for policymakers or the energy-curious.It was built for one specific person: David — a firmware engineer driving north on the E4 toward Linköping.

Long highway. Solo drive. Brain half in traffic, half in state machines.

So we decided to go deep into something that actually matters if you’re building charging infrastructure:

OCPP — Open Charge Point Protocol.

No marketing fluff. No “empowering the green transition.”Just architecture, protocol evolution, firmware headaches, and where this is all going.

What OCPP Actually Is

Strip it down and OCPP is simple:

It is the application-layer language between a charging station (EVSE) and a backend system (CSMS).

That’s it.

Today, that means:

* JSON payloads

* WebSockets transport

* TLS security

* Deterministic state machines

It is the pipe between hardware and cloud.

And if you’re writing firmware, it is the difference between “works in the lab” and “survives production.”

The Early Days: SOAP, XML, and Pain

Before OCPP 1.6, we lived in the SOAP era.

XML everywhere.Heavy envelopes.Verbose messages.Request/response HTTP only.

That created a structural problem: chargers sit behind NATs and cellular modems. Servers couldn’t easily push commands down to them.

So chargers had to poll.

“Do you have work for me?”“Do you have work for me?”“Do you have work for me?”

Inefficient. Expensive. Messy.

And for embedded systems? Parsing XML on a constrained MCU was not fun.

OCPP 1.6J — The WebSocket Revolution

Then came OCPP 1.6J.

The “J” mattered.

JSON instead of XML.Persistent WebSockets instead of pure HTTP.Bidirectional messaging.

Suddenly:

* The backend could push commands instantly.

* Latency dropped.

* Cellular data usage shrank.

* Parsing became lighter.

For firmware engineers, this was a major quality-of-life upgrade.

And 1.6 became everywhere. AC chargers. DC chargers. Public networks. Private networks.

It worked.

But it wasn’t clean.

The Ambiguity Problem

OCPP 1.6 had a philosophical flaw:

It was ambiguous.

Take a simple case.

A user plugs in a cable before authorizing.

The charger sends:

StatusNotification: Preparing

What does that mean?

* Plug inserted?

* Authorized but waiting?

* Internal self-check?

* Something else?

The backend had to infer meaning from sequence patterns.

That’s brittle engineering.

And when you scale across vendors, those interpretations diverge.

OCPP 2.0 → 2.0.1: The Hard Reset

OCPP 2.0 tried to fix everything.

It introduced a massive architectural shift — including a hierarchical device model.

But the specification itself had issues:

* Broken schema references

* Circular definitions

* Inconsistencies

You couldn’t strictly validate against it.

So 2.0.1 replaced it.

And this is important:

* 2.0.1 is not backward compatible with 1.6.

* It’s a structural rewrite.

* If someone says “OCPP 2.0,” they almost certainly mean 2.0.1.

Flat World vs Hierarchical World

In 1.6, configuration was flat.

Key → Value.

Like an INI file with a networking layer.

In 2.0.1, everything becomes a tree.

Charging Station→ EVSE→ Connector

And beyond that:

* Cooling systems

* Power modules

* Converters

* Displays

* Locks

* Subsystems

Each defined as:

* Component

* Variable

* Attribute

This is no longer just a protocol.It’s a digital twin of the hardware.

For firmware engineers, that means:

* Internal state model required

* Memory allocation planning

* Component indexing strategies

* Careful RAM management

You’re not just flipping relays anymore.You’re modeling the machine.

Transactions: From Guessing to Determinism

1.6 had separate messages:

* StartTransaction

* StopTransaction

* MeterValues

2.0.1 consolidates everything into:

TransactionEvent

Each event includes:

* Event type

* Trigger reason

Now the charger can explicitly say:

* CablePluggedIn

* Authorized

* RemoteStart

* EVConnected

No guessing.No backend inference.

Just a deterministic state machine.

This is one of the most important improvements in the protocol’s history.

Offline Handling: The Reality of Cellular Networks

Cellular drops. Forests exist. Power glitches happen.

In 1.6:

* Local whitelist for RFID

* Vague retry behavior

* Data sometimes lost

* Billing inconsistencies

In 2.0.1:

* Defined queuing behavior

* Sequential ordering

* Transaction sequence numbers

* Explicit retry logic

But here’s the firmware cost:

You now need:

* Non-volatile message storage

* Flash wear-leveling

* Circular buffer logic

* Message prioritization

This is where embedded engineering meets infrastructure-grade reliability.

Ping Is Not Heartbeat

One subtle but critical distinction:

WebSocket pingKeeps the TCP connection alive.

OCPP heartbeatConfirms the application logic is running.

You can have:

* Working ping

* Deadlocked firmware loop

If your watchdog logic monitors only socket state, you will miss application failures.

Network uptime ≠ system health.

Error Handling: Stop Using “OtherError”

In 1.6, the error enum was limited.

Anything outside predefined values became:

OtherError

Operationally useless.

2.0.1 improves this with structured NotifyEvent messages tied to components.

Then industry alignment brought standardized Minimum Required Error Codes (MRECs).

Instead of “OtherError,” you can send precise fault codes for:

* Ground fault

* Pilot failure

* UI failure

* Network outage

That difference saves unnecessary truck rolls.

And truck rolls are expensive.

Security: From Naive to Cryptographic

Security evolved dramatically.

Profile 1:Plain HTTP. Not acceptable.

Profile 2:TLS — server authentication.

Profile 3:Mutual TLS — charger and server authenticate each other.

2.0.1 improves:

* Certificate lifecycle management

* CSR handling

* Renewal flows

Add secure firmware updates with signature verification, and now you have something defensible.

Without that, your charger is just an exposed Linux box with high voltage attached.

ISO 15118 and Plug & Charge

Plug & Charge requires certificate exchange between:

* Vehicle OEM

* Mobility operator

* Charging infrastructure

In 1.6, this required awkward tunneling and vendor extensions.

In 2.0.1, it is native.

If you are building serious DC fast chargers today, 2.0.1 is not optional.

OCPP 2.1: The Grid Starts Moving

Released in January 2025, OCPP 2.1 extends 2.0.1 and adds:

* Bidirectional charging (V2X)

* DER integration

* Dynamic payment support

* Secure QR-based session flows

This is where it gets interesting.

When vehicles can discharge power:

* V2H (vehicle-to-home)

* V2G (vehicle-to-grid)

The charger becomes a coordination node.

And the backend becomes an orchestrator of distributed batteries.

At scale, that means millions of mobile storage units participating in grid balancing.

The physical charger becomes infrastructure plumbing.

The real asset becomes the battery — moving down the highway.

The Bigger Picture

The shift from 1.6 to 2.0.1 and 2.1 is a shift:

From ambiguity → determinismFrom flat config → digital twinFrom best effort → structured reliabilityFrom charging → energy orchestration

We are moving from “start a charging session” to:

“Coordinate distributed energy assets dynamically across the grid.”

And that is a completely different future.

The car is no longer just consuming electricity.

The car is becoming part of the grid.

David, if you’re reading this — or listening back —

May your TLS handshakes succeed.May your heap never fragment.May your sequence numbers stay ordered.

And may your latency be low and your uptime high.

See you in the next deep dive.



This is a public episode. If you would like to discuss this with other subscribers or get access to bonus episodes, visit frahlg.substack.com
...more
View all episodesView all episodes
Download on the App Store

Coordinated with FredrikBy Fredrik Ahlgren