
Sign up to save your podcasts
Or


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.
By Fredrik AhlgrenIt 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.