(SOLVED) Proxy switches representing and controling the state of an step item

Using openhab 2.5M1 build 1575 on a Rpi.

I´m trying to figure how to get five (5) proxy switched representing the state of the ventilation speed of my Nilan ventilation system to be visual and controled from Google Home as well as from openhab and the Nilan system itself…
The Nilan ventilation system uses one item in steps from 0 - 4 for controling the fan speed. 0 (zero) is standby. Fan speed is off. Step 1 = Fan speed low. Sted 2, Fan speed middle etc…

In short - When ventilation is set to step 2, ProxySwitch2 should be ON.
And in reverse - If I turn on ProxySwitch3 , then the Nilan system should change to step 3.

This is the nilan item to set the step:

Number Nilan_Control_VentSet         "User ventilation step select [MAP(nilan_ventset.map):%s]"       	<fan_ceiling>   (gNilan) 	{channel="modbus:data:myNilan:controlRegisters:hol1003:number", autoupdate="false"}

I have already created the proxyswitch items as well, cause I use it for manually change the speed through openhab/goole home etc… Its very basic, but it works, except, In google home, all the switches are OFF, because I use the expire binding to set the switch to off. Which ofcouse is wrong. But I havnt figured how to leave one ON, and the rest OFF…

These are the proxy switches, again, very simple:

// Ventilation
Switch   nilanVent0   	"Ventilation trin 0 [%s]" 		<switch> 	 	[ "Switchable" ]	{ expire="1s,command=OFF"}
Switch   nilanVent1   	"Ventilation trin 1 [%s]" 		<switch> 	 	[ "Switchable" ]	{ expire="1s,command=OFF"}
Switch   nilanVent2   	"Ventilation trin 2 [%s]" 		<switch> 		[ "Switchable" ]	{ expire="1s,command=OFF"}
Switch   nilanVent3   	"Ventilation trin 3 [%s]" 		<switch> 	 	[ "Switchable" ]	{ expire="1s,command=OFF"}
Switch   nilanVent4   	"Ventilation trin 4 [%s]" 		<switch> 	 	[ "Switchable" ]	{ expire="1s,command=OFF"}

And this is the rule I use to make use of these switches:

rule "Nilan ventilation trin 0"

when
    Item nilanVent0 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(0)
end


rule "Nilan ventilation trin 1"

when
    Item nilanVent1 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(1)
end


rule "Nilan ventilation trin 2"

when
    Item nilanVent2 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(2)
end


rule "Nilan ventilation trin 3"

when
    Item nilanVent3 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(3)
end


rule "Nilan ventilation trin 4"

when
    Item nilanVent4 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(4)
end

Again, this is very basic, could probably be optimzed somehow, but it works… Also it works with controle from Google Home, except, in Google Home, it doesnt show which proxyswitch is actually turned on. Thats whats bothering me.

Now… what I really wanted was a way to controle this, just like it is today, but also beeing able to see in Google Home, (or openhab) which proxyswitch (step) is ON.
As said, I know the above wont work like this,cause I use the expire binding to turn the proxyswitch OFF after one sec. But if I dont, then the switches will remain ON, if I change the state on the ventilation system. Thats the part I can seem to figure…
I think I probably have to make use of a rule which either uses cases or quite a few “else if” arguements… Like this:

rule "Manual ventilation steps"

when
      Item Nilan_Control_VentSet changed 
then

if(Nilan_Control_VentSet.state === 4)   {
	 nilanVent4.sendCommand(ON) 
   }
 else 
	{	
	nilanVent4.sendCommand(OFF) 
   }
else
if(Nilan_Control_VentSet.state === 3)   {
	 nilanVent3.sendCommand(ON) 
   }
 else 
	{	
	nilanVent3.sendCommand(OFF) 
   }

Etc.........

This might work, at least one way. But I fail to see if it´ll work from openhab/Google to the ventilation system… So in that case I tried to find a rule suitable from the other direction by placing all the proxyswitches in a group, I guess I could do something like this:

rule "Manual ventilation steps opposit direction"

when
      Item g_nilanVent changed 
then

if(nilanVent4.state === ON)   {
	 Nilan_Control_VentSet.sendCommand(4) 
   }
else
if(nilanVent3.state === ON)   {
	 Nilan_Control_VentSet.sendCommand(3)
   }
 else  ......

This will work. But how do I set the other proxy switches to go OFF except for the activated step/switch?

I guess this is the bottom line of my question in this… It´s probably very simple, I just cant see how…

This would handle the expire functionality and would not send a new command to the items just change their status.
You can also use ‘or’ with your when statements

 Item nilanVent1 changed from OFF to ON or
 Item nilanVent2 changed from OFF to ON or
 Item nilanVent3 changed from OFF to ON
etc

Ahh, ofcouse… I like this one. Could probably be optimzed but it makes sense… Thanks alot, will give it a try.

Just double check your work, on more than one occasion I have failed to update all commands I pasted and had some fun troubleshooting times. :wink:

I just tried, but I dont think postupdate works…
When I use Google Home app to turn on one the the switches on, the others switches do no turn off.

You can do a test via a cron rule and watch the event log, to verify OH is changing the states.

The switches changes the state of the ventilation, but the proxyswitches doesnt change… Its a bit strange.

Does (that part of) your rule run? Find out with logInfo.
Are you expecting the state of an Item to reflect a command that you have only just sent in the same rule? (It won’t)

In short, I´m trying to get 5 proxyswitches to reflect the state of an item. One proxyitem for each state.
The same proxyswitches should also be able control the very same item.
(It sounds more confusing than it is). But I´m not sure if its possible at all.

The five proxyitems are these:

Switch   nilanVent0   	"Ventilation trin 0 [%s]" 		<switch> 	(gVentState) 	[ "Switchable" ]	
Switch   nilanVent1   	"Ventilation trin 1 [%s]" 		<switch> 	(gVentState) 	[ "Switchable" ]	
Switch   nilanVent2   	"Ventilation trin 2 [%s]" 		<switch> 	(gVentState)	[ "Switchable" ]	
Switch   nilanVent3   	"Ventilation trin 3 [%s]" 		<switch> 	(gVentState) 	[ "Switchable" ]	
Switch   nilanVent4   	"Ventilation trin 4 [%s]" 		<switch> 	(gVentState) 	[ "Switchable" ]	

Each item should represent one state of the ventilation speed.
The ventilation speed is this item:

Number Nilan_Control_VentSet         "User ventilation step select [MAP(nilan_ventset.map):%s]"       	<fan_ceiling>   (gNilan) 	{channel="modbus:data:myNilan:controlRegisters:hol1003:number", autoupdate="false"}

This item accept commands value from 0 - 4

The problem is… Using the above proxyswitches, I can not get them to turn off. Only one of them should be ON at any time. Untill yesterday I was using the expire binding to turn them off. And it works fine. However, in Google Home all will be off, so I cant see which speed is ON. This is due to the expire binding, ofcouse. And thats the part I´m struggling with.

This is how the rule looks right now:

rule "Nilan ventilation trin 0"

when
    Item nilanVent0 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(0)
end


rule "Nilan ventilation trin 1"

when
    Item nilanVent1 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(1)
end


rule "Nilan ventilation trin 2"

when
    Item nilanVent2 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(2)
end


rule "Nilan ventilation trin 3"

when
    Item nilanVent3 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(3)
end


rule "Nilan ventilation trin 4"

when
    Item nilanVent4 changed from OFF to ON
then
	Nilan_Control_VentSet.sendCommand(4)
end



rule "Manual ventilation steps"

when
      Item Nilan_Control_VentSet changed 
then

if(Nilan_Control_VentSet.state === 4)   {
	 nilanVent4.sendCommand(ON)
         nilanVent0.sendCommand(OFF)
         nilanVent1.sendCommand(OFF)
         nilanVent2.sendCommand(OFF)
         nilanVent3.sendCommand(OFF) 
   }
else
if(Nilan_Control_VentSet.state === 3)   {
	 nilanVent3.sendCommand(ON)
         nilanVent0.sendCommand(OFF)
         nilanVent1.sendCommand(OFF)
         nilanVent2.sendCommand(OFF)
         nilanVent4.sendCommand(OFF) 
   }
else
if(Nilan_Control_VentSet.state === 2)   {
	 nilanVent2.sendCommand(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent1.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
   }
else
if(Nilan_Control_VentSet.state === 1)   {
	 nilanVent1.sendCommand(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
   }
else
if(Nilan_Control_VentSet.state === 0)   {
	 nilanVent0.sendCommand(ON)
         nilanVent1.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
   }
end

The “Manual ventilation steps” does not work. I have tried with both postUpdate as well as sendCommand. It does not turn OFF the proxyswitchs. I havn´t tried inserting any logging, as I assume in this case it makes no sense…
Do you think this is due to beeing in the same rule file?

Don’t sendCommand to your proxy, you risk making an endless loop (as sendCommand triggers a rule that sends a command that might update the target that triggers the rule that sends a command …)

Well, you still don’t know if your “steps” rule ever runs. Not sure what the objection is to finding out.
I’ll predict that it never runs, because postUpdate just works.

Why wouldn’t it run? Let’s look at that. The trigger is changed, that means if the state of your “real” Item changes. Not if gets updated to same value, not when sent a command.
Look in events.log - Item changes are reported there, do you ever get one?
Why might you not get one?
Your Item has autoupdate disabled, so you will not get an OH prediction/force of the state in response to a command.
The only way your Item will get updated/changed is if the binding tells it.

This doesn’t happen to be a write only channel perhaps?

It was for testing purpose only. I have changed it to postUpdate now.

Just inserted a few logging lines… It seems like the rule never runs for some reason I cant see to figure.
The main item do update fine, but my “manual ventilation steps” does not receive the update:

2019-06-10 16:40:51.672 [ome.event.ItemCommandEvent] - Item 'Nilan_Control_VentSet' received command 4
2019-06-10 16:40:57.531 [vent.ItemStateChangedEvent] - Nilan_Control_VentSet changed from 2 to 4

But my proxy items do not update: This is the rule I just tested:

rule "Manual ventilation steps"

when
      Item Nilan_Control_VentSet changed 
then

if(Nilan_Control_VentSet.state === 4)   {
        logInfo("debug", "Vent 4 ON all others OFF")
	 nilanVent4.postUpdate(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent1.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent3.postUpdate(OFF) 

   }
else
if(Nilan_Control_VentSet.state === 3)   {
	 nilanVent3.postUpdate(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent1.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
        logInfo("debug", "Vent 3 ON all others OFF")
   }
else
if(Nilan_Control_VentSet.state === 2)   {
	 nilanVent2.postUpdate(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent1.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
        logInfo("debug", "Vent 2 ON all others OFF")
   }
else
if(Nilan_Control_VentSet.state === 1)   {
	 nilanVent1.postUpdate(ON)
         nilanVent0.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF)
        logInfo("debug", "Vent 1 ON all others OFF") 
   }
else
if(Nilan_Control_VentSet.state === 0)   {
	 nilanVent0.postUpdate(ON)
         nilanVent1.postUpdate(OFF)
         nilanVent2.postUpdate(OFF)
         nilanVent3.postUpdate(OFF)
         nilanVent4.postUpdate(OFF) 
        logInfo("debug", "Vent 0 ON all others OFF")
   }
end

No, its a write channel. Commands 0 - 4 send to the main item works fine.

Wait a minute … what’s that? === is super-duper must exactly match everything including exactly the same type of number. (generally only seen when comparing null and not wanting to confuse with a string or whatever).

The state of a Number Item isn’t exactly the same as an integer primitive (it can be a decimal value for example). You want the == evaluation which looks for less stringent equality.

Ahh, great!! I changed the === to ==, and now it works…
Thanks alot for spotting this one, rossko.

But I dont understand why it wouldnt work with ===. This specific item can only be 0,1,2,3,4. So I would assume that === would work as well.

Because === is the super special must match in every last respect thing.
Typing 3 into a rule I think gives you by default a value which is of type primitive integer. Extracting the state of a Number Item with myItem.state does not give you a primitive Integer, it gives you a Number type.
3-as-integer does not match 3-as-Number in every respect.
It’s like 3 == “3” , no match there either … numeric 3 is not the same as the squiggly string character “3”
It’s just a dumb machine doing what you told it to.

You can probably make === work if you want to by manipulating types to match. Something like (untried) -
if ( (myItem.state as Number) === (3 as Number) )

Ahh okay I get it, I think… Makes sense. So === should only be used for anything else than numbers?

What do you find deficient about using == ?

There are times when you might want super special exact identity comparisons, but they are few and far between.

Nothing… I just thought === would be most correct to use, as I thought numbers couldn´t be more specific :slight_smile:

It’s actually not quite as described. === is the identity operator. It doesn’t test that the left operand and the right operand match all their parts. It tests to see if the left operand and the right operand point to the same place in memory. It literally means “are these two operands the same Object” as opposed to == which means “are these two operands equivalent”.

Because of a quirk in how Java saves memory with how it uses primitives, null exists at only one memory address no matter how many times it’s used. So when you are testing something === null you are literally asking if something points to the same place in memory as null.

Nope. Only if both operands are literally the same Object, not just equivalent will === be true.

val Integer foo = new Integer(4)
val Integer bar = new Integer(4)

foo == bar // true because both are equivalent
foo === bar // false because foo and bar are different Objects pointing to different places in memory

In the OH context, only use === when null is one of the operands.

In programming, numbers are the least specific. Consider:

  • byte - 8-bit unsinged integer
  • short - primitive 16-bit signed integer
  • char - primitive 16-bit unsinged integer
  • int - primitive 32-bit signed integer
  • long - primitive 64-bit signed integer
  • float - primitive 32-bit IEEE 754 floating point number
  • double - primitive 64-bit IEEE 754 floating point number

That’s just the primitives. Then you have an Object version of each of the above and meta classes like BigNumber which can store any of the above and convert between them. There are probably over two dozen different types of “numbers”.

1 Like

There now, goes further than I thought. Thanks for correcting Rick!