Add to ArrayList

I am having issue adding elements to an array list.

val int[] feeders = newArrayList(0, 1)
feeders.add(2)

Is there an obvious error in in? Are there any logs generated by openHab where it writes out why it does not work.

Most rule errors will appear in openhab.log
It is well worth looking in there, as a matter of routine.

The only error I am seeing in that file is

2019-03-24 17:36:12.515 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule ‘play rule’: null

which is not very helpful.

Try:
var feeders = newArrayList(0,1)

It’s the add(2) that fails. If I remove this line the rule excutes

This post says add() needs two arguments.

feeders.add(0,2) fails too. My first understanding is that the first argument is the index and the second the value to be added. However, it does not work.

I also tried changing val to var in the statement below. My understanding being that val is for constants, var for variables. Changing to var by itself works. However, add still fails.

Might be time to share the rule

Will do it tonight. The code is at home, I am at work!

Code is below. I want to build up the feeders array dynamically based on what is selected in the control panel. But any and all attempts to call add fail!

rule “play rule”
when
Item PlayButton received update
then

var int[] feeders = newLinkedList(0,1)

    while (PlayButton.state == ON) {

	var int onTime = (FeederOnTime.state as Number).intValue
	onTime = onTime * 1000

	var int states = feeders.size()

	if ( states > 0 )
	{
		var int idx = (Math::random * states).intValue
		var int feeder = feeders.get(idx)

		if ( feeder == 0 ) {
			FeederSwitchA.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchA.sendCommand(OFF)
		}

		if ( feeder == 1 ) {
			FeederSwitchB.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchB.sendCommand(OFF)
		}

		if ( feeder == 2 ) {
			FeederSwitchC.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchC.sendCommand(OFF)
		}

		if ( feeder == 3 ) {
			FeederSwitchD.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchD.sendCommand(OFF)
		}

		if ( feeder == 4 ) {
			FeederSwitchE.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchE.sendCommand(OFF)
		}

		if ( feeder == 5 ) {
			FeederSwitchF.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchF.sendCommand(OFF)
		}
	}

	var int offTime = (FeederOffTime.state as Number).intValue
	offTime = offTime * 1000

	Thread::sleep(offTime)
}

end

umm, I wouldn’t worry about the array just yet.
The whole rule, with an open-ended while loop and long sleeps is a bad idea in an event driven system like openHAB. You’re tying up resources and it will have an impact on system performance overall.

Can you describe the desired actions here? Seems to be -
So long as Button is on -
Pick a random switch from five, turn it on.
Some time late, turn it off.
Pick a random switch and repeat

That can be restructured for events

When Button becomes on,
Pick a random switch and turn it on.
Set up a timer for future action

When timer expires,
Turn off the switch that is on.
See if Button is still on.
If it is, pick a random switch and turn it on.
And reschedule timer for future action.

I got it to work. I think the issue is with this line.

var int[] feeders = newLinkedList(0,1)

The correct way to do it is

var ArrayList feeders = newArrayList

Your understanding of the code is correct. Randomly pick a switch turn it on. Wait. Then turn in off. Pick again and repeat. My fixed code now is –

import java.util.List
import java.util.ArrayList

rule “play rule”
when
Item PlayButton received update
then
while (PlayButton.state == ON) {

	var ArrayList<int> feeders = newArrayList

	if ( FeederButtonA.state == ON ) {
		feeders.add(0)
	}

	if ( FeederButtonB.state == ON ) {
		feeders.add(1)
	}

	if ( FeederButtonC.state == ON ) {
		feeders.add(2)
	}

	if ( FeederButtonD.state == ON ) {
		feeders.add(3)
	}

	if ( FeederButtonE.state == ON ) {
		feeders.add(4)
	}

	if ( FeederButtonF.state == ON ) {
		feeders.add(5)
	}

	var int states = feeders.size()

	if ( states > 0 )
	{
		var int onTime = (FeederOnTime.state as Number).intValue
		onTime = onTime * 1000

		var int idx = (Math::random * states).intValue
		var int feeder = feeders.get(idx)

		if ( feeder == 0 ) {
			FeederSwitchA.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchA.sendCommand(OFF)
		}

		if ( feeder == 1 ) {
			FeederSwitchB.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchB.sendCommand(OFF)
		}

		if ( feeder == 2 ) {
			FeederSwitchC.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchC.sendCommand(OFF)
		}

		if ( feeder == 3 ) {
			FeederSwitchD.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchD.sendCommand(OFF)
		}

		if ( feeder == 4 ) {
			FeederSwitchE.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchE.sendCommand(OFF)
		}

		if ( feeder == 5 ) {
			FeederSwitchF.sendCommand(ON)
			Thread::sleep(onTime)
			FeederSwitchF.sendCommand(OFF)
		}
	}

	var int offTime = (FeederOffTime.state as Number).intValue
	offTime = offTime * 1000

	Thread::sleep(offTime)
}

end

I welcome suggestions.

Already made suggestion. Don’t do it that way.

This is an Array (uses get and set), but your probably looking for a List, which has add and remove methods…

var List<Integer> = newArrayList

Note, I used Integer and not int. The latter is a primitive and will cause the rule validation to go very slowly, so it is best to avoid them whenever possible…

But I agree with @rossko57… your rule is asking for trouble. Use Timers instead of sleep, or you will be continuously holding on to one of the 5 rule threads (default setting) while this rule runs. There are plenty of examples in the forum. Here’s one from Rich…