HAI Programming 101: How The Code Works

cornutt

Active Member
It occurred to me that a lot of the programming examples we've put here so far have been fairly involved. There's not a lot out there that really tells new HAI users how to get started with automation and writing code for the controller, so I'm going to start a series here on basics of programming automation code for the Omni/Lumina series.

First of all, if you want to write automation code for your Omni or Lumina controller, you really really need PC Access. Since version 3.0 of the Omni firmware introduced multiple and compound conditions, it is no longer really possible to do programming through a console. And even if it was, you really do not want to do things that way -- the interface is just too limited. The end user version is about $50 at the authorized online outlets; the part number is 1106W.

The automation code is divided into blocks, which are independent chunks of code. Each block consists of the following, in this order:

  • At least one trigger
  • Zero or more conditions
  • At least one action

A block of code is executed when its trigger event occurs. An event is when the status of something that the system keeps track of changes -- the time of day, a light being turned on or off, the alarm being armed or disarmed, the status of a security zone, a scene being selected, etc. The trigger condition specifies which event should cause the block of code to be entered. If the block has more than one trigger, the occurrence of any of its trigger events will cause the block to be entered. The block is entered only once; it is not entered again until an event specified by one of its trigger clauses occurs again.

Two of the easiest-to-understand triggers are TIMED and EVERY. TIMED events occur at a specified time of day, or at a time relative to sunrise or sunset. They can be further qualified to only occur on a specific date, or on certain days of the week. Here is an example:

Code:
36.	TIMED 6:20 PM M-W-F--
			THEN SET LIGHTING LEVEL Entrance hall overheads TO 75%

This is exactly how the code appears in PC Access. (The number "36" at left is a sequential block number that PC Access adds; it is not part of the code.) The triggering event for this block will occur when the time becomes 6:20 PM, but only on Mondays, Wednesdays, and Fridays. Note that it will be triggered only once on that day, when the time rolls over from 6:19:59 to 6:20:00; it will not keep reoccurring until the time becomes 6:21.

An EVERY event happens at a specified interval. A simple example:
Code:
15.	EVERY 4 HOURS
			THEN LOG Mark Time

This will write a message to the system log every four hours. Interval settings allowed range from 5 seconds to 12 hours. Note that the triggering event occurs when the time of day is evenly divisible by the interval; it is not based on when the controller was started up. So, in the example above, if we start the controller at 2:33 PM, the first time this block of code will be executed will not be at 6:33 PM; it will be at 4:00 PM.

Here is an example with more than one trigger:

Code:
6.	WHEN Garage door 1 NOT READY
	WHEN Garage door 2 NOT READY
			THEN Workbench and interior door lts ON FOR 10 MINUTES

This code will be entered when either of the two garage doors is opened. (The doors each have a magnetic sensor which is connected to a zone on the controller.)

Note that it is legal for two or more blocks to specify the same trigger. In this case, when the triggering event occurs, each block will be entered in the order that they appear in PC Access. A following block will not be entered until the preceding block has completed.

Next I'll discuss actions (I'll come back to conditions in a bit). Actions are things that the controller can do -- turn lights on and off, change thermostat settings, or arm/disarm the alarm, to name a few. With only a few exceptions, anything that your Omni or Lumina is capable of doing, you can do with an action. In the code listing, all actions start with the word "THEN". An example:

Code:
34.	TIMED 20 MINUTES BEFORE SUNSET MTWTFSS
			THEN Kitchen soffit cans ON
			THEN Rec room TV lamp ON
			THEN Front porch lights ON
			THEN Exterior floodlights ON
			THEN LOG Evening lights on

At the specified time, this code block is executed, and it turns on the specified lights and logs the message. Actions always occur in the specified order, so in this code block, the kitchen soffit fans will be turned on first, and the message logging will be the last thing that happens.

(Note about the trigger: The controller calculates the time of sunrise and sunset each day. It does this based on your latitude, longitude, and time zone, which is why it is important to set these properly when you install your system.)

Now, about conditions. What conditions allow you to do is check additional criteria before the actions in a block are executed. This makes the decision to execute a block much more sophisticated than what can be accomplished with triggers alone. Whatever combination of conditions is specified, they must collectively evaluate to a true statement. If they don't, the block is executed immediately and none of the actions in the block are executed. In the code listing in PC Access, all conditions begin with the word "AND". An example:

Code:
18.	TIMED 5:30 AM MTWTF--
	TIMED 7:30 AM -----SS
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 35 
			THEN Main Floor Tstat HEAT SETPOINT 71

First of all, we see that this block has two trigger conditions. It will be entered at 5:30 AM on weekdays, or 7:30 AM on weekends. The condition (the line starting with AND) will then check to see if the outdoor temperature is below 35 degrees. Only if this is true will the action be executed. If the outdoor temperature is 35 or above, the thermostat's heat setpoint will not be changed.

Note the difference between a trigger and a condition. This block's triggers are the two times of day and days of week specified. The outdoor temperature sensor's value is, in this case, not being used as a trigger; a change in the outdoor temperature cannot trigger this block. Rather, when the block is entered, the condition checks the value of the outdoor temperature at that moment, and it makes a decision based on that.

You can combine conditions. Normally, conditions are combined with an "AND" operation such that they must all be true in order for the actions to be executed. However, you can separate groups of conditions with an "OR" statement, and the total condition will evaluate to true of either of the two groups evaluates to true. In grouping, AND has priority over OR. This is all easier to understand by looking at an example, so here is a fairly complex one:

Code:
19.	TIMED 5:50 AM MTWTF--
		AND IF Main Floor Tstat SYSTEM MODE IS HEAT 
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 60 
		OR
		AND IF Main Floor Tstat SYSTEM MODE IS AUTO 
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 53 
		OR
		AND IF Main Floor Tstat SYSTEM MODE IS EMERGENCY HEAT 
		OR
		AND IF Master Bath Heat Special ON
			THEN Master bath heater ON FOR 40 MINUTES

The master bath heater will be turned on for 40 minutes if at least one of the following is true:
* The main floor thermostat is in the heat mode, and the outdoor temperature is below 60.
* The main floor thermostat is in the auto mode, and the outdoor temperature is below 53.
* The main floor thermostat is in the emergency heat mode.
* The "master bath heat special" flag is on. (I'll talk about flags in a future installment.)

A few further notes about how conditions are evaluated: A light that is dimmable is considered "on" unless it is completely off. (If you look at the light unit's status in PC Access and it says "LEVEL xx%", it's on.) A condition that tests to see if the security mode is NIGHT will also be considered true if the mode is NIGHT DELAY; similarly, a condition that tests for DAY mode will be true if the current mode is DAY INSTANT, and a condition that tests for AWAY mode will be true if the current mode is VACATION. When a condition tests for a time of day, the beginning of the day is considered 12:01 AM and the end of the day is considered midnight; thus, a condition that tests to see if the time is greater than 10:00 AM will be true if the time is between 10:01 AM and midnight.
 
It occurred to me that a lot of the programming examples we've put here so far have been fairly involved. There's not a lot out there that really tells new HAI users how to get started with automation and writing code for the controller, so I'm going to start a series here on basics of programming automation code for the Omni/Lumina series.

First of all, if you want to write automation code for your Omni or Lumina controller, you really really need PC Access. Since version 3.0 of the Omni firmware introduced multiple and compound conditions, it is no longer really possible to do programming through a console. And even if it was, you really do not want to do things that way -- the interface is just too limited. The end user version is about $50 at the authorized online outlets; the part number is 1106W.

The automation code is divided into blocks, which are independent chunks of code. Each block consists of the following, in this order:

  • At least one trigger
  • Zero or more conditions
  • At least one action

A block of code is executed when its trigger event occurs. An event is when the status of something that the system keeps track of changes -- the time of day, a light being turned on or off, the alarm being armed or disarmed, the status of a security zone, a scene being selected, etc. The trigger condition specifies which event should cause the block of code to be entered. If the block has more than one trigger, the occurrence of any of its trigger events will cause the block to be entered. The block is entered only once; it is not entered again until an event specified by one of its trigger clauses occurs again.

Two of the easiest-to-understand triggers are TIMED and EVERY. TIMED events occur at a specified time of day, or at a time relative to sunrise or sunset. They can be further qualified to only occur on a specific date, or on certain days of the week. Here is an example:

Code:
36.	TIMED 6:20 PM M-W-F--
			THEN SET LIGHTING LEVEL Entrance hall overheads TO 75%

This is exactly how the code appears in PC Access. (The number "36" at left is a sequential block number that PC Access adds; it is not part of the code.) The triggering event for this block will occur when the time becomes 6:20 PM, but only on Mondays, Wednesdays, and Fridays. Note that it will be triggered only once on that day, when the time rolls over from 6:19:59 to 6:20:00; it will not keep reoccurring until the time becomes 6:21.

An EVERY event happens at a specified interval. A simple example:
Code:
15.	EVERY 4 HOURS
			THEN LOG Mark Time

This will write a message to the system log every four hours. Interval settings allowed range from 5 seconds to 12 hours. Note that the triggering event occurs when the time of day is evenly divisible by the interval; it is not based on when the controller was started up. So, in the example above, if we start the controller at 2:33 PM, the first time this block of code will be executed will not be at 6:33 PM; it will be at 4:00 PM.

Here is an example with more than one trigger:

Code:
6.	WHEN Garage door 1 NOT READY
	WHEN Garage door 2 NOT READY
			THEN Workbench and interior door lts ON FOR 10 MINUTES

This code will be entered when either of the two garage doors is opened. (The doors each have a magnetic sensor which is connected to a zone on the controller.)

Note that it is legal for two or more blocks to specify the same trigger. In this case, when the triggering event occurs, each block will be entered in the order that they appear in PC Access. A following block will not be entered until the preceding block has completed.

Next I'll discuss actions (I'll come back to conditions in a bit). Actions are things that the controller can do -- turn lights on and off, change thermostat settings, or arm/disarm the alarm, to name a few. With only a few exceptions, anything that your Omni or Lumina is capable of doing, you can do with an action. In the code listing, all actions start with the word "THEN". An example:

Code:
34.	TIMED 20 MINUTES BEFORE SUNSET MTWTFSS
			THEN Kitchen soffit cans ON
			THEN Rec room TV lamp ON
			THEN Front porch lights ON
			THEN Exterior floodlights ON
			THEN LOG Evening lights on

At the specified time, this code block is executed, and it turns on the specified lights and logs the message. Actions always occur in the specified order, so in this code block, the kitchen soffit fans will be turned on first, and the message logging will be the last thing that happens.

(Note about the trigger: The controller calculates the time of sunrise and sunset each day. It does this based on your latitude, longitude, and time zone, which is why it is important to set these properly when you install your system.)

Now, about conditions. What conditions allow you to do is check additional criteria before the actions in a block are executed. This makes the decision to execute a block much more sophisticated than what can be accomplished with triggers alone. Whatever combination of conditions is specified, they must collectively evaluate to a true statement. If they don't, the block is executed immediately and none of the actions in the block are executed. In the code listing in PC Access, all conditions begin with the word "AND". An example:

Code:
18.	TIMED 5:30 AM MTWTF--
	TIMED 7:30 AM -----SS
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 35 
			THEN Main Floor Tstat HEAT SETPOINT 71

First of all, we see that this block has two trigger conditions. It will be entered at 5:30 AM on weekdays, or 7:30 AM on weekends. The condition (the line starting with AND) will then check to see if the outdoor temperature is below 35 degrees. Only if this is true will the action be executed. If the outdoor temperature is 35 or above, the thermostat's heat setpoint will not be changed.

Note the difference between a trigger and a condition. This block's triggers are the two times of day and days of week specified. The outdoor temperature sensor's value is, in this case, not being used as a trigger; a change in the outdoor temperature cannot trigger this block. Rather, when the block is entered, the condition checks the value of the outdoor temperature at that moment, and it makes a decision based on that.

You can combine conditions. Normally, conditions are combined with an "AND" operation such that they must all be true in order for the actions to be executed. However, you can separate groups of conditions with an "OR" statement, and the total condition will evaluate to true of either of the two groups evaluates to true. In grouping, AND has priority over OR. This is all easier to understand by looking at an example, so here is a fairly complex one:

Code:
19.	TIMED 5:50 AM MTWTF--
		AND IF Main Floor Tstat SYSTEM MODE IS HEAT 
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 60 
		OR
		AND IF Main Floor Tstat SYSTEM MODE IS AUTO 
		AND IF Outdoor Temp Sensor CURRENT READING IS LESS THAN 53 
		OR
		AND IF Main Floor Tstat SYSTEM MODE IS EMERGENCY HEAT 
		OR
		AND IF Master Bath Heat Special ON
			THEN Master bath heater ON FOR 40 MINUTES

The master bath heater will be turned on for 40 minutes if at least one of the following is true:
* The main floor thermostat is in the heat mode, and the outdoor temperature is below 60.
* The main floor thermostat is in the auto mode, and the outdoor temperature is below 53.
* The main floor thermostat is in the emergency heat mode.
* The "master bath heat special" flag is on. (I'll talk about flags in a future installment.)

A few further notes about how conditions are evaluated: A light that is dimmable is considered "on" unless it is completely off. (If you look at the light unit's status in PC Access and it says "LEVEL xx%", it's on.) A condition that tests to see if the security mode is NIGHT will also be considered true if the mode is NIGHT DELAY; similarly, a condition that tests for DAY mode will be true if the current mode is DAY INSTANT, and a condition that tests for AWAY mode will be true if the current mode is VACATION. When a condition tests for a time of day, the beginning of the day is considered 12:01 AM and the end of the day is considered midnight; thus, a condition that tests to see if the time is greater than 10:00 AM will be true if the time is between 10:01 AM and midnight.


thanks this is great, I am trying to learn how to program my HAI unit and it is not very strait forward.

a couple question do you know of a good resource besides this site to learn all about programing your HAI unit with examples of code and how too?

also I am trying to create and set a flag but I am not sure how to do that. what I would like to do is turn on all the light in the house for 10mn. I was told that i need to create a flag with a timer but I am not sure how to do that.
 
Hey Cornnutt, Thank you for your post. It covers really important symantics that are not covered in the manuals (anywhere I have found anyway).

I think it does well to post a few Flag usage examples as well. I feel motivated to contribute, so in my next couple of posts I am going to include some basic stuff I think any integrator may do well to at least be exposed to (initially).

Cheers, HTH
 
Flags Example 1
In this segment...

a) When the resident/guest leaves the premises, we run some outside lights for a short period so the parking and surrounding areas are lit while leaving (because the motion sensor lighs sometimes time-out too soon). Some of the lighting is controlled directly, and some via buttons, so we employ flags to help manage this.

B) Oftentimes the Tsat is left on hold. Heat/Cool Setpoints are ineffective while Hold is on. If the resident/guest leaves for an evening out, or a day away, and Tstat is on hold, we may wish to accommodate them to return to a comfortable indoor climate, especially in harsher climates. However, if they don't return for an extended period, we want the facility to take back control. The example below uses a flag with a counter to create a cascading timer to manage this over a period that exceeds the default time-limit will allow.


Code:
<snip>
6. //    ====================================
//    When Securing Away, At the start ...
//    -------------------------------------
//    Note: Security_Off/Nite/Day_Modes_FLAG Flag
//    Allows home automations during Arm Off or Day or Nite
//	 - set to Off only when Arming Away, then On when Entering+Disarming
//    (We'll review this flag's usage later)
7. WHEN ARM AWAY
   THEN SAY STUFF
   THEN SAY SIXTY SECONDS TO EXIT (Short Pause) GOODBYE
   THEN Security_Off/Nite/Day_Modes_FLAG OFF
8. WHEN ARM AWAY
  AND IF DARK
   THEN Garage ON FOR 15 MINUTES
   THEN RUN Out-Lts-50%
9. //    =======================================
//    When Securing Away, After 60 second Exit Delay times out...
10. WHEN AWAY
   THEN RUN Lights Off
   THEN T-Stat LvRm HEAT SETPOINT 50
   THEN T-Stat LvRm COOL SETPOINT 85
   THEN SET Tstat_Hold_Reset_Flag TO 1	  <--set tstat flag
   THEN Tstat_Hold_Counter ON FOR 18 HOURS  <--initialize tstat timer
   THEN Camera ON
   THEN Flag allOffDelay ON FOR 90 SECONDS  <--set flag for outside lights delay-off

11. //    ====================================
//    90 seconds after Secured Away...
//    Turn Off the Outside Lights if its Dark
12. WHEN Flag allOffDelay OFF
  AND IF DARK
   THEN Garage OFF	  <--this line not needed, Garage light is a unit
											 <--I already set it to time out up in #8
   THEN RUN Out-Lts-Off <--but Out-Lts-50% was a button action, so we need this complimentary button action

13. //    Cascade Counter - If Tstat was set on Hold, Setpoints are not affected When Arm Away
//    This Timer Allows Tstat to remain on Hold for up to 30hours before Resetting
//    So if you go away longer than 30 hours the House then takes back control.
//    Note that since 18hours is the longest unit duration available, we have
//    to cascade a custom timed counter to do 30 hours.
//    Tstat flag and counter were initially set above "WHEN AWAY" trigger
14. WHEN Tstat_Hold_Counter OFF
  AND IF House AWAY
  AND IF Tstat_Hold_Reset_Flag ON
   THEN DECREMENT Tstat_Hold_Reset_Flag
   THEN Tstat_Hold_Counter ON FOR 12 HOURS   <--adds 12h onto the initial 18h
15. WHEN Tstat_Hold_Counter OFF
  AND IF House AWAY
  AND IF Tstat_Hold_Reset_Flag OFF
  AND IF T-Stat LvRm HOLD MODE IS ON
   THEN T-Stat LvRm HOLD OFF
   THEN T-Stat LvRm HEAT SETPOINT 50
   THEN T-Stat LvRm COOL SETPOINT 85
16. //    Another Device can also be controlled for the 30hour away trigger
<snip>


Note how at the initial "WHEN AWAY" trigger we still set the Tstat Setpoints. That way, if Tstat "HOLD" was not on at the time, everything sets as desired.

End Flag example 1
 
BTW, if any of my examples resemble work that could be better handled another way, then by all means post!


Flags 2 Example
In this segment...

Sometimes you want to set a group of objects/actions to respond for a specified time.
Problem is, you cannot specify a timeout for a Button Group.
To tackle this problem, I use a flag. Here's an example...


Code:
3.  WHEN BURGLARY ALARM
		    THEN RUN Stuff (number of lines, includes soem Lites_On_Macros stuff)
		    THEN BushLightsSwitchFlag ON FOR 20 MINUTES
		    THEN 20 Min. timer for lights ON FOR 20 MINUTES

4.  WHEN 20 Min. timer for lights OFF
		    THEN RUN This_Lites_Off_Macro
		    THEN RUN That_Lites_Off_Macro

72.  WHEN Driveway NOT READY
	    AND IF Drive Timer ON
		    THEN BushLightsSwitchFlag ON FOR 10 MINUTES

106.    //    ===================================================================
    	   //    When BushLitesFlag On for XX mins, Then BushLitesGroup On for Same

107.    WHEN Bush_Lites_Group_On
		    THEN Bush_Lites ON
		    THEN Backyard North Birch Lite ON

108.    WHEN Bush_Lites_Group_Off
		    THEN Bush_Lites OFF
		    THEN Backyard North Birch Lite OFF

109.    WHEN BushLightsSwitchFlag ON
		    THEN RUN Bush_Lites_Group_On

110.    WHEN BushLightsSwitchFlag OFF
		    THEN RUN Bush_Lites_Group_Off

    //    ===================================================================
169.  WHEN X-10 A-16 ON
		    THEN RUN Bush_Lites_Group_On
170.  WHEN X-10 A-16 OFF
		    THEN RUN Bush_Lites_Group_Off
 
Flags 3 Example
In this segment... Seasonal Pumps. Season defined by Client, and easily adjusted to suit.
I included something from a fountain as well...


Code:
111.  //    ##########################################
	  //	    7b) PUMPS: Never On in Winter
	  //			   Automated Off-Winter Months
	  //    ##########################################
112.  //    --------------------------------------------------------
	  //	  Safety Check- each day that PumpSeason Flag is properly set
	  //	  Set to 1 during Spring/Summer Season
113.  //    ---------- Pump Season: Spring/Summer Active ----------------
	  //	  PumpSeason TO 1 to activate, 0 to deactivate
114.  TIMED 3:45 AM MTWTFSS
	    AND IF DATE IS GREATER THAN 4/29
	    AND IF DATE IS LESS THAN 9/30
		    THEN SET PumpSeason TO 1
115.  //    ---------- Pump Season: Fall/Winter Non-Active ----------------
116.  TIMED 3:46 AM MTWTFSS
	    AND IF DATE IS LESS THAN 4/30
	    OR
	    AND IF DATE IS GREATER THAN 9/29
		    THEN SET PumpSeason TO 0
117.  //    ----------- Pumps Management ---------------------------
	  //    To Temporarily disable Pumps Management
	  //    CHANGE THEN Pumps ON FOR 2 HOURS
	  //    AND    THEN PUMPS ON FOR 4 HOURS
	  //    ...to something like Then UNIT 511 ON for XXX hours
	  //    ...until we lite these back up again
118.  TIMED 10:00 AM MTWTFSS
	    AND IF PumpSeason ON
		    THEN UNIT 511 ON FOR 2 HOURS
119.  TIMED 4:00 PM MTWTFSS
	    AND IF PumpSeason ON
		    THEN UNIT 511 ON FOR 4 HOURS







Now here's a twist. This Fontain runs off a Button instead of directly, so the occupant can never switch it on outside of Pumpseason.....



Code:
120.  //    ---------- Fountain Management ----------------
121.  WHEN FountainPumpSwitchOn
	    AND IF PumpSeason ON
		    THEN Fountain_Pump ON
122.  WHEN FountainLightSwitchOn
	    AND IF PumpSeason ON
		    THEN Fountain_Lite ON
123.  //    TEMP - while Fountain is running 24/7, turn it off for an hour each nite
124.  TIMED 3:17 AM MTWTFSS
	    AND IF PumpSeason ON
		    THEN Fountain_Pump OFF FOR 1 HOUR
	  // ---------- 8) X-10  BUTTON COMMAND PROGRAMS -----------
157.  WHEN X-10 A-10 ON
		    THEN RUN FountainPumpSwitchOn
158.  WHEN X-10 A-10 OFF
		    THEN Fountain_Pump OFF   <<- safe to do this directly
 
This almost seems useless, but I am going to include it, as it may be helpful in other cases...


Flag 4 example

Combining conditions into a Flag for
- use as a substitute condition, and also
- using a Flag's setting for differentiating between various states of different objects.




Before I learned that I could differentiate the Away modes for conditions, I was managing lighting using
- timed trigger
- then If AREA X OFF (meaning house disarmed)

That's because when I first was introduced to the system this was the code employed by the contractor of the time (back in version 2).


So later, I was trying to figure out how to combine specific Away Conditions in order to avoid repetitive code blocks.

So while in this particular circumstance this may not be a necessary method for accomplishing what I wanted, it still demonstrates a method of combining conditions into a Flag for use as a substitute condition, and also using a Flag's setting for differentiating between various states of different objects.

There are various situations where this can save you lines of code, while helping you manage a number of different (logic) triggers in tandem (for a single group of actions).


a) Below, I wanted to allow the Lighting automations to function when the occupant Armed DAY or NITE. Like I said, I didn't know I could simply do...
- timed trigger
- if Day
- OR
- if Nite
- OR
- if Off
- do stuff


...I thought I need some other way to differentiate which AWAY, including Off, I wanted to target.

In this eample I use "AwayType_0off_1Away_2Day_3Nite_FLAG" as my flag....
You could, of course, include the rest of the away modes, and/or also use a number that 'tags' a specific state, say for instance, 'Nite', to also resemble a 'tag' for one or more other related things for 'Nite'...


Code:
<snip>
XX.  WHEN House AWAY
		    THEN stuff/lines
		    THEN SET AwayType_0off_1Away_2Day_3Nite_FLAG TO 1  <<flag indicates type of Away setting
28.  WHEN House DAY
		    THEN SET AwayType_0off_1Away_2Day_3Nite_FLAG TO 2  <<flag indicates type of Away setting
34.  WHEN House NIGHT
		    THEN SET AwayType_0off_1Away_2Day_3Nite_FLAG TO 3  <<flag indicates type of Away setting
20.  WHEN House OFF
	    AND IF AwayType_0off_1Away_2Day_3Nite_FLAG 1   <<--if house was armed away, not 'day' or 'nite'
		    THEN SAY and do sutff, including lights and Tstat, etc
		    THEN SET AwayType_0off_1Away_2Day_3Nite_FLAG TO 0  <<flag indicates type of Away setting (Off)
41. WHEN House OFF
	    AND IF AwayType_0off_1Away_2Day_3Nite_FLAG CURRENT VALUE IS GREATER THAN 1 <<-- if its Away type Day or NIte
		    THEN SAY and Do stuff relevant to disarming from Day/Nite Modes
		    THEN SET AwayType_0off_1Away_2Day_3Nite_FLAG TO 0   <<flag indicates type of Away setting (Off)

    //		   *** 3)  TIMED LIGHTS SECTION   ***
    //    Use Flag instead of "if Area X Off" for allowing automations during Arm Day/Nite as well as Off
    //    (which is what it used to be)
    //    Lots of Timed Lighting, for example....
47. TIMED SUNRISE MTWTFSS
	    AND IF AwayType_0off_1Away_2Day_3Nite_FLAG CURRENT VALUE IS GREATER THAN 1
		    THEN RUN Stuff

Other types of Target Conditions:
  AND IF AwayType_0off_1Away_2Day_3Nite_FLAG CURRENT VALUE IS GREATER THAN 1  <<-- Day/Nite Modes
  AND IF AwayType_0off_1Away_2Day_3Nite_FLAG CURRENT VALUE IS #  <<-- Specify Mode
   etc


Like I said, you don't really need this for the specified application in the example. I almost didn't post this, however, I think it is a simple way of demonstrating a useful method for employing Flags for tagging related things into a value, and using that value as a condition.
 
Flags 5 Example
In this segment... Seasonal Pumps. Season defined by Client, and easily adjusted to suit.
I included something from a fountain as well for demonstrating handlnig a Button object as opposed to a device-directly...


Code:
111.  //    ##########################################
	  //	    7b) PUMPS: Never On in Winter
	  //			   Automated Off-Winter Months
	  //    ##########################################
112.  //    --------------------------------------------------------
	  //	  Safety Check- each day that PumpSeason Flag is properly set
	  //	  Set to 1 during Spring/Summer Season
113.  //    ---------- Pump Season: Spring/Summer Active ----------------
	  //	  PumpSeason TO 1 to activate, 0 to deactivate
114.  TIMED 3:45 AM MTWTFSS
	    AND IF DATE IS GREATER THAN 4/29
	    AND IF DATE IS LESS THAN 9/30
		    THEN SET PumpSeason TO 1
115.  //    ---------- Pump Season: Fall/Winter Non-Active ----------------
116.  TIMED 3:46 AM MTWTFSS
	    AND IF DATE IS LESS THAN 4/30
	    OR
	    AND IF DATE IS GREATER THAN 9/29
		    THEN SET PumpSeason TO 0
117.  //    ----------- Pumps Management ---------------------------
	  //    To Temporarily disable Pumps Management
	  //    CHANGE "THEN Pumps ON FOR 2 HOURS"
	  //    AND    "THEN PUMPS ON FOR 4 HOURS"
	  //    ...to something like "Then UNIT 511 ON for XXX hours"
	  //    ...until we lite these back up again
118.  TIMED 10:00 AM MTWTFSS
	    AND IF PumpSeason ON
		    THEN UNIT 511 ON FOR 2 HOURS
119.  TIMED 4:00 PM MTWTFSS
	    AND IF PumpSeason ON
		    THEN UNIT 511 ON FOR 4 HOURS






Now here's a twist. This Fountain runs off a Button instead of directly, so the occupant can never switch it on outside of Pumpseason, neither can a macro cause it to go on..... just as with "Pumps" switches, we never call any of the Fountain switches directly, only ever thru its singular Button (#s 121 + 122).

Code:
120.  //    ---------- Fountain Management ----------------

121.  WHEN FountainPumpSwitchOn
	    AND IF PumpSeason ON
		    THEN Fountain_Pump ON

122.  WHEN FountainLightSwitchOn
	    AND IF PumpSeason ON
		    THEN Fountain_Lite ON

123.  //    TEMP - while Fountain is running 24/7, turn it off for an hour each nite

124.  TIMED 3:17 AM MTWTFSS
	    AND IF PumpSeason ON
		    THEN Fountain_Pump OFF FOR 1 HOUR


	  // ---------- 8) X-10  BUTTON COMMAND PROGRAMS -----------

157.  WHEN X-10 A-10 ON
		    THEN RUN FountainPumpSwitchOn
158.  WHEN X-10 A-10 OFF
		    THEN Fountain_Pump OFF   <<- safe to do this directly
 
Now, I realize there has been no "basic" discussion of the flags, but really, if you read the manual it actually specifies the basics very clearly, so you know what flags are, and the various ways they can act (their functional parameters). What isn't necessarily clear (especially for novices), is just how to leverage them for solving problems.

The following may be a bit" strange reading", but I think it has some useful tips.
When I was introduced to PC Access version 2 with an Omni IIe / Model 950, there were a lot of limitations, and so I hammered this out in order to help me assemble some actions that were otherwise not possible.


This covers the principles for....
- delayed actions
- custom-timed actions
- pre-delayed custom-timed actions

Although its a bit dated, I think the principles are useful.


Code:
137.    //    #######################################################
	    //	    11) TIMER CONTROL SECTION - CUSTOM TIMERS
	    //    #######################################################
	    //    WHAT IT IS:
	    //	 Using 2 Flags Together you can
	    //	   1) Set Custom-Timed-Actions for Objects not having timed-feature built-in, like
	    //    Temperature Setting.
	    //	   2) You can also create Pre-Delays for Custom-Timed-Actions
	    //   
	    //    HOW IT WORKS: the 'thisTriggerFlag and 'thisPauseValueFlag'
	    //  
	    //	 - 'thisTriggerFlag': set to "ON" for the desired delay (TIMER) before executing another macro.
	    //    Macros waiting for the "thisTriggerFlag" OFF-state will begin checking the next Flag,
	    //    'thisPauseValueFlag' state, to validate*, confirm 'execute' or 'stop'.  Then...
	    //   
	    //	 - 'thisPauseValueFlag': set to a specific/unique value (QUALIFIER).  The macros waiting for
	    //    "thisTriggerFlag" that are *ALSO looking for the particular value set for
	    //    'thisPauseValueFlag' are the only ones that will execute when 'thisTriggerFlag' goes OFF.
	    //  
	    //  Note how this allows 'thisPauseValueFlag's to target specific macros out of group sharing response to the same trigger.
	    //  So using various PauseValueFlags (Qualifiers) in differing macros having the same trigger, a single trigger can induce different affects
	    //  depending on a unique value specified by a 'PauseValueFlag'
	    //
	    // 
	    //
	    //
	    //
	    //    ======================================================
	    //    -- SECTION 1 =========================================
	    //    There are 3 Possible Applications (explained below):
	    //	 - Delayed-Action:
	    //			  *simple delay before Unit-Action, Button, whatever-Call
	    //			   (e.c. after ##mins, Set Light ON 50%, Auto-Off in 30mins [where light is a group of objects specified in a button])
	    //	 - Custom-Timed-Action:
	    //			  *simple timeout for Unit-Action not having built-in auto-timout feature
	    //			   (e.c. Heat ON for 30mins [heat has no built-in time control])
	    //	 - Pre-Delayed Custom-Timed Action:
	    //			  *pre-delay AND timeout for Unit-Action not having builtin auto-timeout feature
	    //   
	    //    #######################################################
	    //    EXAMPLE1: SET A DELAYED-ACTION
	    //    +++++++++++++++++++++++++++++++++++++
	    //   
	    //	  Macro1a: When "thisMacroButton"
	    //					  Set "thisTriggerFlag"=ON FOR ##mins/hrs/etc  (set Pre-Delay Period)
	    //					  Set "customPauseValueFlag"=XX			    (targets Macro_2a)
	    //   
	    //	  Macro_2a: When thisTriggerFlag=OFF			   <-- when both conditions met
	    //				   AND customPauseValueFlag=XX		  -- then executes following lines -->
	    //					  Set...EXECUTE BUILTIN-TIMED-ACTION COMMANDS (set Light=50% FOR ##mins)
	    //					  ReSet customPauseValueFlag OFF   (END of Delayed-Action Sequence)
	    //   
	    //    When customPauseValueFlag signals the end of Macro_2a,
	    //    you can use that to trigger another macro if you wish.
	    //    It deosn't need to be a ReSet, it could be another unique value for targetting a specific macro.
	    //    E.c: Using a Macro starting with When customPauseValueFlag=OFF, then do XXX
	    //    E.c. Using a Macro starting with When customPauseValueFlag=myNewAssignedValue, then do XXX
	    //  
	    //  
	    //    #######################################################
	    //   
	    //   
	    //    ======================================================
	    //    == SECTION 2 =========================================
	    //    NOTE: A 'Unit Object', like Light, can be set to a value/action for a specific time
	    //    period.
	    //	  However, some other objects cannot, for instance, Temperature cannot --->>
	    //   
	    //    SO TO CREATE A "CUSTOM-TIMED-ACTION", for instance,
	    //		 to set the Temperature Heat for 1 Hour with a system not built to support that
	    //		 ADD these steps to MAcros 1 & 2 -->>
	    //   
	    //    THE CHANGES:
	    //	   In Macro_1: Add an 'action line' for Setting Temperature as desired (say, more heat).
	    //				    This will run for the duration you set for 'thisTriggerFlag'
	    //	   In Macro_2: The action-line Sets Temp back to, say, Normal/whatever.
	    //				    This affects the 'end' state to any command
	    //   
	    //    Here's the updated example
	    //    #######################################################
	    //    EXAMPLE 2: SET A "CUSTOM-TIMED-ACTION", for instance,
	    //    +++++++++++++++++++++++++++++++++++++++++++++++++++++++
	    //	  Macro_1b: When "thisMacroButton"
	    //					  Set "thisTriggerFlag"=ON FOR ##mins/hrs/etc   (sets Pre-Delay Period)
	    //					  Set_ON... EXECUTE CUSTOM-TIMED-ACTION COMMANDS  (set HEat=72, etc)
	    //					  Set "customPauseValueFlag"=XX				   (targets Macro_2b)
	    //	  Macro_2b: When thisTriggerFlag=OFF			    <-- when both conditions met
	    //				   AND customPauseValueFlag=XX		   -- then execute the following lines -->
	    //					  ReSet_OFF... EXECUTE CUSTOM-TIMED-ACTION COMMOANDS (turn Off HEat, etc)
	    //					  ReSet customPauseValueFlag OFF    (END Custom-Timed-Action Sequence)
	    //    #######################################################
	    //   
	    //   
	    //    ======================================================
	    //    == SECTION 3 =========================================
	    //    IF YOU NEED A PRE-DELAY before executring your Macro_2b, you need to add a Macro as a
	    //    pre-delay feature to the group for a total of 3 Macros, and adjust accordingly....
	    //   
	    //    Here's the updated example
	    //    #######################################################
	    //    EXAMPLE 3:  Set a PRE-DELAYED CUSTOM-TIMED ACTION
	    //    +++++++++++++++++++++++++++++++++++++++++++++++++++++++
	    //	  Macro_1c: When "thisMacroButton"
	    //					  Set "thisTriggerFlag"=ON for ##mins/hrs/etc   (sets Pre-Delay Period)
	    //					  Set "customPauseValueFlag"=XY				 (targets Macro_2c)
	    //   
	    //	  Macro_2c: When thisTriggerFlag=OFF			    <-- when both conditions met
	    //				   AND customPauseValueFlag=XY		   -- then execute following lines -->
	    //					  Set thisTirggerFlag=ON for ##mins/hrs/etc	 (Sets State-Duration)
	    //					  Set... EXECUTE CUSTOM-TIMED ACTION COMMANDS)  (set heat=##, etc)
	    //					   (Will Stay Set for the duration you set for 'thisTriggerFlag'
	    //					  Set customPauseValueFlag=XZ  (Call Macro_3c when thisTriggerFlag OFF)
	    //   
	    //	   Macro_3c: When thisTriggerFlag=OFF			    <-- when both conditions met
	    //				   AND customPauseValueFlag=XZ		  <-- then execute following lines
	    //					  ReSet CUSTOM=TIMED-ACTION COMMANDS  [to Normal states / whatever]
	    //					  (Affects the 'end' state to any Macro_2c commands that were executed)
	    //					  ReSet customPauseValueFlag OFF    (END of Pre-Delayed Timed Sequence)
	    //    ######################################################


I hope others may find these examples helpful.
Thanks again to Cornutt for intiating this very useful post.
Cheers,
Twohawks
 
Cornutt's made "102" on flags, which has a lot of good stuff in it, go here.
 
I am posting this followup in both places so as to cross-link these, and one other, related postings.
 
I posted an interactive dual-macro use of flags for setting up a hysteresis affect for a pond-fill here.
The idea is to use flags to monitor a zone state change (not ready/secure), while locking the 'intended action' into place for specified periods, even if the state rapidly changes.
The flags are placed into only two 'interactive' macros, effectively informing each other of state changes and how long to allow an 'intended action' to run, including some other features. 
 
It may look a little advanced at first glance, but its not.  The challenge/idea, and the implementation is simple... rather than run a series of macros independently for each state~incident, meaning series~logic for each of 'when not ready' and 'when secure', is it possible to reduce the amount of code needed by scripting the actions interactively (parallel~logic, so to speak).  This is what I asked myself after writing out the code using quite a number of macros for managing each affect individually when first laying out all the basic logistics of what I needed to have happen.  The code provides a decent fundamental example of using flags to allow two macros to interact/respond with one another.
 
Back
Top