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

Tasker backup files and instructions are now added to the original post. Good luck! :stuck_out_tongue_closed_eyes:

1 Like

yes! It checks that you’re connected to your home Wifi. That is, if you forget your phone at home (while being elsewhere) the Tasker task will certainly announce the callers. :joy::joy::joy:


maybe a problem with my installation? When I am trying to run the “showeventdetails.py” example script, I get the followig error and I am nut sure why:

2018-07-12 23:04:00.010 [ERROR] [lucid.ShowSomeEventInfo             ] - Traceback (most recent call last):
  File "/srv/lib/jython/python/lucid/log.py", line 14, in wrapper
    return fn(*args, **kwargs)
  File "<script>", line 20, in execute
NameError: global name 'DEBUG' is not defined

I try to look into this tomorrow.

There was a missing import statement in the script. I’ve uploaded an updated script.

Today, I’ve added a new lucid script example at https://github.com/OH-Jython-Scripters/lucid/blob/master/Script%20Examples/astro.py

This script will calculate and save the “Time of day” and the “Solar time” of the day to items.
“Time of day” can be morning, day, evening or night. These are clock dependent.
“Solar time” can be dawn, day, dusk and night. These are dependent of the sun’s position relative the horizon.
So depending on where you live and the season, the solar time might be “day” while time of day is “night”
and vice versa.
This topic by @rlkoshak might also be of interest: Design Pattern: Time Of Day

If you try it out please let me know the results. Thanks.

1 Like

One thing I noticed in your script is that it will fail when there is a change in Daylight Savings becasue you are using now.withTimeAtStartOfDay. There was some discussion in the DP thread about solutions for this. Here is my preference…

Here is a version using Jython (w/ openhab2-jython).

Thanks @5iver for the suggestion. I wasn’t aware of that.

I’ve made these changes to my example script.

:sunglasses: :sunglasses: :sunglasses:

I’ve just started trying out JSR223/Jython but am having some difficulty in the addRule line when using the Lucid libraries/examples. Every rule fails with the no such field exception for ‘uid’:

2018-09-28 14:15:43.460 [INFO ] [rt.internal.loader.ScriptFileWatcher] - Loading script 'helloworld.py'
2018-09-28 14:15:43.492 [ERROR] [ipt.internal.ScriptEngineManagerImpl] - Error during evaluation of script 'file:/openhab/conf/automation/jsr223/helloworld.py': java.lang.NoSuchFieldException: java.lang.NoSuchFieldException: uid in <script> at line number 18

The offending line 18 is a simple:

Standard Jython rules (without going through Lucid libraries) work fine, e.g. automationManager.addRule(MyRule()).

Can anyone point me in the right direction on this?

Many thanks!

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

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!')


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")

    #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:

  |-- python

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

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")


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

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))


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')))


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))


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.