@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.
@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
@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 )
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).
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:
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
I tried something it little different last night. I used the 000script approach from Simonās examples to create a Groovy
script that always executes first. In that script, I defined my base class, ItemRule. Since the script has access to the events variable, I can push that into ItemRule, and then it will be able to sendCommand() and postUpdate(). Then in the same file I created a new class extending ScriptExtensionProvider and created a preset with my class in it. Then my other scripts could importPreset(āDougā) and access my class definition.
def onRule2 = ItemRule.newInstance("MySwitch")
automationManager.addRule(onRule2)
As convoluted as that sounded, it worked. BUTā¦
I donāt want to just create a new instance. I want to extend it. But
class ItemRule2 extends ItemRule { }
wonāt compile because of āunable to resolve class ItemRuleā
I learned a lot, but I think Iām stuck with this approach. I tried a bunch of different things (imports, etc.), but just couldnāt get ItemRule visible as something I could extend.
I think iām just going to move on and accept that Iām going to pass the events variable in the constructor to my base classes for now.
Anybody know how to find and use an Action from groovy?
I suspect that will be the next thing I bump into. I took a look through Steveās OSGi python classes, but couldnāt mentally translate that into a Groovy approach due to a lack of experience with bouth OSGi and Python.
Thanks,
Doug
Answering my own question after more than a bit of reading codeā¦
My solution was to just use BusEvent and its static methods in my base class. And Iām using ScriptServiceUtil to get the item registry, so I donāt need to pass that in either.
So, Iām making progress on moving my base classes over from OH1 to OH2.
Doug
@steve1 I noticed you added a rule decorator to your library in openhab.rules. Could you please add an usage example to your Readme? I tried using the decorator in the same way as your decorator for Jython/OH1.8, but that doesnāt work.
Iāll add some information soon. Hereās an example of how to use it.
from openhab.rules import rule, addRule
from openhab.triggers import StartupTrigger
@rule
class ExampleRule(object):
def getEventTriggers(self):
return [ StartupTrigger() ]
def execute(self, module, inputs):
self.log.info("rule executed")
addRule(MyRule())
The decorator adds the SimpleRule base class and will call either getEventTriggers
or getEventTrigger
(the OH1 function) to get the triggers, if either function exists. Otherwise you can define a constructor and set self.triggers
to your list of triggers.
The decorator also adds a log object based on the name of the rule (self.log
, can be overridden in a constructor) and wraps the event trigger and execute
functions in a wrapper that will print nicer stack trace information if an exception is thrown.
@steve1 Thanks. Just one small correction to your example. It needs to import automationManager, not addRule. I sent you a PR.
You should pull the latest updates. The addRule
import is correct. The openhab.rules
module doesnāt export automationManager
any more because the module must look it up dynamically from the script-specific scope when addRule
is invoked. I changed it after I noticed that rules were not being deleted when a script was reloaded. The addRule
function should be equivalent to:
scriptExtension.importPreset("RuleSupport")
automationManager.addRule(ExampleRule())