functionGlobalContext on Raspberry PI

Hello everybody,

I have a problem with loading an external function on a Raspberry PI.
To load the module I added it in the "settings.js".

functionGlobalContext: {
		arfunc:require('to-array')
}

In the function-node I include it.

var arFunc = context.global.get('arfunc');

On my Win10 notebook it works fine, but on the rasp i get an error.

21 Oct 21:28:39 - [error] [function:DataToJSON] TypeError: Cannot read property 'toArray' of undefined

I stopped and started node red several times, but it didn't solve it. :laughing:
Any ideas, what I'm doing wrong? :thinking:

Thanks in advance for any answer!

Cheers KeMa

As per documentation:

functionGlobalContext: { osModule:require('os') }

can be accessed in a function node as:

var myos = global.get('osModule');

Wow,

this was a really quick response, thank you bakman2! :+1:

I changed the function node, but unfortunately I get the same error.

@KeMa what versions of Node.js and Node-RED are you running on the Win10 notebook and on the Pi?

On win10 I'm running

20 Oct 14:35:08 - [info] Node-RED version: v0.20.7
20 Oct 14:35:08 - [info] Node.js  version: v10.16.3

on the rasp the latest version

21 Oct 22:33:12 - [info] Node-RED version: v1.0.2
21 Oct 22:33:12 - [info] Node.js  version: v10.16.3

After an update on the win10 to

21 Oct 22:55:39 - [info] Node-RED version: v1.0.2

the flow also runs well.

I made a reinstall on rasp with no effect. Could this problem be related to some rights?

Which directory did you install the module in?

Can you share a bit more of your Function code so we can see how you are trying to use the module?

The location of the folder with the Index.js is

/usr/lib/node_modules/node-red/node_modules/to-array 

I'm using it like that

var datAr = msg.payload;
var arFunc = global.get('arfunc');
var dbg = arFunc.toArray(datAr, 5);

From the docs for the to-array module, the example usage is:

var toArray = require("to-array")
    , elems = document.links
 
var array = toArray(elems)

Note that the toArray function is what the require(...) call returns.

Looking at what you've shared, you are adding the module to global context like this:

arfunc:require('to-array')

This means the arfunc global context value is the toArray function.

Looking at the Function code:

var arFunc = global.get('arfunc');
var dbg = arFunc.toArray(datAr, 5);

You access the global and assign it locally to arFunc. You then try to call .toArray ... but arFunc is already the toArray function you want to use.

This code should be:

var datAr = msg.payload;
var arFunc = global.get('arfunc');
var dbg = arFunc(datAr,5);

Ok, understood!
But now I get the error message

TypeError: arFunc is not a function

I tryed it with the module 'bytes'

functionGlobalContext: {
                arfunc:require('to-array'),
                bfunc:require('bytes')
}

call it

var bytes = global.get('bfunc');
flow.warn(bytes(65535));

and get the error message

TypeError: bytes is not a function

When I send the 'bytes' to a debug-node it is undefined.

I try to understand, how to write and include external functions.

This might suggest the module is not in the correct place.

How did you install these 2 modules?

I don't know your final intended use cases but as a suggestion...

Have you considered using https://flows.nodered.org/node/node-red-contrib-function-npm

This suggests the settings file you are editing is not the settings file Node-RED is using.

Which file are you editing and what settings file does Node-RED log it is using when it starts up?

@knolleary that's it!
I edited the wrong settings file in "/usr/lib/node_modules/node-red" all the time! :man_facepalming:

Thanks a lot to all!:+1:

1 Like

How did you decide which was the correct settings file? I am having exactly the same issue...

  • I am editing home/pi/.node-red/settings.js

  • The JS file is part of a node_module that I installed. The node_module is in /home/pi/.node-red/node_modules/dateformat and the js file is in /home/pi/.node-red/node_modules/dateformat/lib/dateformat.js

  • in my settings.js I have ...

functionGlobalContext: {
dateformat:require("/home/pi/.node-red/node_modules/dateformat/lib/dateformat.js")
},

At first, instead of the path to the JS file, I tried simply dateformat.require("dateformat") but that didn't work either.

  • this all works in Visual Code Editor running as a node.js module.

  • in node-red function node I have...

var dateFormat = global.get("dateformat");
var theDate = new Date(msg.payload);
var formattedDate = dateFormat(theDate, "ddd dd-mmm-yyyy");
msg.payload = formattedDate;
return msg;

And the response I get is TypeError: dateFormat is not a function

I can't find any useful documentation on how to do this.

Any help or pointers would be most appreciated.

Yes, that's the right one.

I did it like this:

dateformat:require('dateformat');

The node module must conform to the conventions!
In the module folder "dateformat" must be the index.js which includes the sub-modules in the lib folder.
It is also possible to type the code direct in the index.js.

https://www.w3schools.com/nodejs/nodejs_modules.asp

That's given me a few ideas as to what is wrong then.

Does that mean that if I copy dateformat.js to become index.js in the dateformat folder that it should work?

I also saw articles about module.exports - does that come into play somewhere?

I'm answering my own last msg :grinning: :grinning:

What I learned is this: when I hit Ctrl-C on the node-red console, it chops the console but it doesn't chop the node-red service, so I had been making edits, hitting Ctrl-C in the console and then kicking off the service again. That did not recycle the service and so did not pick up my changes. I learned that after the Ctrl-C, I need to run node-red-stop followed by node-red-start in order to deploy my changes.

So, backing out stuff I didn't need...

  • I didn't need to add an exports command to my dateformat.js

  • I didn't need to have an index.js file in the dateformat folder - it had already been installed as a node using npm install and that was sufficient.

  • All I needed was...

functionGlobalContext: {
   dateformat:require("dateformat")

},

in the settings.js

  • and in my Function Node...

var dateFormat = global.get("dateformat");

var theDate = new Date(msg.payload);
var formattedDate = dateFormat(theDate, "ddd dd-mmm-yyyy");
msg.payload = formattedDate;
return msg;

then after properly restarting the service it all works.

So, all along, the help given in this thread was spot on, and my problem was that the node-red service was not being recycled like I thought it was.

Thanks for you help guys - I learned a lot.

1 Like