Jump to content

Detecting Daylight Savings Time occurrence with a Variable


kclenden

Recommended Posts

As ISY users eventually discover, any programs that are running timers (e.g. WAIT) stop executing when the time on the ISY either springs forward or falls back because of Daylight Savings TIme.  If those programs happen to loop so that they are long running programs serving a specific function like listening for a heartbeat from a device then they likely won't start running again until your ISY reboots or you open the Admin Console and restart them.  So I decided to try using a variable to detect a change in time caused by DST and have the ISY alert me when DST occurs and have it automatically restart my long running programs.  I wrote my programs  several month ago and then sort of forgot about them until 1:05am today when I got an alert from the ISY that a DST change had occurred.  That's probably the longest I've waited to see if a program actually works.

The idea is to have a variable count the hours from 12am to 3am and detect if the progression is the normal 0...1...2...3.  If it goes 0...1...1 then I know that fall back has happened.  If it goes 0...1...3 then I know spring forward has happened.  Here are the programs:

===================================================================================
Day Lights Savings - [ID 00BE][Parent 0001]

Folder Conditions for 'Day Lights Savings'

If
   - No Conditions - (To add one, press 'Schedule' or 'Condition')
 
Then
   Allow the programs in this folder to run.
 



-----------------------------------------------------------------------------------
DST_Alert - [ID 00C1][Parent 00BE]

If
        $sDST_Alert is $cTrue
 
Then
        
        // Wait a couple seconds because later we're changing the state
        // variable that kicks off this program
 
        Wait  5 seconds
        
        // Restart programs that would have been killed by DST change
 
        Run Program 'Outside Lights - Random Brightness' (If)
        Run Program 'GarageDoorSensor-Control 2' (Then Path)
        
        // Assumes Uptime program was killed by DST change before $iISY_Uptime_Counter was incremented
 
        $iISY_Uptime_Counter += 1
        $iISY_Uptime_Counter Init To $iISY_Uptime_Counter
        Run Program 'ISY Uptime' (Else Path)
        Send Notification to 'Text_KBC' content 'Day Lights Savings Time Alert'
        $sDST_Alert  = $cFalse
 
Else
   - No Actions - (To add one, press 'Action')
 



-----------------------------------------------------------------------------------
DST_Check_0 - [ID 00BA][Parent 00BE]

If
        Time is 12:05:00AM
 
Then
        
        // Need to initialize $iDST_Hour_Check so that the check at 1:05 knows
        // whether it's running after the 12:05 check or a second time in a row
        // because of "Fall Back"
 
        $iDST_Hour_Check  = 0
 
Else
   - No Actions - (To add one, press 'Action')
 



-----------------------------------------------------------------------------------
DST_Check_1 - [ID 00BB][Parent 00BE]

If
        Time is  1:05:00AM
    And $iDST_Hour_Check is 1
 
Then
        
        // $iDST_Hour_Check should have been set to 0 at 12:05AM.  The only way
        // for it to be 1 now is if 1:05AM happened and then happened again.
        // This should only occur during "Fall Back" when DST is changed from ON
        // to OFF and the clock goes from 2:00AM to 1:00AM
 
        $sDST_Alert  = $cTrue
        $iDST_Hour_Check  = 1
 
Else
        $iDST_Hour_Check  = 1
 



-----------------------------------------------------------------------------------
DST_Check_2 - [ID 00BD][Parent 00BE]

If
        Time is  2:05:00AM
 
Then
        
        // Need to update $iDST_Hour_Check so that the check at 3:05 knows
        // whether it's running after the 2:05 check or after the 1:05 check
        // because of "Spring Forward"
 
        $iDST_Hour_Check  = 2
 
Else
   - No Actions - (To add one, press 'Action')
 



-----------------------------------------------------------------------------------
DST_Check_3 - [ID 00BC][Parent 00BE]

If
        Time is  3:05:00AM
    And $iDST_Hour_Check is 1
 
Then
        
        // $iDST_Hour_Check should have been set to 2 at 2:05AM.  The only way
        // for it to be 1 now is if 2:05AM never happened.  This should only 
        // occur during "Spring Forward" when DST is changed from OFF to ON
        // and the clock goes from 2:00AM to 3:00AM
 
        $sDST_Alert  = $cTrue
        $iDST_Hour_Check  = 3
 
Else
        $iDST_Hour_Check  = 3
 



-----------------------------------------------------------------------------------
DST_Init_0 - [ID 00BF][Parent 00BE][Not Enabled][Run At Startup]

If
        From    12:05:00AM
        To       1:04:59AM (same day)
 
Then
        
        // This program should only run when the ISY starts up, either because
        // of a reboot or a power outage.  It initializes $iDST_Hour_Check so
        // that we can detect a Day Lights Savings Time change
        // 
        // The program should be disabled but set to Run at Startup
 
        $iDST_Hour_Check  = 0
 
Else
   - No Actions - (To add one, press 'Action')
 



-----------------------------------------------------------------------------------
DST_Init_1 - [ID 00C0][Parent 00BE][Not Enabled][Run At Startup]

If
        From     1:05:00AM
        To       2:04:59AM (same day)
 
Then
        
        // This program should only run when the ISY starts up, either because
        // of a reboot or a power outage.  It initializes $iDST_Hour_Check so
        // that we can detect a Day Lights Savings Time change
        // 
        // The program should be disabled but set to Run at Startup
 
        $iDST_Hour_Check  = 1
 
Else
   - No Actions - (To add one, press 'Action')
 



-----------------------------------------------------------------------------------
DST_Init_2 - [ID 00C2][Parent 00BE][Not Enabled][Run At Startup]

If
        From     2:05:00AM
        To       3:04:59AM (same day)
 
Then
        
        // This program should only run when the ISY starts up, either because
        // of a reboot or a power outage.  It initializes $iDST_Hour_Check so
        // that we can detect a Day Lights Savings Time change
        // 
        // The program should be disabled but set to Run at Startup
 
        $iDST_Hour_Check  = 2
 
Else
   - No Actions - (To add one, press 'Action')
 


 

Link to comment
13 hours ago, gzahar said:

Thanks for the heads up and the programs!  FYI, It's Daylight SAVING (no s) Time.

Sure it's Daylight Saving time, but after several years they add up to become plural.  ?  My only excuse is that I wrote my post at 1:45am which was really 2:45 am.

Link to comment
13 hours ago, gzahar said:

Upon further inspection of the programs, doesn't appear to be relevant to DST operation.

Yeah, none of the programs run in "DST_Alert" are relevant to DST operation.  They're just programs that got killed by the ISY reaction to DST that I need to restart.  I could make it clearer, and likely easier to support if I move all the "Run" statements into another program called "Restart Stopped Programs" and then ran it.

Link to comment

I'm implementing this.  I don't have much that gets confused, but I do have some heartbeats, an uptime timer, and a few other run time timers that appear to get thrown off.  Great idea.  

I wonder which technique is best for restarting heartbeats, including the full list as run program ____ (then) or just including 'if $sDST_Alert = $cTrue' in the If body of each heartbeat program?  Or even yet another "restart heartbeat" program that adds a few seconds of time between the restarts?   (I have like 18 heartbeat programs but actually need to add a few more too).

It seems like this would also make a great nodeserver, or addition to one of the existing dealing with holidays or sun-data.

Link to comment
10 hours ago, MrBill said:

I wonder which technique is best for restarting heartbeats, including the full list as run program ____ (then) or just including 'if $sDST_Alert = $cTrue' in the If body of each heartbeat program?

I think it's a toss-up.  Including the state variable in the body of the IF for each heartbeat program is the easiest thing to do when originally writing  a program, or creating new ones.  On the other hand, if you already have a bunch of heartbeat programs, including the full list as "run program ____ (then)" is easier than touching all the individual heartbeat programs.  Two additional benefits of the latter method is that 1) you can see which programs will be restarted in one place, without having to look at the IF of each program and 2) it's easier if you want to space out the restart of the heartbeat programs.

Link to comment
13 hours ago, kclenden said:

I think it's a toss-up.  Including the state variable in the body of the IF for each heartbeat program is the easiest thing to do when originally writing  a program, or creating new ones.  On the other hand, if you already have a bunch of heartbeat programs, including the full list as "run program ____ (then)" is easier than touching all the individual heartbeat programs.  Two additional benefits of the latter method is that 1) you can see which programs will be restarted in one place, without having to look at the IF of each program and 2) it's easier if you want to space out the restart of the heartbeat programs.

I ended up with the second so I could delay it a few seconds.  I once a problem where too many things ran at "sunset" and created the dreaded queue full errors in the error log, and ever since I've always tried to be aware of spacing things just slightly.  

this is a great set of programs!

Link to comment
13 hours ago, JBanaszak said:

@kclenden great programs...thanks for sharing!

I'm curious as to why you set your state variable trigger to $cFalse/$cTrue as opposed to 0 and 1?  Are their integer values set to the same elsewhere or are you using text strings (which I did not know was possible)?

They're just variables set to 0 and 1, makes code reading easier.  I used to do it, but now I tend have a lot of Flags rather than just true/false... like my away mode for example is no longer just false or true, instead -1=Off without Auto enable, 0= Off with auto enable, 1=On, with  auto disable, 2=On won't auto disable.

Link to comment
22 hours ago, JBanaszak said:

'm curious as to why you set your state variable trigger to $cFalse/$cTrue

 

9 hours ago, MrBill said:

They're just variables set to 0 and 1

As @MrBill says $cFalse and $cTrue are just integer variables that have been set to a constant value of 0 and 1, respectively.  They are used to make programs more readable.  The "c" at the beginning of the variable name indicates "constant".  My other variables have either an "i" or "s" at the beginning of the variable name to indicate "integer" or "state".

Link to comment
On 11/2/2020 at 12:40 AM, kclenden said:

I could make it clearer, and likely easier to support if I move all the "Run" statements into another program called "Restart Stopped Programs" and then ran it.

As it turns out, I should have done it this way.  Either that or put a "Wait 5 seconds" directly before the "$sDST_Alert  = $cFalse".  My "ISY_Uptime" program didn't get restarted and my theory is that there was a race between getting the program "Run" executed and the "IF" reacting to the change in "$sDST_Alert" which caused the program to switch from running the THEN to running the ELSE.  So I've now changed the alert program to have a WAIT statement before the variable change and moved the list of programs to restart to a separate program that won't be impacted by the IF reacting to the change in state variable.

DST_Alert - [ID 00C1][Parent 00BE]

If
        $sDST_Alert is $cTrue
 
Then
        
        // Wait a couple seconds because later we're changing the state
        // variable that kicks off this program and we want other programs
        // that react to $sDST_Alert to have a chance to run.
 
        Wait  5 seconds
        
        // Restart programs that would have been killed by DST change
 
        Run Program 'DST_Restart_Stopped_Programs' (Then Path)
        
        // Send notification of DST change
 
        Send Notification to 'Text_KBC' content 'Day Lights Savings Time Alert'
        
        // Wait a couple seconds because when we change $sDST_Alert the "IF" will
        // flip this program from executing the "THEN" to executing the "ELSE" and
        // it's possible that will keep some lines in the "THEN" from completing.
 
        Wait  5 seconds
        
        // Cancel DST alert
 
        $sDST_Alert  = $cFalse
 
Else
   - No Actions - (To add one, press 'Action')
 

 

Link to comment
22 minutes ago, kclenden said:

 

As @MrBill says $cFalse and $cTrue are just integer variables that have been set to a constant value of 0 and 1, respectively.  They are used to make programs more readable.  The "c" at the beginning of the variable name indicates "constant".  My other variables have either an "i" or "s" at the beginning of the variable name to indicate "integer" or "state".

Got it, makes sense.  Thanks for the reply to both of you!

Link to comment
  • 4 months later...
  • 5 weeks later...

With the TimeData node server, couldn't these programs might be much simpler with just two alternating programs and no variables needed?

Such as:

DST Spring Forward

If
        Time is  3:00:02AM
    And 'Nodeservers / ISY Time Data' DST is True

Then
        
        // insert programs to restart and notifications here
 
        Enable Program 'DST Fall Back'
        Disable Program 'DST Spring Forward'
 
Else
   - No Actions - (To add one, press 'Action')

========================
DST Fall Back

If
        Time is  1:00:02PM
    And 'Nodeservers / ISY Time Data' DST is False
 
Then
        
        // insert programs to restart and notifications here
 
        Enable Program 'DST Spring Forward'
        Disable Program 'DST Fall Back'
 
Else
   - No Actions - (To add one, press 'Action')
 

 

Link to comment

Your suggested programs would run each day at the programmed times and not just once after DST changes. You need to detect the change of DST from false to true, and vice versa. Once that's achieved (e.g. with a variable), then you don't really need the time of day conditions anymore...

Link to comment
3 hours ago, jfai said:

Your suggested programs would run each day at the programmed times and not just once after DST changes. You need to detect the change of DST from false to true, and vice versa. Once that's achieved (e.g. with a variable), then you don't really need the time of day conditions anymore...

The "IF" in only one program (the active one) is evaluated daily, but the TimeData node server DST flag doesn't change but twice a year. The first time the DST flag switches state is the only incident that occurs because the program (now True) then disables itself and enables the next DST program to watch for the next time it changes back.  Please feel free to show me if that is not the case. I don't see the need for a variable at all, the TimeData DST flag is your variable replacement. The only concern I have is the "IF" time and maybe instead of 2 seconds after DST shifts, it might be better to wait one minute to give the node server time to respond. 

 

Link to comment

If the TimeData NS works as you describe, your programs don't need the time of day conditions, you can fold them into one program, and you can just leave the program enabled all the time. Just don't set [Run At Startup].

If it is furthermore required that the programs affected by DST run at most once each year, more state is needed, e.g., a state variable with an initial value of 0.

Sample program:

If 
    'Nodeservers / ISY Time Data' DST is True
Then
    Repeat While $sDST_Run_State is not 1
        // insert programs to be run at start of DST here
        $sDST_Run_State Init To 1
        $sDST_Run_State = 1
Else
    Repeat While $sDST_Run_State is not -1
        // insert programs to be run at end of DST here
        $sDST_Run_State Init To -1
        $sDST_Run_State = -1

 

Link to comment
22 hours ago, jfai said:

If it is furthermore required that the programs affected by DST run at most once each year, more state is needed, e.g., a state variable with an initial value of 0.

Why have add a state variable if your IF statement works? Just use it on all DST dependent programs. Right? 

'Nodeservers / ISY Time Data' DST is True
Link to comment

That won't enforce 'program runs at most once each year'. If the TimeData NS restarts for some reason while Daylight Saving Time is in effect, it will set the 'DST' node to true. Then it depends on the status of the ISY and other conditions of the program whether or not the program runs.

Link to comment

The problem that the original programs in this thread solve, or the reason we need to programmatically know if a DST shift has occurred is because looping running programs stop when the time shifts and needs to be restarted.  Typically such things as wireless sensor heartbeat programs that have 'wait 25 hours' as a program statement...etc...

I had loaded the TimeData nodeserver once before but deleted it shortly there after because the ISY already calculates sunrise and sunset that is enough for my needs  One reason to use the the original @kclenden programs might be that you don't want the overhead of a nodeserver for just a single DST flag.  The ISY updates the Sunrise/Sunset tables once a day and I'm not sure why I would need a nodeserver that does it every hour instead.  Meaning that my sole reason for having the nodeserver would be the DST flag.  I see that the nodeserver also provides for a shift in season (Spring, summer, etc) but I don't use that programmatically in anything.

I think you would need to use this in conjunction with a program and variable to avoid runs during restarts etc.

If

    'Nodeservers / ISY Time Data' DST is True

And $iDSTFlag = 0

then

   ...do whatever

   Wait 10 seconds

   $iDSTFlag = 1to

  $iDSTFlag Init =1

 

And

If

    'Nodeservers / ISY Time Data' DST is False

And $iDSTFlag = 1

then

   ...do whatever

   Wait 10 seconds

   $iDSTFlag = 0

   $iDSTFlag Init = 0

 

the wait could probably be 1 second but i usually use at least 10 when changing a variable that was used in the IF statement of the same program.

 

The first program by @LFMc above that runs at 3:00:02 two problems that I perceive.....  First, the time should be greater than 2 seconds after the shift...Why?  The program runs based on ISY time.... if polyglots time is more than 2 seconds different the shift may not yet have occurred, so 3:02:00 would be a better choice.   Second, if we are restarting critical programs 3:00 is 2 hours after the "fall back" time shift.  That might be fine for most programs that are in an infinite loop, but it might not be too.  For example: something that might be running a pump for 1 minute every 15 minutes and might need to be restarted sooner.

Link to comment

@MrBill, Concurring with your statements, the programs you posted aren't semantically different from my single program. You don't need the Wait statements if changing a trigger variable is the last statement of the block. Notice the order of setting the init value and setting the value of the variable in my sample program.

Link to comment
13 minutes ago, jfai said:

@MrBill, Concurring with your statements, the programs you posted aren't semantically different from my single program. You don't need the Wait statements if changing a trigger variable is the last statement of the block. Notice the order of setting the init value and setting the value of the variable in my sample program.

I actually didn't understand your program the first time, but I just didn't spend enough time, it does seem to be an elegant single program solution. 

I can't think of the exact instance but I've had to add the wait... It may have been my goodnight routine that is long and has many Insteon, a few Network Resource, and at least one run another program in it, the problem was debugged years ago and I don't remember which item didn't run but adding a wait before resetting the variable solved the issue.    whatever works the 10 second wait doesn't create any overhead......

Link to comment

Perhaps the simplest approach is to do the following.  There are already two time nodes for ISY (ioguys nodelink version and polyglot version) Both have a true/false for DST.  When the True changes to False, or vice-versa, that will be a program trigger indicating you just switched to or from DST.  Makes no difference whether you put true or false in the if since it is just the change you are looking for.  By putting the exact same things into both then/else, these things happen when and only when the DST switches from True to False or vice-versa.  At ISY startup, it will have a true or false status, but it shouldn't run provided you don't click "run at startup" .  I haven't tested this, but I feel pretty good about it.

interupt - [ID 017E][Parent 0093][Not Enabled]

If
        'ISY Data' Daylight Savings is False
 
Then
        
        // Do the things you want to do when it switches
 
 
Else
        
        // Do the things you want to do when it switches
 
 

 

Link to comment
Perhaps the simplest approach is to do the following.  There are already two time nodes for ISY (ioguys nodelink version and polyglot version) Both have a true/false for DST.  When the True changes to False, or vice-versa, that will be a program trigger indicating you just switched to or from DST.  Makes no difference whether you put true or false in the if since it is just the change you are looking for.  By putting the exact same things into both then/else, these things happen when and only when the DST switches from True to False or vice-versa.  At ISY startup, it will have a true or false status, but it shouldn't run provided you don't click "run at startup" .  I haven't tested this, but I feel pretty good about it.
interupt - [iD 017E][Parent 0093][Not Enabled]If       'ISY Data' Daylight Savings is FalseThen       // Do the things you want to do when it switchesElse       // Do the things you want to do when it switches

 


I used new feature of nodelink that sends via relay a reboot ISY command. I save the value of DST in a variable. When the saved value does not equal the current value. I just reboot ISY. This prevents me from having to remember to add programs that have the time change Sensitivity. I’ve been doing same manually for years. I’ve got run at startup on all programs to ensure they set heartbeat etc in motion.
Link to comment

Archived

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


×
×
  • Create New...