All previews
OCPP556 wordsnot yet seeded

Building an OCPP Firmware Stack for AC and DC Chargers

What an embedded OCPP client has to do beyond sending messages: state reconciliation, persistence across reboot, backoff, and the concurrency that causes most defects.

Technically reviewed by Anees P K, Director of Technology. Last reviewed 2026-09-01.

An OCPP client looks like a messaging problem and is really a state synchronisation problem. Two systems hold a view of what a charger is doing, they are connected by an unreliable link, and both must remain correct when the link fails at an inconvenient moment.

Implementations that treat it as message formatting work correctly until the first interruption.

Persistence is the foundation

A charger can reboot mid-session, and when it comes back it must know a transaction was in progress. Without persistence, that session is lost, the connector may be left in an inconsistent state, and the backend has an open transaction that never closes.

What has to survive a reboot is the active transaction, its identifiers, its start reading, and any queued messages not yet acknowledged. This is a storage design decision made early, and adding it later usually means restructuring the state machine.

The outbound queue

Messages generated while offline have to be stored and delivered later, in order, without duplication. Duplication happens when the charger sends, loses the connection before the acknowledgement, and cannot know whether it arrived.

The client must therefore assume duplicates are possible and the backend must detect them. Designing as though an acknowledgement is guaranteed produces double-billed sessions.

Reconnection and backoff

Fleet-wide synchronised reconnection is a real failure mode. A backend that survives normal load can be overwhelmed by a thousand chargers reconnecting simultaneously after a regional network event.

  • Retry with increasing intervals rather than continuously, so a failed backend is not hammered by an entire fleet.
  • Add randomisation, so units that all lost connectivity together do not all reconnect in the same instant.
  • Cap the interval, so a charger does not effectively give up after a long outage.
  • Reset the strategy only on a genuinely established session, not on a TCP connection.

Concurrency is where the defects live

The pilot state machine, the metering loop, the message handler and the update mechanism all run concurrently and all touch shared state. Most difficult OCPP defects are races between them rather than protocol misunderstandings.

A common example is a remote stop arriving as the vehicle disconnects, producing two paths that both try to end the same transaction. Which wins, and whether the result is one clean stop or two conflicting ones, depends on locking nobody documented.

Clock handling

Timestamps must be plausible even when the charger has no network. A unit that boots with an invalid clock and starts a session produces records that cannot be reconciled, and correcting the clock mid-session creates a transaction that appears to end before it started.

The workable approach is a monotonic source for durations and an absolute clock for timestamps, with a defined behaviour for the window before the absolute clock is trusted.

Separating protocol from product

The protocol client should not know about contactors or pilot voltages, and the charging state machine should not know about message formats. Where those concerns mix, supporting a second protocol version means touching charging logic, which is how a protocol upgrade becomes a safety review.

This separation is the single design decision that most affects what a later migration costs.

AC and DC differ more than the protocol suggests

The message set is largely shared. What differs is the underlying charging control: DC involves a communication protocol with the vehicle and a far more involved power control loop, and its timing constraints are tighter.

A stack written for AC and extended to DC usually needs its concurrency model revisited rather than only its state machine widened.