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.
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
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…