Jython helper libraries for OH3

UPDATE: For OpenHAB 3+ Please use this fork instead: GitHub - CrazyIvan359/openhab-helper-libraries: JSR223-Jython scripts and modules for use with openHAB - it’s maintained and contains more updates and fixes.

I stumbled across a problem during upgrading to OH3 because there’s no jython helper libraries for OH3 yet. I have managed to make some quick and dirty modifications to the current helper libraries to make it work on OH3. One last change that I need to do in triggers.py is to replace the Quartz isValidExpression that validates a cron expression, because quartz is no longer included in OH3.

I see that in org.openhab.core.internal.scheduler there’s the CronAdjuster class that I could possibly use to validate the cron expression, however I cannot import this class into jython.

It’s late and I’m about to crash, but I thought I’d post it here to see if someone knows how to replace this isValidExpression. I can implement my own but would rather use an existing code that has been tested.

In the mean time, I’ve created a dummy isValidExpression returning True, and commenting out the some parts of triggers.py in the helper libraries. I’ve created a rudimentary replacement for isValidExpression, which I will improve upon should it be necessary. At least my rules are working on OH3, after converting Joda datetime to ZonedDateTime.

EDIT: I have posted my working version on github here (note the oh3-patch branch):

It’s meant as a temporary fix until the official fix is available from @5iver.

All you need are these two directories:

  • Core/automation/jsr223/python/core
  • Core/automation/lib/python/core

Placed them into your conf/automation/(jsr223 | lib)/python/core correspondingly

8 Likes

The CronAdjuster is an internal class so it is not exported by the bundle. So I think the only way to currently use it is to copy/paste/port it… maybe some logic can be moved to an exported utility class so it can be more easily reused in the future. Based on the CronScheduler JavaDocs the cron expressions used by openHAB differ a bit to the Quartz cron expressions, so it may also prevent some issues.

I think for the purpose of triggers.py isValidExpression, I’ll just implement a simple regex check. Hopefully I’ll manage to fork and publish my modifications on github some time today so others can use it to get their jython rules up and running again, while waiting for @5iver to publish the official update.

1 Like

I think having some working helper libraries for OH3 will make many Jython users very happy! :slight_smile: :+1:

2 Likes

I’ve updated the original post with the link to my patched version.

2 Likes

Seems to work pretty well!
Thank You for sharing!

Thanks! Do you have any reference for ZonedDateTime classes? I need to rewrite a few rules which are still using JodaTime

Did you mean something like this?
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/ZonedDateTime.html

Changing from Joda to ZonedDateTime seems straight forward:

  • from org.joda.time import DateTimefrom java.time import ZonedDateTime
  • DateTime.now()ZonedDateTime.now()
  • .getHourOfDay().getHour()
  • .getMinuteOfHour().getMinute()
  • .plusMillis(x) → '.plusNanos(x * 1000000)`

and so on.

Alternatively, for even less change:

from java.time import ZonedDateTime as DateTime

Then you just need to change getHourOfDay etc to their equivalent methods of ZonedDateTime. Most of the other methods have the same name, e.g. plusMinutes().

2 Likes

I detected another issue with the triggers: StartupTrigger is not working properly. By modifing the StartupTrigger class (around line 720 in triggers.py) I got it working:

Replace
self.trigger = TriggerBuilder.create().withId(trigger_name).withTypeUID("jsr223.StartupTrigger").withConfiguration(Configuration()).build()

with

self.trigger = TriggerBuilder.create().withId(trigger_name).withTypeUID(“core.SystemStartlevelTrigger”).withConfiguration(Configuration({
“startlevel”: “100”
})).build()

Thanks for the nice working version of this. But why don’t you open a PR for this to the official repo?

Thank you. I have updated my version on github too.

I am unsure whether an official fix may have already been prepared but not yet uploaded. It is also not quite polished. I commented out some things instead of removing them, and my replacement implementation is just a quick and dirty solution. I’d be happy to submit it as a PR if Scott wanted it.

Thanks, yes I found them later on. It was not that easy to migrate everything from these deprecated libs.

Right now it seems that most of my rules are working… Only executeCommandLines seems to have problems, even with the new parameter list.

Also it seems for me that System started triggers won’t fire on system startup. Is this possible?

See above. I’ve pushed a new update that should fix the startup trigger, thanks to @pail_frank23
The only change was to triggers.py

I already have that triggers.py, but I will re-check it…

Yes I have that one and still not working…

Hmmm, strange. My @when(“System started”) rules were working prior to applying the changes suggested by @pail_frank23. The changes suggested by @pail_frank23 actually caused my “System started” rules not to fire.

I have setup a test system and as far as I can remember, I had some error in the beggining about StartupTrigger, but after StartupTriggers worked. I will try to rollback to the old triggers.py and try again…

Try this version (the one right before “fixing” the startup trigger)
https://raw.githubusercontent.com/jimtng/openhab-helper-libraries/31da60805dd03b5e199e041e47274a4f1521144d/Core/automation/lib/python/core/triggers.py

Yes this seems to work, thanks!

One last thing which is not working for me regarding Jython rules is executeCommandLine. Did you get this working? I can’t really get any useful info why it is not working. I have changed the parameters as suggested in docs and other posts, but none of them worked. Basically it returns instantly with ‘None’, not even waiting for the timeout.

I was able to solve it. Basically you need to pass every command line argument as a seperate argument for executeCommandLine.