Jython scripting examples using lucid, an openHAB 2.x jsr223 Jython helper library

Can you please post the rest of the rule, and which version of OH are you using?

The full script (taken from Lucid’s examples folder) is:

from lucid.rules import rule, addRule
from lucid.triggers import CronTrigger



@rule
class HelloWorld(object):
    def getEventTriggers(self):
        return [
            CronTrigger(EVERY_MINUTE), # Runs every minute
        ]


    def execute(self, modules, inputs):
        self.log.info('Hello world from lucid!')


addRule(HelloWorld())

I’m on OH 2.4 snapshot build #1370.

The lucid repo has not been updated with some breaking changes in the ESH automation API. I plan to make some updates this weekend to the openhab2-Jython repo, and then make a PR for the lucid repo. So, you can wait for all that, or update the triggers.py module with the TriggerBuilder changes from here…

That would explain it. Thanks for letting me know.

If you’d like to do this by hand, it’s not too difficult. Just add the import…

from org.eclipse.smarthome.automation.core.util import TriggerBuilder

Then change every line formatted like…

Trigger.__init__(self, triggerName, "core.ItemStateUpdateTrigger", Configuration(config))

… to be formatted something like this…

self.trigger = TriggerBuilder.create().withId(triggerName).withTypeUID("core.ItemStateUpdateTrigger").withConfiguration(Configuration(config)).build()

Thanks for this. I’ve updated the triggers.py file with the changes you mentioned (and of course restarted OH), but I’m not sure if I’m missing something obvious, as I’m still getting exactly the same uid error from the helloWorld.py script (and all other Lucid based scripts).

Is there anything else I can try? Also is there any way to get a stack trace, showing where in which module the error is actually occurring?

Try something like this…

from org.slf4j import Logger, LoggerFactory
log = LoggerFactory.getLogger("org.eclipse.smarthome.automation.core.internal.RuleEngineImpl")

try:
    #do stuff here
except Exception as e:
    import traceback
    log.error("when: Exception [{}]: [{}]".format(e, traceback.format_exc()))

You might need to put this into the module, which will require an OH restart. I use the openhab2-Jython modules, which lucid is based on, and they are still working fine. @RRoe, can you check the latest snapshot to see what the issue is? If not, I’ll setup a test environment and take a look.

Thanks, I’ll try that.

If it helps, I’m actually getting exactly the same uid error using the openhab modules with the addRule as well, so the problem is not specific to the lucid enhancements. However, using the openhab modules with the automatic rule registration seems to work fine, e.g. the example in the openhab-jython README on github below works without errors:

from openhab.triggers import item_triggered

@item_triggered("TestString1", result_item_name="TestString2")
def my_item_function():
	if len(items['TestString1']) > 100:
		return "TOO BIG!"

Cool… I won’t need a new test environment then! But can you be more specific on how to reproduce the issue?

I’m running OH2.4 snapshot 1370 (have tried with 134x as well) in a docker container, with volumes mounted outside for my openhab conf/userdata etc. I have jython installed in such a mapped volume.

I have the following path structure under my openhab/conf/automation:

conf/automation
  |--jsr223
  |--000_components
  |--lib
  |-- python
       |--openhab
            |-osgi
       |--lucid
           |-clickatell
           |-osgi

I have updated the triggers.py files under both openhab and lucid, based on your earlier message and your github file - and of course updating the lucid version by hand.

I then have the example script from the openhab-jython readme page below in my jsr223 folder:

from openhab.rules import rule, addRule
from openhab.triggers import StartupTrigger

@rule
class ExampleRule(object):
    """This doc comment will become the ESH Rule documentation value for Paper UI"""
    def getEventTriggers(self):
        return [ StartupTrigger() ]

    def execute(self, module, inputs):
        self.log.info("rule executed")

addRule(ExampleRule())

Saving this rule gives the uid field not found error I mentioned above. The error occurs on the addRule line, and in fact I think happens in the rules.py file, on the line:

uid_field = type(SmarthomeRule).getClass(SmarthomeRule).getDeclaredField(SmarthomeRule, "uid")

That’s as far as I’ve got at the moment.

Thanks again for all your help on this Scott.

OK! I don’t use the rules.py module, so I did not run into this before. This issue is also due to the changes in the ESH Automation API. I’ll look into it. Until then, stick to the examples here…

and here…

Here are some more examples for creating a rule…

from openhab.triggers import item_triggered, ItemStateChangeTrigger, ItemStateUpdateTrigger, ItemEventTrigger, ItemCommandTrigger
from org.slf4j import Logger, LoggerFactory

scriptExtension.importPreset("RuleSimple")
scriptExtension.importPreset("RuleSupport")
log = LoggerFactory.getLogger("org.eclipse.smarthome.model.script.Rules")

class testRawESHRegression(SimpleRule):
    def __init__(self):
        triggerName = "TestTrigger1"
        config = { "itemName": "Test_Switch_1" }
        #config["state"] = state
        #config["previousState"] = previousState
        self.triggers = [ TriggerBuilder.create().withId(triggerName).withTypeUID("core.ItemStateChangeTrigger").withConfiguration(Configuration(config)).build() ]
        
    def execute(self, module, input):
        log.debug("JSR223: Regression Test: Raw ESH test: Test_Switch_1 changed: [{}]".format(input['event'].itemState))

automationManager.addRule(testRawESHRegression())

class testRawESHCronRegression(SimpleRule):
    def __init__(self):
        triggerName = "TestCronTrigger1"
        config = { "cronExpression": "0/10 * * * * ?" }
        self.triggers = [ TriggerBuilder.create().withId(triggerName).withTypeUID("timer.GenericCronTrigger").withConfiguration(Configuration(config)).build() ]
        
    def execute(self, module, input):
        log.debug("JSR223: Regression Test: Raw ESH cron test [{}]".format(input.get('event')))

automationManager.addRule(testRawESHCronRegression())

class testExtensionRegression(SimpleRule):
    def __init__(self):
        self.triggers = [ ItemStateChangeTrigger("Test_Switch_1").trigger ]

    def execute(self, module, input):
        log.debug("JSR223: Regression Test: Jython extensions test: Test_Switch_1 changed: [{}]".format(input['event'].itemState))

automationManager.addRule(testExtensionRegression())  

@item_triggered("Test_Switch_1")
def testDecoratorItemChangedRegression(event):
    log.debug("JSR223: Regression Test: Jython decorator: Short: Virtual Switch 1 changed: [{}]".format(event.itemState))

I’m happy to do it! Let me know if you need anything else. I’m prepping for a pull request for the openhab2-Jython repo that will make writing Jython rules much easier (one decorator for all trigger types that uses natural language, like the Rules DSL). I hope to get it in this weekend, and then submit a post later in the week.

Thanks and yes, I’ve gone through these and they all work fine.

Looking forward to this! It is the tediousness of scripting simple rules that had been putting me off from looking into jython, until I had a real need. Looking at the openhab modules and the lucid extensions, rule writing is much simpler now and well worth investing the time to get an understanding of this.

I’ve merged the PR, so the repo is updated and I could use some testers before I put together a post. It looks like the documentation needs to be reflowed to start people out at an entry level too.

3 Likes