Defining and reuse a "classic" JS function

Hello !
I'm a bit lost in node-red, maybe I didn't wired the right nodes together... :sweat_smile:

The context
I'm working with LoRa sensors that send hexa code in the payload. Those datas are specific informations based on the "port" they use : 5 is battery info, 9 is an alive message, 30 is opening counter + temperature + humidity. So each one must be treated differently.
As we're three to work on the project, I wanted to have a clear flow, so everyone could see what happens.
I have a NR Function node by port used and each hexa data in the payload is converted specifically.

The question
As I'm lazy, like every programmer I guess, I wanted to create some hex2bin, hex2dec, hex2float functions and reuse them in my flow, without redefining them each time. They should be called in every Function node.
But I didn't find how to do this... And as Node-Red is using the concept of "Function", it's hard to find answers on Internet for "JS function" ! :slight_smile:

Create 3 subflows for hex2bin, hex2dec & hex2float

A subflow is kinda like a reusable function.

If you wanted to you could create just one subflow (that does all three operations) and you specify which operation by topic or by a subflow property.

Have a play, see what best suits your needs.

Or a different approach, write them as a JavaScript module and make it available for use in functions through functionGlobalContext, see the configuration documentation

2 Likes

But I didn't find how to do this... And as Node-Red is using the concept of " Function ", it's hard to find answers on Internet for " JS function " !

You can search for javascript hex2bin, you will find something like

function hex2bin(hex){
    return ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8);
}

For use in node-red, use a function node, something like:

function hex2bin(hex){
    return ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8);
}

input = msg.payload
output = hex2bin(input)

return {payload:output} 

I already have the functions, I just want to know how to reuse them in the whole flow, without copy/paste them. :slight_smile:
Like an include, if you prefer.

I'll give a try to a subflow and the functionGlobalContext and let you know. :slight_smile:
A lot of reading for this sunday !

Have a look here:

Ah ok misunderstood then subflow or functionGlobalContext are good ways to go.

1 Like

Works well !
I've done a mix with a subflow. :slight_smile:
My subflow, called "JS classic function", has an Inject node "trigger-on-start" and 2 functions (hex2bin and hex2dec) wired to it, so it's executed at 0.1s after Node-Red start and the functions are in memory.
I just had tyo had my Subflow to the flow to enable the classic JS functions.

image
image

Here's the code, if somebody is trying to do the same. :slight_smile:

[{"id":"f9586397.5973","type":"subflow","name":"JS functions","info":"","category":"","in":[],"out":[],"env":[],"color":"#DDAA99"},{"id":"7d7eee51.7878a8","type":"function","z":"f9586397.5973","name":"hex2dec","func":"global.set('hex2dec', function(hexa) {\n    return parseInt(hexa, 16);\n}, 'memoryOnly');\n","outputs":1,"noerr":0,"x":400,"y":80,"wires":[[]]},{"id":"2012dbe6.92df34","type":"function","z":"f9586397.5973","name":"hex2bin","func":"global.set('hex2bin', function(hex) {\n    return (\"00000000\" + (parseInt(hex, 16)).toString(2)).substr(-8);\n}, 'memoryOnly');","outputs":1,"noerr":0,"x":400,"y":40,"wires":[[]]},{"id":"df964a73.694328","type":"inject","z":"f9586397.5973","name":"Trigger on start","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":140,"y":40,"wires":[["2012dbe6.92df34","7d7eee51.7878a8"]]},{"id":"35ca0b72.bb35ec","type":"tab","label":"Test functions","disabled":false,"info":""},{"id":"92ec9209.762ac","type":"inject","z":"35ca0b72.bb35ec","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":120,"wires":[["3c377357.2eb52c"]]},{"id":"3c377357.2eb52c","type":"function","z":"35ca0b72.bb35ec","name":"Test 2 functions","func":"msg.payload = {\n    bin: global.get('hex2bin', 'memoryOnly')(\"0x777\"), \n    dec: global.get('hex2dec', 'memoryOnly')(\"0x777\") \n}\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":120,"wires":[["867de411.01ff3"]]},{"id":"ce6ea1e.e1e90e","type":"subflow:f9586397.5973","z":"35ca0b72.bb35ec","name":"JS Classic functions","env":[],"x":170,"y":60,"wires":[]},{"id":"867de411.01ff3","type":"debug","z":"35ca0b72.bb35ec","name":"Full msg","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":520,"y":120,"wires":[]}]

I don't think you need the subflow, since you use it to set the global functions once.
I'd use a function node instead.

That is an odd implementation of a subflow, but if it works, it works :wink:

"Normally" you would add an input and an output and route your message through the "node" (read subflow).

The subflow is just to have a "cleaner" view. :slightly_smiling_face:
Our first flow is very messy for the moment as we're new to Node-Red and we're trying to sell our project to our Directors. So it's straight to the result instead of a beautiful and well think code. There's a lot of functions, templates, gauges and other nodes. Maybe we should think differently...
As our LoRa sensor aren't well known, I have to write a full "deciphering" module. So it will probably looks way different at the end !

Anyway, many thanks for your help !

Similar to my approach here: Importing function from another node

Just for completeness. :slightly_smiling_face: