Jump to content

Triggers and conditions and IFs, oh my!


dnl

Recommended Posts

I appreciate the patience others have shown in trying to help me (a newcomer) understand the challenges in ISY programming that arise because all conditions appearing in an IF clause are also trigger events that cause the program to run and the IF clause to be re-evaluated.

It was not until I read a lengthy post by ergodic (linked from the Wiki) that the light began to come 'on' (no pun intended). The concept of the ISY acting like a state machine has helped me understand like nothing else has.

Unfortunately, that post contains revisions and dialog over some fine points that make it more difficult to understand. One person (dbroere) wrote the following:
 

 

For the past hour, I've attempted to clip the entire thread out of the forum and restructure it so that I could save it in a form that anyone trying to learn ISY programming would understand. I FINALLY GAVE UP!
IT's just too complex. There's changes to changes to modificaitons and on and on.

My wish is that there was a way to sort all this out and provide something usefull to someone trying to learn ISY Programming.

I have tried to sort it out by editing that thread (I hope ergodic does not object), replacing some of the original programs with his subsequent revised programs and by redrawing a state diagram to fit the revised programs. I have taken a few editorial liberties and added some text but otherwise the text is essentially as ergodic wrote it.

I may have introduced some errors. I hope others who are more experienced than I (perhaps ergodic himself) will review and correct whatever errors I have made so that we newbies can have an easier document to read.

I can provide the document as a MS Word file or as an HTML file if anyone would like it. Otherwise, the edited text follows in the next post.

EDIT: Version 3 of ISY firmware allows the use of integer-valued variables in our programs. The variables come in two flavors: state variables and non-state variables. Both state and non-state variables can be used to great advantage, simplifying the structure of the state-machine programs that are described below.

Ergodic has described how the state variables can be used. You can see that post here: http://forum.universal-devices.com/topic/6055-state-machine-programming-using-variables-part-1/.

Even if you are running version 3, I believe you will find the following post provides useful background that will help understand the new approach.

 

EDIT 8/10/15 to fix broken link.

Edited by dnl
  • Like 1
Link to comment

ISY Programming Methodology
(state-machine approach)
edited from posts by ergodic in June 2010

The ISY uses what technically would be termed "functional" (i.e.; stateless, variable-less), "event" programming and that is not the way people think at all. So you need some methodology that bridges that gap. Ad-hoc programming in the ISY just doesn't work for me.

If you can identify what you want to do and diagram it, then have some rote mechanical method to develop the ISY programs from that, it is much, much easier to get something that works, that you are sure should work at least, and also can be expanded or changed later without introducing errors that are difficult to find and correct. The end programs may not be pretty to look at, but what ISY programs are?

I'll describe a method that is easy to understand, quick, and once you've outlined your logic on paper, it is straightforward to produce a set of ISY programs that implement it reliably.

I'll start with a simple example:
Press a keypad button ("KPL D") three times in succession to turn on a light.
If more than 5 seconds elapses between presses,
then the sequence resets and you have to start over.I use something like this for my garage door open programming: it prevents the door from opening if you happen to hit the KPL button by accident. You can also have a little fun with this idea, for example, turning the aux buttons of a KPL into a combination lock.

I'll also note that to actually do this, you may know that Insteon requires we create a scene ("Scene KPL-D") with the button in it, just to be able to toggle the keypad light on and off from the ISY.

To start, draw big, labeled circles to represent all the different "states" of your process. These are generally the places where you are "doing" or "waiting" for something. For example, "the garage door is open and we're waiting for the close button." Each situation is different but generally the states will fall out pretty quickly once you've grasped the idea and you start to diagram the flow of your particular logic. States generally map to a particular point of logic: (e.g.; "My garage door was opened by a motion sensor and we're waiting for the off from the motion sensor.") And you'll always have a starting "quiet" state that does nothing.

In this example the states are pretty easy to see, there are four: a start/reset state, a state for the button having been pressed once, pressed twice, and pressed three times. We'll use labels S0, S1, S2 and S3.

Then you draw arrows between the states. Label the arrows with the triggers that cause that particular state change. Anyone with an information science background will immediately recognize this as a basic "state machine". No matter, just diagram how your logic flows from one state to the next. Don't worry about the ISY just yet. And don't worry if your logic isn't fully developed, you can always go back later and expand on it.

For this little example, we draw an arrow out from the edge of the S0 circle to the edge of the S1 circle, indicating a press of KPL-D when you're in state S0 takes you to state S1 (first button press). Likewise S1 to S2, and S2 to S3. These are of course all basically the same transitions, but the only way a state-based system has to "remember" anything is by the state it is in. We don't need no stinkin' variables or, more precisely, the states themselves are our variables. This is partly why this model works so well for the variable-less ISY. The important thing to understand about state diagrams is that you have no idea how you got to the state you're in. If you need to "know" that for your logic, you create more states.

Inside or near each state's circle you note what that state does when it is activated. For example, S1 turns off the KPL light to indicate it is ready for another press, waits 5 seconds and then, assuming nothing else has interrupted it, it returns to state S0.

S1, S2 and S3 all will have arrows back to S0 representing this "timeout" transition (i.e.; you waited too long to press a key and the state reverts to S0). I like to draw these explicit transitions from inside the circle. I'll also point out that in a less trivial example than this, for example, one involving motion sensors, you often have arrows going from a state back to itself. For example, if a motion sensor sends a repeated "on" signal while you are waiting in a state, you want to restart the timeout countdown in that state by re-entering the state.

Now, if you've suffered with this explanation this far, I recommend you try implementing this in your ISY to get a feel for the process. The basic idea is to separate figuring out what you want from the actual ISY programming.

Now that we have our diagram, we can easily implement our logic by set of ISY program from a rote procedure. Each state will be represented by two ISY programs. One program will test the conditions, which correspond to all the incoming "arrows" to that state that represent the various trigger conditions into it. A second program performs whatever that state is supposed to do.

Here were are at the eternal sticking point: Why two programs for one state? All we need is one set of conditions and one "Then" body to execute it. So ... one program, right?

Wrong.

The ISY executes either the Then or Else body of a program whenever any of its trigger conditions are TESTED. (This means the Then or Else body of a program will be interrupted and restarted if that program is currently executing a Wait or Repeat command.) This causes the program to be reset and could be (often is) really a Bad Thing; we want the code for our state to run only when one of the trigger conditions (incoming state changes) is True, not each and every time they are simply checked by the ISY. If you don't understand why, keep reading and thinking about it until it makes sense. It is critical to understanding the difference between the way you might think and the way the ISY thinks.

In this example, we end up with eight programs for our four states. We'll call them here S0Cond, S0Body, S1Cond, S1Body, and so forth.

The structures of the four S#Cond programs are basically the same; just tests for conditions of the incoming triggered transitions that activate into that state. If any of the conditions are True, the "Then" part calls the corresponding S#Body for that state. You must run a separate S#Body program. Do not put your state code in the "Then" part of the S#Cond program. It might work after a fashion but it will not consistently work the way you want.

So here's the basic skeleton of our S1Cond program:

If
Program 'S0Body' is True

And Control 'KPL D' is switched On

Then

Run Program 'S1Body' (Then Path)

The condition program connects each transition coming into this state with a pair of "AND" ed tests. One test identifies the state you're coming from and the other test identifies the event causing the transition from that state to this one. This is simpler to do than to explain.

In this example there is just one transition into S1 from state S0. If there are multiple transitions coming into the state, you merely "OR" a set of these parenthesized tests together to trigger any of the possible incoming transitions that can get you to this state. The ISY nicely takes care of checking these conditions automatically any time a transition might happen.

What is put in an S#Body program? The first thing are statements that set all of the other state's body programs False. This cancels whatever those programs might be doing at the time a transition is made to this state, which effects the actual transition to this state. Remember, we can only be in one state at a time. That also declares the other state programs as being False to the ISY. This is crucial because we are using the True/False status of the S#Body programs to define what state we are in.

After setting all other state body programs to False, an S#Body program does whatever you want to be done in the state (if anything).

Finally, an S#Body program performs any "tail" transition that happens if the state times out or exits before any other condition triggers the ISY to cancel it. These "tail" transitions are performed by calling the body program for the target state. This is usually the last thing that an S#Body program does. They are not included in the trigger condition list for the target state's S#Cond tests. All other incoming (triggered) transitions are included in those tests but these are programmed transitions, not events. That's why I draw those arrows starting from inside the circle, as they are implemented differently,

Here's our S1Body for example:

If

- No Conditions

Then

Run Program 'S0Body' (Else Path)

Run Program 'S2Body' (Else Path)

Run Program 'S3Body' (Else Path)

Set Scene 'Scene: KPL-D' Off

Wait 5 seconds

Run Program 'S0Body' (Then Path)

Again, generating this program is more or less a rote process. In fact I typically first just create one template "cond" and one template "body" and use the ISY to copy and edit since they're all so similar. You also want to use a careful (and terse) naming system to keep things clear. I recommend using a common prefix so that you can more easily watch them grouped together in the ISY Program Summary.

The only things to think about for the S#Body programs are how long to wait before making an explicit timeout transition out of the state, and what to do around that waiting. For the most part, you have the freedom to do whatever you please without worrying about strange interactions because you know the program isn't going to be interrupted - its execution is 'protected' by its companion S#Cond program.

You may have no timeout inside a state. For example, here's the S3Body:

If

- No Conditions

Then

Run Program 'S0Body' (Else Path)

Run Program 'S1Body' (Else Path)

Run Program 'S2Body' (Else Path)

Set 'Our Test Light' On

Set Scene 'Scene: KPL-D' Off

Run Program 'S0Body' (Then Path)

This state just notes that it is in state S3 then resets the KPL button off, turns on the target light ("success!") and transitions back to the resting state S0. (The S0Body does nothing except turn off the other three states and exit itself, staying True.)

Finally, we need something to initialize the state of this logic to S0 when the ISY boots up. We require exactly one of the S#Body programs to be "True" at any time, which indicates the state we are in. We do this by simply marking the S0Body program as the only program in this group of programs to "run at startup".

If you want extra insurance, you can create a separate program that is triggered by all four S#Body programs being False and, when True, runs "S0Body (Then)". This usually is not necessary but it does take care of unusual conditions such as someone manually setting S0Body False from the ISY console.

Here's another example: you want to turn your Denon amplifier off at 11:45 and turn it back on at 7AM but only if it was on at 11:45 in the first place.

This application has two states: the beginning/idle state that we'll call Denon.S0 and a state Denon.S1 that represents the amp being on at 11:45, waits for 7AM to turn it off, and returns to state Denon.S0. Two states require four programs ... Oops, not quite.

We have no easy way in the ISY to wait INSIDE a program for a specific time of day. There are ways you could cook up to shim around this problem such as a little program to trigger True at 7AM and make this test in a repeat loop. But all that nonsense is precisely what we're trying to get away from.

The solution, as always here, is simply to add another state. With this change, the state Denon.S1 merely serves to record that the amplifier was on at 11:45 and exits doing nothing except staying True. A new third state, Denon.S2, triggers from Denon.S1 at 7AM, turns off the amplifier and returns to state Denon.S0. Now we have three states, which requires six programs.

Denon.S0.Cond:

If

- No Conditions

Then

Run Program 'Denon.S0.Body' (Then Path)

Denon.S0.Body: (set to run-at-startup)

If

- No Conditions

Then

Run Program Denon.S1.Body (Else Path)

Run Program Denon.S2.Body (Else Path)

Denon S1.Cond:

If

Program Denon.S0.Body is True

And Time is 11:45PM and Status 'AMP' is On

Then

Run Program 'Denon.S1.Body'

Denon.S1.Body:

If

- No Conditions

Then

Run Program Denon.S0.Body (Else Path)

Set 'AMP' Off

Run Program Denon.S2.Body (Else Path)

Denon S2.Cond:

If

Program Denon.S1.Body is True

And Time is 7AM

Then

Run Program 'Denon.S2.Body'

Denon.S2.Body:

If

- No Conditions

Then

Run Program Denon.S0.Body (Else Path)

Run Program Denon.S1.Body (Else Path)

Set 'AMP' On

Run Program Denon.S0.Body (Then Path)

OK, let's take the gloves off. I hear you: "But I can do this little thing in 3 programs (or 2 or 1 or one-half a condition test with my eyes closed, or whatever). Why 6? You've got programs doing basically nothing - we can get rid of them." Yeah, yeah, yeah. If you want to chase the infamous "Busy Beaver" problem, far be it from me to dissuade you. Enjoy yourself.

But if you've followed me this far, I'd guess you already know from experience that with the ISY, madness lies down that road. Maybe here you can indeed toss out "Denon.S0.Cond" but maybe later you'll really wish it were there when you make some enhancement, Like the one I make below. So my advice: stick with the structure.

The main point here is that, using this technique, everything is simple and more or less as understandable - at least as understandable as anything can be with ISY programs. If my logic diagram does what I want, I can more or less be assured that the programs I generate from it this method will implement it correctly. If I have to change the logic or add more states, I know exactly what to do and where to look to do it. I don't have a Denon amp to test this with but I am still reasonably confident that - absent any typos - the above set of 6 programs will do the job exactly as described without endless fiddling and forum posts.

Here's an illustration of how this technique can save some heartburn. Suppose we want to enhance this application a little. If someone turns on the amp between 11:45 and 7AM, then we want to reset the logic and not turn the amp back on at 7AM. This is done easily. Just add a transition arrow from state Denon.S1 to Denon.S0, triggering on the condition "if AMP is switched on". Put that condition into the Denon.S0.Cond program and you're done.

Let's apply the technique to an application described in a post on this forum:
Between 10PM and sunrise ¦
if we get either of two off signals
but with either of two "test" lights still on
we turn off a few lights.
If neither of those two lights are on then
we turn off a lot of other lights.
From resting state S0, we have a transition to a state S1 between 10PM and sunrise if either of the two test lights are also still on. We have a second state S2 activated from S0 between 10PM and sunrise if neither of the two test lights is on. There are a couple of other ways to structure this state diagram but, however you graph it, you should be able to produce the 6 programs to implement it easily. Again, if you're tempted to "optimize" them down to 4 or 2 programs, my unequivocal advice is to resist that temptation.

Now this technique is hardly perfection. You can still have race conditions in your code, unexpected device interactions, Insteon signal collisions or missed signals. And the ISY has no variables or macro substitution so you can easily get copy/paste errors if you change something in one place and don't mirror it somewhere else where it needs to be. All the usual stuff. But it is much, much easier to debug and solve these problems inside this kind of structure.

It's kind of cool to watch the True indicator jump from program to program (state to state) in the Program Summary screen as the programs run. I always know exactly what the programs should be doing and why. A poor man's debugger. If I see two True body programs, I know I probably added a state and forgot to clear it in one of the other states.

Here is a program set I have for my kitchen. There are two motion sensors.
At night,
turn up the lights over the kitchen island to 50% if they're off
or less than that when somebody walks in.
Regardless whether it is day or night,
after 15 minutes of no activity
shutoff all the kitchen lights using a scene.
There are four states:
S0: Resting state
Go to S1 when motion is detected and it is night
Go to S2 when motion is detected and it is not night
S1: Nighttime state
Turn up the island light
Go to S2
S2: Waiting-for-both-MS off state
Go to S3 when status of both MS goes to 'off'
(failsafe) after 4 hours, go to S3 (haven't really thought this through)
S3: Waiting-for-either-MS-on state
Go to S2 when on is received from either MS
Otherwise after 15 minutes turn off the lights and go to S0

Here's a state diagram:

 

 

                  (motion
                 and night)
             S1 <--------- S0 <---+
             |   (motion  /       |
             |   and not /        |
             |   night) /         |
             v         /          |
   +-------} S2 <-----+           |
   |         |                    |
   |         | (both MS off)      |
   |         |                    |
   |         v                    |
   |         S3                   |
   |        /  \                  |
   |       /    \                 |
   +------+      +----------------+
   (either         (after 15 min)
    MS on)
 

The programs that implement this application are shown below. There are two oddball programs.

The first is the "IsNight" program that has no code for either Then or Else. The program is True or False depending on whether it is "nighttime". I use this because the definition of "nighttime" is used in two conditions and I want to be sure if I change it later I don't need to remember to do it in more than one place.

The second is the "Body.S1.Sub" program. I need something to test whether the island lights are currently below 50% and only raise them in that case. Otherwise, if the lights were already brighter, they'd get dimmed -- far more annoying than you might think if you've never actually had it happen to you.

The ISY has no "if...then" testing inside program clauses, which would be most welcome. So I break out this little routine that is called from S1 to check the lights and raise them only in they are below 50%. You could do this with an added state or two but it really isn't necessary.


Here are the programs

Kit Motion.Cond.S0:

If

- No Conditions

Then

Run Program 'Kit Motion.Body.S0' (Then Path)

Kit Motion.Body.S0: (set to run-at-startup)

If

- No Conditions

Then

Run Program 'Kit Motion.Body.S1' (Else Path)

Run Program 'Kit Motion.Body.S2' (Else Path)

Run Program 'Kit Motion.Body.S4' (Else Path)

Kit Motion.Cond.S1:

If

Program 'Kit Motion.Body.S0' is True

And Program 'Kit Motion.IsNight' is True

And Program 'Kit Motion.IsMotion' is True

Then

Run Program 'Kit Motion.Body.S1' (Then Path)

Kit Motion.Body.S1:

If

- No Conditions

Then

Run Program 'Kit Motion.Body.S0' (Else Path)

Run Program 'Kit Motion.Body.S2' (Else Path)

Run Program 'Kit Motion.Body.S4' (Else Path)

Run Program 'Kit Motion.Body.S1.Sub' (If)

Run Program 'Kit Motion.Body.S2' (Then Path)

Kit Motion.Body.S1.Sub:

If

Program 'Kit Motion.Body.S1' is True

And Status 'Kitchen Island' < 50%

Then

Set 'Kitchen Island' 50%

Kit Motion.Cond.S2:

If

(

Program 'Kit Motion.Body.S4' is True

And Program 'Kit Motion.IsMotion' is True

)

Or

(

Program 'Kit Motion.Body.S0' is True

And Program 'Kit Motion.IsMotion' is True

And Program 'Kit Motion.IsNight' is False

)

Then

Run Program 'Kit Motion.Body.S2' (Then Path)

Kit Motion.Body.S2:

If

- No Conditions

Then

Run Program 'Kit Motion.Body.S0' (Else Path)

Run Program 'Kit Motion.Body.S1' (Else Path)

Run Program 'Kit Motion.Body.S4' (Else Path)

Wait 4 hours

Run Program 'Kit Motion.Body.S4' (Then Path)

Kit Motion.Cond.S4:

If

Program 'Kit Motion.Body.S2' is True

And Program 'Kit Motion.IsMotion' is False

Then

Run Program 'Kit Motion.Body.S4' (Then Path)

Kit Motion.Body.S4:

If

- No Conditions

Then

Run Program 'Kit Motion.Body.S0' (Else Path)

Run Program 'Kit Motion.Body.S1' (Else Path)

Run Program 'Kit Motion.Body.S2' (Else Path)

Wait 15 minutes

Set Scene 'Scene: Kit On' Off

Run Program 'Kit Motion.Body.S0' (Then Path)

Kit Motion: IsMotion

If

Status 'Kitchen: Motion (Oven)-Sensor' is On

Or Status 'Kitchen: Motion (Sink)-Sensor' is On

Then

- No Statements

Else

- No Statements

Kit Motion: IsNight

If

From Sunset - 30 minutes

To Sunrise + 30 minutes (next day)

Then

- No Statements

Else

- No Statements

Kit Motion: Reset State (just for debugging, not needed)

If

Program 'Kit Motion.Body.S4' is False

And Program 'Kit Motion.Body.S2' is False

And Program 'Kit Motion.Body.S1' is False

And Program 'Kit Motion.Body.S0' is False

Then

Run Program 'Kit Motion.Body.S0' (Then Path)

ISY programming is not simple. This is illustrated by the Kit.Motion.Body.S1.Sub substate. One issue is whether the Kit.Motion.Body.S1.Sub substate has to be called explicitly. If it is not called explicitly, the ISY may never get a chance to invoke it because S1 runs through without any wait. (It isn't disabled.)

It has been suggested that if Kit Motion.Body.S1.Sub is enabled, then it should run either Then or Else (as 'Kitchen Island' is, or is not, less than 50%, respectively) as soon as Kit Motion.Body.S1 becomes True. This happens as soon as its Then is called, which in this case is from Kit Motion.Cond.S1. But Kit Motion.Cond.S2 also becomes True as soon as Kit Motion.Body.S1 is True, and then calls Kit Motion.Body.S2, which will make Kit Motion.Body.S1 False. It is possible that this could create a race condition; this could be tested simply by removing the call.


In summary, this method of boils down to the following steps:

1) Draw your diagram. Begin by drawing a circle for the resting state and begin thinking about what events trigger out of that. The rest will flow from that fairly quickly although it may take a few tries to get the logic right.

2) For every state in the diagram you will have two ISY programs: a body.state and a cond.state. Exactly one body.state program can be True at a time; that tells what state you are currently in.

3) The body.state program has no conditions, just a "Then" clause. It first sets all other body.state programs False. It then does whatever you want that state to do, if anything. Sometimes a state merely distinguishes where you are in the flow and may do nothing else.

There is always a starting, rest state that usually does nothing and should be set to run-at-startup.

If the state requires a wait or a wait is acceptable, then you can transit directly to the next state from the last statement ("Run Program Body.Target (Then Part)" instead of using a condition on the target state. The same is true if there is only one transition out of the state.

Otherwise I believe you have to give the ISY a chance to check the other transit-out conditions. You must use conditions to handle every exit path. If there's another / better way to handle this, I'd be most eager to know it.

4) The cond.state lists the condition(s) for all incoming transitions into that state. It ANDs the source state = True with whatever condition takes you from that source state to this target state. This corresponds to a transition arrow on your diagram.

If there is more than one incoming transition to a state, they are simply "OR"ed together to create one test. The "Then" clause for a cond.state has a single statement executing that state's body program. You should resist the temptation to put anything else in here.

5) If you find yourself using the same tests repeatedly, consider making a separate True/False program like the .IsNight and .IsMotion programs above.

EDIT 8/15/11 to correct a few typos in the first example. Thanks to Illusion for pointing out the errors.

 

EDIT 2/28/15 to clean up text by restoring some quotation marks and apostrophes that were converted into weird character strings.

 

EDIT 8/10/15 to fix state diagram.

Edited by dnl
  • Like 1
  • Thanks 1
Link to comment
  • 2 weeks later...

DNL, If this forum used "rep" Id hit that button a few times... EXCELLENT narrative on how to nest programs to do some really cool things. This is EXACTLY the type of thing Ive been looking searching out for some time.

 

Very well written and insightful - thanks for your contribution.

Link to comment
  • 2 months later...

I wonder how this technique would change with the introduction of variables that are in the next release? I quess it's will still be a "state machine" but with variables to use between the states.

Link to comment

Hi vbphil.

 

I have been thinking about updating this post to cover the very thing you mentioned.

 

The introduction of IF conditions using non-state variables allows for conditional logic that is not affected by changes in state.

 

There are also a few optimizations that could be added.

 

Maybe after taxes are done ...

  • Thanks 1
Link to comment
  • 4 weeks later...

My apologies for the double post, but no one has answered my original post in the "Variables" section, and it was this thread that really inspired the question. I've been studying this thread and wish to thank the authors. Here is my original post:

 

I've been planning to start controlling my EZFlora with the ISY. I've done quite a bit of searching and reading but haven't quite found an answer to my question below

 

Some background: I've found these very useful links (and wish to thank the author(s))!

 

http://www.universal-devices.com/mwiki/ ... an_EZFlora

 

http://www.universal-devices.com/mwiki/ ... Program_v2

 

I've also reviewed this explanation of using a state machine (Stochastic) approach to programming that I find very appealing (also thanks to the authors):

 

http://forum.universal-devices.com/viewtopic.php?t=5731

 

I see the author plans an update with the new variable feature incorporated.

 

Here is my question.

 

What is the disadvantage/advantage of having the

 

CURRENT running irrigation zone be represented by a

 

STATE variable, where the value is the zone number and with STATE variable value '0' being no zone on. (one could even have 1 being automatic running zone 1 and 11 be manual running zone 1, etc)

 

Then one would write programs for each state transition to the new running zone that would automatically get triggered when the CURRENT zone state variable was changed and using an IF condition have their respective controlled zone number match the number in STATE variable? Since each of the programs would only run when their zone number matched the current state variable zone number, this approach should eliminate the need to manage testing for changes versus if one was using a non-state variable to represent the current state. Am I missing something about the concept of the STATE variable implementation and programming the ISY in general?

 

I apologize for not including a coded out example, but figured it best to ask before coding!

 

TIA

 

and thanks all for a great system and wonderfully helpful forum.

 

cheers

Link to comment

It might help to know what you are trying to accomplish.

 

I use my EZFlora like this (there are three of these programs for three different schedules):

 

If
       On Sat, Mon, Wed
       Time is  5:30:00AM
Then
       Set 'Irrigation / Front Yard 1' On
       Wait  30 minutes 
       Set 'Irrigation / Front Yard 2' On
       Wait  20 minutes 
       Set 'Irrigation / Front Yard 2' Off

Else
  - No Actions - (To add one, press 'Action')

I don't know what advantage there would be to having each zone execute in a seperate program. My way, all the zones and run times are right there in the schedule, and not spread out over seperate programs. So, to answer your questions, it would better help to understand the functionality you desire.

Link to comment

I am trying to have the wait time / run time be set in a variable, rather than hard coded into the program. That would allow easier adjustment of the run time. For example seasonal adjustments as a percent of the base run time, more accurate adjustment of run time based on actual rainfall etc.

 

The more general question was about the choice of using a state verses an integer variable for the state programming model described.

 

Thanks

Link to comment

Here's another vote for a variable to specifiy Wait times and Repeat times.

 

I actually cycle through my zones 3 times @ 5 mins since the ground is hard clay. It allows the water to soak in and not run off.

 

I would really like to use a variable to specify the repeat # and also the duration for each zone specified by the Wait.

Link to comment
I am trying to have the wait time / run time be set in a variable, rather than hard coded into the program. That would allow easier adjustment of the run time. For example seasonal adjustments as a percent of the base run time, more accurate adjustment of run time based on actual rainfall etc.

I don't think we are there yet with variables. Until you can read real-world values into the variables, e.g. 24-hr rainfall, rainfall rate, humidity, date, device dim level, etc., the current variable capability of the ISY is limited to simple counters.

Link to comment

I would prefer variables as well. I'm still using version 2.8.16 of the 99i and it doesn't support variables.

 

I run each Zone from it's own program that way I can see the progress of the watering routine as it moves from Zone to Zone. I store my many different watering routines in separate folders to keep them organized.

 

Basically I program the THEN path in each program as DNL points out. Like this;

If

Then

Set 'IrrigationZone.1' On

Wait 30 minutes

Set 'IrrigationZone1.' Off

Wait 3 seconds

Run Program 'P2Z2Run' (Then Path)

Else

 

This example is the program for Zone 1 where it runs for 30 minutes and then commands Zone 2 to run which is in the P2Z2Run program. It's all pretty straight forward.

 

-phil

Link to comment
Here's another vote for a variable to specifiy Wait times and Repeat times.

 

I actually cycle through my zones 3 times @ 5 mins since the ground is hard clay. It allows the water to soak in and not run off.

 

I would really like to use a variable to specify the repeat # and also the duration for each zone specified by the Wait.

I also look forward to having extended capabilities for using variables.

 

I have an approach that controls repetition and wait times with variables. I admit it is a kludge but I think it is better than nothing.

 

For repetition:

(1) set a variable (REPLIMIT) to contain the number of repetitions you want

(2) code the repeat loop in your program to repeat 999 times (or some number larger than you will ever want)

(3) initialize another variable (REPCOUNT) to zero just before the repeat loop and increment it by one inside the repeat loop

(3) run the IF clause of another program (REPCONTROL) inside the repeat loop

(4) the IF clause in REPCONTROL compares REPCOUNT against REPLIMIT; when REPCOUNT > REPLIMIT, the THEN clause stops execution of the first program.

 

This approach requires each pass through the repeat loop to run longer than it takes to run the other program so a short WAIT statement may be needed after the RUN command.

 

Alternatively, you could make REPCOUNT a state variable and omit the RUN statement in the loop. Each increment of the variable would invoke the REPCONTROL program.

 

For wait:

This is a similar technique ...

(a) using one variable (WAITLIMIT) to contain the length of the wait that you want,

(B) a repeat loop in your program to repeat some very large number or times

© using another variable (WAITCOUNT) to count loops

(d) running the IF clause of another program (WAITCONTROL) inside the repeat loop

(e) putting a WAIT statement inside the repeat loop.

 

I have not tried this but I suspect it will not be possible to achieve precise control for some small number of seconds but it should work fine for larger increments such as multiples of two- or three-second intervals.

Link to comment

Thanks dnl, this works.

 

It also has a built in fail safe in that the repeat loop count sets an upper limit for the value in REPCOUNT from causing the program to run too long. This would be useful for a pump valve.

 

Ok,

 

this combines both into a program that gets invoked by zeroing the counter with

sIrrig.Counter being a state variable (using seconds to test rather than minutes)

 

If
       $sIrrig.Counter < $iIrrig.Curr_Zn.Min_Total_to_Run

Then
       Wait  1 minute
       $sIrrig.Counter += 1

Else

 

Note: edited to change Wait interval from 1 second to one minute to address concerns below.

THANKS again, dnl

Link to comment

Yikes! I would be interested in hearing from Michel on that program. Two issues I see:

 

1) It is probably not accurate. One thing that event programmers for platforms like Windows know (and I mean that with all due respect) is you can't use a counter as a timer, because event trigger systems tend not to be reliable from a repetitive timing perspective. So, your program relies on the fact that the program will be triggered precisely at the moment that counter is incremented, with no delay. I imagine that will not be the case in the ISY. You may see as much as a one second delay (deferring to Michel, of course) before the program is triggered on the status change. So you may call the program with the variables setup for a 3 minute (180 second) wait, but wind up with a 6 minute wait instead.

 

2) This will be horribly inefficient from a processing point of view. While the program itself is simple, the high overhead comes from status change of variables and determining which programs need to be triggered, triggering the right programs, keeping up with the variable values and program status, etc. For a 3 minute wait, your setup will be doing this 180 times, which probably makes it 180 time less efficient than a simple "Wait 3 minute" statement, IME.

Link to comment

kingwr,

Thanks for thinking through the issues, but fear not, the actual design WAIT will NOT be one SECOND, but MINUTE. I did say that in the post. I watched it run, and it incremented pretty accurately for the 20 second test period several times as I reset the counter. My intent is to eventually control an irrigation valve by setting a variable on a web page, so the units will be minutes and a minute or two extra will not be a crime. Since the repeats would likely be between 5 and 30 at most, a few seconds lag per loop would not be important.

 

I'd be interest in seeing a way that minimizes load and lag and put this up to help move the thread forward.

 

I also suspect at a minute interval, the overhead should not be excessive as only one valve will be running at a time. If you think a minute interval is still too much, than 2 or even 5 minute intervals would likely be enough granularity of control, but seems to me a minute should be fine. After all, since state variables are intended to trigger programs, should not using them that way be better than have a larger number of programs checking state via if statements and integer variables?

 

I would love to see what Michael say about this approach, since many people have wanted variable control of wait or repeat loops. This seems to work fairly well, with the warning to keep the interval above a point to avoid lag and overhead, until he gets Wait/Repeat Variable ability programmed in. It also would be easily converted to the WAIT/VARIABLE construct when that became available.

 

Thanks for your answer and exploring these issues carefully is why I posted and a great feature of the forum!

 

cheers

Link to comment

With a minute interval, I think both the drift (the inaccuracy) and the overhead would be minimal. You are talking about a 1.6% potential drift instead of a 100% potential drift.

 

I do think variable driven WAIT and REPEAT is coming. With the current integer variable system, this would be trivial to implement (again, IMO) and is probably high on the list of next things for variables. I think float type variables and being able to read and manipulate values from the weather module (such as rainfall inches, wind speed, temperature, etc.) are probably farther away.

Link to comment
... I would love to see what Michael say about this approach, ...

 

kingwr's assessment of the issues using a tiny wait interval in a loop are correct.

 

There should be no issues with this approach as long as you keep the wait interval as high as possible. I wouldn't worry about it at all if the interval is above 15 seconds +/-, depending on the number of programs you have, and how many are running.

 

For both accuracy and efficiency, the rule of thumb is to make the wait interval as high as possible.

Link to comment

thanks guys,

 

the short program does show how powerful the state variable implementation can be!

 

Now on to coding the rest of it!

 

cheers

Link to comment
Guest
This topic is now closed to further replies.

×
×
  • Create New...