Skip to content

Examples

Step-by-step flows for common use cases. Each example starts from the default flow:

Exolink Connect - Input Exolink Connect - Output
From CPMS ───────────────────────▶ To Charger
From Charger ───────────────────────▶ To CPMS <id>

If you’re new to the Lab, read How the Lab works first.


Goal: see all OCPP messages of one charger in the designer.

  1. Add a Switch and connect From Charger and From CPMS to it (keep the existing wires).
  2. Settings: Path to object $.chargerId, condition String === DE*EXO*E0001.
  3. Connect the first (green) output to a Debug component.

Open the Console tab: you now see the requests and answers of this charger in both directions.

To see only one kind of message, use an OCPP Action Switch instead of (or after) the Switch.


Goal: send every MeterValues request to your HTTP API, without changing what the CPMS receives.

From Charger ──▶ To CPMS (existing)
From Charger ──▶ OCPP Action Switch ──▶ Code ──▶ HTTP Request ──▶ Debug
(MeterValues)
  1. Add the variables METER_API_URL : https://example.com/metervalues and METER_API_TOKEN : <your token>.

  2. Add an OCPP Action Switch: Protocol Version 1.6, Message direction Charger -> CPMS, one output MeterValues. Connect From Charger to it. The no match output can stay unconnected here, because this is a side branch – the CPMS still receives everything over the original wire.

  3. Add a Code component after the MeterValues output to keep only requests and shape the data:

    if (data.msgType !== 'CALL') return;
    send(0, {
    chargerId: data.chargerId,
    receivedAt: data.msgAt,
    connectorId: data.ocpp[3].connectorId,
    transactionId: data.ocpp[3].transactionId,
    meterValue: data.ocpp[3].meterValue
    });
  4. Add an HTTP Request: URL @[METER_API_URL], method POST, Data passthrough serialization JSON, header Authorization = Bearer @[METER_API_TOKEN].

  5. Connect a Debug component with Path $.status to its first output while testing.


Goal: stream every OCPP message to an MQTT broker, one topic per charger and action.

  1. Add an MQTT Broker component with the host, port and credentials of your broker.

  2. Add a Code component and connect From Charger and From CPMS to it (keep the existing wires):

    send(0, {
    topic: 'ocpp/' + data.chargerId + '/' + data.msgFrom + '/' + data.action,
    data: data
    });
  3. Add an MQTT Publish component, select your broker and leave Topic empty – the topic comes from the message. Connect the Code component to it.


Send a command to a charger with one click

Section titled “Send a command to a charger with one click”

Goal: reset a charger from the designer, e.g. during commissioning.

Trigger ──▶ OCPP Encoder/Decoder (Reset) ──▶ To Charger
  1. Add a Trigger with Data type Object and the data:

    { chargerId: 'DE*EXO*E0001', type: 'Soft', msgId: 'lab-' + Date.now() }
  2. Add an OCPP Encoder/Decoder: Message direction Backoffice -> Charger, Message type Reset.

  3. Connect Trigger → Encoder → To Charger.

Click the Trigger to send the command.

Handle the charger’s answer. The charger answers on From Charger – and with the default flow, that answer is forwarded to your CPMS, which never sent the request. Give your own requests a recognisable message ID (the lab- prefix above) and keep their answers out of the CPMS: put a Code component between From Charger and To CPMS with two outputs:

// Answers to requests sent by the Lab go to output 1, everything else to the CPMS
if (data.msgType !== 'CALL' && data.msgType !== 'event' && String(data.msgId).startsWith('lab-')) {
send(1, data);
return;
}
send(0, data);

Connect output 0 to To CPMS and output 1 to a Debug component to see the charger’s answer.


Goal: another system starts a charging session with an HTTP call:

POST https://<your Lab's address>/api/remote-start/DE*EXO*E0001
x-api-key: <your key>
{ "idTag": "04A2B3C4D5", "connectorId": 1 }
HTTP Route ──▶ Code ──(0)──▶ OCPP Encoder (RemoteStartTransaction) ──▶ To Charger
──(1)──▶ HTTP Response (202)
──(2)──▶ HTTP Response (401)
  1. Add the variable LAB_API_KEY : <a long random key>.

  2. Add an HTTP Route: method POST, URL address /remote-start/{chargerId}, Body type JSON.

  3. Add a Code component with 3 outputs:

    if (data.headers['x-api-key'] !== '@[LAB_API_KEY]') {
    send(2, { error: 'unauthorized' });
    return;
    }
    send(0, {
    chargerId: data.params.chargerId,
    idTag: data.body.idTag,
    connectorId: data.body.connectorId,
    msgId: 'lab-' + Date.now()
    });
    send(1, { accepted: true });
  4. Output 0 → OCPP Encoder/Decoder (Message direction Backoffice -> Charger, Message type RemoteStartTransaction) → To Charger.

  5. Output 1 → HTTP Response with status code 202. Output 2 → HTTP Response with status code 401.

  6. Keep the charger’s answer away from the CPMS as described in the previous example.

The HTTP caller receives 202 as soon as the command was sent. The charger’s answer (Accepted or Rejected) arrives later on From Charger.


Goal: a charger sends DataTransfer requests with the vendor ID com.example.diagnostics, which your CPMS rejects. Accept them in the Lab and forward everything else.

From Charger ──▶ OCPP Action Switch ──(DataTransfer)──▶ Code ──(0)──▶ OCPP Encoder (Response) ──▶ To Charger
│ └─(1)──▶ To CPMS
└─(no match)──────────────────────▶ To CPMS
  1. Replace the wire From Charger → To CPMS with an OCPP Action Switch: Protocol Version 1.6, Message direction Charger -> CPMS, output DataTransfer. Connect no match to To CPMS.

  2. After DataTransfer, add a Code component with 2 outputs:

    if (data.msgType === 'CALL' && data.ocpp[3].vendorId === 'com.example.diagnostics') {
    data.status = 'Accepted';
    send(0, data);
    return;
    }
    send(1, data);
  3. Output 0 → OCPP Encoder/Decoder with Message direction Response (Auto-detect) → To Charger.

  4. Output 1 → To CPMS.

The charger receives [3, "<msgId>", {"status": "Accepted"}]; the CPMS never sees these requests.


See Multiple CPMS.