Using module in function node

I am trying to use the themeparks API package in Node-Red. I've got it installed on my machine, and have added it to the settings.js file, but my JavaScript knowledge is a bit limited on how to create an object that persists throughout the flow. I've tried creating a global variable in the setup tab of the function node, but nothing happens after I deploy and run the flow. Any suggestions on how to make this work are appreciated.

Setup code

Themeparks = global.get('themeparksAPI');
DisneyWorldMagicKingdom = new Themeparks.Parks.WaltDisneyWorldMagicKingdom();
global.set('wdwmk',DisneyWorldMagicKingdom);

Function code

wdwmk=global.get('wdwmk');
msg.openingtimes=wdwmk.GetOpeningTimes();
msg.waittimes=wdwmk.GetWaitTimes();
return msg;

I would first verify that the npm module has been correctly installed and added to settings.js (no typos etc.). Try putting adding a function node with only:

node.warn(global.get('themeparksAPI'));

... in the middle tab of the function node and see what it prints in the debug tab.

Thanks, I gave that a try and it appears to be installed based on the debug output

The node's documentation has examples. It seems GetOpeningTimes() ans GetWaitTimes() return a Promise, meaning they all called asynchronously. If you are running a current Node-RED version (v1.1.x), wee if it makes a difference if you change your function code to:

const wdwmk = global.get('wdwmk');
msg.openingtimes = await wdwmk.GetOpeningTimes();
msg.waittimes = await wdwmk.GetWaitTimes();
return msg;

Edit:
It would likely be better to store wdwmk in the node specific context. So:

// setup
context.set('wdwmk',DisneyWorldMagicKingdom);

// function
const wdwmk = context.get('wdwmk');

Thanks for the async hint, I'm not too familiar with that.

It runs now but never seems to continue beyond the function node (I just have a debug node after this to dump the complete msg object)

Do you get any other debug output if you wrap the calls in a try catch block?

const wdwmk = global.get('wdwmk');
try {
  msg.openingtimes = await wdwmk.GetOpeningTimes();
  msg.waittimes = await wdwmk.GetWaitTimes();
  return msg; // also try: node.send(msg);
} catch (error) {
  node.error(error)
}

Thanks; I think I'm getting somewhere now. This works, however, when ever I deploy the flow a second time, I get the following:

Error: 
 Failed to create second instance of "WaltDisneyWorldMagicKingdom" object.
 Please only create one instance of each location and re-use it.

Is there something in the close code I can add to destroy the instance I've created?

Try adding to the close part:

global.set('wdwmk', null); // or context.set if you used it

This should remove the last reference to the object so that the garbage collection can delete the object.

Thanks, gave that a shot but still getting it on second deploy (even after server restart)

Rather than do it on close. Check for existence at start and only set it if it doesn’t already exist in global.

Quite frustrating. It seems like the library tries to be too smart. Let me think for a moment.

Edit: Try what @dceejay suggested!

1 Like

Could using node context instead of global also help in this case (as I suggested earlier on)?

Thanks; I tried this, and while it only loads the first time, on subsequent deploys, the function can't seem to see it any longer.

TypeError: Cannot read property 'GetWaitTimes' of null

Did you remove the code from the close tab first?

:man_facepalming: ha no. That did the trick! Thanks so much for your help with this, I'm able to get data back and it seems to work through a re-deploy. Thanks again to you and @dceejay !

1 Like

Great! I'd be curious to hear what you're building based on a theme park API?

I had a bunch of iOS shortcuts written that directly accessed the Disney API so I could get wait times and such via Siri. They deprecated that version of the API, and the new one is a hassle to work with (especially given the limitations of shortcuts) so I am going to use this as a backend instead and let the package maintainers keep up with the Disney API changes.

Ah so you (and I assume your family) are frequent visitors or maybe you do some work there. Oh well, it's really not my business. I was just somewhat surprised to find there are API's for that and even a Node module. It's not relevant to me as I don't live in the US but just sounds interesting.

this node module also has the Europa Park in Germany :slight_smile: or Stockholm or similar
I am also curious why there is a node module for this :slight_smile:

Frequent visitors, yes! :slight_smile: The node module is very much unofficial, I believe most of it came from reverse engineering the websites and mobile apps. It supports theme parks around the world, not just Disney World.