Building a Security System with Indigo 6 or greater

When we purchased a travel trailer (TT for short), I hadn't really given much thought to doing any automation. On our first outing with it, my spouse asked me if I could add some kind of security system. Of course, I jumped at the chance. Another thing we quickly found was that the lighting in the TT, particularly at night, was pretty awful - with the overhead lights on, it was glaringly bright direct light (pancakes in R V terms). With them off, it was too dark. We have lots of indirect lights in our house, so I needed to figure out a way to do that in the TT as well.

Before we get into the details, a bit of a warning: this article addresses some pretty complex requirements and therefore it's a pretty complex solution. I don't take the step-by-step approach to implementation as we do in some of the How-To articles: if you're ready to implement a homegrown alarm system, you should probably already be fairly familiar with Indigo. If you find yourself becoming frustrated because you don't understand some of the concepts, I recommend digging into the documentation deeper on those specific topics to help gain a better understanding of how they work. I've provided links to the documentation for most of the concepts used in this article to help you jump directly to the specific discussion. Indigo is a complex DIY automation system and the best way to learn is to experiment. We have a lot of step-by-step How-To articles in the wiki that will help you get started.

A quick note on text styling conventions that I'll be using throughout the rest of this article: Indigo object types (Trigger, Action Group, etc.) will be links to their respective section of the documentation. Object names in this solution will be in italics (30 Second Timer, Arm Security System, etc.). Specific values will be in monospaced text. And, we're walking…

My Requirements

I thought about my requirements and made a list of functions/parts:

  1. Sensors - various sensors to detect when the TT (zone) had been breached.
  2. Zone - a way to create a single object that represented the TT via a collection of sensors.
  3. Device to Arm/Disarm that didn't require a lot of work (I didn't want to have to use the Mac directly). Preferably a remote control that could also be used to operate the lighting (see above).
  4. Alert - some way to alert that the system had faulted. This might include email but would definitely require some kind of audio siren and potentially visual cue.
  5. Arm the system - complete with an audio countdown (30 seconds) for exiting the TT before it actually armed.
  6. Disarm the system - also with a 30 second countdown to complete the disarm before the alarm faulted. Disarm also needed to cancel the arming process if it hadn't finished yet (i.e. you forgot something while exiting).

Selecting the Technology

We would be carrying my MacBook Pro with all of our video media on it and have it connected to the TV so that we could watch anything we want. So, my first thought about automation would be to use the PowerLinc 2448 (RF only dongle) that I have along with a LampLinc to control some kind of 110v lighting (to solve my lighting problem). I also had a TriggerLinc (Door/Window Sensor) and a Motion Sensor that could be used to detect zone breaches. That turned out to be a bust. INSTEON devices that plug into a 110v circuit are susceptible to signal noise (as many will attest). And apparently the power inverter that converts 12v DC to 110v AC in the TT kills INSTEON signals. This would be OK if the device was dual-band and would just ignore the noisy 110v side. But, alas, they don't. If there is too much noise on the 110v side, the whole device becomes unusable. Smarthome doesn't make an RF-only LampLinc so that was out. If I didn't need the LampLinc then INSTEON might have worked (though, to be honest, I don't fully trust the TriggerLinc - but that's another discussion).

My next thought was to use Z-Wave - it was a new technology to us but I felt pretty good about using it. So, I put in a Z-Wave lamp module and connected the Z-Stick to my Mac. It worked perfectly. Now on to the plans for the security system (you can read more about how I solved my lighting problem if you're interested but it is secondary to this discussion).

Selecting the Devices

For #1, the choice was pretty straight-forward. The Aeotec Door/Window sensor, named Door is nice and compact - and the magnet is even smaller (about diameter of a pencil). It fit nicely on the inside of the door. One bit of trouble I had was that the tamper switch (presented in Indigo as as separate device called Door Tamper Switch) tended to go off because the sensor had to sit partly on the wall and partly on the door frame (see pict below). The switch sits on the frame part, which is slightly lower than the wall, so it goes off occasionally. To solve this issue, I inserted a small bit of double-sided foam mounting tape between the mounting bracket and the door frame. See the cut-out box in the upper-right corner of the mounting bracket - that's where the tamper switch goes:


You might ask why I don't just flip the sensor over so the tamper switch is on the bottom rather than the top. Apparently the sensor is on one side of the device so if it's upside down it won't detect the magnet. In any event, this solution seems to be working fine.

The other sensor is an Aeotec Multi Sensor named, very originally, Motion - so I have triple detection power: the door opening, the door sensor being tampered with, and the motion sensor seeing motion. The multi sensor is also great because it can report temp and light which will be useful for other things I might do later. We do have a dog so we may have to play around with the positioning of the multi sensor if we need to arm with the dog inside.

#2 was also easy once I'd implemented a feature request to the existing Device Group device type in the Virtual Devices interface: allow sensor devices which have an on state to be included (available in Indigo 6b9 and later). This allowed me to create a Zone device called Alarm Zone 1 such that when either the door, tamper switch on the door sensor, or the motion sensor goes on, the zone device goes on:

So, much like a zone in your home's security system, which shows a light on your keypads whenever one of the sensors in the zone is open, the Alarm Zone 1 will show ON in Indigo whenever motion is detected, the door is open, or the door sensor has been removed from the wall.

For #3, I decided on an Aeotec Minimote I called, simply, Remote - for which Matt had just implemented support. This is a 4 button remote and each button can have two triggering events (when in scene mode - see the wiki for details): button pressed and button held (unfortunately there is no button released or there would be a lot more potential). For the security system, I'd use button 4 pressed to start the arming process, and button 4 held to disarm. The other buttons were used for controlling the lights.

#4 was a little trickier. My Mac is already hooked up to the built-in sound system in the TT via an AUX jack - so sound from the Mac can go out both the built-in speakers inside and the built-in speakers outside (assuming I have the built-in amp set that way). So I could get sound going that way. However, I really wanted something that was loud and piercing - and perhaps also had some visual aspect (though I also flash the lights from Indigo). I found this Everspring Siren on sale so I thought I'd try it out - maybe we could add support for it without too much difficulty. As it turned out, we didn't have to do anything - it identifies itself as a standard relay device (like an appliance module). Turn it on and it sounds and flashes, turn it off and it stops. And, it's really loud (there's a jumper that you can remove to make it a bit quieter). It also has a tamper function - when the cover is removed it goes off and apparently broadcasts out an alert that we don't currently catch, but we'll eventually add that as well. I named it Siren/Strobe.

One more Indigo device that I added was a Timer Device called 30 Second Timer which will be used for the entry and exit countdowns and for arming and faulting the system as appropriate. We'll discuss it more throughout the rest of this article. See below the full device list for the alarm devices. The Remote and the lights used for parts of the system are in other folders.

Implementing the Logic

So, once I had the devices in place, it was time to make them work together. I ended up using about every type of object and feature that Indigo provides. This makes it an ideal article to showcase Indigo's capabilities. A word of caution here: there are a bunch of different ways to implement this solution. I'm presenting the one that I came up with - and I'll admit that I sometimes selected one particular path over another just because it used a different Indigo feature. The takeaway is that this solution is probably not the most optimal in any respect: in the number of objects involved, in how the logic flows, in reducing the amount of scripts, or even in implementing the system in one really big script. It's my take on a reasonable compromise of all those while illustrating how to use many different Indigo features.


The next task, then, was to figure out how to arm the system. The high-level requirements for arming were this:

  1. Single operation (button press) to begin the arming process.
  2. Single operation (button press) to stop the arming process (we'll discuss that in the Disarming section below).
  3. A spoken 30 second countdown that would speak every 5 seconds how much time was left - and the last 5 seconds needed to be a 5-4-3-2-1 countdown.
  4. An audible beep - once a second during the 30 second countdown (like the alarm system in our house).

There are quite a few moving parts, so I'm going to list each Indigo object used in Arming the system first, then tie them all together. So, here's the list:

  • Alarm Button Pressed to Arm Trigger to arm the system - there are several actions which accomplish this which I'll describe below.
  • Countdown Beep Trigger to beep once a second while entering or exiting - it uses a simple script to accomplish this.
  • Timer Expires While Exiting Trigger to actually arm the system once the timer runs out.
  • alarmStatus Variable to hold the alarm state.
  • Exit TT Action Group to start the exit procedure.
  • Speak Message Upon Exiting Action Group to speak a message that tells you how long you have to exit before arming the system.
  • Speak Seconds Only Action Group to speak just the seconds left on the timer.
  • Create 5 Second Countdown Pester Action Group uses the above action group to speak the 5-4-3-2-1 countdown (also shared with the entering function discussed below).
  • Arm System Action Group which sets the alarmStatus variable to armed and turns off Alarm Zone 1.
Arming Trigger

I decided that starting the arming process would be accomplished by a press of button #4 on Remote and that disarming would be a press and hold on button #4, so those would be the triggering events. Here's the Alarm Button Pressed to Arm trigger definition:

Part of the solution requires that a variable, alarmStatus, represent the various states of the alarm. Specifically: disarmed, exiting, armed, entering, fault. There are other states that are probably possible, but these work for me. And they are pretty self-explanatory.

The conditions for the Alarm Button Pressed to Arm trigger are pretty simple: we only want to arm the system if it's currently disarmed:

The actions for the trigger have been encapsulated in the Exit TT action group:

We'll discuss each of these in the next section.

Exiting Actions

So, when you arm an alarm system, you don't want it to come on immediately - if it did, then when you opened the door to leave the system would go off. So you need some time to exit the TT before the system actually arms itself. That's what the Exit TT action group does. I separated it out into an action group rather than performing the actions directly in the Alarm Button Pressed to Arm trigger in case I decided to add another way to start the exiting process.

Start Timer

The first action starts the 30 Second Timer. This timer will provide the next pester with the amount of time left before the system becomes armed. And if the timer runs out (isn't stopped prematurely) another trigger will fire that will actually arm the system (discussed a bit later).

Create Pester

The next action creates a Pester named Exiting Countdown:

This pester cycles every 5 seconds for 5 times. Each cycle will execute the Speak Message Upon Exiting action group. The only action in this Action Group at the moment is the following embedded Python script:

This script gets the timer device and uses the “timeLeftInSeconds” state inserted into a string, to create a message that's spoken through the Mac's speakers. As a reminder, I have my Mac's sound output connected to my TT's amplifier so the spoken message goes out through the speakers that the amp has selected.

The final action of the pester is different - it's the Create 5 Second Countdown Pester action group. There are 2 actions in this action group: to speak the number 5 (since the group will be executed exactly 5 seconds before the timer expires):

and another Create Pester action that creates a pester called 5 Second Countdown that repeats every second for 5 times. The action group that's executed for all iterations is the Speak Seconds Only group. The only action in this group is an embedded Python script shown on the right:

This script does almost exactly the same thing that the last script does but it just says the number of seconds left with no other text.

Speak Text

The next action in the Exit TT action group is for it to speak the string Exit now (this will happen before any of the other spoken messages since those are pester messages). I could have combined this with any of the other actions since any action can also speak text, but I separated it out for clarity, though another advantage is that it's easier to see everything that's going on.

Set Variable

The final action in the group is to set the alarmStatus variable to exiting. This variable is used in several conditions to make sure the right thing hapen.

Countdown Beep

I also wanted an audible beep, once a second, while counting down the timer (like what my home alarm does). That's what this trigger is for:

It's actually a pretty simple trigger: any time 30 Second Timer's Time Left in Seconds state Has Any Change. So when the timer runs, the trigger attempts to fire. I do have some conditions however:

I only want the trigger to fire if the alarm status is exiting or entering. This will help ensure that we'll really only hear the beeps when we really want to hear them. The action is another very simple embedded Python script:

This will cause Mac OS X to play the selected beep sound. I've selected Morse in the Sound Effects tab of the Sound System Preference. It's very short and not too intrusive.

Arming the System

The final trigger, Timer Expires While Exiting, will actually do the arming of the system after the countdown has expired:

We use the Timer Expired event because we only want the trigger to fire if the timer naturally ran out of time (as opposed to it being explicitly stopped - which will happen if you disarm while exiting which we'll discuss a little later). Again, we'll set the condition such that it only fires if the alarmStatus variable is set to exiting:

The action is to execute the action group Arm System, which is currently defined with two actions: we set the alarmStatus variable to armed and we turn off Alarm Zone 1. The former is self-evident but the latter probably needs a little explanation. When we're leaving the TT it naturally means we're moving around. So Motion is going to be on which means that Alarm Zone 1 is also on. Motion will eventually go off, depending on how I have it configured, but for the interim if I leave it alone there is a small window where someone could get into the trailer without the alarm going off (because the next trigger, which starts the entering process, fires when Alarm Zone 1 turns on). The solution is simple of course - just explicitly turn off the zone. Sure, Motion won't turn it back on until after it's timeout period, but Door and Door Tamper Switch will immediately work so at least we're getting the most common coverage immediately.

Arming Summary

OK, to summarize the arming process: I press button #4 on Remote. That fires the Alarm Button Pressed to Arm trigger (if alarmStatus is disarmed) which announces “Exit now”, starts 30 Second Timer, creates a pester that will announce “25 seconds to exit” (and countdown the last 5-4-3-2-1 with another pester), and sets the variable alarmStatus to exiting. When the 30 Second Timer runs out of time, the alarmStatus variable is changed to armed and the zone is turned off. The TT is now armed and any breach of the Alarm Zone 1 will cause the entry scenario to start (more on that later).


We're now going to discuss how to disarm the system. We haven't yet discussed the entry scenario (when you come back in the TT) because that scenario will require you to disarm the system - so let's address that first.

There are several different times during the alarm lifecycle where you'll want to disarm:

  1. While you're exiting. I don't know about you but it's pretty common for me to forget something only to remember it after I've started the arming process. Disarming must work while the alarmStatus variable is exiting.
  2. When you enter the TT after the system has been armed - the alarmStatus variable will be set to entering.
  3. When the alarm has faulted (the siren is going off, etc.). The alarmStatus variable will be set to fault.

So, the requirement is pretty simple for disarming: when we press and hold button #4 on Remote, and the alarmSystem variable is set to any of the above, we want to disarm the system. Therefore, the Alarm Button Held to Disarm trigger will be defined like this:

To simplify the conditions, we'll just say if the alarmStatus variable is not equal to disarmed since we can disarm in all the other states:

And, finally, the action will be to execute the Disarm System action group. That's by far the most complicated part of disarming the system. Let's go through the actions in the action group one at a time and discuss each in detail.

Stop Timer

Perhaps the most important action is to stop the 30 Second Timer. This will keep it from executing the trigger to arm (or disarm which we'll discuss in a bit) the system if we're in entering or exiting mode - those action groups will either arm the system or fault the system. Very important.

Set the Alarm Status

This one is very simple: we just set the alarmStatus variable to disarmed. Note that we also added some text to speak to this action: “Alarm is now disarmed” to let you know that the alarm has been disarmed.

Cancel Pesters

There are a potential of 3 pesters running when you want to disarm the system: Exiting Countdown, 5 Second Countdown, and Entering Countdown (which we haven't discussed yet). We'll go ahead and do a separate Pester Actions→Cancel Pester action for each of these pesters separately - if you try to cancel a pester that doesn't exist it'll just tell you that in the Event Log but otherwise won't do anyting so we don't have to do any fancy logic. We could, of course, do a Pester Actions→Cancel All Pesters - but if you make some other pesters at a later date you may end up cancelling one you didn't really mean to. So, the future proof way to accomplish this is to explicitly cancel the ones you know you want cancelled.

Stop System Fault

We haven't yet created the Stop System Fault action group since that's part of what happens when the alarm system faults (detects an intruder). For the moment, you can just create an empty action group with that name and we'll fill it in later. Suffice it to say that it's job will be to stop whatever actions we do when we detect an intruder - like turn off the siren. Because we're using this same trigger to recover from a system fault, we need to stop any repetitive tasks from happening as a result of a fault.

Here's the Disarm System action group overview:

Disarming Summary

When we press and hold the #4 button on Remote and if alarmStatus is not disarmed already, then we do several things: we stop the 30 Second Timer so the system won't arm or fault (depending on what status we're in), we set alarmStatus to disarmed, we cancel the 3 potential pesters created in different parts of the entering/exiting process, and we execute the action group that stops any repetitive actions that are happening because of an alarm fault.

Alarm Fault

The final part of the system is when the alarm system detects a zone fault (a breach). There are two stages whenever the system detects that the zone was faulted: it immediately goes into entering mode - where it's unclear whether there's been an illegal entry or whether you've just come back - in which case you'll disarm the system. This stage follows the exiting scenario very closely. The second stage is what happens if the system isn't disarmed during this 30 second interval.


There are quite a few moving parts for entering just like there were for exiting. In fact, some are actually reused. We'll list those here as well for completeness but know that if something is named identically with something earlier in this article we're just referring to it again (it's not something new).

  • Zone Fault Detected Trigger is the trigger that gets fired whenever you open the door or come through a window (and motion is detected), or if somehow motion didn't work but the crook tries to remove the door sensor.
  • Countdown Beep Trigger to beep once a second while entering or exiting - it uses a script to accomplish this.
  • Timer Expires While Entering Trigger to actually fault the system and start any actions (siren, lights flashing, email, etc.)
  • Flash Zone 1 Lights Schedule this schedule flashes a couple of Z-Wave lights that I have inside and outside the TT.
  • Speak Message Upon Entering Action Group to speak a message that tells you how long you have to disarm before the system alerts.
  • Speak Seconds Only Action Group to speak just the seconds left on the timer.
  • Create 5 Second Countdown Pester Action Group uses the above action group to speak the 5-4-3-2-1 countdown (also shared with the exiting function above).
  • Fault System Action Group that starts the alerting to an intruder.
  • Stop System Fault Action Group that stops the alarming started by Fault System.
Zone Fault Detected

This trigger is very straight-forward: when Alarm Zone 1 goes on, that means that the zone has been breached (door opened, door sensor tampered with, motion detected). The definition is:

Of course, we only care when that happens if the alarmStatus variable is armed:

The actions are the interesting part of this trigger:

First, we start the 30 Second Timer. If it counts down to 0 that will be our signal to sound the alarm.

Next, we create a pester called Entering Countdown.

It's much the same as the Exiting Countdown created above: the pester cycles every 5 seconds for 5 times. Each cycle will execute the Speak Message Upon Entering action group. The only action in this Action Group at the moment is the following embedded Python script:

# get the timer device
dev = indigo.devices[3827472] # "30 Second Timer"
# convert the "timeLeftInSeconds" state of the device to an int
# insert that into a string and send the string to the speak server command
indigo.server.speak("%i seconds to disarm alarm" % int(dev.states["timeLeftInSeconds"]))

This script gets the timer device and uses the “timeLeftInSeconds” state inserted into a string, to create a message that's spoken through the Mac's speakers. As a reminder, I have my Mac's sound output connected to my TT's amplifier so the spoken message goes out through the speakers that the amp has selected.

The final action of the pester is the Create 5 Second Countdown Pester action group that we created earlier. So that's the Create Pester action.

The last action in the Zone Fault Detected trigger is to just speak “Disarm alarm now”.

Note that the Disarming process we built above will terminate the countdown and cancel the pesters so we're good to go on that front. Also, the Countdown Beep trigger we made above will also beep during the entry phase just like it did when exiting.

Flash Zone 1 Lights

As an extra visual feature of the alarm system faulting, I want to flash a couple of Z-Wave lights that I have: one is inside and the other is outside. So, this schedule executes every 6 seconds:

I picked 6 seconds because one of the lights that I'm flashing has a relatively slow ramp rate so I wanted it to turn all the way on before I turn it back off (the actions have an auto off of 3 seconds as you'll see below).

The condition should be when the alarmStatus variable is fault:

and the actions are to execute an action group called Flash Lights Once which turns on a couple of lights and has an auto-off after 3 seconds.

The net result is that while this schedule is running, the lights go on for a 3 seconds then go off for 3 seconds. Obviously you'll want to modify this schedule, actions, and action group to be more custom for your environment.

When you create this schedule you'll probably want to immediately disable it - it may go off depending on what the alarmStatus variable is set to! We'll enable it only when we need it and disable it when we reset the system. You may wonder why we have the condition if we're going to enable/disable it - it's just a double guarantee that we won't see flashing lights unless the alarm is really faulting.

Timer Expires While Entering

So, lastly, if the 30 Second Timer expires without disarming, then we need to do all the alerting that we want to do. That trigger is defined like this:

but only if alarmStatus is entering:

and the action will be to execute the Fault System action group - described next.

Fault System

This action group has the following actions:

  • It turns on Siren/Strobe so it starts sounding and flashing.
  • It sets the alarmStatus variable to fault
  • It enables the Flash Zone 1 Lights schedule.
  • It sends me an SMS (via my cell phone provider's email to SMS bridge). Of course, this only works if I happen to be staying in a park that has WiFi available…
  • It inserts a timestamp into a variable named lastAlarmFault - that's just so I can see the last time the alarm went off. Use the Variable Actions→Insert Timestamp into Variable action.
Stop System Fault

This action group just stops the repetitive stuff started above: it turns Siren/Strobe off and it disables the Flash Zone 1 Lights schedule.

Alarm Fault Summary

So - you open a door (or in some other way trip the zone) which starts the 30 Second Countdown with audible alerts. If you press and hold #4 on Remote you will disarm the system. If you don't, then when the countdown reaches 0, the siren goes off, lights start flashing, and you get an SMS. You can then press and hold #4 on Remote to disarm.

Alarm Button Pressed to Reset Fault

One final bit to my solution: another trigger that fires when button #4 is pressed on Remote:

The condition is if alarmStatus is fault

and the action is to execute the Disarm System action group. This makes it easy to disarm the system when it's faulted - you don't have to press and hold #4, just a regular press will also work.


So that's my alarm system. It has a lot of moving parts (9 devices including the lights I flash, 7 triggers, 1 schedule, 10 action groups, 2 variables, pesters, scripts, emails, timers, device groups). However it is a pretty complete solution particularly for my TT. You could also use this article as a starting point for building a security system in your house, though professionally monitored systems are always a better alternative IMO. But the other major use of this article is to show the power and flexibility of Indigo and it's available components. We believe Indigo can be used in a whole bunch of different scenarios and we hope you see the possibilities as well.

homegrown_security_system.txt · Last modified: 2019/01/26 00:10 (external edit)

© Perceptive Automation, LLC. · Privacy