Simplified Jython rule definition (similar to Rules DSL) using a universal decorator

Thank you for pointing this out (an issue or PR in the repo would have been better :wink:). Corrected now,

DefaultScriptScopeProvider.java provides a default scope that is imported into all scripts. Modules load with no context, so you need to explicitly import what you need. As you found, the core.jsr223 can be used to access the default scope/preset in modules. Importing the other presets may also be helpful (core.rules imports RuleSimple).

Thanks for your explanation, that helped me a lot!

I have to figure out, how to create a pull request sn GitHub, the next time I find an issue I will try to create one.

You can do it straight from Guthub. Edit the file, and when you go to save it, there is an option to Create a new branch for this commit and start a pull request. This will create a personal fork of the repo. Navigate to it in your repositories, select Compare, and you will see an option to create a PR. I’ll add this to the docs with some screenshots the next time I submit a PR though GH.

And thanks again, I will try this out!!

If this is Ok for you, I will add the topics discussed here regarding modules in a short paragraph of the „But how do I“ section of the documentation. That I could use to document creating a PR as well.

As I am quite busy in the next days I will probably need a few days until this is finished.

Is enabling and disabling Jython rules (via Karaf or via RuleManager service in Jython) working for you?

I’ve tried to update rules_registry example with latest release and recent snapshot, but once the rule is disabled and re-enabled it is not being run properly. When called with runNow (without checking for predicates), it will appear to run (IDLE -> Running -> IDLE) but action is not executed (looks like missing action handler). In the same way, after re-enabling rule is not run on trigger condition.

And I can confirm, that rules can not be remove via rules global but only with ruleRegistry as said previously in this topic (on side note, why these two are different?)

Just a heads up to anyone using the Jython libraries that uses snapshots… don’t upgrade your OH! I’ve been working on updating the libraries due to the ESH migration, but have found an issue where some of the Java classes, which have not yet been fully migrated, are no longer accessible. So for now, it is best not to use the snapshots (or milestones, when they come) until this gets sorted.

5 Likes

does this support OR in @when conditions ? e.g.

@when("Item A changed" or "Item B changed")   (conceptually)

I can’t quite suss-out the proper syntax to use if it does…

I know that I could define a new group to do this – I have lots of Member Of rules working in Jython…this is more a “does this even work ?” question…

Yes, but not like in the DSL. Just add another one, like in the original example…

@when("Item A changed")
@when("Item B changed")

Hello, Im trying to port the MQTT2 eventbus rule to Jython but Im having a problem when I access the Channel Trigger. A rule like this:

@rule("MQTT Test2")
@when("Channel mqtt:broker:f79d2a84:TriggerIn triggered")
def MQTTPublishIn(event):
    input1 = event.event
    MQTTPublishIn.log.info(input1)

gives this error when beeing loaded:

2019-04-05 14:31:53.244 [ERROR] [tomation.jsr223.jython.core.triggers] - when: Exception [when: "Channel mqtt:broker:f79d2a84:TriggerIn triggered" could not be parsed because Channel "mqtt:broker:f79d2a84:TriggerIn" is not a trigger]: [Traceback (most recent call last):

  File "/etc/openhab2/automation/lib/python/core/triggers.py", line 313, in when

    raise ValueError("when: \"{}\" could not be parsed because Channel \"{}\" is not a trigger".format(target, trigger_target))

ValueError: when: "Channel mqtt:broker:f79d2a84:TriggerIn triggered" could not be parsed because Channel "mqtt:broker:f79d2a84:TriggerIn" is not a trigger

What am I doing wrong? It works without a problem when using it a s a trigger in a DSL Rule. When I use a another channel from a Rockerswitch the Jython rule works without a problem. It just doesnt work with the mqtt publish trigger channel.
Thanks for the great work on this.

After looking at the error in the log again I found the responsible line in the triggers.py:

 elif target_type == "Channel" and scope.things.getChannel(ChannelUID(trigger_target)).kind != ChannelKind.TRIGGER:
raise ValueError("when: \"{}\" could not be parsed because Channel \"{}\" is not a trigger".format(target, trigger_target))

Once I commented it out and restarted Openhab the rule works without an issue.
It looks like the MQTT2 binding doesnt declare the trigger channel right.

I agree. Could you please save this to a test script and post what is logged?

from core.log import logging, LOG_PREFIX
log = logging.getLogger(LOG_PREFIX + ".TEST")
from org.eclipse.smarthome.core.thing import ChannelUID
from org.eclipse.smarthome.core.thing.type import ChannelKind
log.warn("[{}]".format(things.getChannel(ChannelUID("mqtt:broker:f79d2a84:TriggerIn")).kind))

Never mind… I created one and it came through as STATE. I’ll take a look at the binding to see how this is happening.

1 Like

Thank you for looking into it. With the two lines commented out its working fine for now. Im really loving Jython combined with the simplified rule definition.

1 Like

Hello, just a short question, when I try to use the System started trigger I get this:

2019-04-15 16:30:53.582 [ERROR] [tomation.jsr223.jython.core.triggers] - when: Exception [when: "System started" could not be parsed because rule triggers do not currently support target_type "System"]: [Traceback (most recent call last):
  File "/etc/openhab2/automation/lib/python/core/triggers.py", line 325, in when
    raise ValueError("when: \"{}\" could not be parsed because rule triggers do not currently support target_type \"System\"".format(target))
ValueError: when: "System started" could not be parsed because rule triggers do not currently support target_type "System"
]
2019-04-15 16:30:53.596 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/etc/openhab2/automation/jsr223/personal/mqtt1.py': TypeError: 'NoneType' object is not callable in <script> at line number 32

Am I doing something wrong? Or is the Readme ahead of the implementation. This is the rule the trigger belongs too. It works fine without the system started trigger.

@rule("StatePublish")
@when("System started")
@when ("Time cron 0 0 0/1 * * ?")
def statepublish(event):   
    for member in ir.getItem("Stats").members:
        membername = ''.join(re.findall("^\S*", str(member)))
        memberstate = str(ir.getItem(membername).state)
        actions.get("mqtt","mqtt:broker:f79d2a84").publishMQTT("allItemsout/"+membername,memberstate)

Thanks for any insights, best regards Johannes

Short answer… you can’t use StartupTrigger yet.

StartupTrigger broke after an API change, but ScriptedCustomModuleHandlerFactory was recenty fixed. I’ll mention this restriction in the OP to match the readme, which still looks accurate… or are you referring to something else? I have not updated the libraries so that the StartupTrigger can be used, as there are several changes that are also needed in order to be compatible with the new openhab-core, and there was a critical issue for automation that needed to be resolved before the new OH core could be used.

I planned to put a release out for all of these changes, once the snapshots included the new core, but this is taking longer than expected. I’ll try to get something together before the end of the weekend, but this could be delayed as the OH-Jython-Scripters organization is about to be renamed, so that helper libraries for scripting langauges other than Jython can be added. :partying_face:

1 Like

Just had another thought… instead of using the StartupTrigger, you can get the result by just calling the function straight out of the script, so that it runs when the file is loaded or saved.

statepublish(None)
1 Like

Thank you for the answer, your second suggestion doesnt work for me. If I assign statepublish to None I get a syntax error.
But I can wait for the system started trigger. Thank you again, regards Johannes

Did you put it after the function definition?

@rule("StatePublish")
@when ("Time cron 0 0 0/1 * * ?")
def statepublish(event):   
    for member in ir.getItem("Stats").members:
        membername = ''.join(re.findall("^\S*", str(member)))
        memberstate = str(ir.getItem(membername).state)
        actions.get("mqtt","mqtt:broker:f79d2a84").publishMQTT("allItemsout/"

statepublish(None)
1 Like

:man_facepalming: that did it thanks :raised_hands:

1 Like

Would it be possible to extend the decoration to the class level.
something like:

@rule("test time rule", tags=["Tag 1", "Tag 2"])
@when("Channel homematic:HM-PB-6-WM55:3014F711A061A7D5698CE994:NEQ1001667:1#BUTTON triggered SHORT_PRESSED")
@when("Channel homematic:HM-PB-6-WM55:3014F711A061A7D5698CE994:NEQ1001667:1#BUTTON triggered DOUBLE_PRESSED")
class MyRule(MyOtherClass, YetAntherClass):  
    def execute(self, module, input):
        events.postUpdate("TestString2", "some data")