[SOLVED] OH3 JSR 223 Jython - No module named core in AND how to manipulate a cron trigger rule

@stefan.hoehn I don’t know of any way to update a trigger on an existing rule. I have some dynamic rules (not using time triggers) that I need to change the triggers for and I do it by deleting and recreating the rule. For your use case, as others have said, you are better to have a rule that checks the string item and creates a timer to run at the specified time. You can trigger this rule from the scriptLoaded function to make sure it runs when the system starts or the file is modified to create the timer the first time. Also make sure the timer code reschedules itself for the next day (if I understand your usage correctly).

@shorty707 as I stated above, I have not updated any example scripts. I believe the hello world test script uses Joda Time, which is not available in OH3.

hi,
sorry i am afraid i am not good enough in coding to support. but as @CrazyIvan359 mentioned and as you can see in my snipped i create a dynamic rule inside another rule. there i first check if that rule already exists, and if it exists i delete it. so because it is not possible to edit a cron-triggered rule i always delete it and create a new with the new cron. i your snipped i cannot see where you remove and recreate the cron-rule.

I don’t. I intended to try to only update the rule not to create a rule within a rule. Thanks to all for your guidance. Let’s see where that goes.

i tried to extract a fully working example for you:

items:

Number iStartTime "Startzeit[JS(numberToClock.js):%s]" <time>

sitemap:

Setpoint item=iStartTime minValue=0 maxValue=1425 step=15

cron_rule.py (in automation/jsr223/python/personal):

from core.rules import rule
from core.triggers import when
from core.actions import LogAction, ScriptExecution #, Things, Transformation
from core.date import DateTime


trigger_timer = None

@rule("cron_rule")
@when("Item iStartTime changed")
def cron_rule(event):
    global trigger_timer
    LogAction.logInfo(u"cron_rule", u"time changed, wait")

    if trigger_timer is None:
        trigger_timer = ScriptExecution.createTimer(DateTime.now().plusSeconds(5), cron_rule_body)
    else:
        trigger_timer.reschedule(DateTime.now().plusSeconds(5))


def cron_rule_body():
    global trigger_timer
    LogAction.logInfo(u"cron_rule_body", u"create cron rule")
    trigger_timer = None

    time_in_minutes = items["iStartTime"].intValue()
    hour_value = time_in_minutes / 60
    minute_value = time_in_minutes % 60
    LogAction.logInfo(u"cron_rule_body", u"new start time: {}:{}".format(hour_value, minute_value))

    cron = "0 {} {} 1/1 * ? *".format(minute_value, hour_value)

    try:                                                                    # if rule already exists then remove it
        rule_name = "set cron time"
        rule_uid = [rule_object for rule_object in rules.getAll() if rule_object.name == rule_name][0].UID
        LogAction.logInfo(u"cron_rule_body", u"Rule already exists, remove it")
        scriptExtension.importPreset("RuleSupport")
        ruleRegistry.remove(rule_uid)
    except:
        pass

    # create dynamic rule
    @rule("set cron time")
    @when("Time cron {}".format(cron))
    def dynamic_cron_rule(event):
        LogAction.logInfo(u"dynamic_cron_rule", u"############## start dynamic_cron_rule ##############")

numberToClock.js (in transform):
(this nice tool i found somewhere here in the forum, great to have a correct view of the time in sitemap)

(function(i) {
    var hours = Math.floor(i / 60);
    var minutes = i % 60;

    hours = (hours < 10) ? "0" + hours : hours;
    minutes = (minutes < 10) ? "0" + minutes : minutes;

    return hours + ":" + minutes + " Uhr";
})(input)

perhaps this may help :slight_smile:

1 Like

Given that he’s using UI managed rules, there is no scriptLoaded function available (or more precisely it doesn’t get called). Instead a System start level reached trigger can be used. Furthermore, when editing this rule, one will want to manually run the rule through the UI (click the play button on the Rule’s page). I think this is because the rules don’t really get loaded in the same way.

I use this approach for the Time of Day JavaScript version.

Also, I’ve not fully tested it yet but it looks like when using UI created rules you do not need to reload/recreate the rule to pick up changes in Groups for Group based triggers, the main reason I was deleting and creating new rules in Python in the first place. That’s why I went back to using Groups instead of tags/metadata and dynamically created Rules.

I don’t. I intended to try to only update the rule not to create a rule within a rule. Thanks to all for your guidance. Let’s see where that goes.

I finally took the time to investigate the openhab core code to see how it is handled via the UI. I checked the rest API call which is basically a PUT on the rule. I then found the implementation after a whil and saw that the PUT method is basically updating the rule. For the curious the code can be found in RuleResource.update(). So I digged deeply into the code only to find out the the very obvious:

final Rule oldRule = ruleRegistry.update(RuleDTOMapper.map(rule));

:joy: I love open source :joy:

So the solution is very simple:

currentState = itemRegistry.getItem("rollershutter1_time").state
rules = ruleRegistry.getByTag("cronRule1")

for rule in rules:
    triggers = rule.getTriggers()
    for trigger in triggers:
      if (trigger.id=='cron1'):
        config = trigger.getConfiguration()
        config.put("time",currentState.toString())
        ruleRegistry.update(rule)
  • I have a cron triggered rule that can be fully written and updated in the UI (even with blockly)
  • I have a UI page where the User can chose the time
  • The python rules is triggered on update of the chosen time in the UI and manipulates the time of the rule managed through the UI.

Works like a charm and I am so happy :star_struck:

3 Likes

Interesting. I’ve been pondering changing approaches (yet again) on my Time of Day implementation so that the times of day show up in the schedule. For that I’d have to use time based triggers. I was not real keen on managing creating and deleting managed rules from rules to do this but if I can update a rule like this it might be worth revisiting.

I’m still not sure if I want to have such a proliferation of Rules but maybe it’ll be worth it to see the times of day on the calendar.

Glad you got it working!

How very interesting indeed. Thank you @stefan.hoehn for doing the research, and for sharing the results!