OK, I know it took some time, but I've finally written another HAI Programming 101. This one concerns flags, and how to use them in programming.
What is a flag? You can think of it is an imaginary switch, sort of like, for example, a UPB or X-10 light switch that isn't connected to a fixture. Turning it on or off doesn't change anything in the house, but it does still have an on or off status. What's that good for? It's something that you can either trigger a block of code off of, or test within a block of code. Example: Some HAI users like to have a door chime function, where the console beeps whenever an entry door is opened. However, they don't want it to do it at all times of day; for instance, they might want it to be silenced during a child's afternoon nap time. The Omnis have a built-in door chime function; the trouble is, the only to turn it on or off is to go into the setup function that controls it, and automation code can't do that. So plan B is to write a block of code that beeps the console whenever the door is opened:
So far, this isn't an improvement over the built-in function. What we need is some way to tell the code when it's nap time, so that it doesn't beep when we don't want it to. We can use a flag for this. Where do we get a flag? Well, truth is, we often talk in this forum about "creating a flag", but all the available flags already exist. (On the OPII, you get 119 of them. I think the Omni IIe and LT have the same number, but I'm not sure about that; it may be fewer.) Where do you find them? In PC Access. Click on your "Setup" tab and look at the choices on the left; one of them is "Flags". Click on that, and you'll get to the flags screen.
The flags screen is where you assign names to flags. Assigning a name is what we usually mean when we say we are "creating" a flag; the truth is, the flag already exists, but since it doesn't have a name, it will not normally show up in the pick list when we are creating a line of code in a code block. You can change that, but you really don't want to get into the business of referring to flags by their numbers -- that way lies madness. Here's a screen shot of the flags screen:
Note the unit numbers, which start with 393. Don't use numbers 393 or 394 -- they are tied into the internal and external sounder circuits in some way that I don't understand, and if you try to use them, they will act strange. You can see here that I've started with 395. As in the case with lighting units, they each can have a short name and a long name. The short name is what appears on a console, but the long name is used most everywhere else, including in code listings in PC Access.
So for our problem above, we pick an unused flag and name it "Nap Time". Now, our block of code can check the flag to decide if it's nap time, and if so, not beep the console. It now looks like this:
Now, turning on the "Nap Time" flag will prevent the door chime from happening. We can, if we want, turn the flag on and off manually using PC Access by clicking on our Status/Control tab, selecting "Flags", and double-clicking on the Nap Time flag in the list and using the pop-up dialog box. However, if nap time is the same every day, we can have the code do it for us:
As in the case with lights, we can turn a flag on or off for a specified period of time, which allows us to use flags as timers. I have the following in my code:
"Garage door timer" is a flag. When block 60 runs (it's a button that I can run from the console or from the touch screen), after commanding both of the garage doors to close, it sets the timer for 18 seconds. This gives the door openers enough time to actually close the doors, plus a few seconds. When the time runs out, it changes the flag's status from ON to OFF, and that triggers block 63. This block checks to see if either of the two doors is still open (because they jammed or were blocked by some object in the door's path), and if so, it alerts me with a console message.
Unlike a real light, you can't "dim" a flag. However, you can assign a numeric value to a flag. It will accept values between 0 and 255. (Computer types will recognize this as the range of values representable in an 8-bit unsigned byte.) There is an action that will increment (add 1) to the value of a flag, but it will not increment past 255. There is also an action that will decrement (subtract 1) from the value of a flag, but it will not decrement lower than 0. I have a set of "house occupancy mode" flags defined in my code that I have coded to change the behavior of a number of default actions. For instance, I have an electric heater in the master bath, that warms it up on cold mornings. On weekdays, I want it to come on before I wake up so that the bath is already warm when i get up. But it also consumes a fair amount of power and I don't want it to run on days when it doesn't need to. I have the following code:
"House is unoccupied" and "Sleeping in" are both flags. I set "House is unoccupied" if we're away on a trip, and I set "Sleeping in" if we're not getting up at the normal weekday time (say, because it's a holiday). However, it's almost guaranteed that I will forget that I set them until the next day that I get up at my regular time to go to work, and the bathroom is cold. So here's what I do: I set them to the number of days that the condition (house is unoccupied, or sleeping is) is going to be true. The following block of code does the remembering for me:
At noon (okay, one minute past noon), it subtracts one from each of the flags. So if I'm taking Monday and Tuesday off from work, Sunday night I set the "Sleeping in" flag to 2. Monday morning, the bath heat does not come on. Monday at noon, the flag is decremented to 1. Tuesday morning, the bath heat does not come on. Tuesday at noon, the flag is decremented to 0. Wednesday morning, the bath heat does come on. Once the flag is back at 0, the decrement action doesn't do anything, until I set the flag nonzero again.
If a condition checks the on/off status of a flag that has a numeric value assigned to it, the flag will be considered to be "off" if its value is zero, and "on" otherwise. Further, if an increment or decrement action causes the on/off status of a flag to change, that will trigger blocks of code that trigger on that flag. (You can't trigger on the numeric value of a flag, but you can trigger on the on/off status changes.) An example: I have a relative who refinishes furniture in her garage. A finish she uses takes 48 hours to cure. Say she has an Omni and wants it to remind her when the finish is cured and she can move the piece to a shop. Now, if you've played with setting timers, you've probably already figured out that the maximum duration of a timer is 18 hours. How to time a 48-hour interval? Name a flag "Finish reminder", and then write the following:
When she applies a finish to a piece, she sets the "Finish reminder" flag to 48, using PC Access or some other method. That causes the flag's on/off status to change to "on". 48 hours later (less as much as 59 minutes, depending on how many minutes after the hour it was when she set the flag), block 135 decrements the flag from 1 to 0, which causes its on/off status to change to "off". That in turn triggers block 136, and she gets a console message. Once the flag is at 0, block 135 will not have any further effect until she sets the flag to a nonzero value again.
There is one exception to the zero/nonzero rule, which provides a useful trick for a particular situation. Sometimes, when you use a flag as a timer, you want to be able to "cancel" the timer before it expires. Consider: You suspect that your child is getting up in the middle of the night to play games or whatever. You decide that you are going to have your Omni tattle on him, by checking the status of the light in his room: if he turns on the light during what is supposed to be sleep time, your console will beep. However, you want to allow a few minutes' grace so he can turn on the light to go to the bathroom or get a glass of water. So you write this code:
This won't do what you want. It will tattle after five minutes; when the timer runs out, block 132 will be triggered. However, if the light is turned off within the five minutes, that will also trigger block 132. You need some way to shut off the timer without triggering block 132. Here's how you do it:
Setting a numeric value into the flag erases the timer value that was associated with it, without triggering any blocks that trigger on the flag's on/off status. So if the light is turned off within the five minutes, block 131 is triggered; it erases the five-minute timer and block 132 is not triggered.
Although you can't trigger on a specific numeric value of a flag, you can check its value in a condition. A condition can test to see if the flag is equal, not equal, less than, or greater than a given value. When a flag is being used as a timer, a condition can test the time remaining. A 5.7e or 10p touch screen page can retrieve and display the numeric value of a flag. Unfortunately, you can't do math on flags, other than the increment/decrement actions. However, for more sophisticated manipulation of flags, you could use OmniLink to connect them to an external application, such as Homeseer.
What is a flag? You can think of it is an imaginary switch, sort of like, for example, a UPB or X-10 light switch that isn't connected to a fixture. Turning it on or off doesn't change anything in the house, but it does still have an on or off status. What's that good for? It's something that you can either trigger a block of code off of, or test within a block of code. Example: Some HAI users like to have a door chime function, where the console beeps whenever an entry door is opened. However, they don't want it to do it at all times of day; for instance, they might want it to be silenced during a child's afternoon nap time. The Omnis have a built-in door chime function; the trouble is, the only to turn it on or off is to go into the setup function that controls it, and automation code can't do that. So plan B is to write a block of code that beeps the console whenever the door is opened:
Code:
1. WHEN Front door NOT READY
THEN All Consoles BEEP 1
So far, this isn't an improvement over the built-in function. What we need is some way to tell the code when it's nap time, so that it doesn't beep when we don't want it to. We can use a flag for this. Where do we get a flag? Well, truth is, we often talk in this forum about "creating a flag", but all the available flags already exist. (On the OPII, you get 119 of them. I think the Omni IIe and LT have the same number, but I'm not sure about that; it may be fewer.) Where do you find them? In PC Access. Click on your "Setup" tab and look at the choices on the left; one of them is "Flags". Click on that, and you'll get to the flags screen.
The flags screen is where you assign names to flags. Assigning a name is what we usually mean when we say we are "creating" a flag; the truth is, the flag already exists, but since it doesn't have a name, it will not normally show up in the pick list when we are creating a line of code in a code block. You can change that, but you really don't want to get into the business of referring to flags by their numbers -- that way lies madness. Here's a screen shot of the flags screen:
Note the unit numbers, which start with 393. Don't use numbers 393 or 394 -- they are tied into the internal and external sounder circuits in some way that I don't understand, and if you try to use them, they will act strange. You can see here that I've started with 395. As in the case with lighting units, they each can have a short name and a long name. The short name is what appears on a console, but the long name is used most everywhere else, including in code listings in PC Access.
So for our problem above, we pick an unused flag and name it "Nap Time". Now, our block of code can check the flag to decide if it's nap time, and if so, not beep the console. It now looks like this:
Code:
1. WHEN Front door NOT READY
AND IF Nap Time OFF
THEN All Consoles BEEP 1
Now, turning on the "Nap Time" flag will prevent the door chime from happening. We can, if we want, turn the flag on and off manually using PC Access by clicking on our Status/Control tab, selecting "Flags", and double-clicking on the Nap Time flag in the list and using the pop-up dialog box. However, if nap time is the same every day, we can have the code do it for us:
Code:
135. TIMED 3:00 PM MTWTFSS
THEN Nap Time ON
136. TIMED 4:00 PM MTWTFSS
THEN Nap Time OFF
As in the case with lights, we can turn a flag on or off for a specified period of time, which allows us to use flags as timers. I have the following in my code:
Code:
60. WHEN Garage Doors Close
THEN RUN Garage door west close
THEN RUN Garage door east close
THEN Garage door timer ON FOR 18 SECONDS
63. WHEN Garage door timer OFF
AND IF Garage door east side NOT READY
OR
AND IF Garage door west side NOT READY
THEN SHOW Garage door blocked WITH BEEP
THEN LOG Garage door blocked
"Garage door timer" is a flag. When block 60 runs (it's a button that I can run from the console or from the touch screen), after commanding both of the garage doors to close, it sets the timer for 18 seconds. This gives the door openers enough time to actually close the doors, plus a few seconds. When the time runs out, it changes the flag's status from ON to OFF, and that triggers block 63. This block checks to see if either of the two doors is still open (because they jammed or were blocked by some object in the door's path), and if so, it alerts me with a console message.
Unlike a real light, you can't "dim" a flag. However, you can assign a numeric value to a flag. It will accept values between 0 and 255. (Computer types will recognize this as the range of values representable in an 8-bit unsigned byte.) There is an action that will increment (add 1) to the value of a flag, but it will not increment past 255. There is also an action that will decrement (subtract 1) from the value of a flag, but it will not decrement lower than 0. I have a set of "house occupancy mode" flags defined in my code that I have coded to change the behavior of a number of default actions. For instance, I have an electric heater in the master bath, that warms it up on cold mornings. On weekdays, I want it to come on before I wake up so that the bath is already warm when i get up. But it also consumes a fair amount of power and I don't want it to run on days when it doesn't need to. I have the following code:
Code:
19. TIMED 5:50 AM MTWTF--
AND IF House is unoccupied CURRENT VALUE IS 0
AND IF Sleeping in CURRENT VALUE IS 0
THEN RUN Master Bath Heat
"House is unoccupied" and "Sleeping in" are both flags. I set "House is unoccupied" if we're away on a trip, and I set "Sleeping in" if we're not getting up at the normal weekday time (say, because it's a holiday). However, it's almost guaranteed that I will forget that I set them until the next day that I get up at my regular time to go to work, and the bathroom is cold. So here's what I do: I set them to the number of days that the condition (house is unoccupied, or sleeping is) is going to be true. The following block of code does the remembering for me:
Code:
24. TIMED 12:01 PM MTWTFSS
THEN DECREMENT Guests in upstairs bedrooms
THEN DECREMENT House is unoccupied
THEN DECREMENT At home during work hours
THEN DECREMENT Sleeping in
At noon (okay, one minute past noon), it subtracts one from each of the flags. So if I'm taking Monday and Tuesday off from work, Sunday night I set the "Sleeping in" flag to 2. Monday morning, the bath heat does not come on. Monday at noon, the flag is decremented to 1. Tuesday morning, the bath heat does not come on. Tuesday at noon, the flag is decremented to 0. Wednesday morning, the bath heat does come on. Once the flag is back at 0, the decrement action doesn't do anything, until I set the flag nonzero again.
If a condition checks the on/off status of a flag that has a numeric value assigned to it, the flag will be considered to be "off" if its value is zero, and "on" otherwise. Further, if an increment or decrement action causes the on/off status of a flag to change, that will trigger blocks of code that trigger on that flag. (You can't trigger on the numeric value of a flag, but you can trigger on the on/off status changes.) An example: I have a relative who refinishes furniture in her garage. A finish she uses takes 48 hours to cure. Say she has an Omni and wants it to remind her when the finish is cured and she can move the piece to a shop. Now, if you've played with setting timers, you've probably already figured out that the maximum duration of a timer is 18 hours. How to time a 48-hour interval? Name a flag "Finish reminder", and then write the following:
Code:
135. EVERY HOUR
THEN DECREMENT Finish reminder
136. WHEN Finish reminder OFF
THEN SHOW Finish is ready WITH BEEP
When she applies a finish to a piece, she sets the "Finish reminder" flag to 48, using PC Access or some other method. That causes the flag's on/off status to change to "on". 48 hours later (less as much as 59 minutes, depending on how many minutes after the hour it was when she set the flag), block 135 decrements the flag from 1 to 0, which causes its on/off status to change to "off". That in turn triggers block 136, and she gets a console message. Once the flag is at 0, block 135 will not have any further effect until she sets the flag to a nonzero value again.
There is one exception to the zero/nonzero rule, which provides a useful trick for a particular situation. Sometimes, when you use a flag as a timer, you want to be able to "cancel" the timer before it expires. Consider: You suspect that your child is getting up in the middle of the night to play games or whatever. You decide that you are going to have your Omni tattle on him, by checking the status of the light in his room: if he turns on the light during what is supposed to be sleep time, your console will beep. However, you want to allow a few minutes' grace so he can turn on the light to go to the bathroom or get a glass of water. So you write this code:
Code:
130. WHEN Child's bedroom light ON
THEN Tattle Flag ON FOR 5 MINUTES
131. WHEN Child's bedroom light OFF
THEN Tattle Flag OFF
132. WHEN Tattle Flag OFF
THEN SHOW The little brat's out of bed again! WITH BEEP
This won't do what you want. It will tattle after five minutes; when the timer runs out, block 132 will be triggered. However, if the light is turned off within the five minutes, that will also trigger block 132. You need some way to shut off the timer without triggering block 132. Here's how you do it:
Code:
130. WHEN Child's bedroom light ON
THEN Tattle Flag ON FOR 5 MINUTES
131. WHEN Child's bedroom light OFF
THEN Tattle Flag SET VALUE TO 0
132. WHEN Tattle Flag OFF
THEN SHOW The little brat's out of bed again! WITH BEEP
Setting a numeric value into the flag erases the timer value that was associated with it, without triggering any blocks that trigger on the flag's on/off status. So if the light is turned off within the five minutes, block 131 is triggered; it erases the five-minute timer and block 132 is not triggered.
Although you can't trigger on a specific numeric value of a flag, you can check its value in a condition. A condition can test to see if the flag is equal, not equal, less than, or greater than a given value. When a flag is being used as a timer, a condition can test the time remaining. A 5.7e or 10p touch screen page can retrieve and display the numeric value of a flag. Unfortunately, you can't do math on flags, other than the increment/decrement actions. However, for more sophisticated manipulation of flags, you could use OmniLink to connect them to an external application, such as Homeseer.