Presence detection based on IP and Bluetooth

Moderator: leecollings

User avatar
havnegata
Posts: 114
Joined: Wednesday 10 September 2014 11:05
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.10162
Location: Norway
Contact:

Re: Presence detection based on IP and Bluetooth

Post by havnegata »

Have arrived at the spot where I'm to test the script:

pi@raspberrypi:~/domoticz/scripts $ lua presence.lua
lua: presence.lua:85: module 'socket.http' not found:
no field package.preload['socket.http']
no file './socket/http.lua'
no file '/usr/local/share/lua/5.1/socket/http.lua'
no file '/usr/local/share/lua/5.1/socket/http/init.lua'
no file '/usr/local/lib/lua/5.1/socket/http.lua'
no file '/usr/local/lib/lua/5.1/socket/http/init.lua'
no file '/usr/share/lua/5.1/socket/http.lua'
no file '/usr/share/lua/5.1/socket/http/init.lua'
no file './socket/http.so'
no file '/usr/local/lib/lua/5.1/socket/http.so'
no file '/usr/lib/arm-linux-gnueabihf/lua/5.1/socket/http.so'
no file '/usr/lib/lua/5.1/socket/http.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './socket.so'
no file '/usr/local/lib/lua/5.1/socket.so'
no file '/usr/lib/arm-linux-gnueabihf/lua/5.1/socket.so'
no file '/usr/lib/lua/5.1/socket.so'
no file '/usr/local/lib/lua/5.1/loadall.so'

I have made the two new directories and downloaded the two files from https://www.domoticz.com/wiki/Remote_Co ... _Libraries and and extracted them:

pi@raspberrypi:/usr/local/share/lua/5.2 $ ls -l
total 152
-rw-r--r-- 1 root staff 2184 Oct 25 2013 ansicolors.lua
-rw-r--r-- 1 root staff 34843 May 28 2015 JSON.lua
-rw-r--r-- 1 root staff 8331 Sep 25 2014 ltn12.lua
-rw-r--r-- 1 root staff 4812 Sep 25 2014 luacolors.lua
-rw-r--r-- 1 root staff 2487 Sep 25 2014 mime.lua
-rw-r--r-- 1 root staff 62698 Sep 7 2014 mobdebug.lua
drwxr-sr-x 2 root staff 4096 Sep 25 2014 socket
-rw-r--r-- 1 root staff 5011 Sep 7 2014 socket.lua
drwxr-xr-x 2 root staff 4096 Jul 5 2015 ssl
-rw-r--r-- 1 root staff 4663 Jul 5 2015 ssl.lua

pi@raspberrypi:/usr/local/lib/lua/5.2 $ ls -l
total 68
drwxr-sr-x 2 root staff 4096 Sep 25 2014 mime
drwxr-sr-x 2 root staff 4096 Sep 7 2014 socket
-rwxr-xr-x 1 root root 61293 Jul 5 2015 ssl.so
pi@raspberrypi:/usr/local/lib/lua/5.2 $


Why is LUA searching for the files in the /5.1 directory?
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

Guess you also still need to install LUA 5.2 as described a little above the libraries: https://www.domoticz.com/wiki/Remote_Co ... ll_Lua_5.2

Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
User avatar
havnegata
Posts: 114
Joined: Wednesday 10 September 2014 11:05
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.10162
Location: Norway
Contact:

Re: Presence detection based on IP and Bluetooth

Post by havnegata »

OK, then I get:

pi@raspberrypi:~/domoticz/scripts $ lua presence.lua
lua: error loading module 'ssl.core' from file '/usr/local/lib/lua/5.2/ssl.so':
libssl.so.1.0.0: cannot open shared object file: No such file or directory
stack traceback:
[C]: in ?
[C]: in function 'require'
/usr/local/share/lua/5.2/ssl.lua:7: in main chunk
[C]: in function 'require'
/usr/local/share/lua/5.2/ssl/https.lua:10: in main chunk
[C]: in function 'require'
presence.lua:87: in main chunk
[C]: in ?
pi@raspberrypi:~/domoticz/scripts $
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

Did you download both files? Think you missed the second one.

Jos
usrlocalsharelua52.tar.gz
cd /usr/local/share/lua/5.2/
sudo tar -xvf ~/temp/usrlocalsharelua52.tar.gz
(128.81 KiB) Downloaded 1111 times
usrlocalliblua52.tar.gz
cd /usr/local/lib/lua/5.2/
sudo tar -xvf usrlocalliblua52.tar.gz
(142.82 KiB) Downloaded 888 times
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

I have updated the install lines to:

Code: Select all

--
-- Install LUA 5.2 when its not installed yet:
-->  sudo apt-get install lua5.2
--
-- require some LUA libraries: SOCKET.HTTP/SOCKET/JSON/ssl.https
-- includes need to be located in: /usr/local/share/lua/5.2/ and /usr/local/lib/lua/5.2/
-- Download and install usrlocalsharelua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3677
--> wget -O /tmp/usrlocalsharelua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3677"
--> cd /usr/local/share/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalsharelua52.tar.gz

-- Download and install usrlocalliblua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3676
--> wget -O /tmp/usrlocalliblua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3676"
--> cd /usr/local/lib/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalliblua52.tar.gz
-- end - Prerequisites --------------------------------------------------------------------------
Let me know in case this doesn't work.

Thanks for the feedback,
Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
User avatar
havnegata
Posts: 114
Joined: Wednesday 10 September 2014 11:05
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.10162
Location: Norway
Contact:

Re: Presence detection based on IP and Bluetooth

Post by havnegata »

Thank you very much for trying to help me, and the improved installguide is much easier, but following it again gives me exactly the same error. Should say that I'm on RPI3 with Stretch and V3.8661
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

I am on a RPI2b with jessie so can't try what you are doing, but I would have expected when the files are in the correct path shown in the previous error, that things should work... Maybe this is related to the other errors I have seen around this ssl topic & Stretch?
http://www.domoticz.com/forum/viewtopic ... .0#p154713

Jos
Last edited by jvdz on Friday 03 November 2017 14:23, edited 1 time in total.
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
User avatar
havnegata
Posts: 114
Joined: Wednesday 10 September 2014 11:05
Target OS: Raspberry Pi / ODroid
Domoticz version: V4.10162
Location: Norway
Contact:

Re: Presence detection based on IP and Bluetooth

Post by havnegata »

Yes, I was thinking the same too... The only thing different is that I have a working Domoticz.
Anyway, thanks for your efforts!
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

See here in case you have the below ssl warning: http://www.domoticz.com/forum/viewtopic ... 94#p158394
lua: error loading module 'ssl.core' from file '/usr/local/lib/lua/5.2/ssl.so':
libssl.so.1.0.0: cannot open shared object file: No such file or directory
Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
rlg6767
Posts: 8
Joined: Friday 30 March 2018 22:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Presence detection based on IP and Bluetooth

Post by rlg6767 »

So I got this working on a raspberry pi 3 (many thanks by the way!!) but it seems to be crashing Domoticz randomly when it tries to update the switch status (but not always). The following error message appeared in the console whilst running the script:

JSON request <http://192.168.1.90:8080/json.htm?type=devices&rid=25>
lua: /usr/local/share/lua/5.2/JSON.lua:383: nil passed to JSON:decode()
stack traceback:
[C]: in function 'assert'
/usr/local/share/lua/5.2/JSON.lua:383: in function 'onDecodeOfNilError'
/usr/local/share/lua/5.2/JSON.lua:644: in function 'decode'
/home/pi/domoticz/scripts/presence.lua:133: in function 'retrieve_status'
/home/pi/domoticz/scripts/presence.lua:166: in function 'domo_status'
/home/pi/domoticz/scripts/presence.lua:228: in main chunk
[C]: in ?

Any advice please?
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

That error means that the JSON call to the server fails as no data is returned.
I will have a look and add some error checking in that function to Ensure it doesn't crash and post that here.

Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
rlg6767
Posts: 8
Joined: Friday 30 March 2018 22:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Presence detection based on IP and Bluetooth

Post by rlg6767 »

That would be good, much appreciated. I think it might be that Domoticz occasionally doesn't respond to the JSON. I tried the URL in the browser and it returned data on the relevant virtual switch.
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

Could you try this version to see if that now works for you with that error?

Code: Select all

-- ==============================================================================================
-- Presence detection script using both fixed IP and BlueTooth to ensure proper detection
-- ==============================================================================================
-- -Prerequisites -------------------------------------------------------------------------------
-- Install bluetooth support:
--> 	sudo apt-get update    # Update package list
--> 	sudo apt-get upgrade   # Upgrade system
--> 	sudo apt-get install bluetooth bluez-utils blueman
--
-- Perform a scan for BT devices:  (make sure your device is visible on BT)
-->	hcitool scan
--
-- Find the proper directory for your PI bt in /var/lib/bluetooth/??:??:??:??
-- For the found device add a pin code to pincodes file:    # use existing MAC folder
--> echo "<MAC> 0000" > /var/lib/bluetooth/??:??:??:??/pincodes
-- Test device by doing: hcitool name <MAC>
--
-- optionally could need to first Pair device when previous doesn't work. Worked for me without this
--> rfcomm connect 0 <MAC> 10  #and fill pin 0000 on phone/device
-- The rfcomm command can fail, no problem.
--
-- Changed the timeout "Page timeout: 8192 slots (5120.00 ms)" to " Page timeout: 4096 slots (2560.00 ms)"
-->   sudo hciconfig hci0 pageto 4096
--
-- Install LUA 5.2 when its not installed yet:
-->  sudo apt-get install lua5.2
--
-- require some LUA libraries: SOCKET.HTTP/SOCKET/JSON/ssl.https
-- includes need to be located in: /usr/local/share/lua/5.2/ and /usr/local/lib/lua/5.2/
-- Download and install usrlocalsharelua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3677
--> wget -O /tmp/usrlocalsharelua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3677"
--> cd /usr/local/share/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalsharelua52.tar.gz

-- Download and install usrlocalliblua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3676
--> wget -O /tmp/usrlocalliblua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3676"
--> cd /usr/local/lib/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalliblua52.tar.gz
-- end - Prerequisites --------------------------------------------------------------------------

-- # Crontab entries ---------------------------------------------------------------------------
-- !!! do this part when you have completed setting all variables below and things are working. !!!
--> # presence detection script is shelled every 2 minutes to ensure it remains active. The script dected whether it is already running
--> */2 * * * * lua /home/pi/domoticz/scripts/presence.lua -batch >> /var/tmp/presence_check.log
--
--### Start Define all required variables #############################################
ScriptName="presence.lua"  				-- set to the scriptfilename, used for checking occurences
server_url="http://192.168.0.??:8080"  	-- domoticz url
-- update LoopLog with latest time. This file can be used to check whether the process is still running with monit
-- Define "" when you  don't want to use Monit.
-- 	Monit definition used:
-- 		check file Presence with path /var/tmp/presence-monit.log
-- 			stop program = "/usr/bin/pkill -f presence" timeout 60 seconds
-- 			if timestamp > 2 minutes then restart
-- 			if 5 restarts within 5 cycles then timeout
-- Monit_check_log=""   -- don't create this extra Monit logfile
Monit_check_log="/var/tmp/presence-monit.log"
--
LoopTimeShort=10        -- Sleep Timer used when one of the phones is not found to recheck it
LoopTimeLong=30         -- Sleep Timer used when all phones are present
FailTimeout=120         -- Time used to determine the phone is really gone.
LoopTime=LoopTimeLong
debug=2                 -- defines the logging level.
--                             0=basic info is logged
--                             1=some extra info
--                             2=all available info used only in case of issues
-- Phone configuration table ---------------------------------------------------------------
TelName = {}  	  		-- name of the telephone
TelIP = {}	 	  		-- Ip address  (put on "" when on;y using BT)
TelBT = {}		  		-- BT mac address
TelIDX = {}		 		-- IDX of dummy Domoticz On/Off switch for the phone
TelFail = {}	  		-- count of checks that failed subsequently -> used by the script
TelFailTime = {}  		-- Time of the first failure 				-> Used by the script
--  first phone to check -------------------------------------------------------------------
Rec = 0
TelName[Rec] = "Phone1"
TelIP[Rec] = "192.168.0.xx"
TelBT[Rec] = "AA:BB:CC:DD:EE:FF"
TelIDX[Rec] = "??"
TelFail[Rec] = 0       -- don't change
TelFailTime[Rec] = 0   -- don't change
--  Second phone to check (remove block when only one phone is needed ----------------------
Rec = Rec +1
TelName[Rec] = "Phone2"
TelIP[Rec] = "192.168.0.XX"
TelBT[Rec] = "AA:BB:CC:DD:EE:XX"
TelIDX[Rec] = "??"
TelFail[Rec] = 0       -- don't change
TelFailTime[Rec] = 0   -- don't change
--------------------------------------------------------------------------------------------
TelCheckVar=""         -- User Variable in Domoticz which can be used to find the last time the phones were checked.
                       -- Leave empty when not used.
--### End Define all required variables #############################################

-- Load necessary Lua libraries
http = require "socket.http";
socket = require "socket";
https = require "ssl.https";
JSON = require "JSON";
--
-- "2" only works when shelled from crontab else use "3" when testing from commandline
--    so ensure that you add the -batch when running it from crontab!

-- check howmany scripts are running with this name.
local file = io.popen('ps x | grep "'..ScriptName..'"|grep -cv grep')
local output = file:read('*all')
local rc = {file:close()}
output = string.gsub(output,"\n","") -- remove newline from output
if debug > 1 then
   print ('cmd-> ps x | grep "'..ScriptName..'"|grep -cv grep   => rc:'..tostring(rc[1])..'  output:'..tostring(output))
end
if arg[1] == "-batch" and output == "2" then
   print("batch and no=2 so not running yet")
elseif output == "1" then
   print("no=1  so not running yet")
else
   print("Already running -> Exit")
   os.exit(0)
end

--### Start Define all required LUA functions #############################################
function sleep(n)
  os.execute("sleep " .. tonumber(n))
end
-- retrieve status from domoticz
function retrieve_status(idx)
   local t, jresponse, status, decoded_response
   t = server_url.."/json.htm?type=devices&rid="..tostring(idx)
   if debug>=2 then
      print("JSON request <"..t..">")
   end
   jresponse, status = http.request(t)
   if jresponse ~= nil then
      decoded_response = JSON:decode(jresponse)
      result = decoded_response["result"]
      record = result[1]
      status = record["Status"]
   else
      status = "Failed"
   end
   if debug>=2 then
      print("Status JSON request "..status)
   end
   return status
end
-- Change state of Switch in Domoticz
function SwitchName(idx,state)
   local status
   if string.lower(state) == "on" then
      state = "On";
   elseif string.lower(state) == "off" then
      state = "Off";
   end
   t = server_url.."/json.htm?type=command&param=switchlight&idx="..idx.."&switchcmd="..state;
   if debug>=2 then print("JSON request <"..t..">") end
   jresponse, status = http.request(t)
   if jresponse ~= nil then
      result = JSON:decode(jresponse)
      status = result["status"]
   else
      status = "Failed"
   end
   --
   if status ~= "OK" then
      print(os.date("%X").." !!!! SwitchName Not OK -> JSON feedback: ", jresponse)
   else
      if debug>=2 then
         print("JSON feedback: ", jresponse)
      end
   end
   return
end
-- Check and update switch in Domoticz
function domo_status(Name,Fail,PrevFail,FailTime,IDX,source,newstatus)
   curstate = retrieve_status(IDX)
   if debug>=1 then
      print(os.date("%X").." "..IDX.." "..Name.."  current="..curstate.."  New="..newstatus.." from="..source.."  fail="..Fail.."  prevfail="..PrevFail.. " time="..os.time()-FailTime)
   end
   -- skip rest of process in case the call to domoticz failed
   if curstate == "Failed" then
      return
   end
   if Fail == 1 and curstate == "On" then
      print(os.date("%X").." ---- phone failed -> retrying "..Name)
   end
   if PrevFail > Fail and curstate == "On" then
      print(os.date("%X").." ---- phone connected again    "..Name.."  bron:"..source)
   end
   if (newstatus == "Off" and os.time()-FailTime >= FailTimeout and curstate ~= newstatus)
   or (newstatus == "On" and curstate ~= newstatus) then
      print(os.date("%X").." #### Switch phone "..Name.." "..newstatus.."  bron:"..source.." ("..Fail..")" )
      SwitchName(IDX,newstatus)
   end
end
--### End Define all required functions #############################################

--############################################
--# Main loop
--############################################
-- List record to log that are being monitored
for Rec in pairs(TelName) do
   curstate = retrieve_status(TelIDX[Rec])
   print(os.date("%X").." ---- Starting monitoring for "..TelName[Rec].." ("..TelIDX[Rec]..")  CurState="..curstate.."  IPaddres="..TelIP[Rec].."  BTmac="..TelBT[Rec])
end

print("Starting")
-- create poll file to check for Monit
if Monit_check_log ~= "" then
   os.execute("echo " .. os.date("%Y-%m-%d %H:%M:%S") .. " > " .. Monit_check_log)
end

-- Loop to monitor all devices
while true do
   --
   timenow = os.time()
   if debug>=1 then
      print(os.date("%X").." ".."=================================================================")
   end
   for Rec in pairs(TelName) do
      -- first try a IP ping as that is the fastest check
      PrevFail=TelFail[Rec]
      if TelIP[Rec] ~= "" then
         ping_success=os.execute('ping -c1 -w2 ' .. TelIP[Rec].." > /dev/null")
      else
         ping_success=false
      end
      if ping_success then
         TelFail[Rec] = 0
         TelFailTime[Rec] = 0
         domo_status(TelName[Rec],TelFail[Rec],PrevFail,os.time(),TelIDX[Rec],"Ping","On")
      else
         -- If Ping fails try the BT check with hcitool which is faster and less CPU than l2ping
         bt_success=os.execute('hcitool name ' .. TelBT[Rec]..'|grep ".*" > /dev/null')
         -- check for characters returned .. if nothing then phone not found
         if bt_success==nil then
            TelFail[Rec] = TelFail[Rec] + 1
            -- set the failtime at first failure to find phone
            if TelFail[Rec] == 1 then
               TelFailTime[Rec] = os.time()
            end
            domo_status(TelName[Rec],TelFail[Rec],PrevFail,TelFailTime[Rec],TelIDX[Rec],"Both","Off")
            LoopTime=LoopTimeShort    -- set looptime lower when a phone isn't present
         else
            TelFail[Rec] = 0
            TelFailTime[Rec] = 0
            domo_status(TelName[Rec],TelFail[Rec],PrevFail,os.time(),TelIDX[Rec],"BT","On")
         end
      end
   end
   -- update uservariable with the last status check done time.
   if TelCheckVar ~= "" then
      t = server_url..'/json.htm?type=command&param=updateuservariable&vname=' .. TelCheckVar .. '&vtype=2&vvalue=' .. os.date("%X") .. '';
      if debug>=2 then print("JSON request <"..t..">") end
      jresponse, status = http.request(t)
      if jresponse ~= nil then
         result = JSON:decode(jresponse)
         status = result["status"]
      else
         status = "Failed"
      end
      if status ~= "OK" then
         print(os.date("%X").." !!!! Set variable ".. TelCheckVar .." Not OK -> JSON feedback: ", jresponse)
      else
         if debug>=2 then
            print("JSON feedback: ", jresponse)
         end
      end
   end
   -- sleep the number of seconds defined in LoopTime
   if os.time() - timenow <= LoopTime then
      if debug>=1 then
         print(os.date("%X").." ".."sleep "..LoopTime-(os.time() - timenow))
      end
      sleep(LoopTime-(os.time() - timenow))
   end
   LoopTime=LoopTimeLong
   -- update LoopLog with latest time. This file can be used to check whether the process is still running with monit
   if Monit_check_log ~= "" then
      os.execute("echo " .. os.date("%Y-%m-%d %H:%M:%S") .. " > " .. Monit_check_log)
   end
end
Will update first post when it works ok.
Thanks,
Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
rlg6767
Posts: 8
Joined: Friday 30 March 2018 22:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Presence detection based on IP and Bluetooth

Post by rlg6767 »

Great, will check it out tonight and report back. Many thanks.
rlg6767
Posts: 8
Joined: Friday 30 March 2018 22:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Presence detection based on IP and Bluetooth

Post by rlg6767 »

Update:
So I have been running the script from the command line now with no crashes and it all seems very happy. Will run from crontab overnight and report back.

Quick question on functionality. I noticed that when only one device is connected (I have two that I'm monitoring) and the ping frequency increases in order to provide better reconnect detection, it seems to be pinging both devices at the increased frequency. Is this by design?

And great script by the way, pretty much instant detection when I enable wireless and bluetooth on phone (bluetooth detection is especially quick!).
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

Correct, the pause time decreases when one device is not detected and configured with:
LoopTimeShort=10 -- Sleep Timer used when one of the phones is not found to recheck it
LoopTimeLong=30 -- Sleep Timer used when all phones are present

The script is based on work of others that supported a single device and converted that to LUA and added multiple device support with a single script, but haven't bothered to try to complicate the code and simply increase the loop speed for all.
Ideas on how to do that differently?
I am using this script now for about 2 years and it has ran fine without issues supporting also 2 devices,

Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
bvansteyn
Posts: 18
Joined: Wednesday 07 March 2018 18:22
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: The Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by bvansteyn »

jvdz wrote: Friday 06 April 2018 9:14 Correct, the pause time decreases when one device is not detected and configured with:
LoopTimeShort=10 -- Sleep Timer used when one of the phones is not found to recheck it
LoopTimeLong=30 -- Sleep Timer used when all phones are present

The script is based on work of others that supported a single device and converted that to LUA and added multiple device support with a single script, but haven't bothered to try to complicate the code and simply increase the loop speed for all.
Ideas on how to do that differently?
I am using this script now for about 2 years and it has ran fine without issues supporting also 2 devices,

Jos
Nice script/work! I'm going to implement this at home this weekend!
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

rlg6767 wrote: Thursday 05 April 2018 23:51 Quick question on functionality. I noticed that when only one device is connected (I have two that I'm monitoring) and the ping frequency increases in order to provide better reconnect detection, it seems to be pinging both devices at the increased frequency. Is this by design?
Somehow your question intrigued me and triggered a new version which now works as follows:
You define the looptime ( 10 seconds is the default)
When a device failed it will do a check each loop
When a device is active it will be check one time in 3 loops (30 seconds).
This way it does save a little processing time.
Also updated the device definition table into one table making it simpler to define the devices.
It is running for me for a couple of hour now and all seems to be running fine.

Let me know in case there are questions or issues. Will update the initial post after a couple of days testing.

Jos

Code: Select all

-- ==============================================================================================
-- Presence detection script using both fixed IP and BlueTooth to ensure proper detection
-- ==============================================================================================
-- -Prerequisites -------------------------------------------------------------------------------
-- Install bluetooth support:
-->    sudo apt-get update    # Update package list
-->    sudo apt-get upgrade   # Upgrade system
-->    sudo apt-get install bluetooth bluez-utils blueman
--
-- Perform a scan for BT devices:  (make sure your device is visible on BT)
-->   hcitool scan
--
-- Find the proper directory for your PI bt in /var/lib/bluetooth/??:??:??:??
-- For the found device add a pin code to pincodes file:    # use existing MAC folder
--> echo "<MAC> 0000" > /var/lib/bluetooth/??:??:??:??/pincodes
-- Test device by doing: hcitool name <MAC>
--
-- optionally could need to first Pair device when previous doesn't work. Worked for me without this
--> rfcomm connect 0 <MAC> 10  #and fill pin 0000 on phone/device
-- The rfcomm command can fail, no problem.
--
-- Changed the timeout "Page timeout: 8192 slots (5120.00 ms)" to " Page timeout: 4096 slots (2560.00 ms)"
-->   sudo hciconfig hci0 pageto 4096
--
-- Install LUA 5.2 when its not installed yet:
-->  sudo apt-get install lua5.2
--
-- require some LUA libraries: SOCKET.HTTP/SOCKET/JSON/ssl.https
-- includes need to be located in: /usr/local/share/lua/5.2/ and /usr/local/lib/lua/5.2/
-- Download and install usrlocalsharelua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3677
--> wget -O /tmp/usrlocalsharelua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3677"
--> cd /usr/local/share/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalsharelua52.tar.gz

-- Download and install usrlocalliblua52.tar.gz from: http://www.domoticz.com/forum/download/file.php?id=3676
--> wget -O /tmp/usrlocalliblua52.tar.gz "http://www.domoticz.com/forum/download/file.php?id=3676"
--> cd /usr/local/lib/lua/5.2/
--> sudo tar -xvf /tmp/usrlocalliblua52.tar.gz
-- end - Prerequisites --------------------------------------------------------------------------

-- # Crontab entries ---------------------------------------------------------------------------
-- !!! do this part when you have completed setting all variables below and things are working. !!!
--> # presence detection script is shelled every 2 minutes to ensure it remains active. The script dected whether it is already running
--> */2 * * * * lua /home/pi/domoticz/scripts/presence.lua -batch >> /var/tmp/presence_check.log
--
--### Start Define all required variables #############################################
ScriptName="presence.lua"                        -- set to the scriptfilename, used for checking occurences
Domoticz_Server_Url="http://192.168.xx.xx:8080"  -- Define Domoticz server URL
-- update LoopLog with latest time. This file can be used to check whether the process is still running with monit
-- Define "" when you  don't want to use Monit.
--    Monit definition used:
--       check file Presence with path /var/tmp/presence-monit.log
--          stop program = "/usr/bin/pkill -f presence" timeout 60 seconds
--          if timestamp > 2 minutes then restart
--          if 5 restarts within 5 cycles then timeout
-- Monit_check_log=""   -- don't create this extra Monit logfile
Monit_check_log="/var/tmp/presence-monit.log"
--
LoopTime=10       -- recheck Timer used for the phones not detected
--                   A phone that is detected with only be checked each 3rd loop
FailTimeout=120   -- Time used to determine the phone is really gone.
debug=0           -- defines the logging level.
--                   0=basic info is logged
--                   1=some extra info
--                   2=all available info used only in case of issues
-- Phone configuration table ---------------------------------------------------------------
--    idx = Domoticz device idx for the switch of the Phone
--    ip  = ipaddress to check for the phone. No IP check done when left ""
--    bt  = BlueTooth macaddress to check for the phone. No BT check done when left ""
local TelCfgName = {
   ["Phone1"]={idx=??,ip="192.168.??.??",bt="??:??:??:??:??:??"},
   ["Phone2"]={idx=??,ip="192.168.??.??",bt="??:??:??:??:??:??"}}
--------------------------------------------------------------------------------------------
local TelCheckVar=""     -- User Variable name in Domoticz which can be used to find the last time the phones were checked.
                         -- Leave empty when not used.
--### End Define all required variables #############################################

-- include is located: /root/usr/local/share/lua/5.2
-- Load necessary Lua libraries
http   = require "socket.http";
socket = require "socket";
https  = require "ssl.https";
JSON   = require "JSON";
--
-- "2" only works when shelled from crontab else use "3" when testing from commandline
--    so ensure that you add the -batch when running it from crontab!

-- check how many scripts are running with this name.
local file = io.popen('ps x | grep "'..ScriptName..'"|grep -cv grep')
local output = file:read('*all')
local rc = {file:close()}
output = string.gsub(output,"\n","") -- remove newline from output
if debug > 1 then
   print ('cmd-> ps x | grep "'..ScriptName..'"|grep -cv grep   => rc:'..tostring(rc[1])..'  output:'..tostring(output))
end
if arg[1] == "-batch" and output == "2" then
   print("batch and no=2 so not running yet")
elseif arg[1] == "-debug" then
   print("Testing the script from commandline... used for development.")
elseif output == "1" then
   print("no=1  so not running yet")
else
   print("Already running -> Exit")
   os.exit(0)
end

--### Start Define all required LUA functions #############################################
function sleep(n)
  os.execute("sleep " .. tonumber(n))
end
-- retrieve status from domoticz
function retrieve_status(idx)
   local t, jresponse, status, decoded_response
   t = Domoticz_Server_Url.."/json.htm?type=devices&rid="..tostring(idx)
   if debug>=2 then
      print("JSON request <"..t..">")
   end
   jresponse, status = http.request(t)
    if jresponse ~= nil then
      decoded_response = JSON:decode(jresponse)
      result = decoded_response["result"]
      record = result[1]
      status = record["Status"]
    else
        status = "Failed"
    end
   if debug>=2 then
      print("Status JSON request "..status)
   end
   return status
end
-- Change state of Switch in Domoticz
function SwitchName(idx,state)
   local status
   if string.lower(state) == "on" then
      state = "On";
   elseif string.lower(state) == "off" then
      state = "Off";
   end
   t = Domoticz_Server_Url.."/json.htm?type=command&param=switchlight&idx="..idx.."&switchcmd="..state;
   if debug>=2 then print("JSON request <"..t..">") end
   jresponse, status = http.request(t)
    if jresponse ~= nil then
       result = JSON:decode(jresponse)
       status = result["status"]
    else
        status = "Failed"
    end
   --
   if status ~= "OK" then
      print(os.date("%X").." !!!! SwitchName Not OK -> JSON feedback: ", jresponse)
   else
      if debug>=2 then
         print("JSON feedback: ", jresponse)
      end
   end
   return
end
-- Check and update switch in Domoticz
function domo_status(Name,Fail,PrevFail,FailTime,IDX,source,newstatus)
   curstate = retrieve_status(IDX)
   if debug>=1 then
      print(os.date("%X").." "..IDX.." "..Name.."  current="..curstate.."  New="..newstatus.." from="..source.."  fail="..Fail.."  prevfail="..PrevFail.. " time="..os.time()-FailTime)
   end
   -- skip rest of process in case the call to domoticz failed
   if curstate == "Failed" then
      return
   end
   if Fail == 1 and curstate == "On" then
      print(os.date("%X").." ---- phone failed -> retrying "..Name)
   end
   if PrevFail > Fail and curstate == "On" then
      print(os.date("%X").." ---- phone connected again    "..Name.."  bron:"..source)
   end
   if (newstatus == "Off" and os.time()-FailTime >= FailTimeout and curstate ~= newstatus)
   or (newstatus == "On" and curstate ~= newstatus) then
      print(os.date("%X").." #### Switch phone "..Name.." "..newstatus.."  bron:"..source.." ("..Fail..")" )
      SwitchName(IDX,newstatus)
   end
end
--### End Define all required functions #############################################

--############################################
--# Main loop
--############################################
-- List record to log that are being monitored
for Name in pairs(TelCfgName) do
   -- initialise workfields used by the script
   TelCfgName[Name].TelFail=0
   TelCfgName[Name].TelFailTime=0
   TelCfgName[Name].LoopCount=3
   curstate = retrieve_status(TelCfgName[Name].idx)
   print(os.date("%X").." ---- Starting monitoring for "..Name.." ("..TelCfgName[Name].idx..")  CurState="..curstate.."  IPaddres="..TelCfgName[Name].ip.."  BTmac="..TelCfgName[Name].bt)
end

-- create poll file to check for Monit
if Monit_check_log ~= "" then
   os.execute("echo " .. os.date("%Y-%m-%d %H:%M:%S") .. " > " .. Monit_check_log)
end

-- Loop to monitor all devices
while true do
   --
   timenow = os.time()
   if debug>=1 then
      print(os.date("%X").." ".."=================================================================")
   end
   for Name in pairs(TelCfgName) do
      -- only check every 3rd time when detected
      if TelCfgName[Name].LoopCount < 3 and TelCfgName[Name].TelFail == 0 then
         TelCfgName[Name].LoopCount = TelCfgName[Name].LoopCount + 1
      else
         TelCfgName[Name].LoopCount = 1
         -- first try a IP ping as that is the fastest check
         PrevFail=TelCfgName[Name].TelFail
         if TelCfgName[Name].ip ~= "" then
            ping_success=os.execute('ping -c1 -w2 ' .. TelCfgName[Name].ip.." > /dev/null")
         else
            ping_success=false
         end
         if ping_success then
            TelCfgName[Name].TelFail = 0
            TelCfgName[Name].TelFailTime = 0
            domo_status(Name,TelCfgName[Name].TelFail,PrevFail,os.time(),TelCfgName[Name].idx,"Ping","On")
         else
            -- If Ping fails try the BT check with hcitool which is faster and less CPU than l2ping
            bt_success=os.execute('hcitool name ' .. TelCfgName[Name].bt..'|grep ".*" > /dev/null')
            -- check for characters returned .. if nothing then phone not found
            if bt_success==nil then
               TelCfgName[Name].TelFail = TelCfgName[Name].TelFail + 1
               -- set the failtime at first failure to find phone
               if TelCfgName[Name].TelFail == 1 then
                  TelCfgName[Name].TelFailTime = os.time()
               end
               domo_status(Name,TelCfgName[Name].TelFail,PrevFail,TelCfgName[Name].TelFailTime,TelCfgName[Name].idx,"Both","Off")
            else
               TelCfgName[Name].TelFail = 0
               TelCfgName[Name].TelFailTime = 0
               domo_status(Name,TelCfgName[Name].TelFail,PrevFail,os.time(),TelCfgName[Name].idx,"BT","On")
            end
         end
      end
   end
   -- update uservariable with the last status check done time.
   if TelCheckVar ~= "" then
      t = Domoticz_Server_Url..'/json.htm?type=command&param=updateuservariable&vname=' .. TelCheckVar .. '&vtype=2&vvalue=' .. os.date("%X") .. '';
      if debug>=2 then print("JSON request <"..t..">") end
      jresponse, status = http.request(t)
      if jresponse ~= nil then
         result = JSON:decode(jresponse)
         status = result["status"]
      else
         status = "Failed"
      end
      if status ~= "OK" then
         print(os.date("%X").." !!!! Set variable ".. TelCheckVar .." Not OK -> JSON feedback: ", jresponse)
      else
         if debug>=2 then
            print("JSON feedback: ", jresponse)
         end
      end
   end
   -- sleep the number of seconds defined in LoopTime
   if os.time() - timenow <= LoopTime then
      if debug>=1 then
         print(os.date("%X").." ".."sleep "..LoopTime-(os.time() - timenow))
      end
      sleep(LoopTime-(os.time() - timenow))
   end
    -- update LoopLog with latest time. This file can be used to check whether the process is still running with monit
   if Monit_check_log ~= "" then
        os.execute("echo " .. os.date("%Y-%m-%d %H:%M:%S") .. " > " .. Monit_check_log)
   end
end
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
rlg6767
Posts: 8
Joined: Friday 30 March 2018 22:51
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Presence detection based on IP and Bluetooth

Post by rlg6767 »

Sorry for the slow reply. I can confirm the script is working really well from a cron job. Will happily test your new script out. The rationale behind the comment around whether the frequency of pings etc slows down for both devices was from both a CPU cycle and also mobile battery viewpoint. I.e. if the phone is at home it may adversely affect battery life with the additional pings.

I had a quick question on the bluetooth side of things. I find that the script will find the mobile phone once but then won't see it again after that. I must admit I didn't completely follow the bluetooth config with setting the pin code etc as I could see it was initially seeing the device. Also, I don't know where I would tell the phone that a pin code is required, and what it is set to etc. Is this vital?

Many thanks for a great script!!
User avatar
jvdz
Posts: 2266
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Presence detection based on IP and Bluetooth

Post by jvdz »

rlg6767 wrote: Tuesday 10 April 2018 22:26 I had a quick question on the bluetooth side of things. I find that the script will find the mobile phone once but then won't see it again after that. I must admit I didn't completely follow the bluetooth config with setting the pin code etc as I could see it was initially seeing the device. Also, I don't know where I would tell the phone that a pin code is required, and what it is set to etc. Is this vital?
How do you figure the BT only works one time? do devices start failing after that when the ping doesn't respond?
The BT test will only be done in case the ping is failing.
As to BT setup process: I simply copied that from the another person's information, followed it and it worked, so never questioned whether all steps are needed.

Jos
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest