mrp Posted April 10, 2010 Posted April 10, 2010 I believe there is a problem with program execution with respect to Repeat and Wait, or at least something that should be documented in the wiki. Setup We are running 2.7.13 on the ISY. We started by writing a program to close the garage door if it was open. The hardware is an IOLinc connected to a normally-closed switch, and the relay is connected to the garage door motor, of course. The relay is programmed for Momentary-A. We know that Momentary-C is a common deployment, but that is not the issue here. The program, "Subroutines / Do Garage Close Door", looks like: If Status 'Garage Door / Garage Door-Sensor' is not On Then Repeat 3 times Set 'Garage Door / Garage Door-Relay' On Wait 20 seconds Else - No Actions - (To add one, press 'Action') If the program is "Enabled", it works great. First, it checks that the garage door is not already closed. If the door is closed, the program moves to the else clause immediately. If open, the program makes up to three attempts to close the door. Once the door is down, the sensor changes state and any remaining Repeat attempts are abandoned. We implemented the program with three attempts because our garage doors are frequently opened manually. Sometimes they are partially open. Sometimes, they are partially open, and the next relay closure opens them further, so a second try is needed to get them going in the proper direction. But the program has one problem when 'enabled'. Anytime the garage door is open, this program will close them--not what is desired, as this prevents us from ever opening the garage door. The program was designed to run as a subroutine, so we need to 'disable' the program and call it explicitly from elsewhere to have the desired effect. There are many other activities that could call our new subroutine. For instance, periodic monitoring if the burglar alarm is armed (we're away), or as part of a goodnight sequence, or as a manual control on a KeypadLinc. Here is an example of the latter: If Control 'KPL Den / KPLDen-G:Garage Door' is switched On Or Control 'KPL Husband / KPLH-G:Garage Door' is switched On Or Control 'KPL Wife / KPLW-G:Garage Door' is switched On Then Run Program 'Do Garage Door Close' (If) Else - No Actions - (To add one, press 'Action') As such, we dropped the "Subroutines / Do Garage Close Door" program in our 'Subroutines' folder, and disabled it like we do all of our subroutines. Now the program should only execute when called via an explicit "Run (If)" from another program. The Problem Once setup in the configuration described above, we immediately encountered a problem. The subroutine would run for all three iterations even though we watched the ISY report that the Garage Door-Sensor went On. The expected behavior was for the Repeat statement to execute once, then terminate once it saw the door was down. The subroutine worked when 'enabled', but fails when 'disabled'. We finally chased the problem down to Repeat and Wait apparently failing to re-evaluate the "If" condition prior to each iteration if the program is disabled. Needless to say, this is unexpected behavior. If called via "Run (If)", we expect the program to honor the If condition (for Repeat and Wait statements) regardless of whether the program is enabled or disabled. If not fixed, we feel that this at least deserves some documentation in the wiki (e.g., http://www.universal-devices.com/mwiki/ ... tion_Order). We've managed to work around the problem by controlling the subroutine from other enabled programs. However, this feels incredibly dodgy.
Illusion Posted April 11, 2010 Posted April 11, 2010 If the program is not enabled, the 'if' will not be evaluated unless called specifically. You do this from another program but then that is it. The 'if' gets evaluated just there. If the 'if' were true at the time, the then will run. There will be no additional evaluation of the 'if' from that point on unless called again from a program. This is necessary. If the 'if' were to get evaluated again, it would be the same as having the program enabled and then we would loose all the functionality of being able to force an evaluation at a time of our choosing. I have hundreds of programs that would fail if the ISY did not perform in this exact manner.
mrp Posted April 11, 2010 Author Posted April 11, 2010 Hi, Illusion! Thanks for the reply, but I respectfully disagree with your statement: If the 'if' were to get evaluated again, it would be the same as having the program enabled I see a program being 'enabled' as determining whether or not a program will implicitly run as a consequence of the If being evaluated. From my understanding, a program will be started via the If statement under one of the following two conditions: [*:l4bklyx3] the program is 'enabled' (implicitly started through If evaluation)[*:l4bklyx3] another program calls "Run (If)" (explicitly started via If evaluation) It should be noted that there is a very important distinction between evaluating the If statement, and starting the execution of the program. I agree with you that a disabled program should never start program execution through the evaluation of the If statement. This is not what I am asking for. What I'm asking is the Repeat/Wait logic to have the same behavior regardless of whether a program is enabled or disabled. Simply put, changing the behavior of Repeat/Wait based on whether or not the program is enabled just doesn't make sense to me. When a program is disabled, I believe the If condition should be re-evaluated by Repeat/Wait to determine if program execution should continue--just like it does when the same program is enabled. We've already made the decision to start the program--either through an implicit (enabled), or explicit (enabled or disabled) decision to run the program. In an already running program, I just don't see the logic in having Repeat/Wait have one behavior if a program is enabled, and a completely different behavior if the program is disabled. we would loose all the functionality of being able to force an evaluation at a time of our choosing. I believe you've missed the point that... evaluating an If before each execution of Repeat/Wait is a time of our choosing according to the ISY documentation. And the ISY is failing to accommodate this when the program is disabled. Once again... I agree that the If shouldn't be used to trigger program execution if the program is disabled; however, once started, the body of a running the program should function the same whether the program is enabled or disabled. This is not what is currently happening. I do not believe what I am asking for would cause anyone to rewrite programs.
Michel Kohanim Posted April 11, 2010 Posted April 11, 2010 Hello mrp, First of all, thanks so very much for the detailed documentation of the problem. I do very much agree with the need for documentation. In the case of running a disabled program explicitly, when events occur, they are not applied to programs that are disabled. As such, the if conditions will never be re-evaluated while disabled. With kind regards, Michel
Illusion Posted April 11, 2010 Posted April 11, 2010 What I'm asking is the Repeat/Wait logic to have the same behavior regardless of whether a program is enabled or disabled. Simply put, changing the behavior of Repeat/Wait based on whether or not the program is enabled just doesn't make sense to me. When a program is disabled, I believe the If condition should be re-evaluated by Repeat/Wait to determine if program execution should continue--just like it does when the same program is enabled. I do see your point. Just a different way of looking at it. I have spent so long looking at it the way it is, that now, I just accept it as perfectly logical and correct. I can see it from your perspective as well. You could just add the line "run if" of 'Garage Door / Garage Door-Sensor' to the 'then' after the 20s wait. Then it should do exactly what you are talking about. Now again, you get to pick exactly when the 'if' is evaluated. I think this adds even more flexibility to the program. You are clearly very intelligent, and have obviously thought about this quite a bit, but I respectfully disagree with you. To a simpleton such as myself, I think about it in very simple terms. If the program is not enabled, the 'if' part of the program is turned off. I see it as separate and distinct from the 'then' and the 'else'. I have many programs that have no 'if' and I just use the 'then'. I also have programs that have no 'if', 'then', or 'else' used as flags, controlling their 'true'/'false' nature from other programs. I also often run the 'then' from other programs and would not want the 'if' evaluated in this case.
mrp Posted April 11, 2010 Author Posted April 11, 2010 Illusion, THANK you for the reply! You could just add the line "run if" of 'Garage Door / Garage Door-Sensor' to the 'then' after the 20s wait. Putting a "Run (If)" inside the same program that is running the If is a programming paradigm I've completely missed. I was going to convert my dodgy solution to this new paradigm, then I realized the two solutions wouldn't be the same. My solution tries three times, then gives up if the door fails to close. Putting the "Run (If)" inside the Repeat creates an infinite loop which will burn out the garage door opening motor if the door fails to close for some reason. Given the "Run (If)" paradigm, I could completely eliminate the Repeat--this should help make it obvious that its an infinite loop if the door fails to close. The "Run (If)" paradigm you proposed is wonderful and certainly opened my eyes to something I've missed. It is appropriate for many ISY programming applications, but I feel it is a bit dangerous to use for mine. But even given this wonderful paradigm, I'm still of the opinion that a program body should not change behavior based on whether it is enabled or disabled. I have many programs that have no 'if' and I just use the 'then'. I also have programs that have no 'if', 'then', or 'else' used as flags, controlling their 'true'/'false' nature from other programs. I'm sure we all do, using programs as flags is an excellent way to remember previous state in the absence of variables. It is also a good technique for "reversing" program logic, and keeping the programs readable. *smile* I also often run the 'then' from other programs and would not want the 'if' evaluated in this case. I do too. But, that's what "Run (Then)" and "Run (Else)" is for. Thanks again for the enlightenment!
Sub-Routine Posted April 11, 2010 Posted April 11, 2010 You could put the Repeat in your first program. If Control 'KPL Den / KPLDen-G:Garage Door' is switched On Or Control 'KPL Husband / KPLH-G:Garage Door' is switched On Or Control 'KPL Wife / KPLW-G:Garage Door' is switched On Then Repeat 3 times Run Program 'Do Garage Door Close' (If) Wait 20 seconds Else - No Actions - (To add one, press 'Action') If Status 'Garage Door / Garage Door-Sensor' is not On Then Set 'Garage Door / Garage Door-Relay' On Else - No Actions - (To add one, press 'Action')
mrp Posted April 11, 2010 Author Posted April 11, 2010 Thanks, Rand! In fact, my work-around employs the technique you describe. However, I find it a substandard solution because it requires remembering to use a Repeat in each calling program (Garage Door down, Goodnight, Away, etc). It would be preferable to encapsulate the special handling logic in the subroutine where it belongs. I believe I've made my point in that I feel the Repeat/Wait behavior is broken. I'll be quiet about this topic. cheers, mrp
Recommended Posts