Array definition and FOR loops

I’m trying to define and use a simple 2-dimensional array of integers as a global variable, for usewithin a rule.
I think I’ve got the basic syntax, thanks to another post, but its given rise to two more questions.
Firstly, to make things readable I tried to define my array like this:
val int Monday = 0 * 1440
val int Tuesday = 1 * 1440

val int Time0530 = (5 * 60) + 30
val int Time0545 = (5 * 60) + 45
val int Time2230 = (22 * 60) + 30
 
val timeClockInfo = newArrayList(
    newArrayList(Monday + Time0530, 1),
    newArrayList(Monday + Time0545, 3),
    newArrayList(Monday + Time2230, 2)
)

Designer gives multiple ‘Couldn’t resolve reference…’ errors on each of the array definitions (no error if I work out the numeric values myself). So first question is: Is there a way to define array elements using meaningful constant names as I’ve tried to do, or maybe using a preprocessor macro definition?

Within the rule I’ve tried to index through the array elements using syntax obtained from the Xtend web site:

for (var i = 0; i < timeClockInfo.length(); i++)

This line generates multiple errors:

Multiple markers at this line
- Couldn't resolve reference to JvmIdentifiableElement 'length'.
- Couldn't resolve reference to JvmIdentifiableElement 'i'.
- Couldn't resolve reference to JvmIdentifiableElement '+'.
- no viable alternative at input ')'
- This expression is not allowed in this context, since it doesn't
   cause any side effects.
- mismatched input '=' expecting ':'
- extraneous input 'var' expecting RULE_ID
- Couldn't resolve reference to JvmIdentifiableElement '<'.

So second question is the syntax for my FOR loop.

Appreciate any help - I’ve managed to get the rule engine to do some fairly powerful things, but am stuck on this one - being used to C/C++ I’m finding this relatively simple problem somewhat frustrating!

Arrays and loops are areas where the openHAB DSL and Xtend diverge.

As far as I can tell, the Xtend arrays syntax doesn’t work in the DSL and standard for loops also don’t work (btw, there is no ++ in the DSL). Instead you need to use arrayLists and forEach, or while loops, or a different for loop syntax which I’ve never tried and can’t remember off the top of my head.

But lets step back. You are used to C/C++ and I’ve found that when you try to code your rules using a C/C++ (or Java or C#) type style the DSL fights you every step of the way. I did this for my rules for the first several months and ended up with almost a thousand lines of code just to turn on and off my lights on a timer. But there is often a better way to do things then creating data structures up front like this and when I adjusted to the language I was able to reduce my lines of code by more than half across the board and my rules are less brittle and easier to read.

So what is it you are really trying to accomplish with these arrays? There might be a better way.

Rich,
Thankyou for the reply - guess I’m still at the stage you’ve now passed, since I certainly feel that the DSL is fighting me every step of the way! At least this is the first time I haven’t won the fight.

“All” I want to do here is create a simple 7-day time switch, with multiple on/off times per day, and two outputs, independently controlled.

My intent was to put the switching times into an ordered array for easy maintenance.

Initially I’ve set up a cron rule which fires every 5 minutes to re-evaluate the state of the outputs. (In future I proposed setting up an interval timer which triggered at the next time something needed changing).

I also started by representing each time as an integer, which I reckoned to be more efficient than multiple time/date comparisons (I’ve never lost that “every CPU cycle is precious” mentality!)

I searched quite extensively for an example of what I’m trying to do, and was quite surprised not to find anything. I guess that’s because there’s a better way, and hopefully you’ll be able to point me in the right direction.

There are a number of different approaches. The gotcha is that I think that because you have several time periods a day and those time periods are not necessarily the same day to day complicates matters. So my questions are, how different is one day to the next? Is every day different or is it mainly different for weekdays versus weekends? Should the start or stop of any of these times be relative to sunrise or sunset?

Let’s assume the worst and that each day has four periods and the start or stop time of each period varies from day to day.

I can think of a few ways to do this but I’m not sure how satisfying they will be. My first attempt would probably be to expand the approach I describe here.

The tl;dr version is I would create Swtich Items that represent each of the timer periods (e.g. Morning, Day, Evening, Night). Then I would use rules with cron or Astro based (for sunrise and sunset) triggers to turn on or off the proper switches. Then anything that depends on time either triggers on these switches or checks the state of these switches.

However, that could potentially result in up to 29 rules. Though in practice I think you will find that you probably would only need around 10 rules as most days the time periods would be the same.

Another approach could be to use timers that get set at midnight and on system started to trigger the timer period switches. This approach might be a little more compact code wise and I don’t think it would take any more code than you are already facing trying to set up a data structure. It would be something like:

val morningTimer = null
val dayTimer = null
val eveningTimer = null
val nightTimer = null

// lambda, will help us cut down on lines of code below
val Functions$Function4 setTime = [ State m, State d, State e, State n |
    Morning.sendCommand(m)
    Day.sendCommand(d)
    Evening.sendCommand(e)
    Night.sendCommand(n)
]

rule "Create Time of Day Timers"
when
    System started or
    Timer cron "0 0 0 * * ? *" // a little after midnight
then
    // Sunday
    if(now.getDayOfWeek == 0) { // NOTE: the DSL's switch statements do NOT fall through like switch statements in C/C++/Java so I just use if statements
        morningTimer = createTimer(now.plusMinutes(360), [| setTime.apply(ON, OFF, OFF, OFF) ] // 0600
        dayTimer = createTimer(now.plusMinutes(510), [| setTime.apply(OFF, ON, OFF, OFF) ] // 0830
        eveningTimer = createTimer(now.plusMinutes(1080), [| setTime.apply(OFF, OFF, ON, OFF) ] // 1800
        nightTimer = createTimer(now.plusMinutes(1380), [| setTime.apply(OFF, OFF, OFF, ON) ] // 2300
    }
    // Monday
    else if(now.getDayOfWeek == 1) {
        ...

Obviously for days that you want the same start times just add ||'s to the if statements rather than duplicating code. now also has a plusHours method. If you want to use the Astro binding to control something (e.g. set evening to start at sunset) you can use the Astro actions instead of now.plus to set the timer.

Rich,

Thanks for the speedy reply.
I’d seen the thread you reference; I was really trying to avoid having times hard-coded into rules, hence my attempt to create a simple array of times. I don’t need astro times - just simple fixed times of day (And that triggers a thought - does OH use local ‘clock’ time? Or UTC, or local equivalent of UTC?). Pretty much the OH equivalent of a standard (at least in the UK) domestic heating and hot water programmer. So probably 4 times a day (per function) would mostly be enough; some days would be the same, others not (Friday may well be different to Monday to Thursday; Saturday and Sunday each likely to be different again).

I’ve already got part of the pattern you suggest, with a switch item for each of hot water and heating, and the intent is to command these from my timer. In the case of the heating, its basically a master switch, which determines whether the ‘heat wanted’ signals from my thermostatic valves is ignored or not. A separate rule allows it to be overridden by a ‘frost’ setting derived from various temperature sensors.

One thing I liked about my initial approach was that the switch outputs were definitely at the correct state within five minuts of startup or restart - I have had problems when reloading items files that some items which rarely change state remain uninitialised (I’m using MQTT throughout). (Use persistence here?)

On a quick look I like your second approach better - I prefer common code as much as possible, rather than 20 similar but different routines. I’ll have a better think about this over the next few days.

Alternatively, I could just write a quick C or Python program that commands OH through the REST API - that would do the job, but loses the close coupling between the timer and the rest of the system. So I’m going to persevere with a rule for now.

But putting all the times in an array is basically hard coding them into the rules. This is just hard coding them in a different way, one that I believe will take less code and will be easier to write and maintain. I really don’t think there is any way to not have the times hard coded in somehow, either as a cron trigger, a timer setting, or hard coded into an item.

Local clock time.

Either approach should have the states set up almost immediately after startup, depending on what your config files polling periods are set to in openhab.cfg. The System started rule trigger causes the rule to execute as soon as it is read into openHAB so all the timers will be created within seconds of startup or, if using my first approach the rule that determines which time period we are currently in is executed.

Absolutely yes use persistence here and almost everywhere else. Otherwise with the timer approach above you need to add some code to determine which time state you currently are in and update the switches manually which I didn’t include in the timer approach because I assumed you were already using it. It really just amounts to a few additional lines of code but why write more than you have to?

With persistence configured to restore on startup whatever the last state was will populate the items immediately after startup. In this case there is one edge case where if openHAB is offline for a long time or is offline during a transition between time periods the states will be stale until the next period comes around, but it will at least not be Undefined%. You can deal with it as described above but this will likely be a very rare occurrence.

% There is one weird case where if you have more than one .items file and more than one .rules file a .rules file may load and start executing before the .items file that contains the items those rules care about have been loaded resulting in errors. To solve this simply set the polling periods such that the rules files get loaded after the items and persistence files get loaded.

1 Like

Absolutely - I know the times have got to be specified somewhere! I was meaning that I didn’t want adding, deleting or changing times to require code adjustments. Typically in languages such as C (or PHP, or Python, which I have also used a little) this type of information is commonly put in an array, maybe with a helper macro or two to save calculating the values.
To try and explain things better, I’ve written down the framework of the rule structure I originally envisaged; it would readily translate to C (from which a lot of the syntax comes):

/**

  • Array of 3-integer elements, whose functions are:
  •    0 - time + day of week, encoded as the number of minutes from 00:00 on Monday morning
    
  •    1 - 1 if hot water switch to be on, 0 of to be off
    
  •    2 - 1 if heating master switch to be on, 0 of to be off
    
  • Each item in the array represents one time clock trigger.
  • Items must be in ascending order of time/date
    */
    const unsigned int timeClockInfo[][3] = {
    { 30, 0, 0 }, // Monday 0030
    { 480, 1, 0 }, // Monday 0600
    { 510, 1, 1 }, // Monday 0630
    { 1470, 0, 0 }, // Tuesday 0030
    }

unsigned int listPointer = 0;

/* Rule processing routine - called every 1-5 minutes (not critical) */
void ruleExec(void)
{
// Current time + day of week (shown in joda syntax!)
unsigned int curTime = ((now.getDayOfWeek() - 1) * 1440) + now.getMinuteOfDay()
unsigned int curRecord = listPointer
unsigned int nextRecord = curRecord + 1
const unsigned int listCount = (sizeof(timeClockInfo) / sizeof(timeClockInfo[0]))

unsigned int i
for (i = 0; i < listcount; i++)        // This loop just guarantees an end stop
{
    if (curRecord >= listCount)
    {
        curRecord = 0
    }
    if (nextRecord >= listCount)
    {
        nextRecord = 0
    }
    if ((curTime >= timeClockInfo[curRecord][0]) && (curTime < timeClockInfo[nextRecord][0]))
    {
        // Found the required timer record
        if (listPointer != curRecord)
        {
            // We've moved on a step - note new position
            listPointer = curRecord
            break
        }
    }
    curRecord++            // Move to next timer record
    nextRecord++
}
// At this point listPointer and curRecord indicate which timer record is current. Update outputs
if (timeClockInfo[curRecord][1])
{
        // Turn on hot water
}
else
{
        // Turn off hot water
}
// Ditto for heating

}

The “meat” of this flow is encapsulated in about 30 lines of code, with about the same again to carry out actions.
The list of times is all in one place, so readily modified (and, as mentioned, I would prefer to add some helper macros)
The script automatically arrives at the correct timer state on the first execution
Other than a simple cron-derived tick, no outside help is needed from persistence, timers or anything like that.
Execution is very efficient - mostly the loop within the script will execute just once, and at most twice (I know we’re not usually starved of computing resources nowadays, but there’s no point in wasting them!)

I’m wondering whether it would be better to code this using the JSR223 Script Engine - I’ve done a little Javascript and Python, and they seem to be better suited to this particular problem. Do you have any experience with this addon? (The wiki says “Use openHAB >= Version 1.8.0” - presumably a typo?)

Thanks for your help on this - in the absence of precise documentation, its invaluable

Unless you are loading the values from a file or a DB or something, that is still hard coded. You’ve just hard coded it into a data structure instead of hard coding it into logic.

There are four (really more but lets focus on four) “styles” of programming languages: structural, object oriented, functional, and actor.

In a structural language one would solve this problem just as you describe above. Create a data structure and some functions that operate on that data structure. This is your approach.

In an object oriented language one would create one or more classes which encapsulate the data and provide methods for executing the logic. The state (i.e. data) and the logic are combined. This was my approach until I really started to grok the DSL.

In a functional language everything is a function so the state would get passed around as arguments to functions instead of being represented as any data structure (particularly in strict languages like Haskel).

In and actor based language what you have are a bunch of self contained actors (similar to objects) that are activated by events. State is mainly carried around in the events instead of within the actors or as separate data structures. In this way it is kind of a hybrid of OO and functional.

Of the four styles, the openHAB DSL most resembles an actor based language with the events being rule triggers and the actors being the rules. This is why it doesn’t like to let you set up data structures like this in the rules. Unlike an actor based language that only stores state in events, the openHAB DSL actually does provide a mechanism for storing state, Items.

So, in openHAB we have a nice mechanism for encoding state in the Items. The more of your state that you can encode in your Items the happier the DSL will be (i.e. the shorter and simpler your rules will become). Understanding how Groups work and some of the wonderful things you can achieve with them in your rules can really take you far.

We also have a nice mechanism for managing the actors. Each rule is an actor. The more you can make your rules autonomous and the less you make them dependent on internal state (i.e. global vals and vars) the happier your rules will be.

Unfortunately we don’t have a nice separate mechanism for managing the events and this is our problem here. The events are only managed and encoded in the “when” clause of the rules. This isn’t necessarily a bad way to do it but it does have a limitation that we can’t define an event using state. For example, I can’t set up something like an Item myVar received update where myVar is defined by a global variable or the state of an Item. Similarly I can’t do a Time cron myVar trigger where the cron string is defined by a global car or some Item’s state. Events are separate from state are separate from actors.

This leaves us with the unfortunate limitation that we don’t have a nice way to encode a bunch of events in a central consolidated way. You can fake it by using a rule’s global vals or vars, as you are attempting to do, but that is really mixing the events and the actors which the DSL will fight against, as you have noticed.

The big big problem is there isn’t a way to centralize the encoding of events so we want to try to store the events as state (inside the actor no less) and convert them events.

The most DSL “pure” way to implement what you want to achieve would be my first solution. The events are encoded in the “when” clause of rules. But this is unsatisfactory because it results in a proliferation of rules.

The next most DSL “pure” way to implement what you want to achieve would be to save the state (i.e. the start days and times) in Items and use a System started rule to read the Items and create Timers to generate the start events.

Getting further still from a DSL “pure” way to implement what you want to achieve is my second solution above where I basically hard code the start days and times in the logic. I call this approach the next “pure” because at least the “state” is encapsulated wholly within an actor.

The next step away from “pure” but probably still doable is to encode the start day and times as a global var using arrayLists or hashMaps and use the System started actor to generate Timers based on that encoding. You might find this the most comfortable as it is the most like structured programming but I’m not convinced that it will save you much in terms of lines of code or complexity verses some of the options above. You can search the examples for how to create and populate a hashMap and arrayList, and you can even embed them inside each other to build up a data structure like what you want but you can’t just define it like a const like you can in C/C++/Java/etc.

You will need to actually populate it inside a System started rule and I can say from experience that it will be very ugly indeed and take hundreds of lines of code. By the time you’ve done that you would appreciate that my second option above is actually a pretty clean approach.

Perhaps a happy medium would be to store the data structure in a config file that you read in, parse, and create your timers based on its contents. You will need to import and learn to use the java.io classes to do this but it should be achievable.

It is indeed a clean and efficient structured programming approach. The openHAB DSL will not support it. It is too close to structured programming and much too far from actor based programming to translate as is.

I’m not sure what this means. All of the options arrive at the correct state on first execution.

This isn’t necessarily a good thing in openHAB IMO. It is far more efficient, far less error prone, and far easier to debug, and far more flexible if you use the facilities of openHAB in your rules instead of implementing your own. Also, in actor based programming any user implemented polling (i.e. the cron derived tick) is considered a failure of design.

Almost all of the approaches I describe are even more efficient, executing once at startup and then once per day. Don’t forget, there is overhead every time the rule triggers whether or not it actually does something. Though personally worrying about runtime efficiency in openHAB is a form of engineering masturbation. If feels good to make the code super efficient but at the end of the day it doesn’t matter and you’ve only pleased yourself.

I would say that they are better suited to your particular approach to the problem (not necessarily the problem in general) and I know at least one active poster on this forum uses JSR223 and Jython exclusively for his rules. Both Python (Jython) and JavaScript are closer to structural programming than the DSL so they will be more forgiving to that approach.

1 Like

Rich,

Thanks for the comprehensive reply; very useful explanations - sorry its taken me a while to get back on this one.

I quite agree that I’ve adopted a structural approach - partly because its what I’ve grown up with, and partly because it seemed a straightforward and appropriate solution to the specific problem. (I do also use object-orientated programming when its appropriate - however I mostly program for embedded systems, and OOP can be resource-hungry)

One point of semantics; I suppose by “hard coded” for my time values I really meant “embedded in the code”. So I wanted to avoid having to add another “if (time = value)” or cron line or whatever if I need another time match. I would regard your second solution as being “hard-coded” on that basis, and its actually how I started to form my rule initially. (Incidentally, it looks as if that rule wouldn’t start up correctly, because all the timers would presumably be triggered with reference to the time the rules file was loaded, rather than midnight, unless the rule was made more complicated to take account of it) Adding another entry to a data structure is potentially much less error-prone. And having all the entries in a structure makes it easy to load that structure from a file or database later, without need to change the underlying functional code.

Really I think we have a case of “horses for courses”. I can see the power of the DSL for some situations, such as when operating on a group, and until now have used it for all of my rules (and also cursed the fact that you can’t have arrays of items which are handled identically - you have to individually define everything - and I have a dozen or more radiator valves with about 10 parameters each…).

I’ve installed the jsr223 addon and Jython (which, incidentally I’ve established does require a snapshot of OH 1.8). I was then able to implement a Python-based solution in a couple of hours (and I’ve only dabbled in Python - very much a case of manual in one hand, keyboard in the other). For this particular problem, this seems a good result to me:

  1. The entire solution is in one place
  2. It uses a “well known” language, which is well documented and with lots of examples available
  3. The solution is compact - other than the table of times, the actual code (all of it) is just under 50 lines
  4. If I want to initialise the table of times from a file or database later, that should be very easy to add

Plus two points unique to me:
5. I happen to want to improve my knowledge of Python for other reasons
6. I can understand what’s going on more easily!

I was pleased to see that the JSR233 addon is being made to work in OH2 - however much OH’s DSL is appropriate to the use case, it’s essentially unique to OH, so newcomers are bound to struggle a bit to get going, and may even be put off. The addon gives the possibility of working in a familiar language, removing one hurdle. Certainly I’ve noticed a reasonable number of people running OH on the Raspberry Pi, and they are likely to already have some acquaintance with Python.

Anyway, thankyou again for your assistance; you’ve certainly improved my knowledge of the DSL and how it should be used.

I’m glad you found the JSR233 plugin to work for you. I agree, it can be a powerful way to help along newcomers who are also already programmers avoid the fight that inevitably pops up when learning to write rules. I’ve been very surprised and impressed with how well the DSL works for this use case though that I tend to try and defend it when the opportunity arises.

For grins I made an attempt at writing something in a DSL way to see if it would work and I’m reasonable happy with the result.

NOTE: I’m just typing this so typos are a certainty. I don’t expect anyone to use the code so it isn’t that big of a deal.

Items:

Switch Morning
Switch Day
Switch Evening
Switch Night
Switch CreateTimers

Group gStartTimes

Number SundayMorning (gStartTimes)
Number SundayDay (gStartTimes)
Number SundayEvening (gStartTimes)
Number SundayNight (gStartTimes)

Number MondayMorning (gStartTimes)
Number MondayDay (gStartTimes)
Number MondayEvening (gStartTimes)
Number MondayNight (gStartTimes)

Number TuesdayMorning (gStartTimes)
Number TuesdayDay (gStartTimes)
Number TuesdayEvening (gStartTimes)
Number TuesdayNight (gStartTimes)

Number WednesdayMorning (gStartTimes)
Number WednesdayDay (gStartTimes)
Number WednesdayEvening (gStartTimes)
Number WednesdayNight (gStartTimes)

Number ThursdayMorning (gStartTimes)
Number ThursdayDay (gStartTimes)
Number ThursdayEvening (gStartTimes)
Number ThursdayNight (gStartTimes)

Number FridayMorning (gStartTimes)
Number FridayDay (gStartTimes)
Number FridayEvening (gStartTimes)
Number FridayNight (gStartTimes)

Number SaturdayMorning (gStartTimes)
Number SaturdayDay (gStartTimes)
Number SaturdayEvening (gStartTimes)
Number SaturdayNight (gStartTimes)

Rules:

// Its always good to keep track of our timers
val List<Timer> timers = createArrayList

rule "Init start times"
when
    System started
then

    // Here is the "data structure" of start times
    // With persistence set up this part only need ever run once when updated, though it is just as easy to leave it in

    // For ease in coding I store the time as minutes from midnight
    SundayMorning.postUpdate(6*60) // 06:00
    SundayDay.postUpdate(8*60+30) // 08:30
    SundayEvening.postUpdate(17*60) // 17:00
    SundayNight.postUpdate(23*60) // 23:00

    // initialize the rest

    CreateTimers.sendCommand(ON)
end

rule "Create Timers"
when
    Item CreateTimers received command ON or
    Time cron "1 0 0 * * ? *"
then

    // clear out the old timers if there are any
    timers.forEach[ t | t.cancel ]
    timers.clear

    var String dayofweek = ""

    // Probably a better way to do this but I don't know joda very well
    switch(now.getDayOfWeek) {
        DateTimeConstants.SUNDAY : dayofweek = "Sunday"
        DateTimeConstants.MONDAY : dayofweek = "Monday"
        DateTimeConstants.TUESDAY : dayofweek = "Tuesday"
        DateTimeConstants.WEDNESDAY : dayofweek = "Wednesday"
        DateTimeConstants.THURSDAY : dayofweek = "Thursday"
        DateTimeConstants.FRIDAY : dayofweek = "Friday"
        DateTimeConstants.SATURDAY : dayofweek = "Saturday"
    }

    gStartTimer.members.filter(n | n.name.startsWith(dayofweek)).forEach[n | 
        timers.add(createTimer(now.withTimeAtStartOfDay.plusMinutes(n.state as DecimalType), [|
            if(n.name.endsWith("Morning"))  {
                Night.sendCommand(OFF)
                Morning.sendCommand(ON)
            }
            else if(n.name.endsWith("Day")){
                Morning.sendCommand(OFF)
                Day.sendCommand(ON)
            }
            else if(n.name.endsWith("Evening")){
                Day.sendCommand(OFF)
                Evening.sendCommand(ON)
            }
            else if(n.name.endsWith("Night")){
                Evening.sendCommand(OFF)
                Night.sendCommand(ON) 
            }
        ]
    ]
end
1 Like

Rich,

Your enthusiasm for the DSL definitely shines through!
And there are some very interesting constructs in your example, that I’ve not come across elsewhere.

Just for completeness, here’s my Python-based solution (I’ve found I need another control output - very easily added):

import time

MON = 0
TUE = 1
WED = 2
THU = 3
FRI = 4
SAT = 5
SUN = 6

def timeCalc(dow, hh, mm):
return 1440 * dow + 60 * hh + mm

# Array of times and settings. Each entry comprises four elements:
# [1] - Setting for hot water - 1 = ON, 0 = OFF
# [2] - Setting for heating - 1 = ON, 0 = OFF
# [3] - Setting for immersion - 1 = ON, 0 = OFF
# If we use curved brackets the following becomes constant ("immutable") - but probably the helper function wouldn't work then
timeList = [
[ 30, 0, 0, 0 ], # Monday 0030 - really a tidy up rule

[ timeCalc(MON,  5, 30), 1, 0, 1 ],        # Monday 0530
[ timeCalc(MON,  5, 45), 1, 1, 1 ],        # Monday 0545
[ timeCalc(MON,  7, 30), 0, 1, 0 ],        # Monday 0730
[ timeCalc(MON,  8, 30), 0, 0, 0 ],        # Monday 0830
[ timeCalc(SUN, 22, 30), 0, 0, 0 ]

]

class HtgTimer(Rule):
currentRecord = 0 # Normally points to the element of timeList which is active

def __init__(self):
    oh.postUpdate("hotWaterTimedState", "0")            # First timer tick will turn this on if necessary
    oh.postUpdate("heatingTimedState", "0")                # First timer tick will turn this on if necessary
    oh.postUpdate("immersionTimedState", "0")            # First timer tick will turn this on if necessary
    self.logger = oh.getLogger("HtgTimer")
def getEventTrigger(self):
    return [
        StartupTrigger(),

# Run once a minute, at 11 seconds past the minute
TimerTrigger(“11 * * * * ?”)
]

def execute(self, event):
    global timeList
    lim = len(timeList)
    ctr = lim
    ptr = self.currentRecord
    now = time.localtime()
    timeNow = (1440 * now.tm_wday) + (60 * now.tm_hour) + now.tm_min        # Current time, day of week in our format
    oh.logInfo("HtgTimer", "Execute rule at time: " + str(timeNow) + "  Array size: " + str(ctr))
    while ctr > 0 :
        nxtPtr = ptr + 1
        if nxtPtr >= lim :
            nxtPtr = 0            # Loop round as necessary
        # Test whether current time is between ptr and nextPtr - if it is, we're done in the loop
        if timeNow >= timeList[ptr][0] and timeNow < timeList[nxtPtr][0] :
            if self.currentRecord != ptr :
                # We've moved on - note new position
                self.currentRecord = ptr
                oh.logInfo("HtgTimer", "New time entry: " + str(ptr) + ": " + str(timeList[ptr][0]))
                # Optionally, if we haven't moved on we could just exit here - i.e. only update outputs on a transition
                # Or we could set up a timer to only call this script again on the next transition and delete the cron trigger
            break                # this stops the loop
        ptr = ptr + 1
        if ptr >= lim :
            ptr = 0
        ctr = ctr - 1
    `# Out of the loop here - ptr and self.currentRecord have the time record which is applicable`
    `# We could check the current state of the target items before setting them; for now, set them regardless`
    be.postUpdate("hotWaterTimedState", str(timeList[ptr][1]))
    be.postUpdate("heatingTimedState", str(timeList[ptr][2]))
    be.postUpdate("immersionTimedState", str(timeList[ptr][3]))

def getRules():
return RuleSet([
HtgTimer()
])