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.
⚙️ – Settings
Section titled “⚙️ – Settings”| 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);🧰 – What you can use in your code
Section titled “🧰 – What you can use in your code”| 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).
Limitations
Section titled “Limitations”- The code runs in an isolated sandbox.
require, network access (fetch), timers (setTimeout) andconsoleare not available. Use an HTTP Request component for calls to other systems, a Delay component for waiting, anddebug()instead ofconsole.log. - The code must be synchronous.
async/awaitand promises are not supported. - Values in
context.instanceandcontext.globalare 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. getreturns a copy. If you change an object you got fromget,setit 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.
💡 – Examples
Section titled “💡 – Examples”Change a value in a CPMS answer
Section titled “Change a value in a CPMS answer”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);Rewrite a field in a charger request
Section titled “Rewrite a field in a charger request”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);Route to several outputs
Section titled “Route to several outputs”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);}Use variables
Section titled “Use variables”@[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 otherssend(testChargers.includes(data.chargerId) ? 0 : 1, data);Remember the last status per charger
Section titled “Remember the last status per charger”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);Keep a value for a later component
Section titled “Keep a value for a later component”context.flowdata travels with the message, e.g. through an HTTP Request and its answer:
// before the HTTP Requestcontext.flowdata.set('chargerId', data.chargerId);send(0, { evseId: data.chargerId + '*' + data.ocpp[3].connectorId });// after the HTTP Requestconst chargerId = context.flowdata.get('chargerId');debug(chargerId + ': ' + data.status);🐞 – Debugging your code
Section titled “🐞 – Debugging your code”- 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.