Jython helper libraries for OH3

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?

Changing from Joda to ZonedDateTime seems straight forward:

  • from org.joda.time import DateTime -> from 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.

I have reverted the StartupRule trigger for the time being. I don’t quote understand why the old one worked and the new one doesn’t. It seems that the new one should be the one that works.

This works for me:

class StartupTrigger(Trigger):
    """
    This class builds a StartupTrigger Module to be used when creating a Rule.

    See :ref:`Guides/Rules:Extensions` for examples of how to use these extensions.

    Examples:
        .. code-block::

            MyRule.triggers = [StartupTrigger().trigger]

    Args:
        trigger_name (string): (optional) name of this trigger

    Attributes:
        trigger (Trigger): Trigger object to be added to a Rule
    """
    def __init__(self, trigger_name=None):
        trigger_name = validate_uid(trigger_name)
        self.trigger = TriggerBuilder.create().withId(trigger_name).withTypeUID("jsr223.StartupTrigger").withConfiguration(Configuration()).build()

This seems like it should work instead, but it doesn’t

class StartupTrigger(Trigger):
    """
    This class builds a StartupTrigger Module to be used when creating a Rule.

    See :ref:`Guides/Rules:Extensions` for examples of how to use these extensions.

    Examples:
        .. code-block::

            MyRule.triggers = [StartupTrigger().trigger]

    Args:
        trigger_name (string): (optional) name of this trigger

    Attributes:
        trigger (Trigger): Trigger object to be added to a Rule
    """
    def __init__(self, trigger_name=None):
        trigger_name = validate_uid(trigger_name)
        self.trigger = (
            TriggerBuilder.create()
            .withId(trigger_name)
            .withTypeUID("core.SystemStartlevelTrigger")
            .withConfiguration(Configuration({"startlevel": "100"}))
            .build()
        )

I’m not sure how executeCommandLine would be related to jython, especially the helper libraries, but for the benefit of others who might come across the same issue, could you post your code both before and after?

Yes, I can’t understand this either. But the old one is working for me. Though (I don’t know why) my rules loads much slower on startup. This is not a real issue, now it loads almost as slow as DSL rules do, before on 2.5.x Jython rules loaded instantly…

I think it is related to changes in the core libraries, so this affects all scripting languages (even DSL), that is where I found the solution for Jython as well.

I’m not sure how the old syntax looked like, but it was something like this:

from core.actions import Exec

# Usual Jython helper decorators here @rule, @when, etc...
# The actual commandLine call was something like this:

Exec.executeCommandLine("python3 /etc/openhab/scripts/openhab.py", 10000)

Now you have to do it this way:

from core.actions import Exec

from java.time import Duration

Exec.executeCommandLine(Duration.ofSeconds(100), "python3", "/etc/openhab/scripts/openhab.py")

Notice that you now need to import the Duration class from java.time and the timeout is now in seconds, previously it was in milliseconds.
Also you need to seperate all parameters as a seperate parameter. Previously you could pass the whole command in one string. So basically where you had spaces in your command before, now you need to make it a seperate parameter.

executeCommandLine is part of OpenHAB core, not just jython.

With Duration, you could use .ofMillis, ofMinutes, etc. See Duration (Java Platform SE 8 )