Jump to content

Understanding IF then Else


curtbl

Recommended Posts

I'm new to the forums but have been around the automation community for a bit now, originally using X-10 and JDS Stargate along with Crestron, i have upgraded to Insteon and the ISY99, nice stuff Michael and team.

But I have a question that I am stumbling on and can't figure our what I'm doing incorrectly. Follows is a program out of the system. I would expect that the THEN section would be executed if the IF statements were true.... so If I turned off the MBed Ceiling Floods and the status of either the status lines were correct Then should be executed, however if status of both units are off instead of on I would expect Else to be executed In my case if I turn on one of the moudles indicated in a status line then the else runs, I selected Status not control, what am I missing.

 

 

If

From 10:01PM

To Sunrise +20 minutes (next day)

And-(

Control 'Mbed ceiling floods' is switched off

or X10 'B5/off (11) is recieved

And Status 'Fam Rm Tbl Lamp' is on

or Status 'Curts office" is on

-)

Then

Set Scene 'Mbedroom' off

Set Scene 'MainHall' 22%

 

Else

Set Scene 'Mbedroom' off

Set Scene 'MainHall' off

Set Scene 'EntLite' off

Set Scene 'Kitchen' off

etc............

 

Thanks for the thoughts

Curt

Link to comment

I looked quickly, but my suspicion is that you have an issue with your priorities between ands and ors (I forget the term used in math and boolean logic). "And" are executed ahead of "or"

 

I have added a couple of parentheses to illustrate how I suspect your logic is flowing based on standard priority:

 

-(

Control 'Mbed ceiling floods' is switched off

or

(

X10 'B5/off (11) is recieved

And Status 'Fam Rm Tbl Lamp' is on

)

or Status 'Curts office" is on

-)

 

In this case, this condition would be true if either of the three "or" conditions are true. This means that if the Mbed ceiling floods is switched off, then this condition will be true regardless of anything else. If Curts office is on, this statement will be true regardless of anything else. etc... Is this how you want it?

Link to comment

Curt,

 

You are confused regarding the difference between what causes a program to be executed (trigger conditions) and what is evaluated in order to go down the THEN or ELSE branches (IF conditions). Believe me, you are not by far the only one.

 

The way it works is that if you have a status condition in your IF, the program will run everytime the status of that device CHANGES. If you have a control condition in your IF (Control Device Is Switched On), then the program will run everytime that command is received from the device (or any command is received from the device if the condition is (Control Device Is Not Switched On).

 

See this thread:

 

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

Link to comment

Sorry, I forgot that no post is good unless there is a solution:

 

I would suggest two programs, one with the condition:

(Control 'Mbed ceiling floods' is switched off

or X10 'B5/off (11) is recieved)

And (Status 'Fam Rm Tbl Lamp' is on

or Status 'Curts office" is on)

 

and one with the condition:

(Control 'Mbed ceiling floods' is switched off

or X10 'B5/off (11) is recieved)

And Status 'Fam Rm Tbl Lamp' is not on

And Status 'Curts office" is not on)

 

Put the THEN branch of your original program in the THEN branch of the first program, and the ELSE branch of your original program in the THEN branch of the second program.

 

Note that I have advocated for the seperation of trigger conditions from IF conditions in the ISY. The way that it is now is very different from other automation controllers and software. Maybe if enough people are confused, some changes can be made.

Link to comment

This comes up so often I thought I would share the methodology I now use to develop all my ISY programs.

 

This method 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'm afraid this may end up being lengthy so please bear with me; I have no way to draw paper diagrams here so everything will have to be via tedious description.

 

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

 

I'll also note that to actually do this, you may know Insteon requires we create a scene ("Scene KPL-D") with the button in it - this is just in order 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: (Eg. “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-A 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 diagram 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 you have no idea how you got to the state you're in. If you need to "know" that for your logic, you simply break out 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, then waits 5 seconds, and then - assuming nothing else has interrupted it - returns to state S0.

 

S1, S2 and S3 all will have arrows back to S0 representing this "timeout" transition (ie you waited too long to press and the state reverts back 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 - one involving say 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 in that state by re-entering the state.

 

Now, if you've suffered this so far, I'd really recommend you actually draw this out in some fashion on a piece of paper even though it may seem obvious or even trivial. You might want to implement this in your ISY to get a feel for the process. The basic idea is to separate out figuring out what you want from the actual ISY programming.

 

Now that we have our diagram, we can easily get to an ISY program set by a rote procedure. Each state will be represented by two ISY programs: one program will test the conditions - these are all the incoming "arrows" to that state that represent the various trigger conditions into it. The second program will actually perform whatever that state is supposed to do.

 

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

 

As has been explained on this forum in innumerable posts including this very thread, the ISY executes either the Then or Else body of a program whenever any of its trigger conditions are TESTED. This causes the program to be reset and would be really a Bad Thing: we only want the code for our state to be run 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 the difference, keep re-reading it until it makes sense. It is critical to understanding the difference between the way you think and the way the ISY thinks.

 

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

 

The structure of the four S*Cond programs is all basically the same, short, sweet and simple: just test the conditions for 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. Once again, you must run a separate "body" program. Do not just put your state code in the condition test "Then" part. It might work after a fashion, but I can promise you it will never work the way you want.

 

So here's our S1Cond (excuse the reformatting for brevity)

 

If (Program 'S0Body' is True And Control 'KPL D' is switched On)

Then Run Program 'S1Body' (Then Path)

 

That's it. The condition list connects each transition coming in to this state with a pair of "and"-ed tests. One part of the "and" to name state you'd be coming from, and the other for the event causing the transition from that state to this one. This is honestly far simpler to actually do than to explain.

 

In this example there is just one transition into S1 (from stating state S0). But if you have multiple transitions coming in to the state you merely "or" a set of these parenthesized tests together to trigger off 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.

 

Now, what is in the S*Body programs? The first thing it must do is set all of the other state's body programs false. This cancels whatever they might be doing, effecting the actual transition to this state. Remember, we can only be in one state at a time. That also declares those other state programs false" to the ISY. This is crucial because we are using the true/false status of the S*Body programs to “remember†what state we are in.

 

After that you just do whatever you want to in the state - if anything, and then put in any explicit transition that happens if the state times out or exits before any other condition triggers in the ISY to cancel it.

 

These 'tail' transitions are explicitly in your state code - by calling the body program for the target state, usually as the last thing that state does. So they are not called out in the trigger condition list for the target state's S*Cond tests. All other incoming (triggered) transitions are, but these are transitions are programmed, not an event. 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 and I recommend using a common prefix so you can watch them grouped together in the ISY Program Summary.

 

The only things to think about for the Body programs are how long to wait before making an explicit timeout transition out, and what you to do around that waiting. For the most part you have the freedom to do whatever you please without worrying about strange interactions, since you know the program isn't going to get self-disrupted - it is 'protected' by it's S*Cond wrapper.

 

In some cases you may have no timeout inside a state. For example, here's our 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 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. (S0Body of course 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. Remember, we require exactly one of the S*Body programs to be "True" at any time, indicating the state we are in. I do this by simply marking S0Body as 'run at startup'. Easy.

 

If you're the worrier type, you can create a separate program that triggers on all four Body programs being false and if so runs “S0Body (Then)â€. I don't bother with this, but it takes care of someone, say, manually setting S0Body false from the ISY console or something odd like that happening to make things inconsistent.

 

Here’s another example I just ran into on the forum: 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.

 

We have here two states: the beginning/idle state we'll call Denon.S0 and a state S1 that represents the amp was on at 11:45 and waits for 7AM to turn it off and goes back to S0. Two states = four programs... Oops, not quite.

 

We have no way - at least no easy way I know of - in the ISY to wait inside a program for a specific time of day. Now, there are all sorts of ad-hoc ways you could cook up to shim around this problem: some stupid little thunk program to trigger true at 7AM and test that in a repeat loop and so forth. But all that nonsense is precisely what we're trying to get away from. Fuggedaboudit.

 

The solution, as always here, is simply to add another state. Now, S1 merely serves to record that AMP was on at 11:45 and exits doing nothing except staying true. A new, third state, S2, triggers from S1 at 7AM, turns off AMP and returns to S0. Three states. Six programs. OK.

 

Again, excuse the reformatting.

 

Denon.S0.Cond:

If (nothing)

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

 

Denon.S0.Body: //set to run-at-startup

If (nothing)

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 (nothing)

Then

Run Program Denon.S0.Body (Else Path)

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 (nothing)

Then

Run Program Denon.S0.Body (Else Path)

Run Program Denon.S1.Body (Else Path)

Set 'AMP' Off

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 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 way will implement it correctly. And 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. Suppose we want to enhance this a little. If someone turns on the amp between 11:45 and 7AM then we want to 'reset' the logic and so not turn the amp back on at 7AM. Easy. Just add a transition arrow from S1 to S0, triggering on 'if AMP is switched on'. So, you put that condition on Denon.S0.Cond and you're done.

 

Let’s apply the technique to this specific post: 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. I’m assuming the idea is that people are still up. 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 now “optimize†it down to 4 or 2 programs, my unequivocal advice: 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 one place and don’t mirror it somewhere else 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 sit and watch the “True†indicator jump from program to program (state to state) in the Program Summary screen as it runs. I always know exactly what it should be up to 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.

 

I would certainly agree with the suggestion that ISY programs’ semantics could be fleshed out a tiny bit without violating the ISY’s essentially functional, stateless nature. Maybe a third “onlyif†clause. Or perhaps a program modifier to indicate that current then/else execution shouldn’t be interrupted until the conditions actually test true. Lots of possibilities, any of which would be welcome. This would collapse this method into needing half the number of programs and would also make things easier to understand regardless of what method you use to produce them.

 

I will make one other note, I have an ISY99ir/pro. As I understand it, it has limit of around 1000 programs. I've never come anywhere close to that - my little room logic programs rarely get past 8 states and I only have 10 rooms including the patio. But, maybe you live in a mansion and you're an ambitious ISY programmer with a non-Pro ISY. Just be aware that there are limits of some sort, though I personally don't know what they all are as I've never bumped into any of them.

 

HTH

Link to comment

ergodic!

 

This is an excellent write-up! It is clear and complete, even to start-up conditions and error handling.

 

A minor point on the Denon example; the requirements were:

 

Here’s another example I just ran into on the forum: 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.

Accordingly, shouldn't the Denon.S1.Body program turn the amp off, and shouldn't Denon.S2.Body Set 'AMP' On, rather than Off?

 

Thanks so very much for posting this, and would you permit us to place it on our wiki? We would be happy to do the formatting for you. And if you would like to draw out the diagrams on paper and scan them (or use a drawing program), and send the image files to us, we would be happy to include them in the wiki article as well--I'm sure they would be a great help to the reader.

Link to comment
This comes up so often I thought I would share the methodology I now use to develop all my ISY programs.

 

Been traveling and haven't had a chance to say thanks for all that responded, and especially the long detail which I'm still absorbing and it looks great. I came from the JDS Stargate world where we had flags, timers etc and I'm still trying to get a handle around how some of this is working .... I'm sure it is all here just getting used to a change is time consuming when I'm traveling as much as I do these days.

Does the ISY deal with simple ASCI either in or out... ? I experimented with the SmartHome 2410S and didn't have a lot of luck and it appears from what I have read neither did others.

 

Thanks again all for the comments and help.

 

Curt

Link to comment

Darrell:

 

Clearly I should probably stick with an example of what I actually use :-)

 

Here's the program set I have for my kitchen. There are two motion sensors. The idea is I think fairly typical:

 

At night, I want to turn up the lights over the kitchen island to 50% if they're off or less than that when somebody walks in. And regardless of whether it is day or night, after 15 minutes of no activity I want all the kitchen lights to shut off using a scene I've defined.

 

The full set of programs is below. There are four states in this little engine:

 

S0: Resting state

Jumps to S3 when motion is first detected

 

S3: Motion initially detected

Jumps to S1 if it is night, otherwise jumps to S2

 

S1: Nighttime

Turns up the island light

Jumps into S2

 

S2: Waiting-for-no-motion

Jumps back into itself when any motion is redetected

After 15 minutes flows back to S0

 

Here's the little diagram - I hope it's legible - this stuff worked better back in the days before variable width fonts :lol: ....

 

S0

|

| (motion)

|

V . . (night)

S3 -------> S1

| . . . . . . . . |

| (not . . . . .|

| night) . . . .|

V . . . . . . . .|

S2 <---------+

. / .^

+---+

(motion

redetcted)

 

The S2 state is the interesting one. It has three incoming transitions, so three clauses in it's condition list.

 

This brings up an issue: why not just exit to S2 at the end of S3 with one of those "tail transitions," instead of using conditions on the target states for both exits out of S3?" In other words, remove the "if...S3 and not night" check from S2's condition list and just put a 'run program S2' at the end of S3? It would certainly be simpler.

 

My answer is that this can work, but you also have to put a "wait 1 second" before you make that leap. The ISY may be event-driven but like any single processor it can only be doing one thing at a time. Without a wait to suspend execution of S3 and allow the ISY to test the other conditions, specifically the one that takes it to S1, it appears it never gets a chance to check that before making the direct leap to S2.

 

In the past, I've experimented with a 'wait 0 seconds'. One might expect this would be enough to just put S3 back at the end of the ISY's execution queue without any minimum delay and so give it a chance to check on what else might be going on. But it appears to just optimize it out instead or something else like that; this is all speculation since I don't know anything about the ISY's execution model. In some cases the wait isn't a problem - you're waiting in the state anyway. But here it would just slow down the program to no other good purpose.

 

If anyone from UDI, or anyone else, has any ideas on how to do this better or more easily, I'd be very much interested. It comes up often.

 

There are two oddball programs. The "IsNight" program is just 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 have to remember to do it in more than one place.

 

The other thing that needs comment is the "Body.S1.Sub" program. I need something to test if 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 down -- far more remarkably annoying than you might think if you've never actually had it happen to you.

 

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

 

The programs I use for this are these.

 

=====

Kit Motion.Cond.S0:

=====

 

If

Then

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

 

=====

Kit Motion.Body.S0: (marked for run-at-startup)

=====

 

If

Then

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

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

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

Run Program 'Kit Motion.IsNight' (If)

 

=====

Kit Motion.Cond.S1:

=====

 

If

Program 'Kit Motion.Body.S3' is True

And Program 'Kit Motion.IsNight' is True

Then

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

 

=====

Kit Motion.Body.S1:

=====

 

If

Then

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

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

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

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

 

=====

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.S2' is True

And (

Control 'Kitchen: Motion (Oven)-Sensor' is switched On

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

)

)

Or (

Program 'Kit Motion.Body.S3' is True

And Program 'Kit Motion.IsNight' is False

)

Or (

Program 'Kit Motion.Body.S1' is True

)

Then

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

 

=====

Kit Motion.Body.S2:

=====

 

If

- No Conditions - (To add one, press 'Schedule' or 'Condition')

Then

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

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

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

Wait 15 minutes

Set Scene 'Scene: Kit On' Off

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

 

=====

Kit Motion.Cond.S3:

=====

 

If

Program 'Kit Motion.Body.S0' is True

And-(

| Control 'Kitchen: Motion (Oven)-Sensor' is switched On

| Or Control 'Kitchen: Motion (Sink)-Sensor' is switched On

-)

Then

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

 

=====

Kit Motion.Body.S3:

=====

 

If

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)

 

=====

Kit Motion: IsNight

=====

 

If

From Sunset - 30 minutes

To Sunrise + 30 minutes (next day)

Then

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

Else

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

 

 

=====

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

=====

 

If

Program 'Kit Motion.Body.S3' 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)

Link to comment

I won't disagree with that in the slightest, except I was hoping that what I wanted the programs to do was clear. I'll try and explain anything I can, but as with all things like this it is much easier to just try one than to dissect it verbally.

 

The ISY uses what technically would be termed 'functional' (ie stateless, variable-less), 'event' programming and that indeed 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.

 

So if you can separate out what you want to do and diagram it, and 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. The end programs may not be pretty to look at, but what ISY programs are?

 

If I were to suggest one simple change to the ISY, it would be to relabel the display of the existing trigger "If...Then...Else" program p-code as "When...Then...Otherwise". Then add a real, synchronous "if" test for use inside program clauses. A subset of the existing "if" trigger tests would be fine.

 

This one change would eliminate a ton of program hair as well as a lot of confusion regardless of how you go about programming your ISY. "If (my-light < 50%) Then Set My-Light 50%". This doesn't require any retooling of the basic ISY model that I can see and doesn't need variables or such.

 

Of course variables, even simple, global, boolean variables, would be helpful. But they don't seem to be forthcoming any time soon. And without a conditional test statement I frankly doubt they could be employed to their full usefulness anyway.

Link to comment

Hello ergodic,

 

Thanks for the additional very good example. I really like your 'state machine' approach to developing ISY programs.

 

In the past, I've experimented with a 'wait 0 seconds'. One might expect this would be enough to just put S3 back at the end of the ISY's execution queue without any minimum delay and so give it a chance to check on what else might be going on. But it appears to just optimize it out instead or something else like that; this is all speculation since I don't know anything about the ISY's execution model.

That's a good question, but I'll need to defer to Chris for the answer :? .

 

There are two oddball programs. The "IsNight" program is just 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 have to remember to do it in more than one place.

Yes, I have several conditions, tested in various places, for which I use the same technique.

 

The other thing that needs comment is the "Body.S1.Sub" program. I need something to test if 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 down... The ISY of course has no "if...then" testing inside program clauses, something that would be most, most welcome. So I break out this little routine that's called from S1 to check the lights and raise them only in that case.

And I have many, many sub-program like this. It is currently the only way to nest conditions, aside from using folders with conditions.

 

May I assume (always dangerous) that program Kit Motion.Body.S1.Sub is not enabled, since its If is being called from Kit Motion.Body.S1? In this particular case, if S1.Sub were enabled, the call from Body.S1 could be eliminated as the test would be automatic. But perhaps you've written it this way to keep the logic clear and the state machine consistent?

 

Along the same lines, I'm not sure why Kit Motion.Body.S0 calls Kit Motion.IsNight (If), since the latter must surely be enabled?

 

Also, I notice that your Kit Motion.Cond.S2 program tests for either of the motions sensors to be switched on in order to re-trigger the program timer. However, if motion is continuous, the motion sensors' internal timer will never time out, and therefore an additional On command will never be sent.

 

This is one of the major weaknesses of the INSTEON motion sensors, and can be worked around by waiting for an Off command before starting the program timer.

Link to comment

I think the Kit.Motion.Body.S1.Sub substate has to be called explicitly, otherwise the ISY never gets a chance to invoke it because S1 runs through without any wait. (It isn't disabled.) Is this incorrect?

 

The call to .IsNight from the resting state was just initialization. You're entirely right that it is probably superfluous.

 

Believe it or not, I didn't know that about the motion sensor design, but it perfectly explains the occasional odd behaviors I've noticed -- I'd just chalked them up to comm issues. They ought to make that jumper 5. Thanks! Now that I've also replaced all my evil V35 switches I'm getting back very close to Insteon Nirvana once again!

 

I do have a buttload of the X10 MSs sitting in a box, bought on one of their endless, hyperactive-GIF, email "closeouts," and an EZX10RF I don't really use for anything now. And stylewise I (and my Ms.) prefer the little X10s as they're less obtrusive - the bulky 2420M seems a little obnoxious used indoors. I may switch back to the X10s and just endure the every-three-months battery changing ritual.

 

Anyway, using your idea to fix it I just added another state (S4). But I also realized while I was doing it that the S3 state isn't really necessary. I also put in a little .IsMotion program/function to tighten it up.

 

So here's what I end up with. I just made the changes, tested it, and seems to work fine, at least at nighttime.

 

And now that it just occurred to me I can insert code in this #!%@!% bbs, it should be a whole lot easier to read!

 

S0: Resting state 
 Jumps to S1 when motion is detected and it is night
 Jumps to S2 when motion is detected and it is not night

S1: Nighttime state
 Turns up the island light 
 Jumps into S2 

S2: Waiting-for-both-MS off state
 Jumps to (new) S4 when status of both MSs goes to 'off'.
 Just as a failsafe, after 4 hours, flows to S4 anyway, haven't really thought this through...

S4: Waiting-for-either-MS-on state
 Jumps back to S2 when on is received from either MS
 Otherwise after 15 minutes turns off the lights and flows back to S0

 

Here are the revised programs

 

===== 
Kit Motion.Cond.S0: 
===== 

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

===== 
Kit Motion.Body.S0: (marked for run-at-startup) 
===== 

If
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
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
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
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
Else

===== 
Kit Motion: IsNight 
===== 

If
       From    Sunset  - 30 minutes
       To      Sunrise + 30 minutes (next day)
Then
Else

===== 
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)

 

Overall I think the formula kind of boils down to this:

 

1) Draw your diagram. Begin by drawing a circle for the resting state and being thinking about what events trip you out of that. The rest will flow from that pretty quickly though 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. Just boilerplate. It then does whatever you want that state to do, if anything. Sometimes a state is just to be able to distinguish where you are in the flow, and may do nothing.

 

There is always a starting, resting state that usually does nothing and should be marked run-at-startup.

 

If the state does a wait or you don't mind putting one in, then you can transit directly to the next state as 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 and so you have to use conditions to handle every exit path. Again, 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 "and"s the source state = true, with whatever condition takes you from that source state to this target one. 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 the one test. The "then" clause for a cond.state has a single statement executing that state's body program. If you're tempted to put something else in here along with that, I'd also recommend a comment to the effect: "welcome to the 7th level..." or "abandon all hope..." Anything along those lines will do nicely.

 

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

Link to comment
Hello ergodic,
In the past, I've experimented with a 'wait 0 seconds'. One might expect this would be enough to just put S3 back at the end of the ISY's execution queue without any minimum delay and so give it a chance to check on what else might be going on. But it appears to just optimize it out instead or something else like that; this is all speculation since I don't know anything about the ISY's execution model.

That's a good question, but I'll need to defer to Chris for the answer :? .

 

You are correct, it optimizes out the wait 0.

Link to comment

Hello ergodic,

 

I think the Kit.Motion.Body.S1.Sub substate has to be called explicitly, otherwise the ISY never gets a chance to invoke it because S1 runs through without any wait. (It isn't disabled.) Is this incorrect?

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 (which happens as soon as its Then is called--in this case from Kit Motion.Cond.S1).

 

However, 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, though I doubt it (but Michel or Chris should be able to say for sure). However, it would be easy to test simply by removing the call.

 

I do have a buttload of the X10 MSs sitting in a box, bought on one of their endless, hyperactive-GIF, email "closeouts," and an EZX10RF I don't really use for anything now. And stylewise I (and my Ms.) prefer the little X10s as they're less obtrusive - the bulky 2420M seems a little obnoxious used indoors. I may switch back to the X10s and just endure the every-three-months battery changing ritual.

I also use a combination of INSTEON and X-10 motion sensors (though with a V572RF32 rather than an EZX10RF--what is your satisfaction level with that device?). I do agree that the smaller package is less obvious/distracting. And yes, you can sure buy a whole lot of them at extremely low prices if you grab the sales!

 

The two do operate quite differently however, especially with regard to the resending of On/Off commands as mentioned above. As I've written elsewhere, I set my X-10 motions for the maximum timeout to reduce the sending of Off commands as much as possible, and then simply ignore incoming Off commands from them and program based on their repeated On commands. Unfortunately, there is no similar way to reduce the frequency of their On commands, which can clutter the power line especially when multiple motions are used.

 

However, they also operate differently in that the X-10 motions send light/dark commands immediately, while the INSTEON motions wait for 3.5 minutes without light-level transitions before sending a light/dark command.

 

So, I've been toying with the idea of using INSTEON sensors for motion, and modifying these cheap X-10 sensors to eliminate any motion transmissions at all and simply use them as quick-response light sensors. With the On/Off transmissions gone, there wouldn't be nearly as much power line clutter, and it should also extend their battery life.

 

I haven't really done any testing in this vein though, and don't know how effectively they can be used as light monitors, since they don't have the light sensitivity adjustment that the INSTEON sensors have.

 

The INSTEON sensor, with the ability to eliminate the Off command and to adjust the re-trigger time for the On command, would have eliminated much of the difficulty, if only Smarthome had seen fit (or would add to future firmware revisions), the ability given to some later devices, to send an Off command to a different group number than the On command. This would allow the sensor to be directly linked to a responder for the On command, while still not be linked for the Off command, thereby allowing the off programming/timing to be handled by the ISY or other controller, while still ensuring the fastest possible turn-on times of a direct link (no program latency).

 

So here's what I end up with...

The new programs look good to me!

Link to comment

Chris:

 

Could a wait 0 could be interpreted in a future release as with any other wait, but with a 0 minimum delay?

 

It seems - just standing from the outside of course - that it would be quite useful, since the current wait minimum is 1 second and it would be most helpful to have some way just to let the ISY check what's going on.

 

Darrell:

 

I obviously have a lot of rethinking to do as regards motion sensors.

 

The EZX10RF works flawlessly for what I've used it for and the ISY hooks in the Insteon scene-linked X10s perfectly. I only have a couple of X10 devices left on it, but it seems that may change soon, just based on what you've told me. Again, thanks for that.

 

Since the X10 MS is an RF device, I'm wondering if there's any solution to translate X10 RF directly to either Ethernet/wifi network commands or to IR? That would serve to keep all that X10 jibberjabber off the powerline entirely until it got to the ISY, assuming there is no open X10 pickup plugged in. And the EZX10 and (I think) the 572 both can filter things out selectively as I recall.

Link to comment

But if the X10 from the MS is just being translated to Insteon scene commands, isn't that pretty much the same thing signal-jabbering-on-the-line-wise? Or am I missing the point, as I frequently do....

 

My musing mainly was to whether there is something available that could receive RF directly from the X10s and translate to network commands (which could then be sent to the ISY via the network module).

 

I'm pretty sure it would be do-able with something like Homeseer and an X10 pickup isolated behind a Filterlinc or some such, but aside from requiring a PC to work, the net delay would probably be unacceptable. Especially given that the ISY program response delay is already kind of at the edge of what one wants to live with.

Link to comment
Chris:

Could a wait 0 could be interpreted in a future release as with any other wait, but with a 0 minimum delay?

 

We could add a feature like that, but to stay compatible with existing programs it would more than likely be a different action or option and not actually "wait 0".

 

Chris

Link to comment
But if the X10 from the MS is just being translated to Insteon scene commands, isn't that pretty much the same thing signal-jabbering-on-the-line-wise? Or am I missing the point, as I frequently do....

 

My musing mainly was to whether there is something available that could receive RF directly from the X10s and translate to network commands (which could then be sent to the ISY via the network module).

 

Only that IMO Insteon traffic is better than X!0 traffic, in both reliability and bandwidth usage. I rely on Insteon for home automation traffic. I wouldn't want such traffic on my ethernet network, for example. But as we can see from the start of this thread, I prefer to follow the KISS principle in each aspect of my implementation.

 

If you have an Elk or other security system, perhaps you could use that to monitor your motion sensors out-of-band from the Insteon network and communicate with the ISY over the REST interface (does not require the network module).

Link to comment

Can't this already be accomplished with Run Program?

 

Chris:

Could a wait 0 could be interpreted in a future release as with any other wait, but with a 0 minimum delay?

 

We could add a feature like that, but to stay compatible with existing programs it would more than likely be a different action or option and not actually "wait 0".

 

Chris

Link to comment

No, if you're writing event-driven conditions then you don't know which program to run, or if you want to run one at all - only the conditions on the target states "know".

 

IOW you just want to give the ISY the opportunity to evaluate any changed conditions and run the appropriate program. If not, it just comes back. Then if you get there you know nothing is pending and you can indeed do a run program to jump to somewhere else.

 

Since a "wait 0" has no documented semantics currently and does nothing anyway, I can't see the harm in having it do this. But wait .1 seconds would be OK too. An unnecessary 1 second delay in program execution is too long though.

Link to comment

So you are saying that the ISY is single threaded and you want a WAIT 0 to allow the ISY to run other programs at the same time your program is running?

 

My understanding is that all the WAIT will give you is the ability for the ISY to preempt your currently running program in favor of a new instance of the same program becuase the trigger conditions have occurred again.

Link to comment

I'd like the wait 0 (or something) to be able to allow the ISY to check whatever conditions have changed and call the appropriate body program. The same as any other wait - just without a minimum delay.

 

As long as the condition program and the body program are separated (as they are) it could be that body program or some other. Whatever the various transitions call for.

 

In more specific terms, if you have S1.Cond/Body and S2.Cond/Body. S2.Cond says: "If S1.Body is true and " and the S2.Body it runs has this new "wait 0", there's no way it's re-entering S2 again because S1 is now false.

Link to comment
  • 3 weeks later...

First, Thanks to EVERYONE involved in this discussion. There's so much good informatino here it almost blows my mind! It's nowhere else and that's part of the problem.

 

I've owned my ISY for a little over two years and have been totally frustrated by the programming model. And I can't find a good document that can help me learn it.

 

I mean this in a constructive way -- I've found that the whole Universal Devices area suffers from poor (if nonexistent) documentation. There's the out-dated manual that shipps with the unit. For programming it's little to no help at all. The programming section is (I'm sorry) a joke.

 

All that's available are a few good (but extremely complex) threads in this forum, then the Wiki which is a poor subistitute for a programming or operating manual.

 

This thread, for example, is EXTREMELY hard for anyone trying to learn anything to follow. I know you guys have put alot into it. I'm sorry, but the end result is a geek-to-geek discussion with examples, corrections to examples, and changes.

 

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.

 

You guys are the experts - if you have any ideas, I'm willing to write and compile learning and/or reference documents. Problem is, I can't do it by myself because my level of expertise is relatively low.

 

DB

Link to comment

Archived

This topic is now archived and is closed to further replies.


  • Recently Browsing

    • No registered users viewing this page.
  • Forum Statistics

    • Total Topics
      36.9k
    • Total Posts
      370.2k
×
×
  • Create New...