Global functions for use in rules

  • Platform information:
    • Hardware: Raspberry Pi 3
    • OS: openHABian
    • openHAB version: 2.1

Hello,

I’m stuck here and I do not find much here in the forums or through Google. Or maybe I just do not understand how to read and use what I found.

What I try to achive is creating global functions (like I know from PHP) which I can use in my rules. Especially notifications are the same for most of my rules, like for example:

sendXMPP("roi@jabber", new DateTimeType() + ": Text")
sendTelegram("telegram1", new DateTimeType() + ": Text")
sendXbmcNotification("kodi:xxx@1.2.3.4", 80, "Topic", "Text")

So I write the same again and again, also with the users and passwords and everything else (e.g. before sending a notification to Kodi/XBMC I check if the host is online).

So is there something I can use, like

MyOwnXbmcNotification("Topic","Text")

which I define somewhere as a globally usable function?

Thank you very much for pushing me in the right direction.

Cheers,
Roi

1 Like

So is there something I can use … which I define somewhere as a globally usable function?

The answer, I’m afraid, is no. There is no support for global functions in openHAB.

I think the two options you are faced with are the following:

  1. Define an item (e.g. String MyOwnXbmcNotification) and post an update to this like this:

MyOwnXbmcNotification.postUpdate(“Topic; Text”)

and then create a rule to do the notification work.

  1. Create a script/program outside openHAB that can do the notification work, and call this using the “executeCommandLine”-action.

Granted, none of these approaches are ideal, but I think it is the best you can do as the situation is.

1 Like

@KjetilA Thank you for your answer - although it does not sound very promising. Are global functions a feature which is planned for the future, or maybe already has a milestone? I am sure many people would like to see this as, at least for me, my problem does not look very special. :wink:

If I cannot use a global function, can I use something which I create at the top of the rules file maybe? Like a semi-global function which I can use for all rules inside one rules file?

The solution you suggested will work, yes, but does not sound very practical to me. Then I would stick to my over and over same definitions for the notifications and if I need to change something it will remain a cut-n-paste orgy.

I am not up to speed on this, but I believe this may be supported (in the future) by the “next-generation rules engine”, so let’s keep our fingers crossed, :slight_smile:

Yes, this would be a “lambda function”. Take a look at this tutorial:

@KjetilA Ah, cool. Thank you, I will try that and will wait for real global functions. :wink:

You may use scripts as some kind of global functions. But have to find a convention for yourself to use Items as parameters because you can not delegate script parameters to callScript(“filenameOfMyScript”)

I migth be missing the point, but what is the difference between the desired global functions and the lambdas shown above? Have all your rules and lambdas in a single file and you are set!

This is one of the driving requirements behind the creation of the Experimental Rules Engine. Kai’s vision is we would have ready made off the shelf rules that users can download and install from the IoT Marketplace. No more copy and paste from examples in the forum.

So, in addition to lambdas and what might be coming in the future, a great way to handle cross-cutting code like this is Design Pattern: Separation of Behaviors. This is particularly handy for notifications as it lets you add additional logic around alerts more easily (e.g. use a different mechanism at night than during the day).

@opus The big difference here is for me that putting all rules into one file creates a big pile of sh*t and looks like programming back in 1990 :wink: and also would not show the intention of the openHAB idea behind this - in my eyes. Also I imagine that putting everything into one file creates more problems, e.g. when putting a typo into one of these rules which causes all rules to fail at once as the updated file might not be loaded into openHAB anymore.

@rlkoshak Sounds promising, I stay tuned! :slight_smile:

I think what opus was intending is not that you put ALL rules into a single file. If you organize your files by function, you will be very unlikely to need to access any lambdas from some other file. And if you do have a cross-cutting concern like alerting or the like, you can use the Separation of Behaviors to call those.

Well, the problem is that I e.g. want to make notifications from many different functions - so there we have the problem. I understood opus not like you. In my understanding he suggests putting everything into one big file and use lambdas then.

As usual, my answer was not as precise as the one from @rlkoshak.
The quick anser was to put everything into one file, the more elaborate(as said by @rlkoshak) is to seperate by function, by that the rules needing a specific lambda could be in a seperated file.
Since you do forsee the need for such a lambda in (nearly) all your rules you could find yourself in the single file situation.

@rlkoshak I completely agree with your thoughts about ‘programming in the 1990s’.

I have some complex rules, resulting if .rules files close to 64kB, thus it’s a bit of a nightmare to debug. It also takes very long after saving the file before it’s compiled and it starts executing.

So I tried to put a bunch of the lambda functions in a .script file.
However, you cannot call includeScript(“name_wo_ext”) outside a rule (thus global within the .rules file.
So my next try: include the .script in the rule. Yes, no error. However, I cannot call the lambda functions. It seems they only exist in the context of the .script file. Nasty!

Apparently there are no ways to trick the system.
At least, I couldn’t find them.

But you never know…
What I haven’t tried (since so far it always resulted in errors within the .rules files), is to define a class. I mean: is that somehow possible? In that case we might be able to simply use an include a.b.c at the top of the .rules file and call the methods.
Unfortunately I haven’t found any examples, so whether this is or isn’t possible… who knows.

In the meantime I’m a bit fed up with the limitations of xtend, so I’m doing more and more in PHP. For me this could end up in using openHAB as just the bus and the drivers for the hardware and doing all the automation logic in PHP.

A global lambda is a global variable. As a global variable is must follow all the same restrictions and scope of any other global variable. This means:

  • only can be accessed from the file they are defined in
  • cannot see any other global variables
  • are not thread safe

Since you cannot pass arguments to Rules DSL Scripts nor get a return value, lambdas are pretty much useless in that context.

There are not, and frankly if you are hoping to use lambdas to simplify your Rules you are probably heading down the wrong path anyway. See Design Pattern: DRY, How Not to Repeat Yourself in Rules DSL for better approaches. Or consider moving to one of the JSR223 supported languages.

No, not possible

Why not use JSR223 and code your rules in Jython, JavaScript, or Groovy instead and keep everything local?

Or if you want something easier to use configure NodeRed as your Rule engine.

Or, as illustrated in the DP I linked to above, there are techniques and best practices one can use to avoid duplicated code in Rules DSL that don’t involve lambdas. Based on experience, you can probably reduce your lines of code by 60-80% using those techniques.

Hi @rlkoshak,
Thank for the feedback.
I wasn’t aware that classes aren’t possible; that saves me some time in fruitless attempts. :wink:

Good point.
I haven’t explored the JSR223 route yet.

On the other hand I have my UI in apache/php anyway (it’s an alternative remote control UI, as well as a configuration UI for my automation rules – program once, configure many), so it’s not such a big step to do even more in php.
The reason why my rules are rather large, is because the OH rules are basically interpreting my configuration. Thus I don’t mind to use the OH REST API even more than I do now. :smiley:

There’s another reason why I like php: it’s very well documented.
In my experience Xtend is a real struggle; never happened for such an elongated period for any other languages / libraries I’ve used over many years.

Anyway, I’m keeping an open mind – and I don’t mind completely redesign at a point in the future if some new promising route becomes available. :+1:

I know this is an old thread, but I stumbled upon this a few days ago via google. Since there isn’t an easy way to do global variables / functions in the default rule engine, I decided to code myself a tool to allow this.

I know the general advice to get reusable code is to use “virtual” items with a rule attached to them, but that gets messy quick in my opinion.

Anyway, if someone else also ends up here after googling like I did, here’s a solution for you, neatly packaged in a docker container: https://hub.docker.com/r/finalfrag/dynamicrules

Source code is also available if you don’t have docker set up: https://github.com/FinalFrag/dynamicrules

All feedback is welcome.