[SOLVED] Define item as val

I have defined this item:

Switch Relay4 "inverter BIG" { mqtt=">[brokerInverter:openhab/relay4:command:ON:ON],>[brokerInverter:openhab/relay4:command:OFF:OFF]"}

I want to define this item as val in the rule to be able to write and easy to remember the code I’m working on later and to be able to replace faster the hardware involved. So, I tried to add this before the rule:

val inverterBig = Relay4

then wrote the code:

inverterBig.sendCommand(ON)

But this code failured. If I replace “inverterBig” with “Relay4” in the code then everything is working well. So, how to define corectly the val ?

Try this

val SwitchItem inverterBig = Relay4
val inverterBig = Relay4.state

He wants to use inverterBig as an item --> inverterBig.sendCommand(ON)

1 Like

So this is something that I ran into long while ago. The tl;dr is this will not work. Every time the Rule runs it gets and needs a new instance of Relay4 created for it. You can’t reuse Items from Rule to Rule. In my case I was using the Item as the key in a HashMap.

Your description for why you want to do this is not very clear but it sounds like a really bad idea from a Rules DSL programming perspective. A more appropriate approach would be to use Groups, Member of triggers, and triggeringItem implicit variable to make your code to be able to handle what you seem to be wanting to do.

Or if you really mean you want to easily change out the hardware for inverterBig, well that is what Items are for. Create an InverterBig Item and if you change out the hardware that does InverterBig, just change the binding config or the channel that Item Links to. Items should model your home automation system and Items are hardware independent.

Any other approach will lead to lengthy, complex, and non-working code.

If you desire to ignore the warnings and continue down this path I’ll recommend using JSR223 Rules instead which will give you more tools to do this sort of thing. But realize that I think even there you can’t save a reference to an Item from one Rule to the next and have that Item work.

H102, mhilbush… tried your suggestions without success.
rikoshak… thanks, I’ll change my approach.

Thank you all.

I don’t understand. How did it not work? Are you declaring the val inside or outside the body of the rule? If outside the body of the rule, it won’t work. If inside, it will work.

What exactly do you mean when you say it won’t work?

I don’t know the specifics but when you save an Item to a global var or val, you are saving a reference to the Object that represents that Item at that point in time. On subsequent runs of a Rule, a new instance of the Object for the Item gets created. Over time (I’m not sure if it is the very next run of a Rule or just after a certain amount of time) that first Item Object gets stale and no longer works when calling .state or persistence calls.

I’ve declared variable inside of the rule.

rule "Switch from OVER"
when Item HabpanelBattery changed from "OVER"  
then    
        val inverterSmall = Relay3.state
        val inverterBig = Relay4.state
        
if      (HabpanelBattery.state == "NORMAL") {}  // do nothing
else if (HabpanelBattery.state == "ECO"){ // check the battery status
    timer = createTimer(now.plusSeconds(5) [|if (HabpanelBattery.state == "ECO"){ 
            inverterBig.sendCommand(OFF)
            timer = createTimer(now.plusSeconds(5) [|
                        while (inverterBig.state == (ON)){}
                        inverterSmall.sendCommand(ON)])
            timer = null
        }])  
        }  
end

Got this error:

2018-12-13 12:46:05.873 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Switch from OVER': An error occurred during the script execution: index=1, size=1

You are using the same timer variable inside the timer itself
Furthermore, you are using a while loop which is always dangerous and can lock threads.
Remember that you have only 2 timer threads available.
There is no need for your inverter variables

var Timer timer = null
var Timer timer2 = null

rule "Switch from OVER"
when Item HabpanelBattery changed from "OVER"  
then    
    if (HabpanelBattery.state == "NORMAL") return;  // do nothing
    if (HabpanelBattery.state == "ECO") { // check the battery status
        timer = createTimer(now.plusSeconds(5) [ |
            if (HabpanelBattery.state == "ECO") { 
                Relay4.sendCommand(OFF)
                timer2 = createTimer(now.plusSeconds(5) [ |
                    if Relay4.state == OFF) {
                        Relay3.sendCommand(ON)
                        timer2 = null
                    } else {
                        timer2.reschedule(now.plusSeconds(5))
                    }
                ])
            }
            timer = null
        ])  
    }  
end
1 Like

vzorglub, got your notice about “timer in timer”. I didn’t know it about. I managed to apply your example to my work. Thank a lot!

Please post your working code and mark the thread as solved, thanks.