JS in OH 5.2.0 no longer supports "load"

Hello,

I use a lot of JS libraries that, for example, are included in currently OH 5.1.3 as follows:

load(OPENHAB_CONF + ‘/automation/lib/javascript/personal/HJK_Lib_V11.js’);
load(OPENHAB_CONF + ‘/automation/lib/javascript/personal/Heating_Lib_V11.js’);
load(OPENHAB_CONF + ‘/automation/lib/javascript/personal/AC_Lib_V11.js’);

In OH 5.2.0, the “load” statement is apparently no longer available. OH is running on Debian 13.6.0 in a virtual machine environment.

Does anyone have any idea how to re-enable the load statement?

Regards,
Hans-Jürgen König

No, I don’t think the load statement can be re-enabled and I wasn’t even aware that it was supported at all.

The proper way to load a library is to use require in JS Scripting. However, it requires you to format and “install” your library as a node module. More details can be found at JavaScript Scripting - Automation | openHAB.

Hi Rich,

Thanks so much for the quick help.

I’ve been using the load command for a long time; I actually learned it from you:

I’ve read quite a bit about the npm method and always thought, why make it so complicated when it can be done simply with load:slight_smile:

I think rewriting the libraries will take some time, and I’ll have to test it first, especially the dependencies between the libraries.

Back then we were talking about Nashorn JS, not JS Scripting which is a wholly different and more up to day JS environment.

You probably don’t need to rewrite the libraries at all. You just need to add a couple files to the folder and put the folder in the right place in the right way so it looks like a node module. And npm will do most of the work for you.

Once that’s done you just replace load(OPENHAB_CONF + ‘/automation/lib/javascript/personal/HJK_Lib_V11.js’); with const {Class1, Function2} = require('scubas-library'); where “Class1” and “Function2” are just the stuff you are using from that library.

load actually copies the .js file into the rule as it is written. If you, for example, had the variable foo defined and used one way in HJK_Lib_V11 and in AC_Lib_V11, the second load would overwrite the first one. And any time HJK_LIB_V11 writes to the variable foo it interferes with AC_Lib_V11.

If you did const {HJK, AC} = require('scubas-library');, then all of HJK is isolated under “HJK” and all of “AC” is isolated under “AC”. So that foo variable defined in both won’t interfere with each others.

In addition, I don’t think load does dependency tracking so if you change the library you have to reload your rule to pick up the changes. JS Scripting has dependency tracking so if you change the library, all the rules that use it reload themselves.

Finally, the node module construction allows you to define what gets exposed and what remains internal to the library which also can help prevent collisions in the namespace.

I think there are other benefits as well.

Anyway, it’s this way becuase this is how Node.js works and JS Scripting is a Node.js environment.

But if you follow the instructions, you’ll create an empty node module using npm which will create a index.js and package.json file for you using the information it asks for.

You don’t need to touch package.json.

index.js will be where you define what is exported and how.

You can start with this empty node module, tar it up and install it to your OH. Then you can add in your library to that folder and continue editing your library in place. You only need to do this step once.

Here’s my index.js:

module.exports = {
  get alerting() { return require('./alerting.js') },
  get utils() { return require('./utils.js') }
}

I would expect yours to look something like

module.exports = {
  get HJK() { return require('./HJK_Lib_V11.js') },
  get Heating() { return require('./Heating_Lib_V11.js') },
  get AC() { return require('./AC_Lib_V11.js') }
}

Then in your library you just need to add export to your functions or anything else you want to make available. Here’s my alerting.js file.

exports.sendAlert = function(message, logger) {
  var logger = (logger) ? logger : log('sendAlert');
  logger.warn('ALERT: ' + message);
  actions.notificationBuilder(message).addUserId('some email address')
        .withTitle('Alert')
        .send();
}

exports.sendInfo = function(message, logger) {
  var logger =  (logger) ? logger : log('sendInfo'); 
  logger.info('INFO: ' + message);
}

exports.isNight = function() {
  const currToD = items.getItem('TimeOfDay').state;
  return currToD == 'NIGHT' || currToD == 'BED';
}

exports.isAway = function() {
  return exports.isNight() || items.getItem('Presence').state != 'ON';
}

exports.getNames = function(group, filterFunc) {
  return items.getItem(group.name || group).members
                             .filter(filterFunc)
                             .map(s => (s.getMetadata()['name']) ? s.getMetadata()['name'].value : s.label)
                             .join(', ');
}

To call the isAway() function in a rule:

const alerting = require('rlk_personal');

...

if(alerting.isAway()) {
...

Maybe you can do it another way, using “require” and without npm.

Write your functions and objects and save them wherever you want. Then you can export and load them. Here is an example:

The library: (example_conf.js)

const ventilationDefaults = {
  defaults: {
    Humidity: 40,             // [%]
    minTemperature: 20,       // [°C]
    maxFanTime: 20,           // [min]
    intervalFan: 20           // [min]
  },
  intervallWarnMessageLog: 60 // [min]
}

// function to add gVentialtion to nessesary items
const prepaireItems = () => {
  // do what's to do
  // ...
}

module.exports = { prepaireItems, ventilationDefaults }

In your rule- file:

const ventilationDefaults = require('../conf/example_conf.js').ventilationDefaults
const { prepaireItems } = require('../conf/00_RNTs-ventilation_conf.js')

prepaireItems()

Here, the example_conf.js file is on the same level as the js file.

Thank you so much for both solutions!

I’ve already successfully tested the slightly simpler one.