Skip to content

Code component

The Code component runs your own JavaScript for every message it receives. Use it whenever the ready-made components are not enough: changing an OCPP payload, combining several conditions, building a new message, or remembering values between messages.

Setting Description
Number of outputs How many outputs the component has. Outputs are numbered from 0.
Code Your JavaScript. It runs once per incoming message.

The default code passes every message on unchanged:

send(0, data);
Name Description
data The incoming message, see The message object. It is a copy – changing it has no effect until you send it.
send(output, value) Sends value to the output with the given number. Can be called several times, also for different outputs.
send(value) Sends value to all outputs.
debug(value) Shows value in the Console tab of the designer.
error(message) Reports an error. The component turns red and shows the message.
@[NAME] Replaced by the text of the variable NAME before the code runs. Wrap it in quotes in your code: '@[API_URL]'.
context.flowdata Values that travel with this message to the next components – get(key), set(key, value), rem(key).
context.instance Values stored in this component, shared by all messages – get, set, rem.
context.global Values shared by all components of the Lab – get, set, rem, plus variable(name) to read a variable at runtime.

If you don’t call send, the message stops here. That is how you filter messages – but remember that a dropped request is never answered (see Message flow).

  • The code runs in an isolated sandbox. require, network access (fetch), timers (setTimeout) and console are not available. Use an HTTP Request component for calls to other systems, a Delay component for waiting, and debug() instead of console.log.
  • The code must be synchronous. async/await and promises are not supported.
  • Values in context.instance and context.global are kept in memory. They are reset when the Lab restarts, e.g. during an update. Don’t use them as the only place for data you can’t lose.
  • get returns a copy. If you change an object you got from get, set it again.
  • If your code contains a syntax error, the component shows Erroneous code and stops processing messages until you fix the code and save again.

Override the heartbeat interval the CPMS sends in its BootNotification answer. Connect From CPMS → Code → To Charger:

// Answers have their payload in ocpp[2]
if (data.action === 'BootNotification' && data.msgType === 'CALLRESULT') {
data.ocpp[2].interval = 300;
}
send(0, data);

Some chargers send RFID tags in lower case, while the CPMS expects upper case. Requests have their payload in ocpp[3]:

const payload = data.msgType === 'CALL' ? data.ocpp[3] : null;
if (payload?.idTag && ['Authorize', 'StartTransaction'].includes(data.action)) {
payload.idTag = payload.idTag.toUpperCase();
}
send(0, data);

With Number of outputs set to 3: output 0 for everything, output 1 for meter values, output 2 for errors reported by the charger.

send(0, data);
if (data.action === 'MeterValues' && data.msgType === 'CALL') {
send(1, data);
}
if (data.action === 'StatusNotification' && data.ocpp[3]?.errorCode !== 'NoError') {
send(2, data);
}

@[NAME] is replaced by the text of the variable before the code runs, so text values need quotes in your code:

const url = '@[WEBHOOK_URL]';

For json, number or boolean variables, read the value with context.global.variable() instead – it returns the parsed value. With the variable TEST_CHARGERS (json) : ["DE*EXO*E0001", "DE*EXO*E0002"]:

const testChargers = context.global.variable('TEST_CHARGERS') || [];
// output 0: test chargers, output 1: all others
send(testChargers.includes(data.chargerId) ? 0 : 1, data);
if (data.action === 'StatusNotification' && data.msgType === 'CALL') {
const key = 'status_' + data.chargerId + '_' + data.ocpp[3].connectorId;
const previous = context.global.get(key);
context.global.set(key, data.ocpp[3].status);
// only pass on real changes
if (previous !== data.ocpp[3].status) {
send(1, { chargerId: data.chargerId, from: previous, to: data.ocpp[3].status });
}
}
send(0, data);

context.flowdata travels with the message, e.g. through an HTTP Request and its answer:

// before the HTTP Request
context.flowdata.set('chargerId', data.chargerId);
send(0, { evseId: data.chargerId + '*' + data.ocpp[3].connectorId });
// after the HTTP Request
const chargerId = context.flowdata.get('chargerId');
debug(chargerId + ': ' + data.status);
  • Use debug(value) anywhere in your code. Objects are shown expanded in the Console tab.
  • Put a Debug component on each output while you develop.
  • If the component turns red, select it – the error message is shown in its status and in the Console tab.