How Flowion maps onto OCPP
See where the protocol ends and Flowion's model begins: how three OCPP versions become one API, and how each translation is handled.
On this page
Flowion's API is built so that you never handle OCPP. This page shows the seam: what belongs to the protocol, what Flowion adds above it, and how the translation between the two is done.
The dividing line
Everything a charging station knows about is OCPP's. Everything above it is Flowion's.
Organization ─┐
└─ Project │ Flowion's: accounts, isolation, sites,
├─ Site │ electrical topology, live metering.
│ └─ Circuit │ OCPP has no idea these exist.
│ └─ Monitor ─┘
└─ Charger ─┐
└─ EVSE │ OCPP's: the three-tier hardware model,
└─ Connector │ transactions, cards, meter readings.
─┘
The charger is where the two meet. Above it, concepts exist because operators need them; below it, because the specification defines them.
| Flowion concept | What it gives you |
|---|---|
| Organization | Your account, billing and membership. |
| Project | The isolation boundary: one per brand, client or country. |
| Site | A physical location (a location in the API). OCPP has a Charging Location but gives it no protocol meaning. |
| Circuit | The wiring chargers hang off, as a tree. What load management works from. |
| Energy monitor | Live load on a circuit, from a meter beside the chargers. |
Core concepts covers these in full.
You ask for an outcome, Flowion picks the message
The API never names an OCPP message. You will not find StartTransaction or TransactionEvent in it. You ask for an outcome, and Flowion works out what goes on the wire for that charger:
| You ask for | Flowion sends |
|---|---|
| Start or stop a session, release a cable, restart | The command for the charger's version, queued until it is reachable |
| A setting, such as light intensity | A 1.6 configuration key or a 2.x device-model variable, and keeps it there |
| Who may charge, and offline behaviour | The station's authorization settings and, on 1.6, its local list of cards |
| A current limit on a charger | A charging profile |
| A share of a site's capacity | Current limits, updated as load changes |
| A message on the charger's screen | Display messages, re-sent if the charger loses them |
Several of these are desired state, not one-off commands. You say what a charger should hold; Flowion compares that with what the charger reports and corrects any drift it finds.
The result: one integration for a mixed fleet. A 1.6 charger and a 2.1 charger are the same kind of object to your code.
One model, shaped like OCPP 2.x
Flowion's model follows 2.x's structure, and 1.6 is mapped into it. That direction is deliberate: wherever the two differ, 1.6's shape is a special case of 2.x's, so mapping upward only ever adds structure and never throws any away.
For a 1.6 charger, that means:
Each connector becomes an EVSE. 1.6 has no EVSE tier, so connector n becomes EVSE n, holding one connector. Your code walks the same hierarchy for every charger.
Status is split in two. 1.6's single connector status mixes availability with what the outlet is doing. Flowion stores 2.x's split: a connector status, and a charging state on the session.
The transaction becomes an event log. StartTransaction, MeterValues and StopTransaction become Started, Updated and Ended events on one session, the same shape a 2.x charger produces.
Meter start and stop become readings. There are no meterStart or meterStop fields in Flowion's model. 1.6's two numbers become ordinary energy readings at the start and end of the session, which is what 2.x sends, so energy is worked out the same way for every charger.
Two identities per object
Every object has a Flowion UUID, and many also carry the identifier the protocol uses on the wire. Sessions show why both matter:
| Version | Who assigns the transaction id | Type | API field |
|---|---|---|---|
| 1.6 | the CSMS, in its answer to the start | integer | numericId |
| 2.x | the charging station, from the first event | string, up to 36 chars | textId |
A 2.x charger may pick the string "90210", which is not the same as a 1.6 integer 90210. Flowion keeps the two apart, so an id from one version can never be mistaken for the other.
Key on Flowion's UUIDs. They are stable and the same shape for every charger. The protocol ids are there for matching against a charger's own screen or logs.
When a charger cannot carry a request
Flowion's model is wider than any single protocol version. When you ask for something a charger's version cannot express, Flowion refuses with an error that says so, rather than sending something close:
| Request | Why a 1.6 charger cannot take it |
|---|---|
| Stop a session identified by a string id | 1.6 transaction ids are integers |
Release the cable on connector 0 | On 1.6, connector 0 is the whole station |
| Show a message on the screen | 1.6 has no display messages |
Check ahead with GET .../commands/capabilities, which the console also uses. Which OCPP version am I dealing with? lists the features tied to one version.
Values that change on the way in
A few 1.6 values have no exact 2.x equivalent. Each is mapped on purpose:
| 1.6 value | Becomes | Note |
|---|---|---|
Stop reason HardReset | ImmediateReset | 2.x's name for the same thing |
Stop reason SoftReset | Reboot | Reads the same as 1.6's own Reboot |
Stop reason UnlockCommand | Other | 2.x has no unlock stop reason |
Measurand Temperature, RPM | Charger metrics | Kept as diagnostic readings, not on the session |
| Signed meter data | Kept as received | Stored as the signed blob, not as a number |
| No stop reason | Local | The only case both versions allow it to be left out |
The other direction narrows too. Flowion can reach verdicts on a card that 1.6 has no word for, such as "not at this location" or "not at this time". Those reach a 1.6 charger as Blocked, while Flowion records the real reason, so your records say why even when the charger could not be told.
Fields only 2.x chargers fill in
These stay empty for a 1.6 charger rather than being guessed, so "the charger did not say" is always distinguishable from a real value:
Card type. 1.6 never says whether a card was RFID or anything else.
Trigger reason. 2.x says why it sent each transaction event.
Remote start link. 2.x sessions carry the
remoteStartIdof the remote start that began them.Offline flag. 1.6 cannot say "this happened while I was disconnected", so it always reads
false.Sequence numbers. A 2.x charger numbers its events, which reveals a gap. For 1.6, Flowion numbers them in arrival order, which keeps them ordered.
What Flowion adds on top
Some of the most useful records have no OCPP message at all. Flowion keeps them for every charger:
Boot history, so a firmware change or a restart loop shows up.
Registration progress, step by step, for a charger being set up.
Command history, with each command's status and the charger's answer.
Every inbound message the charger sent, for when you need the raw detail.
Status history and active faults per charger and outlet.
Where to go next
Quickstart: get a charger reporting.
API reference: every endpoint.