Loops and arrays - can't figure out how!

I need to get dimming values of each light in a group into an array for use in a rule.

Currently I have this, which works, but it means I need to create switch routines for each light. I’d rather have all values stored into a single array instead of individual variables.

var Number lightcircuit1level = BedroomLights.members.get(0).state as DecimalType var Number lightcircuit2level = BedroomLights.members.get(1).state as DecimalType var Number lightcircuit3level = BedroomLights.members.get(2).state as DecimalType var Number lightcircuit4level = BedroomLights.members.get(3).state as DecimalType

Also I’d like to determine the number of items in the Item group and stop when I have reached this, if that makes sense!

I’m coming from a C background and have struggled with various ways using a basic for loop, what am I doing wrong?

Hi,

you can iterate through the members of a group very easily with the following syntax:

gMyLights.members.forEach [ LightSwitch |
    /* your code here */
]

As for the arrays, you can define native arrays, hashmaps and more. I suggest you take a look at the examples provided here (keywords: array, iteration):

Cheers,

In my experience, going down this path in the Rules DSL is a path in the wrong direction.

I think you will find that if you put your items into a group and use the group.members.* methods you will end up with much simpler code.

For example, to do something with each item in the group:

myGroup.members.forEach[dimmer | dimer.sendCommand(foo)]

Or to get all the dimmers greater than a certain value:

val highDimmers = myGroup.members.filter[dimer|(dimmer.state as DecimalType) > foo]

Or to put them in order:

val ordered = myGroup.members.sortBy[state]

I have a pretty good description of how I use these instead of arrays and hashmaps (and basically halved my lines of code count in the process) here..

val numItems = myGroup.members.size

or count of Items above a certain dimming value

val numItems = myGroup.members.filter[(state as DecimalType) > foo].size

I could have guess you came from a structural programming language background. I did too. You will find that if you try to program in the Rules DSL the same as you would in C (i.e. create data structures and iterate over them) you will be unhappy with the size, look, and maintainability of the code. If you instead treat your Items and Groups as your data structures instead of trying to create your own within the rules your code will be shorter, cleaner, and easier to write.

If however, you can’t get into the groove of the DSL, I do recommend the JSR233 binding which lets you write your rules in Python or javascript.

Hi @rlkoshak - top advice, thanks so much. I read your comprehensive design pattern. Haven’t fully gotten my head around it yet, but I’ll read it a few more times.

You wrote “This approach is best suited for cases where one has multiple items that do the same thing based on certain events, or multiple items that generate the same kind of event”

The rule in question is triggered on receiving a message over MQTT. The message is a string like “light_1_up”, “light_2_up”, or “light_1_down” etc. These are commands sent by an arduino wall controller.

Ideally of course I would have my rule split the string somehow, such as;

switch(Bedroomvector.state) {
	case "light_x_up" : 
	var String[] buffer
	// split string somehow using toString.split("_")
	sendCommand(BedroomLights.members.[x], BedroomLights.members.get(0).state + 1)
}

Obviously the above wouldn’t work, but I’m trying to describe what I want to do. This would mean there’s only one switch routine for this particular command coming over this MQTT topic. Right now I have this:

case "light_1_up" : {
	lightcircuit1level = lightcircuit1level + 3
	if(lightcircuit1level>100) lightcircuit1level = 100
	Light_LG_Bedroom_Ceiling.sendCommand(lightcircuit1level); // send command to light
}
case "light_1_down" : {
	lightcircuit1level = lightcircuit1level -3
	if(lightcircuit1level<0) lightcircuit1level = 0
	Light_LG_Bedroom_Ceiling.sendCommand(lightcircuit1level);
}
case "light_2_up" : {
	lightcircuit2level = lightcircuit2level + 3
	if(lightcircuit2level>100) lightcircuit2level = 100
	Light_LG_Bedroom_Wall.sendCommand(lightcircuit2level); // send command to light
}
case "light_2_down" : {
	lightcircuit2level = lightcircuit2level -3
	if(lightcircuit2level<0) lightcircuit2level = 0
	Light_LG_Bedroom_Wall.sendCommand(lightcircuit2level);
}
    ... etc

Which is a right mess.

Actually you can do something like your split String example above. You just need to make sure to name your Light Items such that it is easy to rebuild their name from the “light_1_up” String.

For example if your LightItems followed a pattern like “light_1_Dimmer” instead of Light_LG_Bedroom_Ceiling you can do the following:

val cmdSplit = Beedroomvector.state.split("_")
val dimmerName = cmdSplit.get(0) + "_" + cmdSplit.get(1) + "_Dimmer"
val dimmer = BedroomLights.members.filter(dimmer|dimmer.name == dimmerName).head
dimmer.sendCommand((dimmer.state as DecimalType) + 1)

There is one warning about the above i just remembered. When a rule is triggered by a received update on a group the rule will be triggered more than once.