Port JSR223 bundle to openHAB 2

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

@Jue_Wis Thanks for your code sample.

Has anybody found out how to create a timer in jython? That seems to be the last roadblock on my way to switch off OH1.

Have you tried using standard Python Timers or the sched module? I haven’t tried it (and my computers are packed for a move) but it should work. Also note that one advantage of Jython is that there is no Global Interpreter Lock (GIL) so threaded programs work even better than CPython.

https://docs.python.org/2/library/threading.html#timer-objects

https://docs.python.org/2/library/sched.html

1 Like

@steve1 your solution works for me. Thanks for pointing me towards this direction.

Here’s my sample code:

from threading import Timer

def timerScript():
    logging.info("Timer fired")

myTimer=Timer(10,timerScript)
myTimer.start() 

logging.info("Timer created")

myTimer.cancel() will cancel the running timer.

I was trying to replace a bunch of rules with one jython script and added multiple triggers to the list of triggers.
It seems that only the first trigger is registered and executed.
It that the intended behaviour?

ITEMLIST = ['Temperature_GF_Library','Temperature_GF_Wigarden','Temperature_GF_Corridor',
'Temperature_GF_Toilet','Temperature_GF_Living','Temperature_GF_Eating','Temperature_GF_Kitchen',
'Temperature_FF_Bath','Temperature_FF_Office','Temperature_FF_Child','Temperature_FF_Bed','CC_humi','Temperature_Outside']
...
        self.triggers = [Trigger("OnUpdate", "core.ItemStateUpdateTrigger",
                    Configuration({ "itemName": _item})) for _item in ITEMLIST]

@Jue_Wis I do the same like this:

       self.triggers = []
        for item in list:
            self.triggers.append( ItemStateChangeTrigger( item, None, item ) )

(this is typed from memory, and therefor untested :slight_smile: )

BTW the above is using @steve1 library code.

I’m not sure, but it may be a requirement to have a unique identifier for each trigger of a rule (my wrappers generate a unique ID).

@steve1, @ralle thank you, appending the name for every trigger was the solution.

Looks like there has been tremendous progress on this since I last checked in. I pulled down the Docker image of the latest 2.2.0 snapshot, added the experimental rules engine, added the Groovy jar files, and magic, the example script worked. Nice.

I’m going to start playing around with porting my 1.x groovy rules, but need a little guidance.

What is the best and/or easiest way to create a jar file such that the classes are available from my groovy rules?

I have some “base classes” that I have written (in Java) to share common functionality and easily create new rules for specific use cases For OH 1, I had to fork the openhab1-addons repo and add my classes. Since OH2 has significant architecture changes, I thought there might be a better way.

Thanks,

Doug

I’ve never used Groovy, but it looks like some interesting ideas on this page:

http://www.javaworld.com/article/2073966/core-java/groovy-scripts-master-their-own-classpath-with-rootloader.html

It sounds like it might be possible to put the jars into $OPENHAB_HOME/.groovy/lib too (???).

It didn’t work under OH1. Something was preventing them from actually getting on the classpath used by the rules. Something with the framework, I think.

Honestly, I should have tried that before I posted… It’s an easy thing to try - create a jar file and throw it in with the rest of the groovy libs. I’ll give it a shot tonight.

No luck just dropping a jar in with the groovy ones. I think OGSi prevents that. I read a bit about creating “bundles” and whatnot, but looks like I have a lot of reading to do before I can go down that route.

Doug

Did you try the RootLoader technique described in the article?

Yes. I thought that had a good shot at working since it wasn’t something I had tried with OH1. It’s also entirely possible I messed something up as there were a fair number of distractions at home when I was trying it. I’ll try it again if I get a chance, as it’s a good technique to have in the toolbox.

For now, I ended up using the same approach I used on OH1, which is just to put them inside the existing rule engine bundle, build via maven, and replace the distribution jar with my own. That took longer than it should have because I didn’t know I needed to delete the OH2 cache directory for it to pick up my changes. (Maybe deleting the cache would have helped with the RootLoader approach?) I wasted a couple of hours because of that.

My current plan is to fork the smarthome repo and push some changes up for comments once I get a little further with my approach.

Thanks,

Doug

In OH1, I could
import org.openhab.core.jsr223.internal.shared.Openhab;
then in my base class do something like:
Openhab.sendCommand(item, commandString);
to access the sendCommand and/or postUpdate functions.
In OH2, sendCommand() and postUpdate() are passed into the JSR223 script in a “magic” events variable, which seems to be of type org.eclipse.smarthome.automation.module.script.defaultscope.internal.ScriptBusEvent

I want to sendCommand() and postUpdate() from my base class, which exists outside of the script.

I searched through a lot of code in the IDE, and I could not find a similar static way to instantiate the events variable - type ScriptBusEvent. There is a BusEvent class, which does have static operations for sendCommand() and postUpdate() but that’s not in the imports for the bundle… It looks very similar to ScriptBusEvent, other than it is has static methods and ScriptBusEvent does not.

Any ideas on how I can call sendCommand() and postUpdate() outside of the scope a script? That is, in my own external base class? I could probably require the events variable to be passed via constructor, but I was hoping just to “take care of it” internally.

Thanks,

Doug