Port JSR223 bundle to openHAB 2

That did the trick, but couldn’t it just be an argument that is passed when calling?
Anyway, the startup trigger doesn’t seem to work. I have created this sample class:

class SampleRule(SimpleRule):
	
	_logger = LoggerFactory.getLogger("org.eclipse.smarthome.automation.examples")
	_configName = ""
	def __init__(self, configName):
		self.triggers = [ ]
		self._configName = configName

	def getLogger(self):
		return self._logger
	
	def AddItemStateUpdateTrigger(self, itemName):
		self.getLogger().info("Adding ItemStateUpdateTrigger for item '" + itemName + "'")
		triggerName = itemName
		self.triggers.append(ItemStateUpdateTrigger(itemName, None, triggerName))
	
	def AddItemStateChangeTrigger(self, itemName):
		self.getLogger().info("Adding ItemStateChangeTrigger for item '" + itemName + "'")
		triggerName = itemName
		self.triggers.append(ItemStateChangeTrigger(itemName, None, triggerName))
	
	def AddItemCommandTrigger(self, itemName):
		self.getLogger().info("Adding ItemCommandTrigger for item '" + itemName + "'")
		triggerName = itemName
		self.triggers.append(ItemCommandTrigger(itemName, None, triggerName))

	def AddItemEventTrigger(self, eventSource, eventType, eventTopic, triggerName):
		self.getLogger().info("Adding ItemEventTrigger for eventSource '" + eventSource + "'")
		self.triggers.append(ItemEventTrigger(eventSource, eventType, eventTopic, triggerName))
		
	def AddStartupTrigger(self, triggerName):
		self.getLogger().info("Adding StartupTrigger '" + triggerName + "'")
		openhab.STARTUP_MODULE_ID = "jsr223.StartupTrigger"
		self.triggers.append(StartupTrigger(triggerName))

	def AddCronTrigger(self, triggerName, cronExpression = EVERY_MINUTE):
		self.getLogger().info("Adding CronTrigger '" + triggerName + "' with schedule='" + cronExpression + "'")
		self.triggers.append(CronTrigger(cronExpression, triggerName))
		
	def execute(self, module, input):
		self.getLogger().info("[" + self._configName + "] Executing Trigger.....")
	

If I Initialize like below, the StartupTrigger nor the CronTrigger will run (haven’t checked the others):

sr = SampleRule("MyTriggerConfig")

sr.AddStartupTrigger("MyStartupTrigger")
sr.AddCronTrigger("MyCronTrigger", EVERY_FIVE_SECONDS)
sr.AddItemStateUpdateTrigger("TriggerItem1")
sr.AddItemStateChangeTrigger("TriggerItem2")
sr.AddItemCommandTrigger("TriggerItem3")

automationManager.addRule(sr)

If I instead does like here below, the CronTrigger runs fine, but StartupTrigger doesn’t run at all (the others haven’t been tested) :

sr1 = SampleRule("StartupTriggerConfig")
sr = SampleRule("OtherTriggerConfig")

sr1.AddStartupTrigger("MyStartupTrigger")

sr.AddCronTrigger("MyCronTrigger", EVERY_FIVE_SECONDS)
sr.AddItemStateUpdateTrigger("TriggerItem1")
sr.AddItemStateChangeTrigger("TriggerItem2")
sr.AddItemCommandTrigger("TriggerItem3")

automationManager.addRule(sr1)
automationManager.addRule(sr)

It looks like the StartupTrigger is registered to late, and thus never called? And that is does at least cause CronTrigger not to run.

This isn’t really a big problem to me, just an observationthat might be usefull to others…

I’m not sure what we’re doing differently but both examples work for me. The indentation is not correct in the code block you posted. Could that be the issue?

There is no EVERY_FIVE_SECONDS defined in my library. I’m assuming you defined that somewhere. I used the EVERY_SECOND for my testing.

Argh I see, seems that it has happend during copy/paste. I will check my code more carefully tonight.
I cloned your library about a week ago from GitHub, so if something has changed since then, that could be the reason.

Correct, Once a second gave me a log file with too many CronTrigger entries (where I am looking for other trigger events as well. So I defined a five second crontab schedule - and forgot it in the post :-(.

After looking a more carefully at your code, it seems that you are doing things a little bit different than I am, so when I get the time i will experiment with your sample (and hopefully understand what is happening :slight_smile: )

Just to be clear, when I indented your code and added imports, your examples appeared to work.

Now it is working. The ‘components/000_StartupTrigger.py’ wasn’t loading as I expected, thus the startup trigger was not registered properly.

Have you found out how to use an action by now? If so, would you share how to go about it?

I have an idea how to do it, but I haven’t had time to try it yet. The way OH1 actions work is that there is a service interface (e.g., org.openhab.core.scriptengine.action.ActionService) that is registered with OSGi. That service interface has a method called getActionClass that returns the action class (org.openhab.action.astro.internal.Astro in this case). The OH1 “actions” are static methods on this class.

My openhab.osgi Python package has helper functions for getting OSGi services. I’d define a Python module, something like openhab.astro, that finds the service and exposes the action class static methods as module functions. They you could do something like the following:

from openhab.astro import getAstroSunriseStart

...
start = getAstroSunriseStart(date, lat, lon)
1 Like

@ralle and @mr_eskildsen. I’ve added an openhab.actions Jython module to my openhab2-jython github repo. This module will use OSGi to discover action classes and then exposes them as attributes of the module. So the Astro action class can be accessed as openhab.actions.Astro. There is an example in the scripts/examples/action_example.py file.

This works for me, but all of this is experimental code so no guarantees.

2 Likes

So cool…
Works as excpected, though I had some problems installing the action in openHAB :slight_smile:

Thank you @steve for your sample code! Your openhab.actions jython module solved my problem with actions which was using the pushover action. Your module makes it really simple:

from openhab.actions import Pushover
Pushover.pushover("Test")

This is impressively easy :). I think I can finally start converting my jython code over to OH2!

Can anybody tell me how to set a rule’s id? My logging shows a lot of lines alike

2017-07-28 21:44:46.058 [DEBUG] [.automation.core.internal.RuleEngine] - The trigger 'wRegen' of rule '16d0f281-d8fb-4649-a064-eedd8cbcb2b0' is triggered.

I’m using @steve1’s openhab2-jython library where I’ve found the correct place to set the trigger name, but even setting

self.name or self.id won’t change the above logging to a more readable form. My rule init looks like this:

    def __init__(self):
        self.triggers = [ ItemStateChangeTrigger('MyItem', None ,'TriggerName') ]
        self.name= 'MyRuleName'
        self.id='MyRuleId'

What am I missing?

An internally-generated unique SmartHome Rule UID is what’s logged from the rule status events, not the rule name. I’ve added a small utility function to my openhab2-jython repository that will add a prefix to this UID so that logs are easier to interpret.

The following example shows how to use it (see openhab.rules.set_uid_prefix). By default, the function uses the rule type name as the prefix. However, you can provide an optional second argument to specify a custom prefix.

scriptExtension.importPreset("RuleSimple")
scriptExtension.importPreset("RuleSupport")

from openhab.rules import set_uid_prefix

class TestRuleWithUidPrefix(SimpleRule):
    def __init__(self):
        set_uid_prefix(self)

# Only for logging side-effects
automationManager.addRule(TestRuleWithUidPrefix())

Example log entries:

2017-07-29 07:10:04.001 [TRACE] [.e.s.a.events.RuleEventFactory:57   ] - creating ruleEvent of type: RuleStatusInfoEvent
2017-07-29 07:10:04.001 [INFO ] [home.event.RuleStatusInfoEvent:43   ] - TestRuleWithUidPrefix-581cb170-8a71-494f-a59a-a460217dd418 updated: INITIALIZING
2017-07-29 07:10:04.001 [TRACE] [.e.s.a.events.RuleEventFactory:57   ] - creating ruleEvent of type: RuleStatusInfoEvent
2017-07-29 07:10:04.001 [INFO ] [home.event.RuleStatusInfoEvent:43   ] - TestRuleWithUidPrefix-581cb170-8a71-494f-a59a-a460217dd418 updated: IDLE
3 Likes

@steve1 You rock!! Thanks!

I would just like to send a thank you to all of you who have contributed to the JSR223 bundle. Finally I can avoid having two openHAB installations! Actually I have killed my openHAB 1.8.3 in the beginning of the week, and today I have finalised a first rough port of my scripts in openHAB1. Actually I have started from scratch, bot I now have the close to 100% coverage of what I had in openHAB1. I am very happy!
I was just wondering if there would be some place to share script libraries that we create. @steve1 has already shared his work on GitHub, that have been to great help to me (thanks for that!)
I need to clean my code and then I would also like to share my work as well - hopefully somebody would be inspired or maybe even want to use the code.
What I have until now is án advaced mechanishm to control my indoor and outdoor light (When I am out the light can run on a schedule, and when I am home, it doesn’t. I also have rules, that would cause light to turn on when a pir sensor registers activity.

A couple options are a GitHub repo or the Eclipse Marketplace. I recommend starting a new topic and tag Kai for his comments.

1 Like

I’m trying to get at an item.historicState that was PersistenceExtensions (alias: pe) in OH1.
Is this also available yet in OH2? Could you give advice how to use it?
Thank you for your support and making jython scripting work.

1 Like

@Jue_Wis I would like to add pe.changedSince and pe.minimumSInce/maximumSince to your list of missing functionality from OH1. :slight_smile:

I have found out that the missing functions are in package org.eclipse.smarthome.model.persistence.extensions, but I’m lacking the python skills to extend the library @steve1 has created for the persistence extensions.

If you can spare some time, would you take a look and extend your library for these functions, please?

@Ralle and @Jue_Wis,

in JavaScript I use:

var DateTime = Java.type("org.joda.time.DateTime");
var pe= Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions");

print("changedSince: 	" + pe.changedSince( [ANY ITEM SAVED IN DB], DateTime.now().minusDays(3) ) );

Similar in jython: (untested!!)

from org.joda.time import DateTime
from org.eclipse.smarthome.model.persistence.extensions import PersistenceExtensions

print "changedSince: 	" + PersistenceExtensions.changedSince( [ANY ITEM SAVED IN DB], DateTime.now().minusDays(3))

Hope this helps.
Helmut

@lewie and @ralle Thank you for the helpful tips.
Access to historicState is now working with jython.
maximumSince, minimumSice and changedSince work in the same way.

scriptExtension.importPreset("RuleSupport")
scriptExtension.importPreset("RuleSimple")

import org.joda.time.DateTime

from org.slf4j import LoggerFactory
from openhab.rules import set_uid_prefix

from org.eclipse.smarthome.model.persistence.extensions import PersistenceExtensions

class OnWeatherUpdate(SimpleRule):
    def __init__(self):
        set_uid_prefix(self)
        self.name = 'OnWeatherUpdate'
        self.id = 'weatherupdaterule'
        self.description = 'rule to execute when the rain item is updated'
        self.triggers = [
             Trigger("OnUpdate", "core.ItemStateUpdateTrigger",
                    Configuration({ "itemName": "Niederschlag"}))
        ]

    def execute(self, module, input):
        _item = ir.getItem("Niederschlag")
        _rainlasth = PersistenceExtensions.historicState(_item, DateTime.now().minusMinutes(60)).state
        events.postUpdate(ir.getItem("Rain_Last_H"), _rainlasth)
        _rainlast12h = PersistenceExtensions.historicState(_item, DateTime.now().minusMinutes(720)).state
        events.postUpdate(ir.getItem("Rain_Last_12H"), _rainlast12h)
        _rainlast24h = PersistenceExtensions.historicState(_item, DateTime.now().minusMinutes(1440)).state
        events.postUpdate(ir.getItem("Rain_Last_24H"), _rainlast24h)
        LoggerFactory.getLogger("org.eclipse.smarthome.automation.weatherupdate").info('{} {}'.format(_item.label, "was updated"))
automationManager.addRule(OnWeatherUpdate())

Now the time has come to retire the openHAB 1 server.

Thanks again for your help.

1 Like