Jsr223: script collection

This looks reasonable to me. The example is more complex than defining rules in OH1, but it looks like much of the extra complexity could be hidden in a Jython rule class that looks very similar to the OH1 rules.

I’m wondering about the action “inputs” and if that is as powerful as the current approach or providing parameters to a rule constructor. In OH1 rules I can use the rule attributes to generate names for items in triggers, dynamically create a set of triggers or use the attributes as an input to the execute function.

Yes, it has indeed some complexity, but I wanted it to be as feature complete as possible. This example uses different techniques to build up the Rule/Action/Condition/Trigger configurations. Builder, direct Constructor initialization etc.

Another way would be the rule class of the jsr223-openhab addon. I will look into this compatibility in the next step.

I don’t know what you mean here. This is all possible with this approach or I cannot see what is missing. If you have an example of something that you think is not possible, I can try to give an example in the current state of the API.

But I will try to explain this example a little bit further:

The “MyAction” class is just the execution block of a Rule. The generation of Triggers etc. is done in a Rule (e.g. by constructing it with the help of the RuleBuilder). The Action should just execute and can be configured by a Rule. (The configuration can be received by module.configuration).

What the “MyAction” class does here is:

  • define the ActionType in its constructor as it is used by the HandlerRegistry to make the ActionHandler public to the RuleEngine/REST-API etc… This means
    • each instance of MyAction is a ModuleType and ActionHandler in the new RuleEngine
    • each MyAction instance can be used in multiple Rules
  • define a execution block which contains of two parameters (+ self):
    • the module: this allows getting configuration parameters etc. from the Rule-block (see here and here). So you can have configuration parameters in form of a “JSON”-like hashmap (Strings, Decimals, …), but no objects. I guess this is enough for most modules, otherwise the Module has to provide its own configuration handling - as it is a single instance across Rules, this would be another option. In this example the configuration parameter “test” is defined and assigned to 123 in the rule.
    • the inputs: this is at least like the parameter event in jsr223 openhab 1.7, but you can configure even more input fields.

The output of MyAction in this example:

org.eclipse.smarthome.automation.core.internal.RuntimeAction@126a5fd
{trigger2.event: Sun_Elevation updated to 6.54}

This is probably slightly off topic but will we be able to write rules where we specify the conditions as item states as opposed to events?

As an example: motion detected whilst away.

Currently using Xtend rules we’d have to do something like

rule "Alarm"
when 
  Item motion received change to ON
then
  if (myPresenceItem.state == OFF) {
    \\ call the police1!!1
  }
end

Would we be able to write the rule such that we specify “motion.state==ON” and “myPresenceItem.state==OFF” as the condition for the action?

Edit: I understand it would still need to trigger on a related item’s event occurrence, I guess I’m just after a simpler, clearer way to describe the conditions.

Thanks for the extra information. This could very well be a case of me not having a clear understanding of the ESH terminology in this context (like “module”). I’ll hopefully have more useful comments when the bundling approach is defined (and rule and rule template definitions are supported).

Not knowing the ESH design rationale, it doesn’t make immediate sense to me that all rule behaviors (actions) should be exposed via registries, REST, and so on. In many cases, the logic in my rules is not something I want to share between rules or access externally as an action separate from the rule. (I’m assuming that rule-specific complex conditional logic is implemented in a ActionHandler implementation.) If I want a reusable “action” in Python, I’d just write a function or define a class. It seems like a registered ESH action should only be required if I want to export an action for use outside of Python.

Although the rule parameter types are more limited than OH1, I can think of some workarounds for that issue.

Yes, you are right, it is not clear why all actions should be registered and its correct that this is not needed in many cases.

The actions provided as modules can be set HIDDEN for UIs, but not completely removed as they have to be known to the registry.

In the last revision of the sourcecode I have added “ScriptedAction” and “ScriptedCondition”, which help in that matter, as these are the only modules known to the RuleEngine, the mapping to the actual Rule/Action is done by the JSR-Loader.

In this version, I can already write something very similar to the openhab 1 jsr223 implementation:


def itemStateChangeTrigger(triggerName, itemName):
    return Trigger(triggername, "ItemStateChangeTrigger", {
        "itemName": itemName
    })

# SimpleRule can combine any TriggerType and ConditionType registered to the RuleEngine
class MySimpleRule(SimpleRule):
    def __init__(self):
        pass

    def getTriggers(self):
        return [itemStateTrigger("trigger1", "Sun_Elevation")]

    def getConditions(self):
        return []

    def execute(self, module, inputs):
        print "module:", module
        print "configuration:", module.configuration
        print "inputs:", inputs

        print dir(inputs)
        for k, v in inputs.iteritems():
            print "key:", k, "value:", v.TYPE, "value dir:", dir(v)


class ChangedEventTrigger:
    UID = 0
    def __init__(self, itemName, fromVale, toValue):
        self.UID += 1
        self.condition = None

        self.trigger = Trigger(itemName+str(self.UID)+str(toValue), "GenericEventTrigger", {
                                "eventSource":itemName,
                                "eventTopic":"smarthome/items/*",
                                "eventTypes":"ItemStateChangedEvent"
                            })
        #todo: build condition for fromValue (and toValue)


class Rule():
    pass

class CompatRule(SimpleRule):
    def __init__(self, rule):
        self.rule = rule

    def getTriggers(self):
        return [t.trigger for t in self.rule.getEventTrigger() if t.trigger]

    def getConditions(self):
        return [t.condition for t in self.rule.getEventTrigger() if t.condition]

    def execute(self, module, inputs):
        return self.rule.execute(inputs[inputs.keys()[0]])


class Openhab1Rule(Rule):
    def getEventTrigger(self):
        return [ChangedEventTrigger("Light_FF_Child_Ceiling", None, OnOffType.ON)]

    def execute(self, event):
        print "my event:", event



RuleRegistry.addSimple(CompatRule(Openhab1Rule())) 

output:

my event: Light_FF_Child_Ceiling changed from OFF to ON

Still missing: script removal logic: actions and module types need to be removed if the script is updated or removed…

Great job. That’s looking very good.

Just out of curiosity, what is the benefit in ESH of having condition objects rather than having the conditional logic in the “action” (execute function).

Not specifically related to ESH but in general having the correct
separation between logic and actions means that they can be reused more
easily but it’s also more likely to be easier to maintain if you need to
change the condition, for example. In that case you know all the changes are localised and shouldn’t have any unintended side-effects on the action.

I don’t have the time to dive deep into your code, so at a glance I could not make out the change concerning ModuleHandlerFactory that you are referring to. Do you have a direct link to the change?

Should I open another community thread for this and/or an Issue/Pull Request on Github?

It is probably best if you create small PRs for independent changes & improvements (as long as you don’t think they need a bigger discussion upfront).[quote=“steve1, post:26, topic:5232”]
Just out of curiosity, what is the benefit in ESH of having condition objects rather than having the conditional logic in the “action” (execute function).
[/quote]

Well, the logic is usually not related to the (sequence of) actions themselves. If you have a rule “when something happens, send a notification”, it is much better to be able to add a “but not at night” or “only when I am not at home” - the “notification” action type does not need to have anything about presence or time as an input this way.

My question wasn’t as clear as it should have been. I put “action” in quotes because that appeared to be the proposed OH2 implementation of the current JSR223 rule execute function. I don’t believe that an action object/abstraction represents the execute function well for the reasons you and others are describing. In most cases, it’s not an encapsulated, reusable behavior (like a notification action) and therefore it doesn’t seem correct to expose it through a handler registry.

I’m wondering about the phrase you used “the (sequence of) actions”. Does the ESH model represent a rule as a single sequence of actions? If so, this will be much less flexible than the current rule implementation that supports invoking alternate actions based on conditional logic and doesn’t force an action execution sequence since actions can be run asynchronously (using timers, for example).

It would be interesting to see a translation of some relatively complex rules to the new model. For example, the rules described in the wiki at…

I have made a PR for that. After thinking about that, I guess it is ok the I way I’ve done it.

I also introduced some other PRs that are necessary for the loader extension I’m currently developing. As I want to split it into multiple bundles, the feature/loader-branch is not made available as PR request right now.

I will add the following bundles:

  • loader: this allows defining scripts in a script directory and in bundles
  • extensions.rules (or similar name): ability to add modulehandlers (trigger, condition, action) in general form (with a unique name) and in “simple form” (as ScriptedAction etc.) loadable by ScriptExtension.importPreset("RuleSupport")
  • (openhab1 compat): Additional classes to provide backward compatiblity to Jsr223 of openhab1. As some Triggers and Conditions do not exist currently, which would be necessary to match the triggers of the old ScriptEngine, I don’t know if I will provide it at this state. I might start with triggers I can provide right now. (In the future loadable by): ```
    ScriptExtension.importPreset(“RuleSupport”)
    ScriptExtension.importPreset(“RuleOh1Compat”)
1 Like

Thanks @smerschjo!

I’ll probably not have the time to review them next week, so please allow me detailed feedback by mid of January.
For the “openhab1 compat” part, better wait until I have included the new rule engine as an experimental feature in OH2 - your compat bundle should most likely not be contributed to ESH, but OH2 then.

No, it will be fully support all current situations as well. You will simply have a rule with a few triggers and a single action, which will be a script action - in this, you an code as much complex stuff as you like :smile:

Note that the ESH modules are meant to be simple blocks to use for assembling rules through a UI. I deliberately constrained this, because I want the UI to be easy (IFTTT-like) and not end up as a graphical programming tool like Blockly or Node-RED (which are great tools, so don’t get me wrong - but they are not a good choice for non-technical people).

1 Like

@Kai, I’m really excited to try a scripting alternative to Xtend in OH2. Please let us know when this feature makes it to OH2 at cloud bees!

(I’m currently reluctantly learning Xtend since I can’t get habmin blockly to work (no “when” clause problems).

Of course, take your time.

Yes, that is mainly the reason why I split this up in the first place :wink: I will wait then.

2 Likes

Hi,

is it possible to write settings to the Buderus KM200 gateway as well (like day mode / night mode, water circulation etc)?

No one using the KM200 in openhab?
I did not connect it yet, but would love to control the functions mentioned above.

Yes, you can control some settings as well. At least all settings you can
set by the Android application, can be controlled through this REST
service. You might even find options that are not exposed through the
Android app.

The Python script allows you to dig into the API.

Thanks @smerschjo,
I will do my best to Figure it out! :slight_smile: