Function Node Programming-Part 1

Introduction

The function node is used to run JavaScript code against the msg object.

The function node accepts a msg object as input and can return 0 or more message objects as output.

This message object must have a payload property (msg.payload), and usually has other properties depending on the proceeding nodes.

In order to use the function node you will need a basic understanding of JavaScript.



In this series of tutorials will be covering JavaScript basics to get you started using the function node.

Variables

In JavaScript you need to create a variable before you can use it.

Variables are declared and assigned usually at the same time but that can be done separately.

var name; //declared
name=”steve”; assigned

There are three ways to create a variable using the keywords var, let and const.

var name=”steve” //declared and assigned
let name=”steve”
const name=”steve”

Let is relatively new so in older scripts you will only see the var and const declarations.

Let is commonly used in newer scripts in place or var but there is a difference in the two.

The difference is the variable scope. Variables assigned with the var keyword are global or functional scope whereas let is block scoped.

Anything enclosed in a curly brace is a block.

Another thing with let is that you cannot re-declare it in a block.

Const is for constants which are variables that do not change.

Very often you will see constant variable names as all Caps e.g

const NAME=”steve”

Variable names in JavaScript are camel case, but I often use underscores as I also do quite a bit of Python coding which uses underscores. So we have

firstName=”steve” //JavaScript

first_name=”steve” //Python

This code works

let payload=msg.payload;
let x=0;
if (payload>=2)
{    x=2;
}
else
{  
 x=1;
} 

msg.payload=x;
return msg;

this code doesn’t work

let payload=msg.payload;
 if (payload>=2)
{  
let  x=2;
}
else
{   
let x=1
;

and we get this error:

References

Context Variables (Objects)

Note: Node red documentation uses the term context variables but I find the term context objects less confusing

Variables in a function node are only valid when the code in the function node is running.

The code runs when a message is passed into the function node.

If you need to store the state of a variable so that it is available the next time the code on the function node runs then it needs to be placed in a “context object”.

There are three types of “context object” available

context – available only in the function node it was declared in
flow -available in all nodes in the flow (tab) it was declared in.
global – -available in all nodes in all flows (tabs).

The variables are retrieved using the following syntax

let data =context.get(“data”);
let data =flow.get(“data”);
let data =global.get(“data”);

Any changes are stored back in the “context object” using the set method.

context.set(“data”,data);
flow.set(“data”,data);
global.set(“data”,data);

Data stored in the context, flow and global variables is known as context data and it is normally stored in memory.

This means that if you restart node-red then the data is lost.

However from version 0.19 it is possible to store the context data in the file system.

In order to do this you will need to modify the settings file and add the following entry:

contextStorage: {   default: “memoryOnly”,   memoryOnly: { module: ‘memory’ },   file: { module: ‘localfilesystem’ }},

It doesn’t matter where in the settings file you place it and depending on the version of node-red you started with you may already have an entry that is commented out.

The settings above configure node-red to use the default store in memory and also the file system for the filestore.

We therefore have two stores.

When saving data to the context variables or retrieving data from them you will need to specify the store they are in. The default is in memory.

So if you use:

var count=context.get(“count”);

You will retrieve the count variable from memory and to get the count variable from the file store use:

context.get(“count”, “file”);

To store data use:

context.set(“count”, count,”file”);

The system stores the variables in a JSON file in a folder called context under the .node-red folder.

Even though you are storing data in the file system it is still possible to loose data as the data is only flushed to the file system every 30 seconds.

You can change this (no real need) and other configuration options see the docs here.

You should also note that you can have two variables with the same name but one is stored in memory and the other in the file system as shown in the screen shot below:

Using a Single Variable or an Object

When storing data in context variables you can use an object like an array or object to hold multiple variables or a collection of single variables.

So imagine we have 2 counters we could use:

Single variables e.g. count1 and count2

Or an object called data with two counters data.count1 and data.count2.

My preference is for the object as it is easier to initialize and more flexible.

To initialize we use:

Let count1=context.get(“count1”) || 0; //single variable

However this can cause problems due to how JavaScript treats true and false.

This is illustrated in the following code;

The count is set to 2 by the first line of code if the count variable doesn’t exist which is true when the code is first run. However the counter is decremented and should quickly go negative but doesn’t.

This is because when the count=0 the count is reset to 2 and JavaScript treats 0 as false. This is shown in the output of the debug node.

To overcome this I use the code below:

Notice the use of typeof which checks for the existence of the count variable and sets it if it doesn’t already exist.

 

Creating New Message Objects

If the function node has multiple outputs then it is common to use a different message object for each output.

Often you will assign a blank object at the start of the function and assign properties and values later on.

Generally you assign a topic and payload to the message object but it is not mandatory and you can assign any properties that you wish.

let msg1={};

let msg2={};

msg1.payload=””;

msg1.topic=”test”;

Returning From a Function Node

You will see several return options

return ; // will return from the function and nothing is passed on the outgoing link.

return msg; // will return from the function and pass the message object on the outgoing link.

return null; //same as simple return

return [msg1,msg2];//return from the function and pass msg1 on output1 and msg2 on output 2.

return[[msg1,msg2]]; // return from the function and pass msg1 and then msg2 on output1. There is no output 2.

Returning a Message before the end of a Function

There is often a need to return a message object while the function is still running. To do this we use node.send(msg). The following code will return ten messages from a function node.

For (let i=0,i<10,i++)

{

msg.payload=i;

node.send (msg);
}


There should be no return statement from the function node.

You can return multiple messages and messages on multiple outputs using the same syntax as shown in the return statement. For example to return a message on output 1 and output 2 use:

node.send([msg1,msg2]);

Part 2–>Function Node Programming-Arrays,objects and Loops

Related resources and tutorials:

 

Click to rate this post!
[Total: 0 Average: 0]

Leave a Reply

Your email address will not be published. Required fields are marked *