Constants for multiple rule-files

Hello alltogether,
I am using OpenHab 3.

I created a rules file for every Room. (z.B.: Office.rules, Kitchen.rules)

I build in some buttons with different actions, depending on the time, the button was pressed.

These times I want to setup in a global file, and use this setting in every rule.

Definition of constants:

val int TIME_1 = 5
val int TIME_2 = 10

An example of the block, I use in multiple files:

var Timer timer1 = null
var Timer timer2 = null

rule "Name"
when
  Item input changed from OFF to ON
then
  timer1?.cancel
  timer2?.cancel
  timer1 =
    createTimer(
      now.plusSeconds(TIME_1))
    [|
      ...
      timer1 = null 
    ]
  timer2 =
    createTimer(
      now.plusSeconds(TIME_2))
    [|
      ...
      timer2 = null 
    ]
end

I don’t think creating Items for every value is not the right way, cause I want to enshure these values are not overwritten by the users. I don’t want to create these constants in every file, cause if I repair a failure, I have to fix multiple files.

What’s the best solution?

English please, this is an international community!

Changed text to english.

Keep all rules depending on those values in one file.

Another option is to use shared cache

afaik it’s possible to use this from Rules DSL, too. You will have to implement the constants via a system started script.

In the past, I have also used either variables defined within a rule, or Items containing ‘Parameters’.
I wasn’t super keen on either approach, as I didn’t want a huge number of items for just storing values, and in my case, I also preferred not to use variables, as I would prefer such a simple change not to require scripting changes (sometime across multiple rules)…

So lately, I have started using Custom NameSpace MetaData to store such values within an item (but not the item value itself). Some benefits are:

  • Its value cannot be set by a user, unless they are logged in as an Admin (Well - I’m reasonably sure they cannot!!)
  • Its value CAN be set via the Admin UI (Or via a script as well if you wish)
  • It’s non-volatile, so survives a reboot, without needing any persistence-service ‘restore on startup’ (unlike an item value)
  • Multiple Metadata Fields can be set within the context of an item

The latest scripts I have written, start using this approach, and seem to work well so-far. It lends itself well to Generic scripts, working with different items, each storing their own value

So in ECMA2021, getting a value from MetaData is as easy as:

runtime = parseInt(items[itemname].getMetadata("close_time").value)

And setting them is done in the UI:

I have some disclaimers here:

  • I am using OpenHAB 4, and not sure which version of OpenHAB introduced Custom NameSpace MetaData, but I think it’s been there for a while
  • I have transitioned all my DSL rules over to ECMA2021 JS - I don’t believe in the past it was supported in DSL rules, but no idea if that has changed in subsequent releases
  • I also have made a few assumptions about the use case you describe, so perhaps values aligned to/contained within an item you are trying to control is not quite right !!

Next winter, I will also refactor all my older rules to use this approach, and hopefully get rid of quite a few items I used to just store parameters, and also those defined in the rules themselves.

Cheers

Can you update the metadata with a script or is the data static?

Would anyone who knows how to do it in rules DSL care to give a code example ? Thanks.

Yup - An example, whilst for Expire MetaData, can be found hidden in this gem: https://community.openhab.org/t/expire-updater-4-0-0-0-4-9-9-9/144640

Whilst I started going down this route (updating MetaData from scripts etc), I quickly realised I was trying to solve a problem I didn’t yet have !!

For my requirements, I now think in a analogous fashion to an Alarm system configuration, which has a user-mode, and installer mode in the control panel:

  • The type of settings which would only be available/configurable in ‘Installer Mode’ in an alarm (e.g. Entry Delay, Exit Delay, Zone Setting Flags), are the kinds of settings I would store in Custom Namespace MetaData - They should not need to be changed frequently, and if doing so, a bit of thought should be applied. I think of ‘Admin mode’ in the OpenHAB UI as being similar to Installer Mode in the alarm
  • Other settings which should be user controllable, I am using Item values, with every-change/restore-on-startup persistence, and these can easily be displayed/controlled via Main UI pages

Again, this suits my current use-cases, but there is no one-size-fits-all in OpenHAB, right? :slight_smile:

What I am asking is there a way and an example to update the metadata with a piece of code similar to the example you have supplied to get the data?

Can you post the example of how to do it?

Thanks

Correct.

Not necessarily. You can pass a lambda that initializes the value in the cache if it’s not already defined.

sharedCache.get('foo', [ | 'bar'])

That will initialize the entry for ‘foo’ to ‘bar’ if there isn’t already a value there.

That’s not terribly useful for this particular use case but it is really handy in others, for example timers.

I think they can. Setting metadata is through the /items API endpoint and that endpoint is allowed to all users. I doubt the constraints are more constrained than that but it’s worth a test.

OH 2.0. It’s been around for as long as we’ve had Things.

Setting and retrieving Item metadata from Rules DSL I believe is still not possible.

See above for getting with a default.

sharedCache.get('foo') // returns null if doesn't exist
sharedCache.put('foo', 'bar')
shareCache.put('foo', null) // deletes the entry

The same methods exist on privateCache. privateCache is a way to store values between runs of the same rule.

Note that timers stored in either cache will get cancelled when the last rule with a reference to that entry is unloaded. This is a great way to avoid orphaned timers.

OK, back to the original post, @Lexor .

You don’t need to show them to your users. There is a visibility flag on Items that you can set the Item to be hidden from regular users. It’s not a security measure but unless you have some particularly crafty and malicious users in your home, they aren’t going to be issuing REST API requests to change things.

Is there an if there somewhere? There’s no logic to do something different at different times of day in this example. I’ll assume it’s there and just not represented in this redacted example.

This might be the root cause of your issue. If you are using file based configs, it’s rarely the case where organizing everything by location makes sense. You will have lights in most of the rooms. The lights will behave similarly in most of the rooms. If you split this logic up between multiple files you end up smearing your logic across lots of files which results in lots of duplication.

If you organize based on function then similar logic ends up being colocated in the same file and this problem largely disappears. Have some logic or constants that are shared by all your lights? Well if all the lighting logic is in the same file you can make them global variables and reuse them across all your rooms because all the lighting rules are in the same file.

Therefore, even as far back as OH 1.6 I’ve always recommended organizing your files based on functionality, not location. That ensures that the rules that are similar to each other are colocated in the same file, allowing for more opportunity to reuse.

The fact that you have many rules with the same “block” of code in multiple files is a code smell. It is a further indication that your current organization is not ideal. If these were in the same file would you need to duplicate that same block of code over and over? Maybe you could use a global lambda instead. Maybe you could just have the one rule to handle the lights in all the rooms.

Not in Rules DSL. You can in any other rules language including Blockly.

1 Like