Jump to content

Subroutines with no Call Stack - how?


Recommended Posts

Posted

I'm slowly groking how EISY/ISY programming works.

My first learning was that If-Then-Else is really When-Then-Else. That is the If() block is called when something inside it changes (assuming your variables, if any, are State and not Integer).

The second was that programs are not re-entrant. If a program is called while it is still running, that first "instance" will terminate at the next Wait or Repeat line. No passing Go or collecting $200 - the rest of that program won't be called. Instead the new "instance" of the program runs.

After instrumenting my code with lots of UD Mobile notifications, I'm seeing that if in MyProgram1 you have: 

Run Program 'MyProgram2' (If)

Then MyProgram2 will run the If block and execute either Then or Else...BUT

The execution of MyProgram1 does NOT wait for MyProgram2 to finish executing. It's not on a Call Stack, it's just you have multiple programs running simultaneously. I assume this is the same whether calling the (If) or (Then) or (Else) blocks directly.

If I'm correct, this means that I can't use this mechanism to have subroutines. Which I'd really like to have since it prevents duplicating the same code in multiple programs. 

So, my real question is: How to have subroutines?

TIA

Posted

If your goal is to have Program 2 run "in the middle" of program 1, you can put a wait in program one, right after the "call" for a length of time you need for program 2 to complete. Just be aware that program 2 can NOT change the If state of program one in any way, or program one will either start over or run false etc, as it will be re-evaluated at the WAIT.

 

Posted

Just call program2 from program1, and if you don't want program2 to be self-triggered just disable it.

Enable/disable of any program only affects the If section triggers. The code will still run and the conditions will only act as conditions/filters.

However program1 will not wait for program2 to return.

All programs surrender their current time slice to the ISY executive logic engine, and I/O handlers, when encountering a Wait or Repeat program line, to be continued when the system "gets the chance" at the end of the programmed Wait or Repeat time.

Posted (edited)

I just ran into a related issue with a hot water recirculating pump routine. I wanted movement in a bathroom to run the pump for 2 minutes to get the hot water into the pipes. But, if the pump has been recently run (say 15 minutes), it shouldn't run because it's wasteful. So, I wrote this program:

If
        'Bathroom Motion-Sensor' is switched On
    And $RecirRanRecently is not 1
 
Then
        $RecirRanRecently  = 1
        Set 'Recir Pump' On
        Wait  2 minutes
        Set 'Recir Pump' Off
        Wait  13 minutes
        $RecirRanRecently  = 0
 
Else
   - No Actions - (To add one, press 'Action')
 

Now, given that there is no Reentrancy and no Call Stack, I understand why it fails, but don't know the best way to fix. 

The first time through it works. And the second time through it'll work, too. But, if that second time is rejected for being too soon (RecirRanRecently is 1), then first instance is terminated at one of the two Waits, and so RecirRanRecently is never reset to 0. And so the pump would never run again until reboot initializes RecirRanRecently to 0.

EDIT: I'm not using the time-out in the motion sensor hardware because I have another program that runs the pump on timed intervals (every half hour) and it uses the same RecirRanRecently variable in an attempt to get this motion program to not run soon after the timer program rang

What's the best way to accomplish this?

Edited by smorgasbord
Posted

@smorgasbord

Try making your if statement 

Bathroom Motion-Sensor' is switched On
    And $RecirRanRecently is 0

And then eliminate the first line in your THEN.  

As you have it written, when it hits the first WAIT, the IF is re-evaluated. Since you just changed the variable to a 1, it fails the IF and turns False, stopping the program.

 

Posted

RecirRanRecently is not a State variable, so the IF isn't re-evaluated. Isn't convention to put a lower-case "s" in front of State variable names?

I'm trying new program logic now, where I have double-stacked routines to perform the test and then the run. I'll post here in a little bit if it looks like it's working.

Posted
19 minutes ago, smorgasbord said:

RecirRanRecently is not a State variable, so the IF isn't re-evaluated. Isn't convention to put a lower-case "s" in front of State variable names?

I'm trying new program logic now, where I have double-stacked routines to perform the test and then the run. I'll post here in a little bit if it looks like it's working.

Ok.. that makes more sense then now..

Your motion sensor could be turning off, which would also stop the program, and then back on, restarting the program. How do you have that set up? 

Posted (edited)

OK, I ended up with 2 variables and 4 programs:

RecirRanRecently: An integer (not state) that is True (1) if pump has recently run

sOnVacay: A state variable that is True if we've set a Vacation Mode, which stops the pump from running automatically and turns lights on/off semi-randomly.

Repeat Loop(): A "Repeat While" loop that asks to run the Pump every 35 minutes.  Started at 7am and stopped at 10:30pm.

Bathroom Motion(): When the Motion Sensor detects motion, asks to run the Pump

Run If(): If Pump hasn't been run in last 15 minutes, runs the Pump routine

Run Once(): The routine that runs the pump. Only the "THEN" block is called and only from Run If(), so the Waits don't get interrupted. Uses $RecirRanRecently variable to prevent Run If() from calling it when it shouldn't. Runs pump for 1.75 minutes and then Waits for 13.25 minutes.

Run Once:
If
   - No Conditions - (To add one, press 'Schedule' or 'Condition')
Then
        $RecirRanRecently  = 1
        Set 'Recir Pump' On
        Wait  1 minute and 45 seconds
        Set 'Recir Pump' Off
        Wait  13 minutes and 15 seconds
        $RecirRanRecently  = 0
Else
   - No Actions - (To add one, press 'Action')
——
Run If:
If
        $RecirRanRecently is not 1
Then
        Run Program 'Run Once' (Then Path)
Else
   - No Actions - (To add one, press 'Action')
——
Bathroom Motion:
If
        'Bathroom Motion-Sensor' is switched On
    And $sOnVacay is not 1
    And $RecirRanRecently is not 1
Then
        Run Program 'Run If' (If)
Else
   - No Actions - (To add one, press 'Action')
——
Repeat Loop:
If
        From     6:59:00AM
        To      10:31:00PM (same day)
    And $sOnVacay is not 1
Then
        Repeat While $sOnVacay is not 1
           Run Program 'Run If' (If)
           Wait  35 minutes 
Else
   - No Actions - (To add one, press 'Action')

Run If() has two Waits that combine for a 15 minute minimum time period between successive pump runs. The Repeat Loop() program only asks for pump runs every 35 minutes. Motion in the bathroom will ask for a pump run if the 15 minute minimum time has elapsed. While Repeat Loop() only runs during waking hours, motion in the bathroom at any time can run the pump.

I thought about trying to reduce this to 3 programs instead of 4, but since Repeat Loop() might ask for a pump run soon after a Bathroom Motion requested and granted pump run I think it's needed. If we could compound the While clause of the Repeat instruction, such as:

  Repeat While ( ($sOnVacay is not 1) AND (sRecirRanRecently is not 1) )

Which isn't possible as I understand it. I could maybe create a third variable and have it be the sum of those two variables, and then have Repeat While ThirdVariable is 0, but I don't know about addition and of an integer and a state. Thoughts/ideas welcome.

Edited by smorgasbord
Posted
12 hours ago, dbwarner5 said:

Your motion sensor could be turning off, which would also stop the program, and then back on, restarting the program. How do you have that set up? 

Motion sensors set to ON Commands only, and there are no programs looking for a "switched Off." I also have about a 5 minute time-out so the motion sensor isn't constantly sending commands. 

Posted (edited)

Typically you disable the program rather than using lots of variables. Also, for flags, just use a PGM status rather than a 0/1 variable. 

 

Pgm1

If motion 

And PGM on vacation false

Then

Run then pgm2

 

Pgm2 disabled

If blank

Then

Disable pgm1

Turn on pump

Wait 15 minutes 

Enable pgm1

Turn off pump

 

 

Only caveat is if you happen to reboot during the 15 minute wait, the program will be disabled at start and be stuck. So I use a single program that runs at startup to ensure that all of those programs are set to the correct state. 

 

As a side note, programs with blank if will run true if set to run at startup. 

Edited by apostolakisl

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...