OpenHAB 2.4 - java.lang.ArrayIndexOutOfBoundsException: 1 with ohscheduler

Hello guys.

Using openHABian 2.4 on a RPI 3

I’m playing with openhab for I while now and have a little room temperature control working.

Now I want to make it posable to make a little schedule that regulates the temperature. So I found this widget to get that https://github.com/nepotu/ohscheduler.
I installed and configure it like the github tells me and it is working until a extend. Bud as soon as I try to use the scheduler it gifs me the error in the log

[del.script.temperature-control.rules] - Temperature control error: java.lang.ArrayIndexOutOfBoundsException: 1

I have been toying with it to fix the problem for multiple hours bud I can’t get it to work. Is there someone who can help me or can point me to a widget that does work?

The problem exist in the following rule:

// --- By Geo Magadan | nepotu.ro --- //
// ---        version 1.2        --- //
//HVAC Scheduler - Target Temperature Management Rules
import java.util.concurrent.locks.ReentrantLock

//Global variables
var ReentrantLock tempCtlLock = new ReentrantLock()
var ReentrantLock tempQueueLock = new ReentrantLock()
var Timer tempCtlTimer = null

// HVAC Scheduler - Target Temperature Management
rule "HVAC Scheduler - Target Temperature Management"
when
    Time   cron "0 0/1 * * * ?"           or
    Item   HVAC_Mode received update      or
    Item   HVAC_Mode received command     or
    Item   HVAC_Schedule received update  or
    Item   HVAC_Schedule received command
then
    if (tempCtlLock.tryLock()) {
        try {
            //tempCtlLock.lock()
            if (HVAC_Mode.state == 'AUTO' || HVAC_Mode.state == 'COOL' || HVAC_Mode.state == 'HEAT') {
                val DateTime timeNow = now()
                val Number trimToMin = 60000
                val String runningMode = (HVAC_Mode.state as StringType).toString
                var String triggeredBy = null
                try {
                    triggeredBy = triggeringItem.name
                } catch(Exception e) {
                    triggeredBy = receivedCommand
                }
                // Cancel the timer if the command was received on HVAC_Mode or HVAC_Schedule change
                if (tempCtlTimer !== null && triggeredBy !== null) {
                    tempCtlTimer.cancel()
                    tempCtlTimer = null
                }
                if (tempCtlTimer === null || tempCtlTimer.hasTerminated) {
                    var String currentTime = null
                    var String temperatureQueue = null
                    var DateTime upToTime = null
                    if (timeNow.getHourOfDay() < 10) {
                        currentTime = 'T0' + timeNow.getHourOfDay() + timeNow.getMinuteOfHour
                    } else {
                        currentTime = 'T' + timeNow.getHourOfDay()+ timeNow.getMinuteOfHour
                    }
                    if (HVAC_Schedule.state != NULL) {
                        grpTargetTemp.members.forEach [ targetItem | {
                                var String jsonHVACSchedule = (HVAC_Schedule.state as StringType).toString
                                var String jsonItemSchedule = null
                                var String jsonItemDaySchedule = null
                                // Parse the item schedule
                                if (jsonHVACSchedule.contains('"' + targetItem.name.toString + '"')) {
                                    jsonItemSchedule = transform('JSONPATH', '$.' + targetItem.name, jsonHVACSchedule)
                                    // Replace the equal with colon
                                    jsonItemSchedule = jsonItemSchedule.replaceAll('=', ':')
                                    if (jsonItemSchedule !== null && jsonItemSchedule != '') {
                                        var Number i = 0
                                        var String nextDay = null
                                        var String prevDay = null
                                        var String nextTime = null
                                        var String prevTime = null
                                        var Number nextVal = null
                                        var Number prevVal = null
                                        var String nextTimeVal = null
                                        var String[] nextTimeValArray = null
                                        var String[] jsonItemDayScheduleArray = null
                                        // Loop: week days
                                        //begin problem
                                        while ((i=i+1) <= 7) {
                                            // Parse the (item) daily schedule
                                            var Number j = -1
                                            if (jsonItemSchedule.contains('D' + i)) {
                                                jsonItemDaySchedule = transform('JSONPATH', '$.D'+i, jsonItemSchedule)
                                                // Remove empty objects
                                                jsonItemDaySchedule = jsonItemDaySchedule.replaceAll('[{}]', '')
                                                if (jsonItemDaySchedule !== null && jsonItemDaySchedule != '') {
                                                    jsonItemDayScheduleArray = jsonItemDaySchedule.split(',')
                                                    // Loop: each day schedule
                                                    while ((j=j+1) < jsonItemDayScheduleArray.length) {
                                                        nextDay = 'D' + i
                                                        nextTimeVal = jsonItemDayScheduleArray.get(j.intValue()).replaceAll(' ', '')
                                                        nextTimeValArray = nextTimeVal.split('=')
                                                        nextTime = nextTimeValArray.get(0)
                                                        nextVal = DecimalType.valueOf(nextTimeValArray.get(1))
                                                        if (prevDay !== null && ('D' + i + nextTime) > ('D' + timeNow.getDayOfWeek + currentTime)) {
                                                            // Force exit from both i and j while loops
                                                            j = jsonItemDayScheduleArray.length
                                                            i = 8
                                                        } else if (('D' + i + nextTime) <= ('D' + timeNow.getDayOfWeek + currentTime)) {
                                                            prevDay = 'D' + i
                                                            prevTime = nextTime
                                                            prevVal = nextVal
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        // If no previous value found so far, then use the last available
                                        if (prevDay === null && nextTime !== null && nextVal !== null) {
                                            prevDay = nextDay
                                            prevTime = nextTime
                                            prevVal = nextVal
                                        }
                                        // Validate next. If no other future values, then use the first one available as next
                                        if (prevDay == nextDay && prevTime == nextTime && prevVal == nextVal) {
                                            i = 0
                                            while ((i=i+1) <= 7) {
                                                if (jsonItemSchedule.contains('D' + i)) {
                                                    jsonItemDaySchedule = transform('JSONPATH', '$.D'+i, jsonItemSchedule)
                                                    // Remove empty objects
                                                    jsonItemDaySchedule = jsonItemDaySchedule.replaceAll('[{}]', '')
                                                    if (jsonItemDaySchedule !== null && jsonItemDaySchedule != '') {
                                                        nextDay = 'D' + i
                                                        jsonItemDayScheduleArray = jsonItemDaySchedule.split(',')
                                                        nextTimeVal = jsonItemDayScheduleArray.get(0)
                                                        nextTimeValArray = nextTimeVal.split('=')
                                                        nextTime = nextTimeValArray.get(0).replaceAll(' ', '')
                                                        nextVal = DecimalType.valueOf(nextTimeValArray.get(1))
                                                        i = 8
                                                    }
                                                }
                                            }
                                        }
                                        //end problem
                                        // Process the schedule values
                                        if (nextDay !== null && nextTime !== null && nextVal !== null) {
                                            // The changeTime is computed from the Dx-Txxxx pair and marks the next schedule change
                                            var Number upToNext = null
                                            var DateTime changeTime = null
                                            if (timeNow.getDayOfWeek <= Integer.valueOf(nextDay.substring(1,2))) {
                                                upToNext = Integer.valueOf(nextDay.substring(1,2)) - timeNow.getDayOfWeek
                                            } else {
                                                upToNext = 7 - timeNow.getDayOfWeek + Integer.valueOf(nextDay.substring(1,2))
                                            }
                                            // upToNext = minutes since midnight until the next schedule change
                                            upToNext = upToNext*24*60 + Integer.valueOf(nextTime.substring(1,3))*60 + Integer.valueOf(nextTime.substring(3,5))
                                            changeTime = timeNow.withTimeAtStartOfDay().plusMinutes(upToNext.intValue())
                                            if (upToTime === null) {
                                                // Init the queue
                                                upToTime = changeTime
                                                temperatureQueue = targetItem.name + '=' + nextVal
                                            } else {
                                                if ((upToTime.millis/trimToMin).intValue() > (changeTime.millis/trimToMin).intValue()) {
                                                    // Reset the queue
                                                    upToTime = changeTime
                                                    temperatureQueue = targetItem.name + '=' + nextVal
                                                } else if ((upToTime.millis/trimToMin).intValue() == (changeTime.millis/trimToMin).intValue()) {
                                                    // Add item to queue
                                                    temperatureQueue = temperatureQueue + ';' + targetItem.name + '=' + nextVal
                                                }
                                            }
                                            // [fail-safe] Init target temperature if not set
                                            if (prevVal !== null && (targetItem.state == NULL || targetItem.state == '')) {
                                                logInfo('temperature-control.rules', 'Target temperature for item ' + targetItem.name + ' initiated to : ' + prevVal)
                                                targetItem.postUpdate(prevVal)
                                            }
                                        }
                                    }
                                }
                            }
                        ]
                        // Activate the timer
                        if (upToTime !== null) {
                            logInfo('temperature-control.rules', '[' + runningMode + '] Next change @' + upToTime + ' | Changes : ' + temperatureQueue)
                            HVAC_Next_Change_Time.postUpdate(upToTime.toString)
                            tempCtlTimer = createTimer(upToTime, [|
                                    HVAC_Queue.postUpdate(temperatureQueue)
                                    tempCtlTimer.cancel()
                                    tempCtlTimer = null
                                ])
                        }
                    }
                }
            } else {
                // Cancel the timer
                if (tempCtlTimer !== null) {
                    tempCtlTimer.cancel()
                    tempCtlTimer = null
                }
            }
        } catch(Exception e) {
            logInfo('temperature-control.rules', 'Temperature control error: ' + e.toString)
        } finally {
            tempCtlLock.unlock()
        }
    }
end

// HVAC Scheduler - A queue item, used to set the target temperature for multiple items at the same time
rule "HVAC Scheduler - Target Temperature Queue"
when
    Item HVAC_Queue received update  or
    Item HVAC_Queue received command or
    Item HVAC_Queue changed
then
    if (tempQueueLock.tryLock()) {
        try {
            if (HVAC_Queue.state != NULL && HVAC_Queue.state != '') {
                grpTargetTemp.members.forEach [ targetItem | {
                        var Number j = -1
                        var String[] itemsTempArray = null
                        itemsTempArray = (HVAC_Queue.state as StringType).toString.split(';')
                        while ((j=j+1) < itemsTempArray.length) {
                            if (itemsTempArray.get(j.intValue()).split('=').get(0) == targetItem.name) {
                                logInfo('temperature-control.rules', 'Target temperature for item ' + targetItem.name
                                    + ' changed from ' + targetItem.state
                                    + ' to ' + DecimalType.valueOf(itemsTempArray.get(j.intValue()).split('=').get(1)))
                                targetItem.postUpdate(DecimalType.valueOf(itemsTempArray.get(j.intValue()).split('=').get(1)))
                            }
                        }
                    }
                ]
                // Cleanup the queue 
                HVAC_Queue.postUpdate('')
                logInfo('temperature-control.rules', 'Target Temperature Queue cleaned up')
            }
        } catch(Exception e) {
                logInfo('temperature-control.rules', 'Target Temperature Queue control error: ' + e.toString)
        } finally {
                tempQueueLock.unlock()
        }
    }
end

rule "monitor_tempreture"
when 
    Item HVAC_KB_Temp changed or
    Item HVAC_KB_Target_Temp changed
then
    if (HVAC_KB_Temp.state >= HVAC_KB_Target_Temp.state)
       TempHumVerwarming_kamer_Relay.sendCommand(ON)
    else
        TempHumVerwarming_kamer_Relay.sendCommand(OFF)
end

Thank you in advance.
Kind regards,
Sander

Somebody filed an issue with the developer. This does not appear to be an openHAB issue. The README says it works with Eclipse Smart Home, not openHAB. I would not expect it to work with openHAB 2.5+ anyway due to the deprecation and renaming of the ESH namespaces.

That’s me.

I first issued a problem there. After that continued to fix it myself, bud I can’t get it working.

Can you recommend any other widget that will do the same, especially the scheduling part?

Thank you for your response.

Greetings

If you want to tackle it, you’d probably want to sprinkle some logInfo() in your rule to see progress and crucial values. I see there is an array handling section as a likely area, so variables used there would be under suspicion.

1 Like