Alarm Setup

From Domoticz
Jump to: navigation, search

Practical guide to building an alarm system using Domoticz


Setting up a fully capable, industry grade alarm system using Domoticz is pretty doable and quite cost effective. Obviously Domoticz will not be using wired devices and wireless devices are never as secure as wired ones. If that's what you need then you will be better off buying a separate, wired alarm system. That said, using a mixed system of devices (z-wave, 433) will make it hard for any burglar to jam everything at the same time giving quite a decent base system.

There is quite a bit of info in this wiki and it may seem complex but it really isn't. It does require basic knowledge of domoticz but you should not have to do any (major) lua programming yourself if you don't feel comfortable.

PLEASE NOTE THAT THIS WIKI REQUIRES A CHANGE IN ORDER TO FUNCTION PROPERLY: after the wiki was created, domoticz behaviour changed such that variable changes no longer trigger events. Rather than using variables as described below, replace variables with dummy devices and check those instead. At some point, this wiki will be updated to reflect the change.

General concept

This design is based on the following basic principles:

  1. use the domoticz built-in security panel (arm, disarm, check states)
  2. use any standard detection devices: motion detectors as well as door/window sensors and name them such that you can easily detect them generically (motion detected, door opened) : 2 simple lua scripts handle either motion detection (PIR) or door/window sensor detection. All motion/PIR sensors need to be named PIR_something (e.g. PIR_hallway, PIR_livingroom), all door/window sensors need to be named MCS_something (e.g. MCS_backdoor, MCS_frontdoor). This way, you can easily add sensors without having to change anything in the rest of system.
  3. separation between detection and action: instead of dealing with the threat in the detection script itself, I decided to handle any action outside of the detection scripts. That gives me a lot more flexibility in dealing with these. The detection scripts set a user variable “AlarmDetected” to 1 if an alert is detected. Using either scripting or (blocky) events, you can then act on these. I currently use events (being lazy by nature, it's easier to make a change rather than to have to login and change/test lua scripts). Either way, once an action is done, you need to set the user variable “AlarmDetected” back to 0 in order for new alarms to be raised.
  4. separation between action and siren: the (blocky) events that trigger the actions can set a variable called SoundSiren (causing the siren to go off) a certain time after detection. That allows for both a silent alarm as well gives the opportunity to shut the alarm off before the siren goes off (so you can get in the door without the alarm going off).
  5. any PIR or MCS activity when the alarm is armed is notified through the notification system. Set that up and you get a notification on the exact trigger.
  6. keep scripts to a minimum so you don't need to do any programming or even change scripts. Change events instead.

Building resilience & security

Any alarm system built on computing technologies is as good as the availability of the system. Once the computer is down, so is your alarm. A couple of things that can be done to increase the resilience of the system. Also, it's tempting to connect domoticz to the internet and access it from outside your house. Once domoticz controls your alarm, that may not be the best idea as you don't want hackers to control your security in any way.

In order to increase resilience, I can recommend using (some of) the following:

  • Equip domoticz with a (small) UPS. I use the very cheap Sweex 1000VA UPS (usually around 85 bucks) for both my electronics cabinet as well as for domoticz (which is in a different place). Since domoticz, in my case, runs on a raspberry pi, it can go on for days on the UPS if need be
  • use a watchdog if your system has one. The raspberry pi does. This ensures that if the system locks up (hangs or CPU max), it gets restarted automatically. There are general pages for the pi as well as a specific page for domoticz. Google is your friend.
  • Make sure that not only domoticz is on an UPS but everything else you need in order to get a message out. If your router is not on the UPS then no internet if the power is down.
  • Consider a cell network data plan with a dongle in order to send messages even if all the power in the neighborhood is out. Neighborhood wide power outages are notorious burglar events. Some routers support a dongle based backup if the main internet is out but you can also equip your system directly with a dongle.
  • Just make sure that the entire end to end chain (end points and switches in between), is on an UPS as, having a pi desperately trying to alert you without a network is not good. Note that it's not uncommon for a burglar to short-cut an outside electricity socket to trip the main switch/RCD in your home. If your power is down, can you still get a message out?
  • If using radio modules, be aware air-interface may be jammed. So a way to detect jamming, for instance checking periodically that one remote module of each used radio technology can be reached (may need a protocol able to return device state). See jamming chapter for an implementation using z-wave.

In order to increase security, I strongly recommend to NOT directly connect domoticz to the interenet. Whilst domoticz can be secured in a reasonable way, there are too many vulnerabilities to allow any direct connection to the box. Never put domoticz in a DMZ and I strongly recommend to not even use port forwarding. If you do want to access domoticz outside of your home, use a VPN. Most routers these days are equipped with a VPN server. Setting one up is not complex at all. If you have a choice in VPN server (if the router has a VPN server, it usually allows some choice between e.g. PPTP and OpenVPN), I recoomend NOT using PPTP as it's much more hackable than e.g. OpenVPN. Unfortunately my windows phone does not support OpenVPN which, for me, means I will not use my windows phone as PPTP is, IMO, just not good enough any more. Apple devices will support OpenVPN. Once the VPN tunnel is up, you can connect to domoticz as if you were on your home network.

Detect jamming

Radio based detectors used in an alarm scenario may be jammed, so it may be a good idea to be able to detect they can be reached. This may be done by trying to send commands to a device periodically and check for errors, but if it's a switch for instance you'll have to send back current on/off status and may interfere with other scripts if one order manages to make it's way between status read and re-write, maybe canceling it.

For z-wave, you can also activate pooling for one module used by checks but the problem is AC plugged modules will lead to false jam alarms in case of power fail (if the host running Domoticz is battery backed, as advised for an alarm setup) and battery-only modules will be drained by heavy pooling (or may keep sleeping)!

There is also some AC modules having an integrated rechargeable battery backup: In an alarm setup, this should be true for at least one element, the Siren. This is what this implementation use (tested hardware is the Aeon Siren gen 5).

So here's the jamming detector proposal:

1) Create a virtual switch, name it JamZwave for instance (tip: Using a naming convention, as for detectors hereunder, may help integration of other JamXXX in a generic alarm scenario if you decide to build other jamming detectors targeting other radio interfaces). Keep it's IDx and name for script configuration.

2) In hardware tab, select your z-wave controller tuning button to show all z-wave devices. In the pool interval, you can use 30s if you do not pool too many devices (this is only required for some old modules not showing changes themselves, so nowadays you'll probably only have the Siren you'll set using this mode). Then select you siren devices and click on activate pooling. You should now see the last seen updating every 30s if you refresh the current z-wave hardware devices page.

4) Python script that gets all z-wave devices properties and will extract Siren last seen item (the same as seen in hereupper hardware tab pooling setup) for check. As input, this script needs the z-wave controller idx, JamZwave virtual switch idx, the name of the pooled z-wave device (Siren, in this example) and the number of pools that may be missed before triggering the JamZwave switch. The current JamZwave switch state can also be given (0/1 = on/off), as the script will only send the command if state changes (and if there is a Json API to write a switch state, there is nothing to read it. So Lua reads current state and gives it to python...).

This file should be located under domoticz/scripts and made executable (chmod a+x You can call it manually, if needed with loglevel set to DEBUG, to verify there is no error reported on a console. See Lua side for parameters.

As this is not easy to verify everything is OK, you may set debug loglevel mode, this will also bypass the test for pooling enabed on the JamZwave vSwitch. Using this tip you may desactivate pooling in z-wave devices hardware page and wait a minute (with default 30s/2 pool miss limit) then check the JamZwave switch change state. Reactivate pooling, wait another minute and call back script to see state reversal. Then reverse source changes. See hereunder for a debug mde output...

Also take care to install python modules dependencies (using "apt-get install python-requests" etc...).

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Check a zwave device with pooling enabled presence and trigger
# a virtual switch to indicate possible radio jam if not seen...
# Returns 0 if no jamming, 1 if jamming, -1 if an error occured.
# But return value cannot be used from Lua??? So use -s.
# Changelog : 21/01/2017, YL, 1st version.
import getopt
import logging
import json
import sys
import requests
import datetime
logLevel='INFO' # DEBUG / INFO
# Domoticz json API url
dmtJurl         = ''
# Command parameters in json format (only change if API change!)
dmtJsonGetZwNodes = {"type":"openzwavenodes", "idx":"999"}
dmtJsonSwitch = {"type":"command", "param":"switchlight", "idx":999, "switchcmd":"Off"}
# Domoticz time format on LUA side:
dmtLuaTimeFmt   = "%Y-%m-%d %H:%M:%S"                   
def usage():
    Display usage
    sys.stderr.write( "Usage: [-h] [-c<CtrlIdx>] [-j<jamSwitchIdx>] [-n<DevName>] [-m<missedPoolNbLimit>] -s[<0|1>]\n")
    sys.stderr.write( "       'c' = IDx of Z-Wave controller.\n")
    sys.stderr.write( "       'j' = IDx of Z-Wave jamming vSwitch.\n")
    sys.stderr.write( "       'n' = Z-Wave device name to monitor.\n")
    sys.stderr.write( "       'm' = Missed pool(s) nb for device not seen alert.\n")
    sys.stderr.write( "       's' = Current state from Lua (need update eval).\n")
def dmtJsonApi(url, jsonApiCmd, logger):
    Send Domoticz json command
        # Connect to Domoticz via JSON API and send data
        dmtRget=requests.get(url, params=jsonApiCmd)
    except requests.exceptions.RequestException as dmtErr:
        logger.log(logging.ERROR, "Unable to connect with URL=%s \nGet requests error %s" % (dmtRget.url, dmtErr))
        logger.log(logging.DEBUG, "Sent data: [%s]" % (dmtRget.url))
	return dmtRget.json()
def main(argv):
    logger = logging.getLogger()
    handler = logging.StreamHandler(sys.stdout)
    # Checks the parameters
        opts, args = getopt.getopt(argv, "h:c:j:n:m:s:",["help","ctlIdx","jamIdx","name","miss","state"])
    except getopt.GetoptError:
    # Defaults    
    devName       = '999'
    missPoolLimit = 2
    ctlIdx        = '0'
    jamIdx        = '0'
    curState      = -1
    for o, a in opts:
        if o in ("-h", "--help"):
        if o in ("-c", "--ctlIdx" ):
        if o in ("-j", "--jamIdx" ):
        if o in ("-n", "--name" ):
        if o in ("-m", "--miss" ):
        if o in ("-s", "--state" ):
    # Configure the logger
    handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
    dmtJsonSwitch['idx'] = jamIdx
    logger.log(logging.DEBUG, "Controler IDx=%s, Jamming vSwitch IDx=%s, Device=%s, Miss Pool Limit=%ds." %(ctlIdx, jamIdx, devName, missPoolLimit))
    # Get all zwave nodes data
    dmtJsonGetZwNodes['idx'] = ctlIdx
    zwNodesData = dmtJsonApi(dmtJurl, dmtJsonGetZwNodes, logger)
    #logger.log(logging.DEBUG, "Zwave Nodes: [%s]" % (zwNodesData))
    # Get devices nb...
    logger.log(logging.DEBUG, "Found %d nodes, extract data for %s" % (devNb, devName))
    if (devNb < 2):
        logger.log(logging.INFO, "%d < 2 devices found !!!", devNb)
    # Get controller poll interval
    if (zwNodesData['result'][0]['config'][0]['label'] == 'Poll Interval'):
        pollSec = int(zwNodesData['result'][0]['config'][0]['value'])
        logger.log(logging.DEBUG, 'Controller Pool Interval = %dsec.', pollSec)
        logger.log(logging.INFO, "Cannot find controller pool interval config !!!")
    # Find device to pool using it's name...
    devFound = 0
    for node in zwNodesData['result']:
        if (node['Name'] == devName):
            logger.log(logging.DEBUG, 'Found: %s ; PollEnabled=%s ; LastUpdate=%s',
            devFound = 1
    # Device name not found, exit...
    if (devFound == 0):
        logger.log(logging.INFO, "Device %s : NOT FOUND." % devName)
    # If found node is pool enabled, check last seen time vs current...
    ret = 0
    if (node['PollEnabled'] == 'true'):
        curDate =
        lstDate = datetime.datetime.strptime(node['LastUpdate'], dmtLuaTimeFmt)
        lastSec = (curDate - lstDate).seconds
        logger.log(logging.DEBUG, "Current date/time : %s", curDate)
        logger.log(logging.DEBUG, "LastUpd date/time : %s (%s) ; Diff=%ssec.", node['LastUpdate'], node['Name'], lastSec)
        if (lastSec > (pollSec * missPoolLimit)):
            logger.log(logging.INFO, "%s: No pool response since %dsec ; Jamming?", devName, lastSec)
            ret = 1
            if (curState == 0):
                dmtJsonSwitch['switchcmd'] = 'On'
                dmtJsonApi(dmtJurl, dmtJsonSwitch, logger)
            if (curState == 1):
                dmtJsonSwitch['switchcmd'] = 'Off'
                dmtJsonApi(dmtJurl, dmtJsonSwitch, logger)
        logger.log(logging.INFO, "Must enable device pooling !!!")
    # Happy ending!
    logger.log(logging.DEBUG, "%s: Last=%ds / Pool=%ds (Miss limit=%d).", devName, lastSec, pollSec, missPoolLimit)
if __name__ == "__main__":

Checking with loglevel = DEBUG set in source code will return this kind of output (current JamZwave status supposed to be off/0, idx=XXX, controller idx=2):

./ -c2 -jXXX -nSiren -m2 -s0
DEBUG:root:Controler IDx=2, Jamming vSwitch IDx=XXX, Device=Siren, Miss Pool Limit=2s.
INFO:urllib3.connectionpool:Starting new HTTP connection (1):
DEBUG:urllib3.connectionpool:"GET /json.htm?type=openzwavenodes&idx=2 HTTP/1.1" 200 11087
DEBUG:root:Sent data: []
DEBUG:root:Found 15 nodes, extract data for Siren
DEBUG:root:Controller Pool Interval = 30sec.
DEBUG:root:Found: Siren ; PollEnabled=true ; LastUpdate=2017-01-24 11:58:17
DEBUG:root:Current date/time : 2017-01-24 11:58:30.969908
DEBUG:root:LastUpd date/time : 2017-01-24 11:58:17 (Siren) ; Diff=13sec.
DEBUG:root:Siren: Last=13s / Pool=30s (Miss limit=2).

Last seen 13s ago here ; inside limits => No jamming!

5) Lua time script will be triggered every minute and call (in the background, to avoid the >10s execution warning message that may be triggered from time to time), with appropriate idx/names/Jam switch current state. Update IDX/names/path to your own setup.

This script_time_JamChk.lua must be located under domoticz/scripts/lua, no need to make it executable:

-- Call z-wave jamming check python from this Lua time script,
-- and update jamming virtual switch if needed...
-- NEEDS python script.
-- Changelog : YL 21/01/2017, 1st version.
-- User config editable settings :
chkZwPyPath  = '/home/domo/domoticz/scripts/'
devJamSwitch = 'JamZwave' -- vSwitch showing jamming name.
devJamIdx    = '999'      -- vSwitch IDx (both must match).
devJamCheck  = 'Siren'    -- Z-Wave device in pool mode used for checks.
jamMissLimit = '2'        -- Nb of consecutive pools miss limit.
devCtlIdx    = '999'      -- Z-Wave controler IDx.
commandArray = {}
-- Debug, to show otherdevices & valid command statuses used hereunder...
--for i, v in pairs(otherdevices) do print(i, v) end
-- Need to pass current status to python because messy Lua os.execute does not properly handle return values...
if (otherdevices[devJamSwitch] == 'On') then
-- Build command (in background, to avoid Lua/Domoticz lock-up)
cmd = chkZwPyPath..' -c'..devCtlIdx..' -j'..devJamIdx..' -n'..devJamCheck..' -m'..jamMissLimit..' -s'..jamStatus..' &'
return commandArray

Detection devices

Building the system, you have a choice of detection devices:

  • Movement detection devices aka PIR or passive infra-red: these come in various technologies both 433, z-wave and probably others. This wiki will use both KAKU AWST-6000 (the downside is that they create a 5-10s signal burst during which rfxcom cannot send/receive other signals so essentially not a good choice, I need to replace them) as well as z-wave Philio PST02-1B. Again, call these PIR_something.
  • Door-window sensors: these also come various technologies. I use the KAKU AWST-606 (they are cheap). Obviously the Philio sensors are much more dependable and you will not miss a signal but they are 3-4x more expensive. Since it's strongly advised to equip all external and some internal doors/windows with a sensor (and I have a lot) then decide whether you want to spend the money (in my case, 12x a difference of 35 euros ie 400 euros for just the door sensors). Also recognise that you should combine these with motion detection as any burglar smashing in a window will not trigger the window/door sensor. Make sure you put a sensor on your utilities cabinet (Meterkast) in case anyone is looking to cut off your electricity. My sensor triggers an immediate alarm if the alarm system is armed. Again, call these MCS_something.
  • Glass break sensors: this seems to be a rather weak area in home automation as there don't seem to be too many options here. I have found the vision security ZS5101 z-wave shock sensor which is listed as being able to detect glass breaks. It has mixed feedback on the internet. Please report any confirmed working glass break sensors
  • Camera's: you have a choice of confirmed supporting camera's that you can buy in local shops or order any of these cheap chinese IP wifi camera's and pray they will work. Many of them have both infrared support as well as some form of motion detection. In most cases, the motion detection is not integrated in domoticz AFAIK but there are guides on how to do this. Again, google is your friend. It's not difficult to add a (supported) camera to domoticz (Setup→>More Options→Camera → Add Camera) and then to add the camera to a dummy switch. When you press the switch, the camera takes a picture and sends it to you vial email.


There are a number of different sirens on the market in various technologies. I have used 433 based linked smoke detectors up until now, in my case the König SAS SA200. These are cheap but connectable smoke detectors. I have 3 of them (garage/laundry, kitchen/living and upstairs) that are linked. If one goes off, so do the others. Domoticz can also trigger them causing a 3x 85db noise which I can assure you is quite effective. There are other options including z-wave sirens. Again, these are more dependable and will definitely go off if Domoticz tells it to (again, a 433 signal may get undetected). A z-wave device will probably cost as much as my 3 smoke detectors together. That said, smoke detectors are built to detect (and alarm) smoke so their noise is not as much and they tend to only trigger for a very limited period (i.e. usually not minutes).


Domoticz has a security panel built in which works perfectly but requires a computer (phone, tablet) to arm. For convenience, I have added the z-wave zipato mini keypad. Not only is it very small and easy to use but it uses rfid tags to arm/disarm. There is an excellent wiki on how to install with domoticz: Adding rfid tags (and user pin codes) was a breeze and you can have it up and running in a matter of minutes. It creates multiple devices of which I use 2 (3 if you count the tamper switch which I don't think I will use as I hope my alarm has gone off by then):

  • Alarm level: on means the keypad was armed (away button), off means disarmed (home button)
  • Switch: this is the feedback of the device ie the beeps when you arm it. I renamed it to keypad Ack based on 'lolautruche' recommendations in the domoticz forum and set it to on when the keypad is disarmed. That way, next time the alarm is armed, you hear the beeps indicating the system is about to arm.

Once the zipato keypad is installed and configured, you need to integrate it into your security setup as, by default, it only creates an on/off switch that does nothing else. Since Domoticz already has the built-in security panel and the system has specific functionalities built in to handle security states and alerts, I used this rather than to build my own. Simplest way is to arm/disarm the security panel once after which it shows up in your devices list allowing you to include it in your switches list and on your dashboard if you so choose.

Once that's done, you need to let the zipato keypad control the domoticz alarm state. There are different ways this can be done. I used a simple lua script that sets the domoticz security state based on the keypad action as follows:

-- Title: script_device_AlarmPanel.lua
-- Date: 19-11-2015
-- this scrip switches the Alarm Status according to the alarm panel
commandArray = {}
if (Panel == 'Keypad Alarm Level') then
--      set the group to the status of the switch
        if (devicechanged[Panel] == 'On') then
                print('AlarmPanel Arm Away')
                commandArray['Security Panel'] = 'Arm Away'
                print('AlarmPanel Disarm')
                commandArray['Security Panel'] = 'Disarm'
                commandArray['Keypad Ack'] = 'On'
return commandArray

Sweet and simple. The beauty is that arming the security panel uses the built in security panel's delay as configured in the domoticz settings. Again, there are different ways you can do this.

Putting it all together

  1. Create 3 user variables called “AlarmDetected” (without the quotes obviously), SoundSiren and AlarmActive, all of type string and set them to “0”.
  2. If you use the zipato keypad, save the AlarmPanel script in the domoticz/scrips/lua directory. If not then use the built-in web keypad
  3. Set up any notifications you want in the domoticz notifications system. I use both pushalot for my windows phone and that works really well. I also use pushover for my ipad (and soon my wife's iphone) which also works well
  4. Save the following 2 lua scripts in the domoticz/scrips/lua directory:
-- Title: script_device_MCSAlarm.lua
-- Date: 12-11-2015
-- checks for MCS during Alarm Away status
-- if detected then alert and set the alarm flag
commandArray = {}
if (MCS_switch:sub(1,3) == 'MCS') then
	if(otherdevices['Security Panel'] == 'Arm Away') then
		print('MCS motion detected:'..MCS_switch)
		commandArray['SendNotification']='MCS motion detected:'..MCS_switch
		commandArray['Variable:AlarmDetected'] = '1'
return commandArray
-- Title: script_device_PIRAlarm.lua
-- Date: 12-11-2015
-- checks for PIR during Alarm Away status
-- if detected then alert and set the alarm flag
commandArray = {}
if (PIR_switch:sub(1,3) == 'PIR') then
	if(otherdevices['Security Panel'] == 'Arm Away') then
		print('PIR motion detected:'..PIR_switch)
		commandArray['SendNotification']='PIR motion detected:'..PIR_switch
		commandArray['Variable:AlarmDetected'] = '1'
return commandArray

  1. If you use a camera, set it up as described above and create the dummy switch so you can take a picture when triggering the switch. Make sure you set up your email address so it can actually send you the picture as well (instead of the burglar ending up with a nice picture of him/herself)
  2. Decide how you want to deal with the alarms generated. A simple way could be to create an event called AlarmNotification with the following blocky:


This sends a notification and switches the AlarmDetected flag off after 20 seconds. It also sets the SoundSiren variable such that in 90 seconds, the Siren will go off. This allows for a 90 second window to shut off the alarm if you want to enter the house.

This AlarmOff event will shut down the alarm once the keypad disables it and will kill any siren if that currently on.


This AlarmOn event ensures is triggered when the system is armed:


This SoundSiren event will start the siren but only if the the system is armed and will not go off if you disarm the system when you enter the house:


In my case, this is still WIP. Considerations for me are:

  • if after sundown and before sun-up (simple addition to the event above), switch on the lights and use my indoor camera to take a picture (or start recording?)
  • if I get an alarm notification on my phone, am I better off asking my neighbors to check up on the house using our community whatsapp group? If after 1am and before 7am, should I still sound the alarm since nobody is looking at their phones?
  • Do I want any speaker connected to my pi saying that the police is on their way now?

As you can see, the possibilities are endless and I still need to make up my mind how exactly I will handle them. Domoticz at least allows us to do whatever I would want to do in a way that is much more flexible than any standard alarm system. I suspect this approach may have some flaws here and there so feedback is appreciated.