dzVents presence detection and security alarms

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
commodore white
Posts: 63
Joined: Sunday 14 July 2013 11:19
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Ipswich, UK
Contact:

dzVents presence detection and security alarms

Post by commodore white »

The following code implements a presence detector based on the proximity of (android) mobile phones. Unusually, its written using features found in the dzVents package found here:

http://www.domoticz.com/forum/viewtopic ... 23&t=10834

Enjoy.

I've taken the liberty of publishing my security alarm code having found things so easy to write using dzVents compared to writing in native LUA.

Suggestions for improvements would be appreciated.

Code: Select all

--[[ lua/scripts/phones.lua by commodore white

This dzVents script implements an android phone presence detector using the
Domoticz System Alive Checker (Ping) feature.

For each phone being monitored, you need two virtual devices, one that you bind to the System
Alive Checker, and another that keeps you informed of the phones proximity. I needed the second
because our phones kept losing and regaining connectivity as we moved around the house or we went outside
for a few minutes perhaps to the washing line.

The script is in two parts, the first responds to pings while the second implements a 'grace period' during
which time a phone can be out of earshot for a short while without raising the alarm.

The script also maintains another virtual device called "AnyPhone" which is On whenever any phone is
in reach.

My virtual devices are called:

Peter and pingPeter
Rita  and pingRita, and
AnyPhone

... that is, 2n+1 virtual devices in total.

--]]

return {
   on = { "ping*", "timer" },
   active = true,
   execute = function(domoticz, _pingPhone)

   local phone
   local pingPhone
   local GRACE = 10
   local lost_or_found
   local AnyPhone
   local _AnyPhone
   local _phone
   local _pingPhone

   printf = function(s,...) return print("dzVents Phones: " .. s:format(...)) end
   
   _AnyPhone = domoticz.devices["AnyPhone"]

   if _pingPhone ~= nil then
     phone = _pingPhone.name:sub(5,99)
     _phone = domoticz.devices[phone]

     if    _pingPhone.state == "On" and _phone.state == "Off"
     then  _phone.switchOn()
           if _AnyPhone.state == "Off" then _AnyPhone.switchOn() end
     end
   else
     AnyPhone = "Off" -- assume no phones found
     domoticz.devices.forEach(function(_pingPhone)
  	   if (_pingPhone.name:sub(1,4) == "ping") then
          phone = _pingPhone.name:sub(5,99)               _phone = domoticz.devices[phone]
          m_phone     = _phone.lastUpdate.minutesAgo      m_pingPhone = _pingPhone.lastUpdate.minutesAgo
         
          if _phone.state == "On" then           -- recently seen
            if    _pingPhone.state == "Off"      -- but currently not seen
            and   m_pingPhone > GRACE            -- and has been so for several minutes
            then  _phone.switchOff()
                  printf("%s's phone lost %um ago", phone, m_pingPhone)
            else
                  printf("%s's phone found %uh %um ago", phone, m_phone/60, m_phone%60)
                  AnyPhone = "On"
            end
          else
             if _pingPhone.state == "On" and _phone.state ~= "On" then _phone.switchOn() end -- incase the ping was missed
             printf("%s's phone lost %uh %um ago", phone, (m_phone+GRACE)/60, (m_phone+GRACE)%60)
          end -- if phone.state        
  		 end
  	 end) -- for each
    
    if AnyPhone ~= _AnyPhone.state then _AnyPhone.setState(AnyPhone) end

    end -- if ping

  end -- function
  
} -- return
I've re-uploaded the phones script since I had foolishly tainted it with unrelated functionality, namely issuing a notification message.I've put the annexed functionality into a separate script below. Not great but it works.

Code: Select all

-- proximity.lua

return {
	active = true,
	on = { 'Peter', "Rita"},

	execute = function(domoticz, phone)
 
		if      phone.state  == "On" 
    and     domoticz.security == domoticz.SECURITY_DISARMED
    then    domoticz.notify(phone.name .. " has arrived home", '',
				      domoticz.PRIORITY_EMERGENCY,
				      domoticz.SOUND_SIREN)
    else
            domoticz.notify(phone.name .. " has arrived home - ALARMS ON", '',
				      domoticz.PRIORITY_EMERGENCY,
				      domoticz.SOUND_SIREN)
		end

	end -- function
}
Security Panel handler in dzVents

Code: Select all

--[[ /lua/scripts/security.lua

This script handles the Security Panel. When security is enabled it first checks if any doors or windows
are alarmed and reports it via messaging.

Shortly after security is enabled, the alarms are enabled and disabled immediately security is disabled.

You'll need to create a virtual device called AlarmsEnabled to use this script.

--]]

return {
	active = true,
	on = { "Security Panel", "AlarmsEnabled",
         "timer" },

	execute = function(domoticz,_device)
  
    DELAY = 30
    _AlarmsEnabled = domoticz.devices["AlarmsEnabled"]
    
    -- If the Security Panel has changed state

    if    _device == domoticz.devices["Security Panel"]
    then
         if    domoticz.security == domoticz.SECURITY_DISARMED
         then         
             if    _AlarmsEnabled.state == "On"      -- prevent spurious disarm events
             then  _AlarmsEnabled.switchOff() end
         else
         
         -- check if any doors or windows are alarmed

              openings = 0
-- disregard perimeter sensors for now
              domoticz.devices.forEach(function(_sensor)
                if    (_sensor.name:sub(1,3) == "msc")
                and   _sensor.state == "Alarm"
                then  openings = openings + 1 end
              end) -- for each
-- perimeter alarms
              if    _AlarmsEnabled.state == "On"
              then  message = "Alarms already enabled"
              else  message = "Alarms enabled in " .. DELAY .. "s" end
              
              if    openings == 0
              then  domoticz.notify("Property seems secure", message)
              else  domoticz.notify(openings .. " openings need securing", message) end
      
              -- schedule alarms to be enabled in DELAY seconds if its not already On
      
              if    _AlarmsEnabled.state ~= "On"
              then  _AlarmsEnabled.switchOn().after_sec(DELAY) end

          end -- security panel state is disarmed
      
    end -- if security panel state changed
    
    -- If the Security Panel state was changed to DISARMED while the alarms are waiting
    -- to be enabled, switch Off the alarms. Shame there's not a cancel function.
    
    if     _AlarmsEnabled.state == "On"
    and    domoticz.security == domoticz.SECURITY_DISARMED
    then   _AlarmsEnabled.switchOff() end
    
    -- Notify everyone when alarms have been enabled or disabled
    
    if    _device == _AlarmsEnabled
    then
          if    _device.state == "On"
          then  domoticz.notify("Alarms enabled", '')
          else  domoticz.notify("Alarms disabled", '') end
    end

  end -- function
}
Perimeter and internal detector handling in dzVents

Code: Select all

--[[ /lua/scripts/motion.lua by commodore white

Report PIR and door/window opening/closing events unless alarm reporting is disabled
sounds a fire alarm if security is high unless a registered phone is nearby

          disarmed or
           suspended     armed home       armed away
          +-------------------------------------------
internal  |  No              No          Notify+Siren                 
          |
perimeter |  No            Notify        Notify+Siren
          +-------------------------------------------
--]]

return {
  active = true,
	on = { 'pir*',    -- internal detectors
        "msc*"    -- perimeter detectors
  },
	execute = function(domoticz, _detector)
 
-- test mode: no alarms if someone is at home, comment out for normal operation
--    if domoticz.devices["AnyPhone"].state == "On" then return end
--

    if    domoticz.security == domoticz.SECURITY_DISARMED then return end         -- don't report if security is DISARMED
    
    if    domoticz.devices["AlarmsEnabled"].state == "Off" then return end        -- ... or if alarms are temporarily suspended

    if   _detector.name:sub(1,3) == "pir"                                         -- ignore internal detectors in
    and  domoticz.security == domoticz.SECURITY_ARMEDHOME                         -- low security mode
    then 
          return
    end

    domoticz.notify('SECURITY BREACH', _detector.name:sub(4), domoticz.PRIORITY_EMERGENCY, domoticz.SOUND_SIREN)
       
    if    domoticz.security == domoticz.SECURITY_ARMEDAWAY                        -- in high security mode
    and   domoticz.devices["AnyPhone"].state == "Off"                             -- check no one is at home
    then
          domoticz.devices["Siren"].switchOn()                                	-- then set off the siren
    end
 
	end -- execute
}
Fire Alarm notification

Code: Select all

--[[ /lua/scripts/fire.lua by commodore white

Notifies which alarm has been triggered

All fire alarms have names that begin with the characters "fire", for example, fireLounge, fireGarage, etc

--]]

return {
	active = true,
	on = { "fire*" },

	execute = function(domoticz, _sounder)
 
    if _sounder.state == "On" then        
 
       local DURATION = 40
     
       domoticz.notify("FIRE ALARM: " .. _sounder.name, '',
          domoticz.PRIORITY_EMERGENCY,
          domoticz.SOUND_SIREN)
          
       domoticz.devices["Alarm"].switchOn()    -- turn on the notify system
       
    end -- if sounder On

	end -- function
}
Panic button notification

Code: Select all

--[[ /lua/scripts/PanicButton.lua by commodore white

Always report panic button presses. There's one in my aged relatives bedroom (panicBedroom),
one in their bathroom (panicBathroom), and another by the front door (panicFrontDoor)

If any panic button is pressed, then the "Alarm" button is turned on.

--]]

return {
  active = true,
	on = { 'panic*'},
	execute = function(domoticz, _panicbutton)
 
    local _alarm = domoticz.devices["Alarm"]                 -- Get id of alarm button
 
    domoticz.notify("PANIC BUTTON", _panicbutton.name:sub(6) .. ' button was pressed')
    if _alarm.state == "Off" then _alarm.switchOn() end      -- enable the Cancel Panic button
    
	end -- execute
}
Door bell button press notification. Needs to work with cameras.

Code: Select all

--[[ /lua/scripts/doorbellpush.lua by commodore white

Notify if any door bell was pressed
Ignore multiple presses within a minute, you need a "BellPressed" variable for this
to work

--]]

return {
  active = true,
	on = { 'bell*' },
	execute = function(domoticz, _bell)
 
    if    domoticz.variables['BellPressed'].lastUpdate.minutesAgo > 1
    then

          domoticz.notify("DOOR BELL", _bell.name:sub(5) .. ' bell was pressed')
  		    domoticz.variables['BellPressed'].set(0)
                                                       
    end                                                     
      
	end -- execute
}
Notification handler

Code: Select all

--[[ /lua/scripts/Notify.lua by commodore white


--]]

return {
   on = {
      ['timer'] = 'every 5 minutes',
      "Alarm"
   },
   active = true,
   execute = function(domoticz, _alarm)
   
      local DURATION = 20

      if    _alarm ~= nil
      then
            if    _alarm.state == "Off"          -- alarm just got cancelled
            then
            
 -- commandArray["OpenURL"]="http://192.168.1.22:8080/json.htm?type=command&param=resetsecuritystatus&idx=86&switchcmd=Normal"
            
                  domoticz.devices["fireLanding"].switchOff()
                  domoticz.devices["fireLanding"].switchOff()
                  domoticz.devices["fireLanding"].switchOff()

                  domoticz.notify("Alarm cancelled",' ')
            end
 
      else
          
          _alarm = domoticz.devices["Alarm"]
          m_alarm = _alarm.lastUpdate.minutesAgo
          
          if     _alarm.state == "On"                            -- Alarm still active ?
          then                                                   -- If so, ...
                  if    m_alarm < DURATION
                  then
                        domoticz.notify ("Alarm raised " .. m_alarm .. "m ago", "Visit Control Panel to clear")
                  else
                        _alarm.switchOff()
                  end
           end

       end -- end if alarm
      
   end -- execute
}
... and not a commandArray in sight!

Peter
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest