Do what when:In last week’s blog we covered how to set the real time clock (RTC) in a PAC Controller with an accurate time server over the Internet using SNTP.
Now that our controller knows exactly what time it is, how do we turn on that pump at 6:00 a.m. on the dot?
Like most aspects of programming, there are a few different ways to achieve the same result, so join me in this week’s blog while we look at one way to manage real-time scheduling.
Seconds since midnight:
Preface: Keep in mind that there is no hard-and-fast right or wrong way to do a lot of tasks in code. I often, probably wrongly, think of programming as being as much art as science. Perhaps that’s why I write more bugs than good code!
There are a slew of time-related commands in PAC Control. Please check out the fantastic manual for the full rundown, but in short, we can get the date and time all at once, or get the time, get the day of the year, the day of the week, the hour, the minutes, the seconds, and the number of seconds since midnight. Think of it as coarse time down to fine time, a year all the way down to seconds. With those options, it’s just down to the required resolution of your task at hand and your code comfort level to get that task done at the right time.
Let’s take a close look at working with seconds since midnight.
If your task is simply to turn on a pump (that is, turn on a digital output) at 6:00 a.m., then it's as simple as looking to see if the seconds since midnight equal 21,600, and if so, do it. The code might look like this:
// Test for our desired on time.
if (GetSecondsSinceMidnight() == 21600) then
I’m sure you can convert that to a flowchart if you are not comfortable in OptoScript. But to get you going, here is an outline. The only thing to note is the extra step in the "get seconds since midnight" block. We have to put the seconds since midnight value in a variable, since the flowchart won't let us get and check in one move like we can in OptoScript. In this example, I called the variable SSM.
Hint: Be sure that this OptoScript or flowchart code runs at least every second. Any less, and you may miss capturing the seconds-since-midnight value that you are checking against. How can we be sure if it runs often enough? Look through your code and make sure that the seconds since midnight code will run at least every 500 milliseconds. Just check the entire flow of your code for delays, and make sure none of them will keep this new section from running frequently enough.
Calculate the seconds since midnight.
Since we are talking about the number of seconds since a fixed point in time (midnight), it’s simple to do tasks at any time of the day. For example, if we need to start the pump at 6:30 a.m. rather than 6:00 a.m., then your code should test against the value 23400.
As you can see, it’s just a bit of math to convert the desired hours:minutes:seconds time into seconds since midnight, and thus any task can be done very quickly with precision in seconds. It is the main way that I did fixed-time scheduled tasks at the hospital when I worked there. Here’s the formula:
(Hours * 3600) + (Minutes * 60) + (Seconds) = Seconds Since Midnight
Hint: The result will always be a value between 0 and 86399 as there are 86400 seconds in a day.
You can use the same idea if you want a task to run for a set amount of time, but honestly, a timer might be better for something like that (programming; it’s art as much as science). If you do use seconds since midnight as a timer, keep in mind that the seconds will go back to zero and start counting up again. So be sure and check for that in your code if your task is going to run over the midnight threshold.
Time in a user interface (UI).
If you have a situation where you require a user interface to work with scheduled tasks, then having the user convert all their times to seconds since midnight might be a bit problematic. The solution perhaps then becomes a matter of choosing between a simple UI or simple code. What do I mean? If your user can enter the hours in one field, and the minutes in another, then your code simply has to check if the controller hours value is equal to the UI hours and if so, test the real-time minutes against the UI minutes.
Here is a really quick example of this in groov. The hours and minutes are two different text entry areas. Both are integers and each has its own variable name.
If you don’t want to test the real time against the UI hours and minutes, then you could plug these values into a bit of code that calculates the Seconds Since Midnight from the hours and minutes entered in groov (or whatever your UI happens to be), and you will have the SSM value to test against:
//hours minutes sec = SSM
(21 * 3600) + (30 * 60) + (0) = 77400
If on the other hand your UI requires that the time be entered something like "21:30" or "2130", then you’ll need to write some code to first convert the hours and minutes as a string or integer into a Seconds Since Midnight (SSM) integer value that can be tested against in the controller. The key is to remember that when testing time, it has got to be integers against integers. (Broadly speaking; but in case you are wondering, yes, you can test if two strings are equal. We will talk more about time as a string in a future blog).
Checking time within limits.
Another way to use seconds since midnight is to test if the time is between two values. In this way we can have a simple code structure to turn a point on and off. Here is an example in OptoScript:
// If the time is between 6am and 9.30pm turn on the pump
If (IsWithinLimits(GetSecondsSinceMidnight(), 21600, 77400)) then
Else // we are outside run time.
Note that this code will turn the pump on over and over within those times, and turn it off over and over when outside those times. Usually this is not a problem for local I/O points, but keep it in mind if the pump digital point is remote from the controller running the code.
Having a simple integer that increments in one-second intervals is pretty useful. The fact that it is also tied to a fixed point of real time is what makes it very powerful. From a simple equation we can work out what the real time is, what value the integer will be in the future, and a simple "if equal" or "if between these limits" check can allow us to schedule tasks with precision in seconds.
At the stroke of midnight:
We really have just scratched the surface with the time-based commands in PAC Control. For more inspiration on working with seconds since midnight, check out the Opto 22 Forums on the topic.
Till next week, Cheers Mate.