(Check) Rule transition help

  • Platform information:
    Intel CPU i5-6200U, 8GB RAM, 1TB HDD, Linux Debian Jessie (8.10), Oracle 64bit JVM build 1.8.0_161-b12, OH 2.3 Snapshot 1216

  • Issue of the topic: No issue, just a simple Rule syntax validation :wink: (going from if statements to switch/case statements)

  • Please post configurations (if applicable):

/etc/openhab2/rules/Fib_Buttons.rules file

old rule (version 1):

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	if (FibBut01_Scene.state == 1.0) {
		logInfo("FB01", "FB01 1x pushed")
		WDim01_Dim.sendCommand(0)
	}
	if (FibBut01_Scene.state == 1.1) {
		logInfo("FB01", "FB01 let go")
		WDim01_Dim.sendCommand(10)
	}
	if (FibBut01_Scene.state == 1.2) {
		logInfo("FB01", "FB01 kept in")
		WDim01_Dim.sendCommand(50)
	}
	if (FibBut01_Scene.state == 1.3) {
		logInfo("FB01", "FB01 2x pushed")
		WDim01_Dim.sendCommand(100)
	}
	if (FibBut01_Scene.state == 1.4) {
		logInfo("FB01", "FB01 3x pushed")
		WDim01_Dim.sendCommand(3)
	}
	if (FibBut01_Scene.state == 1.5) {
		logInfo("FB01", "FB01 4x pushed")
		WDim01_Dim.sendCommand(2)
	}
	if (FibBut01_Scene.state == 1.6) {
		logInfo("FB01", "FB01 5x pushed")
		WDim01_Dim.sendCommand(1)
	}
end

new rule (version 2):

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	var	FB01State = FibBut01_Scene.state
	switch (FB01State) {
		case 1.0: {
			logInfo("FB01", "FB01 1x pushed, set Lights at 0%")
			WDim01_Dim.sendCommand(0)
		}
		case 1.1: {
			logInfo("FB01", "FB01 1x let go, set Lights at 10%")
			WDim01_Dim.sendCommand(10)
		}
		case 1.2:	{
			logInfo("FB01", "FB01 1x kept in, set Lights at 50%")	
			WDim01_Dim.sendCommand(50)
		}
		case 1.3:	{
			logInfo("FB01", "FB01 2x pushed, set Lights at 100%")
			WDim01_Dim.sendCommand(100)
		}
		case 1.4:	{
			logInfo("FB01", "FB01 3x pushed, set Lights at 3%")
			WDim01_Dim.sendCommand(3)
		}
		case 1.5:	{
			logInfo("FB01", "FB01 4x pushed, set Lights at 2%")
			WDim01_Dim.sendCommand(2)
		}
		case 1.6:	{
			logInfo("FB01", "FB01 5x pushed, set Lights at 1%")
			WDim01_Dim.sendCommand(1)
		}
		default:	{
			logInfo("FB01", "FB01 State is: " + FB01State)
		}
	}
end

.
relevant items:

Dimmer	WDim01_Dim		"Staircase LED Dim [%d %%]"	<slider>	(gZWave)	{channel="zwave:device:ZW090C:node4:switch_dimmer"}
Number  FibBut01_Scene	"FB01 Scene: [%s]"			<contact>	(gZWave)	{channel="zwave:device:ZW090C:node9:scene_number"}
  • If logs where generated please post these here using code fences:
    No logs, since no errors existing in either case.

“optimized/cleaner/shorter” version 3 of the new rule syntax:

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	var	FB01State = FibBut01_Scene.state
	switch (FB01State) {
		case 1.0:	{WDim01_Dim.sendCommand(0)}
		case 1.1:	{WDim01_Dim.sendCommand(10)}
		case 1.2:	{WDim01_Dim.sendCommand(50)}
		case 1.3:	{WDim01_Dim.sendCommand(100)}
		case 1.4:	{WDim01_Dim.sendCommand(3)}
		case 1.5:	{WDim01_Dim.sendCommand(2)}
		case 1.6:	{WDim01_Dim.sendCommand(1)}
		default:	{logInfo("FB01", "FB01 State is: " + FB01State)}
	}
end

Any further improvement ideas on version 3 of the rule? :slight_smile: (maybe cut that extra var FB01State line?)

if your Goal is to have as few lines and characters as possible:

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	var Number dimValue = 0
	switch (FibBut01_Scene.state) {
		case 1.0:	dimValue = 0
		case 1.1:	dimValue = 10
		case 1.2:	dimValue = 50
		case 1.3:	dimValue = 100
		case 1.4:	dimValue = 3
		case 1.5:	dimValue = 2
		case 1.6:	dimValue = 1
		default:	logInfo("FB01", "FB01 State is: " + FibBut01_Scene.state)
	}
	WDim01_Dim.sendCommand(dimValue)
end

of course you could shorten dimValue to dV and get rid of the case 1.0, since dimValue has already the default value of 0…

hint:
default: will only trigger, if no other case is met before. So, if you have some state the FibBut01_Scene item can have despite 1.0 til 1.6 only then there’s a log entry. So, especially after startup (UNDEF), the sendCommand will be 0 in my example, as no case is met and within default you only generate the log entry.

If you’d like to have as little Zwave traffic as possible, you could also Change your trigger to Item FibBut01_Scene changed

2 Likes

another thought to further shorten the rule :smirk:: If you’re able to name the scenes in the Fibaro device (I know nothing on Zwave), you could name them as percentage and just take the value for the command:

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	if (FibBut01_Scene.state != UNDEF) WDim01_Dim.sendCommand(FibBut01_Scene.state)
	else logInfo("FB01", "FB01 State is: " + FibBut01_Scene.state)
end

hmmmm. that’s a nice idea…
maybe I can find a way to “map” the Button states (1.0 to 1.6 = 7 options) that the Fib_Button provides to percentage values and use this mapping to send the dimming level in the command… I will try to find a way to do this and let you know.

On the other hand, I like your approach with the variable since I can set multiple vars per case (scene) and do more complex scene management like that (to control several destination endpoints based on the Scene state value case)

Thanx a lot for version 4 of the rule! I like it and I will implement it now :slight_smile:

Ps: I use mapdb to restoreOnStartup the state of FibBut01_Scene and it works fine. The rule doesn’t fire upon OH2 startup, so I always have a valid state (and never fall into the default case, so I could remove it). I will go with the Item FibBut01_Scene changed trigger method

1 Like

Not only is this version of the rule shorter but it has one other very important quality. It only calls WDim01_Dim.sendCommand once. I really like this approach and try to implement it in all my code as well, even if it makes the Rule a little bit longer.

The reason I like it is that it is a great application of Don’t Repeat Yourself (DRY). Even if it is just one line, it is better to only call the function on one line if the only difference is the arguments passed to that function. It will also make it a lot easier on down the road when you need to do some extra checking or calculations before calling sendCommand. By only having one place where sendCommand is called you can add the checking or testing there.

I also really like this sort of approach as well. I will often default the value and only test to see if I need to change the default.

Or check to see if dimValue is different from the current state and only sendCommand if they are different. Hey, look at that, we are already benefiting from putting the call to sendCommand at the end. :slight_smile:

if(WDim01_Dim.state != dimBValue) WDim01_Dim.sendCommand(dimValue)

I’ll leave Design Pattern: Human Readable Names in Messages here for you. :wink:

scene.map

1.0=0
1.1=10
1.2=50
1.3=100
1.4=3
1.5=2
1.6=1
NULL=0
UNDEF=0

Don’t forget NULL and UNDEF.

Then the Rule becomes:

rule	"Fibaro Button 01 Pushing"
when
	Item FibBut01_Scene received update
then
	var dimValue = transform("MAP", "scene.map", FibBut01_Scene.state.toString)
	if(WDim01_Dim.state.toString != dimValue) WDim01_Dim.sendCommand(dimValue)
end

It is kind of a false efficiency. The switch statement will run a whole lot faster, and in some ways it becomes a little harder to understand what the rule does because you have to look in two places to see what it does. But now you can change the map file without touching your Rule to change the dimming values and add new scenes.

2 Likes