2014-09-19 10:20:15 +00:00
# $Id$
2013-02-01 19:10:25 +00:00
##############################################################################
#
2013-02-01 19:15:20 +00:00
# 73_PRESENCE.pm
# Checks for the presence of a mobile phone or tablet by network ping or bluetooth detection.
# It reports the presence of this device as state.
2013-02-01 19:10:25 +00:00
#
# Copyright by Markus Bloch
# e-mail: Notausstieg0309@googlemail.com
#
# This file is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
package main ;
use strict ;
use warnings ;
use Blocking ;
2014-03-10 16:58:36 +00:00
use Time::HiRes qw( gettimeofday usleep sleep ) ;
2013-02-01 19:10:25 +00:00
use DevIo ;
2013-02-13 22:50:26 +00:00
2013-02-01 19:10:25 +00:00
sub
PRESENCE_Initialize ( $ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash ) = @ _ ;
# Provider
$ hash - > { ReadFn } = "PRESENCE_Read" ;
$ hash - > { ReadyFn } = "PRESENCE_Ready" ;
$ hash - > { SetFn } = "PRESENCE_Set" ;
$ hash - > { DefFn } = "PRESENCE_Define" ;
$ hash - > { UndefFn } = "PRESENCE_Undef" ;
$ hash - > { AttrFn } = "PRESENCE_Attr" ;
2014-09-19 10:20:15 +00:00
$ hash - > { AttrList } = "do_not_notify:0,1 disable:0,1 fritzbox_speed:0,1 ping_count:1,2,3,4,5,6,7,8,9,10 powerCmd " . $ readingFnAttributes ;
2014-01-10 21:26:50 +00:00
2013-02-01 19:10:25 +00:00
}
#####################################
sub
PRESENCE_Define ( $$ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash , $ def ) = @ _ ;
my @ a = split ( "[ \t]+" , $ def ) ;
my $ dev ;
2014-03-10 16:58:36 +00:00
my $ username = getlogin || getpwuid ( $< ) || "[unknown]" ;
2014-08-01 21:24:14 +00:00
my $ name = $ hash - > { NAME } ;
2014-01-10 21:26:50 +00:00
if ( defined ( $ a [ 2 ] ) and defined ( $ a [ 3 ] ) )
{
if ( $ a [ 2 ] eq "local-bluetooth" )
{
unless ( $ a [ 3 ] =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*$/ )
{
my $ msg = "given address is not a bluetooth hardware address" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg
}
$ hash - > { MODE } = "local-bluetooth" ;
$ hash - > { ADDRESS } = $ a [ 3 ] ;
$ hash - > { TIMEOUT_NORMAL } = ( defined ( $ a [ 4 ] ) ? $ a [ 4 ] : 30 ) ;
2014-02-06 19:33:24 +00:00
$ hash - > { TIMEOUT_PRESENT } = ( defined ( $ a [ 5 ] ) ? $ a [ 5 ] : $ hash - > { TIMEOUT_NORMAL } ) ;
2014-01-10 21:26:50 +00:00
}
elsif ( $ a [ 2 ] eq "fritzbox" )
{
unless ( - X "/usr/bin/ctlmgr_ctl" )
{
my $ msg = "this is not a fritzbox or you running FHEM with the AVM Beta Image. Please use the FHEM FritzBox Image from fhem.de" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
2014-01-11 12:00:42 +00:00
unless ( $ username eq "root" )
2014-01-10 21:26:50 +00:00
{
my $ msg = "FHEM is not running under root (currently $username) This check can only performed with root access to the FritzBox" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
$ hash - > { MODE } = "fritzbox" ;
$ hash - > { ADDRESS } = $ a [ 3 ] ;
$ hash - > { TIMEOUT_NORMAL } = ( defined ( $ a [ 4 ] ) ? $ a [ 4 ] : 30 ) ;
2014-02-06 19:33:24 +00:00
$ hash - > { TIMEOUT_PRESENT } = ( defined ( $ a [ 5 ] ) ? $ a [ 5 ] : $ hash - > { TIMEOUT_NORMAL } ) ;
2014-01-10 21:26:50 +00:00
}
elsif ( $ a [ 2 ] eq "lan-ping" )
{
2014-01-12 10:16:24 +00:00
if ( - X "/usr/bin/ctlmgr_ctl" and not $ username eq "root" )
2014-01-10 21:26:50 +00:00
{
my $ msg = "FHEM is not running under root (currently $username) This check can only performed with root access to the FritzBox" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
$ hash - > { MODE } = "lan-ping" ;
$ hash - > { ADDRESS } = $ a [ 3 ] ;
$ hash - > { TIMEOUT_NORMAL } = ( defined ( $ a [ 4 ] ) ? $ a [ 4 ] : 30 ) ;
2014-02-06 19:33:24 +00:00
$ hash - > { TIMEOUT_PRESENT } = ( defined ( $ a [ 5 ] ) ? $ a [ 5 ] : $ hash - > { TIMEOUT_NORMAL } ) ;
2014-01-10 21:26:50 +00:00
}
elsif ( $ a [ 2 ] =~ /(shellscript|function)/ )
{
if ( $ def =~ /(\S+) \w+ (\S+) ["']{0,1}(.+?)['"]{0,1}\s*(\d*)\s*(\d*)$/s )
{
$ hash - > { MODE } = $ 2 ;
$ hash - > { helper } { call } = $ 3 ;
$ hash - > { TIMEOUT_NORMAL } = ( $ 4 ne "" ? $ 4 : 30 ) ;
2014-02-06 19:33:24 +00:00
$ hash - > { TIMEOUT_PRESENT } = ( $ 5 ne "" ? $ 5 : $ hash - > { TIMEOUT_NORMAL } ) ;
2014-01-10 21:26:50 +00:00
if ( $ hash - > { helper } { call } =~ /\|/ )
{
my $ msg = "The command contains a pipe ( | ) symbol, which is not allowed." ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
if ( $ hash - > { MODE } eq "function" and not $ hash - > { helper } { call } =~ /^\{.+\}$/ )
{
my $ msg = "The function call must be encapsulated by brackets ( {...} )." ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
}
}
elsif ( $ a [ 2 ] eq "lan-bluetooth" )
{
unless ( $ a [ 3 ] =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*$/ )
{
my $ msg = "given address is not a bluetooth hardware address" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg
}
DevIo_CloseDev ( $ hash ) ;
$ hash - > { MODE } = "lan-bluetooth" ;
$ hash - > { ADDRESS } = $ a [ 3 ] ;
$ hash - > { TIMEOUT_NORMAL } = ( defined ( $ a [ 5 ] ) ? $ a [ 5 ] : 30 ) ;
2014-02-06 19:33:24 +00:00
$ hash - > { TIMEOUT_PRESENT } = ( defined ( $ a [ 6 ] ) ? $ a [ 6 ] : $ hash - > { TIMEOUT_NORMAL } ) ;
2014-01-10 21:26:50 +00:00
$ dev = $ a [ 4 ] ;
$ dev . = ":5222" if ( $ dev !~ m/:/ && $ dev ne "none" && $ dev !~ m/\@/ ) ;
$ hash - > { DeviceName } = $ dev ;
}
else
{
2014-08-01 21:24:14 +00:00
my $ msg = "unknown mode \"" . $ a [ 2 ] . "\" in define statement: Please use lan-ping, lan-bluetooth, local-bluetooth, fritzbox, shellscript or function" ;
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg
}
}
else
2013-02-01 19:10:25 +00:00
{
2014-08-01 21:24:14 +00:00
my $ msg = "wrong syntax for define statement: define <name> PRESENCE <mode> <device-address> [ <check-interval> [ <present-check-interval> ] ]" ;
Log 2 , "PRESENCE ($name) - $msg" ;
2014-01-10 21:26:50 +00:00
return $ msg ;
2013-02-01 19:10:25 +00:00
}
2014-01-10 21:26:50 +00:00
my $ timeout = $ hash - > { TIMEOUT_NORMAL } ;
my $ presence_timeout = $ hash - > { TIMEOUT_PRESENCE } ;
if ( defined ( $ timeout ) and not $ timeout =~ /^\d+$/ )
{
my $ msg = "check-interval must be a number" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
}
2013-02-01 19:10:25 +00:00
if ( defined ( $ timeout ) and not $ timeout > 0 )
{
2014-01-10 21:26:50 +00:00
my $ msg = "check-interval must be greater than zero" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) -" . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
2013-02-01 19:10:25 +00:00
}
2013-03-02 13:34:34 +00:00
if ( defined ( $ presence_timeout ) and not $ presence_timeout =~ /^\d+$/ )
{
2014-01-10 21:26:50 +00:00
my $ msg = "presence-check-interval must be a number" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
2013-03-02 13:34:34 +00:00
}
if ( defined ( $ presence_timeout ) and not $ presence_timeout > 0 )
{
2014-01-10 21:26:50 +00:00
my $ msg = "presence-check-interval must be greater than zero" ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - " . $ msg ;
2014-01-10 21:26:50 +00:00
return $ msg ;
2013-03-02 13:34:34 +00:00
}
2014-01-10 21:26:50 +00:00
delete $ hash - > { helper } { cachednr } if ( defined ( $ hash - > { helper } { cachednr } ) ) ;
if ( $ hash - > { MODE } =~ /(lan-ping|local-bluetooth|fritzbox|shellscript|function)/ )
{
2014-09-26 15:11:20 +00:00
delete $ hash - > { helper } { RUNNING_PID } if ( defined ( $ hash - > { helper } { RUNNING_PID } ) ) ;
2014-01-10 21:26:50 +00:00
RemoveInternalTimer ( $ hash ) ;
2014-09-26 15:11:20 +00:00
InternalTimer ( gettimeofday ( ) , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
2014-01-10 21:26:50 +00:00
return ;
}
elsif ( $ hash - > { MODE } eq "lan-bluetooth" )
{
return DevIo_OpenDev ( $ hash , 0 , "PRESENCE_DoInit" ) ;
}
2013-02-01 19:10:25 +00:00
}
#####################################
sub
PRESENCE_Undef ( $$ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash , $ arg ) = @ _ ;
RemoveInternalTimer ( $ hash ) ;
if ( defined ( $ hash - > { helper } { RUNNING_PID } ) )
{
BlockingKill ( $ hash - > { helper } { RUNNING_PID } ) ;
}
DevIo_CloseDev ( $ hash ) ;
return undef ;
2013-02-01 19:10:25 +00:00
}
2013-02-13 22:50:26 +00:00
sub
PRESENCE_Set ( $@ )
{
my ( $ hash , @ a ) = @ _ ;
2014-07-12 22:00:35 +00:00
my $ name = $ hash - > { NAME } ;
2013-03-16 20:09:05 +00:00
return "No Argument given" if ( ! defined ( $ a [ 1 ] ) ) ;
2014-01-10 21:26:50 +00:00
2013-12-07 18:39:02 +00:00
my $ usage = "Unknown argument " . $ a [ 1 ] . ", choose one of statusRequest" ;
2014-01-10 21:26:50 +00:00
2014-07-14 20:58:50 +00:00
my $ powerCmd = AttrVal ( $ name , "powerCmd" , undef ) ;
$ usage . = " power" if ( defined ( $ powerCmd ) ) ;
2014-07-12 22:00:35 +00:00
2013-02-13 22:50:26 +00:00
if ( $ a [ 1 ] eq "statusRequest" )
{
2014-01-10 21:26:50 +00:00
if ( $ hash - > { MODE } ne "lan-bluetooth" )
{
2014-07-12 22:00:35 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - starting local scan" ;
2014-12-10 20:49:34 +00:00
return PRESENCE_StartLocalScan ( $ hash , 1 ) ;
2014-01-10 21:26:50 +00:00
}
else
{
if ( exists ( $ hash - > { FD } ) )
{
DevIo_SimpleWrite ( $ hash , "now\n" , 0 ) ;
}
else
{
2014-07-12 22:00:35 +00:00
return "PRESENCE Definition \"$name\" is not connected to " . $ hash - > { DeviceName } ;
2014-01-10 21:26:50 +00:00
}
}
2013-02-13 22:50:26 +00:00
}
2014-07-14 20:58:50 +00:00
elsif ( defined ( $ powerCmd ) && $ a [ 1 ] eq "power" )
2014-07-12 22:00:35 +00:00
{
my % specials = (
"%NAME" = > $ name ,
"%ADDRESS" = > $ hash - > { ADDRESS } ,
"%ARGUMENT" = > $ a [ 2 ]
) ;
2014-07-14 20:58:50 +00:00
$ powerCmd = EvalSpecials ( $ powerCmd , % specials ) ;
2014-07-12 22:00:35 +00:00
2014-07-14 20:58:50 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - executing powerCmd: $powerCmd" ;
my $ return = AnalyzeCommandChain ( undef , $ powerCmd ) ;
2014-07-12 22:00:35 +00:00
2014-07-14 20:58:50 +00:00
if ( $ return )
2014-07-12 22:00:35 +00:00
{
2014-07-14 20:58:50 +00:00
Log3 $ name , 3 , "PRESENCE ($name) - executed powerCmd failed: " . $ return ;
readingsSingleUpdate ( $ hash , "powerCmd" , "failed" , 1 ) ;
return "executed powerCmd failed: " . $ return ;
2014-07-12 22:00:35 +00:00
}
else
{
2014-07-14 20:58:50 +00:00
readingsSingleUpdate ( $ hash , "powerCmd" , "executed" , 1 ) ;
2014-07-12 22:00:35 +00:00
}
return undef ;
}
2013-02-13 22:50:26 +00:00
else
{
return $ usage ;
}
}
2013-02-01 19:10:25 +00:00
##########################
sub
PRESENCE_Attr ( @ )
{
2014-01-10 21:26:50 +00:00
my @ a = @ _ ;
my $ hash = $ defs { $ a [ 1 ] } ;
if ( $ a [ 0 ] eq "set" && $ a [ 2 ] eq "disable" )
{
if ( $ a [ 3 ] eq "0" )
{
readingsSingleUpdate ( $ hash , "state" , "defined" , 0 ) if ( exists ( $ hash - > { helper } { DISABLED } ) and $ hash - > { helper } { DISABLED } == 1 ) ;
if ( defined ( $ hash - > { DeviceName } ) )
{
if ( defined ( $ hash - > { FD } ) )
{
PRESENCE_DoInit ( $ hash ) if ( exists ( $ hash - > { helper } { DISABLED } ) ) ;
$ hash - > { helper } { DISABLED } = 0 ;
}
else
{
$ hash - > { helper } { DISABLED } = 0 ;
DevIo_OpenDev ( $ hash , 0 , "PRESENCE_DoInit" ) ;
}
}
else
{
$ hash - > { helper } { DISABLED } = 0 ;
PRESENCE_StartLocalScan ( $ hash ) ;
}
$ hash - > { helper } { DISABLED } = 0 ;
}
elsif ( $ a [ 3 ] eq "1" )
{
if ( defined ( $ hash - > { FD } ) )
{
DevIo_SimpleWrite ( $ hash , "stop\n" , 0 ) ;
}
RemoveInternalTimer ( $ hash ) ;
$ hash - > { helper } { DISABLED } = 1 ;
readingsSingleUpdate ( $ hash , "state" , "disabled" , 1 ) ;
}
}
elsif ( $ a [ 0 ] eq "del" && $ a [ 2 ] eq "disable" )
{
readingsSingleUpdate ( $ hash , "state" , "defined" , 0 ) if ( exists ( $ hash - > { helper } { DISABLED } ) and $ hash - > { helper } { DISABLED } == 1 ) ;
if ( defined ( $ hash - > { DeviceName } ) )
{
2014-11-11 21:09:42 +00:00
$ hash - > { helper } { DISABLED } = 0 ;
2014-01-10 21:26:50 +00:00
if ( defined ( $ hash - > { FD } ) )
{
PRESENCE_DoInit ( $ hash ) if ( exists ( $ hash - > { helper } { DISABLED } ) ) ;
}
else
{
DevIo_OpenDev ( $ hash , 0 , "PRESENCE_DoInit" ) ;
}
}
else
{
$ hash - > { helper } { DISABLED } = 0 ;
PRESENCE_StartLocalScan ( $ hash ) ;
}
}
2014-07-12 22:00:35 +00:00
elsif ( $ a [ 0 ] eq "set" and $ a [ 2 ] eq "powerOnFn" )
{
my $ powerOnFn = $ a [ 3 ] ;
$ powerOnFn =~ s/^\s+// ;
$ powerOnFn =~ s/\s+$// ;
if ( $ powerOnFn eq "" )
{
return "powerOnFn contains no value" ;
}
}
2014-01-10 21:26:50 +00:00
return undef ;
2013-02-01 19:10:25 +00:00
}
#####################################
# Receives an event and creates several readings for event triggering
sub
PRESENCE_Read ( $ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash ) = @ _ ;
2014-07-12 22:00:35 +00:00
my $ name = $ hash - > { NAME } ;
2014-01-10 21:26:50 +00:00
my $ buf = DevIo_SimpleRead ( $ hash ) ;
return "" if ( ! defined ( $ buf ) ) ;
chomp $ buf ;
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - received data: $buf" ;
2014-01-10 21:26:50 +00:00
readingsBeginUpdate ( $ hash ) ;
2013-02-01 19:10:25 +00:00
if ( $ buf eq "absence" )
{
2015-05-26 19:34:04 +00:00
readingsBulkUpdate ( $ hash , "state" , "absent" ) unless ( $ hash - > { helper } { DISABLED } ) ;
2015-01-09 16:16:07 +00:00
readingsBulkUpdate ( $ hash , "presence" , "absent" ) ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf =~ /present;(.+?)$/ )
{
2015-05-26 19:34:04 +00:00
readingsBulkUpdate ( $ hash , "state" , "present" ) unless ( $ hash - > { helper } { DISABLED } ) ;
2015-01-09 16:16:07 +00:00
readingsBulkUpdate ( $ hash , "presence" , "present" ) ;
2014-01-10 21:26:50 +00:00
if ( $ 1 =~ /^(.*);(.+)$/ )
{
readingsBulkUpdate ( $ hash , "room" , $ 2 ) ;
readingsBulkUpdate ( $ hash , "device_name" , $ 1 ) ;
}
else
{
readingsBulkUpdate ( $ hash , "device_name" , $ 1 ) ;
}
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf eq "command accepted" )
{
2014-01-10 21:26:50 +00:00
readingsBulkUpdate ( $ hash , "command_accepted" , "yes" ) ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf eq "command rejected" )
{
2014-01-10 21:26:50 +00:00
readingsBulkUpdate ( $ hash , "command_accepted" , "no" ) ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf =~ /socket_closed;(.+?)$/ )
{
2014-08-01 21:24:14 +00:00
Log3 $ name , 3 , "PRESENCE ($name) - collectord lost connection to room $1" ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf =~ /socket_reconnected;(.+?)$/ )
{
2014-08-01 21:24:14 +00:00
Log3 $ name , 3 , "PRESENCE ($name) - collectord reconnected to room $1" ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf =~ /error;(.+?)$/ )
{
2014-08-01 21:24:14 +00:00
Log3 $ name , 3 , "PRESENCE ($name) - room $1 cannot execute hcitool to check device" ;
2013-02-01 19:10:25 +00:00
}
elsif ( $ buf =~ /error$/ )
{
2014-08-01 21:24:14 +00:00
Log3 $ name , 3 , "PRESENCE ($name) - presenced cannot execute hcitool to check device " ;
2013-02-01 19:10:25 +00:00
}
2014-01-10 21:26:50 +00:00
2013-02-01 19:10:25 +00:00
readingsEndUpdate ( $ hash , 1 ) ;
}
sub
PRESENCE_DoInit ( $ )
{
my ( $ hash ) = @ _ ;
2013-11-02 19:59:09 +00:00
if ( not exists ( $ hash - > { helper } { DISABLED } ) or ( exists ( $ hash - > { helper } { DISABLED } ) and $ hash - > { helper } { DISABLED } == 0 ) )
2013-02-26 21:57:48 +00:00
{
2014-01-10 21:26:50 +00:00
readingsSingleUpdate ( $ hash , "state" , "active" , 0 ) ;
DevIo_SimpleWrite ( $ hash , $ hash - > { ADDRESS } . "|" . $ hash - > { TIMEOUT_NORMAL } . "\n" , 0 ) ;
}
else
{
readingsSingleUpdate ( $ hash , "state" , "disabled" , 0 ) ;
2013-02-26 21:57:48 +00:00
}
2014-01-10 21:26:50 +00:00
return undef ;
2013-02-01 19:10:25 +00:00
}
sub
PRESENCE_Ready ( $ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash ) = @ _ ;
return DevIo_OpenDev ( $ hash , 1 , "PRESENCE_DoInit" ) if ( $ hash - > { MODE } eq "lan-bluetooth" ) ;
2013-02-01 19:10:25 +00:00
}
##########################################################################################################################
#
#
# Functions for local testing with Blocking.pm to ensure a smooth FHEM processing
#
#
2013-02-13 22:50:26 +00:00
sub PRESENCE_StartLocalScan ( $ ; $ )
2013-02-01 19:10:25 +00:00
{
2013-02-13 22:50:26 +00:00
my ( $ hash , $ local ) = @ _ ;
2014-02-23 21:41:47 +00:00
my $ name = $ hash - > { NAME } ;
my $ mode = $ hash - > { MODE } ;
2013-02-13 22:50:26 +00:00
$ local = 0 unless ( defined ( $ local ) ) ;
2014-02-23 21:41:47 +00:00
if ( not ( exists ( $ hash - > { ADDRESS } ) or exists ( $ hash - > { helper } { call } ) ) )
{
2014-12-10 20:49:34 +00:00
return undef ;
2014-02-23 21:41:47 +00:00
}
2014-01-10 21:26:50 +00:00
2014-12-10 20:49:34 +00:00
unless ( exists ( $ hash - > { helper } { RUNNING_PID } ) )
2014-02-23 21:41:47 +00:00
{
2014-12-10 20:49:34 +00:00
$ hash - > { STATE } = "active" if ( $ hash - > { STATE } eq "???" or $ hash - > { STATE } eq "defined" ) ;
2014-01-10 21:26:50 +00:00
2014-12-10 20:49:34 +00:00
if ( $ local == 0 )
{
Log3 $ name , 5 , "PRESENCE ($name) - stopping timer" ;
RemoveInternalTimer ( $ hash ) ;
}
if ( $ mode eq "local-bluetooth" )
{
Log3 $ name , 5 , "PRESENCE ($name) - starting blocking call for mode local-bluetooth" ;
$ hash - > { helper } { RUNNING_PID } = BlockingCall ( "PRESENCE_DoLocalBluetoothScan" , $ name . "|" . $ hash - > { ADDRESS } . "|" . $ local , "PRESENCE_ProcessLocalScan" , 60 , "PRESENCE_ProcessAbortedScan" , $ hash ) ;
}
elsif ( $ mode eq "lan-ping" )
{
Log3 $ name , 5 , "PRESENCE ($name) - starting blocking call for mode lan-ping" ;
$ hash - > { helper } { RUNNING_PID } = BlockingCall ( "PRESENCE_DoLocalPingScan" , $ name . "|" . $ hash - > { ADDRESS } . "|" . $ local . "|" . AttrVal ( $ name , "ping_count" , "4" ) , "PRESENCE_ProcessLocalScan" , 60 , "PRESENCE_ProcessAbortedScan" , $ hash ) ;
}
elsif ( $ mode eq "fritzbox" )
{
Log3 $ name , 5 , "PRESENCE ($name) - starting blocking call for mode fritzbox" ;
$ hash - > { helper } { RUNNING_PID } = BlockingCall ( "PRESENCE_DoLocalFritzBoxScan" , $ name . "|" . $ hash - > { ADDRESS } . "|" . $ local . "|" . AttrVal ( $ name , "fritzbox_speed" , "0" ) , "PRESENCE_ProcessLocalScan" , 60 , "PRESENCE_ProcessAbortedScan" , $ hash ) ;
}
elsif ( $ mode eq "shellscript" )
{
Log3 $ name , 5 , "PRESENCE ($name) - starting blocking call for mode shellscript" ;
$ hash - > { helper } { RUNNING_PID } = BlockingCall ( "PRESENCE_DoLocalShellScriptScan" , $ name . "|" . $ hash - > { helper } { call } . "|" . $ local , "PRESENCE_ProcessLocalScan" , 60 , "PRESENCE_ProcessAbortedScan" , $ hash ) ;
}
elsif ( $ mode eq "function" )
{
Log3 $ name , 5 , "PRESENCE ($name) - starting blocking call for mode function" ;
$ hash - > { helper } { RUNNING_PID } = BlockingCall ( "PRESENCE_DoLocalFunctionScan" , $ name . "|" . $ hash - > { helper } { call } . "|" . $ local , "PRESENCE_ProcessLocalScan" , 60 , "PRESENCE_ProcessAbortedScan" , $ hash ) ;
}
2015-08-22 16:46:24 +00:00
if ( ! $ hash - > { helper } { RUNNING_PID } )
{
delete ( $ hash - > { helper } { RUNNING_PID } ) ;
my $ seconds = ( ReadingsVal ( $ name , "state" , "absent" ) eq "present" ? $ hash - > { TIMEOUT_PRESENT } : $ hash - > { TIMEOUT_NORMAL } ) ;
Log3 $ hash - > { NAME } , 4 , "PRESENCE ($name) - fork failed, rescheduling next check in $seconds seconds" ;
RemoveInternalTimer ( $ hash ) ;
InternalTimer ( gettimeofday ( ) + $ seconds , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
}
2014-12-10 20:49:34 +00:00
return undef ;
2013-04-12 21:31:49 +00:00
}
2014-12-10 20:49:34 +00:00
else
2013-04-12 21:31:49 +00:00
{
2014-12-20 17:30:27 +00:00
Log3 $ hash - > { NAME } , 4 , "PRESENCE ($name) - another check is currently running. skipping check" ;
if ( $ local == 0 )
{
my $ seconds = ( ReadingsVal ( $ name , "state" , "absent" ) eq "present" ? $ hash - > { TIMEOUT_PRESENT } : $ hash - > { TIMEOUT_NORMAL } ) ;
Log3 $ hash - > { NAME } , 4 , "PRESENCE ($name) - rescheduling next check in $seconds seconds" ;
RemoveInternalTimer ( $ hash ) ;
InternalTimer ( gettimeofday ( ) + $ seconds , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
}
2014-12-10 20:49:34 +00:00
return "another check is currently running" ;
2013-02-03 00:28:15 +00:00
}
2013-02-01 19:10:25 +00:00
}
sub
2013-02-13 22:50:26 +00:00
PRESENCE_DoLocalPingScan ( $ )
2013-02-01 19:10:25 +00:00
{
my ( $ string ) = @ _ ;
2013-05-18 11:57:34 +00:00
my ( $ name , $ device , $ local , $ count ) = split ( "\\|" , $ string ) ;
2013-02-01 19:10:25 +00:00
2014-08-01 21:56:21 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - starting ping scan: $string" ;
2014-01-10 21:26:50 +00:00
2013-02-01 19:10:25 +00:00
my $ retcode ;
my $ return ;
2013-02-07 22:08:38 +00:00
my $ temp ;
2013-05-18 11:57:34 +00:00
2013-02-09 12:38:05 +00:00
if ( $^O =~ m/(Win|cygwin)/ )
2013-02-01 19:10:25 +00:00
{
2014-01-10 21:26:50 +00:00
$ temp = qx( ping -n $count -4 $device ) ;
chomp $ temp ;
if ( $ temp ne "" )
{
Log3 $ name , 5 , "PRESENCE ($name) - ping command returned with output:\n$temp" ;
$ return = "$name|$local|" . ( $ temp =~ /TTL=\d+/ ? "present" : "absent" ) ;
}
else
{
2014-08-01 21:24:14 +00:00
$ return = "$name|$local|error|Could not execute ping command: \"ping -n $count -4 $device\"" ;
2014-01-10 21:26:50 +00:00
}
2013-02-01 19:10:25 +00:00
}
2015-10-14 17:01:10 +00:00
elsif ( $^O =~ m/solaris/ )
{
$ temp = qx( ping $device 4 ) ;
chomp $ temp ;
if ( $ temp ne "" )
{
Log3 $ name , 5 , "PRESENCE ($name) - ping command returned with output:\n$temp" ;
$ return = "$name|$local|" . ( $ temp =~ /is alive/ ? "present" : "absent" ) ;
}
else
{
$ return = "$name|$local|error|Could not execute ping command: \"ping -n $count -4 $device\"" ;
}
}
2013-02-01 19:10:25 +00:00
else
{
2014-10-07 21:24:25 +00:00
$ temp = qx( ping -c $count $device 2>&1 ) ;
2014-01-10 21:26:50 +00:00
chomp $ temp ;
if ( $ temp ne "" )
{
Log3 $ name , 5 , "PRESENCE ($name) - ping command returned with output:\n$temp" ;
2014-10-07 21:24:25 +00:00
$ return = "$name|$local|" . ( ( $ temp =~ /\d+ [Bb]ytes (from|von)/ and not $ temp =~ /[Uu]nreachable/ ) ? "present" : "absent" ) ;
2014-01-10 21:26:50 +00:00
}
else
{
$ return = "$name|$local|error|Could not execute ping command: \"ping -c $count $device\"" ;
}
2013-02-01 19:10:25 +00:00
}
2013-02-07 22:08:38 +00:00
return $ return ;
2013-02-01 19:10:25 +00:00
}
2013-05-22 16:09:38 +00:00
sub
2013-05-19 16:47:50 +00:00
PRESENCE_ExecuteFritzBoxCMD ( $$ )
{
2014-01-10 21:26:50 +00:00
my ( $ name , $ cmd ) = @ _ ;
my $ status ;
my $ wait ;
2013-05-19 16:47:50 +00:00
2014-01-10 21:26:50 +00:00
while ( - e "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" and ( stat ( "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" ) ) [ 9 ] > ( gettimeofday ( ) - 2 ) )
{
$ wait = int ( rand ( 4 ) ) + 2 ;
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - ctlmgr_ctl is locked. waiting $wait seconds..." ;
2014-03-10 23:01:01 +00:00
$ wait = 1000000 * $ wait ;
usleep $ wait ;
2014-01-10 21:26:50 +00:00
}
unlink ( "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" ) if ( - e "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" ) ;
2013-05-19 16:47:50 +00:00
2014-01-10 21:26:50 +00:00
qx( touch /var/tmp/fhem-PRESENCE-cmd-lock.tmp ) ;
2013-05-19 16:47:50 +00:00
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - executing ctlmgr_ctl: $cmd" ;
2014-01-10 21:26:50 +00:00
$ status = qx( $cmd ) ;
2014-03-10 16:58:36 +00:00
usleep 200000 ;
2014-01-10 21:26:50 +00:00
unlink ( "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" ) if ( - e "/var/tmp/fhem-PRESENCE-cmd-lock.tmp" ) ;
2013-05-19 16:47:50 +00:00
2014-01-10 21:26:50 +00:00
return $ status ;
2013-05-19 16:47:50 +00:00
}
2013-02-03 00:28:15 +00:00
sub
PRESENCE_DoLocalFritzBoxScan ( $ )
{
my ( $ string ) = @ _ ;
2014-09-19 10:20:15 +00:00
my ( $ name , $ device , $ local , $ speedcheck ) = split ( "\\|" , $ string ) ;
2014-01-10 21:26:50 +00:00
2013-08-17 11:32:09 +00:00
Log3 $ name , 5 , "PRESENCE_DoLocalFritzBoxScan: $string" ;
2014-09-19 10:20:15 +00:00
my $ number = 0 ;
my $ status = 0 ;
my $ speed ;
2013-02-18 17:49:27 +00:00
2014-09-19 10:20:15 +00:00
my $ check_command = ( $ device =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*$/ ? "mac" : "name" ) ;
$ device = uc $ device if ( $ device =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*$/ ) ;
if ( defined ( $ defs { $ name } { helper } { cachednr } ) )
2013-02-18 17:49:27 +00:00
{
$ number = $ defs { $ name } { helper } { cachednr } ;
2014-01-10 21:26:50 +00:00
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - try checking $name as device $device with cached number $number" ;
2014-09-19 10:20:15 +00:00
my $ cached_name = "" ;
$ cached_name = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/$check_command" ) ;
2013-02-18 17:49:27 +00:00
chomp $ cached_name ;
2014-01-10 21:26:50 +00:00
2013-02-18 17:49:27 +00:00
# only use the cached $number if it has still the correct device name
if ( $ cached_name eq $ device )
{
2014-09-19 10:20:15 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - checking state with cached number ($number)" ;
$ status = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/active" ) ;
2014-01-10 21:26:50 +00:00
chomp $ status ;
2014-09-19 10:20:15 +00:00
if ( $ status ne "0" and $ speedcheck eq "1" )
{
$ speed = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/speed" ) ;
chomp $ speed ;
Log3 $ name , 5 , "PRESENCE ($name) - speed check returned: $speed" ;
$ speed = undef if ( $ speed eq "0" ) ;
}
2014-01-10 21:26:50 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - ctlmgr_ctl (cached: $number) returned: $status" ;
if ( not $ status =~ /^\s*\d+\s*$/ )
{
return "$name|$local|error|could not execute ctlmgr_ctl (cached)" ;
}
2014-09-19 10:20:15 +00:00
return ( $ status == 0 ? "$name|$local|absent|$number" : "$name|$local|present|$number" ) . ( $ speedcheck == 1 and defined ( $ speed ) ? "|$speed" : "" ) ;
2014-01-10 21:26:50 +00:00
}
else
{
2014-09-19 10:20:15 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - cached device ($cached_name) does not match expected device ($device). perform a full scan" ;
2014-01-10 21:26:50 +00:00
}
2013-02-18 17:49:27 +00:00
}
2013-05-19 16:47:50 +00:00
my $ max = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice/count" ) ;
2014-01-10 21:26:50 +00:00
2013-02-03 00:28:15 +00:00
chomp $ max ;
2014-01-10 21:26:50 +00:00
2013-08-17 11:32:09 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - ctlmgr_ctl (getting device count) returned: $max" ;
2014-01-10 21:26:50 +00:00
2013-02-03 00:28:15 +00:00
if ( not $ max =~ /^\s*\d+\s*$/ )
{
2014-01-10 21:26:50 +00:00
return "$name|$local|error|could not execute ctlmgr_ctl" ;
2013-02-03 00:28:15 +00:00
}
2014-01-10 21:26:50 +00:00
2013-02-03 00:28:15 +00:00
my $ net_device ;
2013-02-25 21:41:13 +00:00
$ number = 0 ;
2014-01-10 21:26:50 +00:00
2013-02-03 00:28:15 +00:00
while ( $ number <= $ max )
{
2014-09-19 10:20:15 +00:00
$ net_device = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/$check_command" ) ;
2013-02-03 00:28:15 +00:00
chomp $ net_device ;
2014-01-10 21:26:50 +00:00
2014-09-19 10:20:15 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - checking device number $number ($net_device)" ;
2014-01-10 21:26:50 +00:00
if ( $ net_device eq $ device )
{
2014-09-19 10:20:15 +00:00
$ status = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/active" ) ;
chomp $ status ;
if ( $ status ne "0" and $ speedcheck eq "1" )
{
$ speed = PRESENCE_ExecuteFritzBoxCMD ( $ name , "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/speed" ) ;
chomp $ speed ;
Log3 $ name , 5 , "PRESENCE ($name) - speed check returned: $speed" ;
$ speed = undef if ( $ speed eq "0" ) ;
}
2014-01-10 21:26:50 +00:00
2014-09-19 10:20:15 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - state for device number $net_device is $status" ;
2014-01-10 21:26:50 +00:00
last ;
}
$ number + + ;
2013-02-03 00:28:15 +00:00
}
2014-09-19 10:20:15 +00:00
return ( $ status == 0 ? "$name|$local|absent" : "$name|$local|present" ) . ( $ number <= $ max ? "|$number" : "|" ) . ( $ speedcheck == 1 and defined ( $ speed ) ? "|$speed" : "" ) ;
2013-02-03 00:28:15 +00:00
}
2013-02-01 19:10:25 +00:00
2013-05-19 16:47:50 +00:00
2013-02-01 19:10:25 +00:00
sub
2013-02-03 00:28:15 +00:00
PRESENCE_DoLocalBluetoothScan ( $ )
2013-02-01 19:10:25 +00:00
{
my ( $ string ) = @ _ ;
2013-02-13 22:50:26 +00:00
my ( $ name , $ device , $ local ) = split ( "\\|" , $ string ) ;
2015-03-10 22:34:23 +00:00
2013-02-01 19:10:25 +00:00
my $ devname ;
my $ return ;
my $ wait = 1 ;
my $ ps ;
2014-01-10 21:26:50 +00:00
my $ psargs = "ax" ;
if ( qx( ps --help 2>&1 ) =~ /BusyBox/g )
{
2015-03-10 22:34:23 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - found busybox variant of ps command, using \"w\" as parameter" ;
2014-01-10 21:26:50 +00:00
$ psargs = "w" ;
}
else
{
2015-03-10 22:34:23 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - found standard variant of ps command, using \"ax\" as parameter" ;
2014-01-10 21:26:50 +00:00
$ psargs = "ax" ;
}
2015-03-10 22:34:23 +00:00
Log3 $ name , 4 , "PRESENCE ($name) - executing: which hcitool" ;
my $ hcitool = qx( which hcitool ) ;
Log3 $ name , 4 , "PRESENCE ($name) - 'which hcitool' returns: $hcitool" ;
2013-02-20 22:04:57 +00:00
chomp $ hcitool ;
2014-01-10 21:26:50 +00:00
2013-02-20 22:04:57 +00:00
if ( - x $ hcitool )
2013-02-01 19:10:25 +00:00
{
while ( $ wait )
{ # check if another hcitool process is running
2014-01-10 21:26:50 +00:00
$ ps = qx( ps $psargs | grep hcitool | grep -v grep ) ;
if ( not $ ps =~ /^\s*$/ )
{
# sleep between 1 and 5 seconds and try again
Log3 $ name , 5 , "PRESENCE ($name) - another hcitool command is running. waiting..." ;
sleep ( rand ( 4 ) + 1 ) ;
}
else
{
$ wait = 0 ;
}
}
2015-03-10 22:34:23 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - executing: hcitool name $device" ;
2014-01-10 21:26:50 +00:00
$ devname = qx( hcitool name $device ) ;
chomp ( $ devname ) ;
Log3 $ name , 4 , "PRESENCE ($name) - hcitool returned: $devname" ;
if ( not $ devname =~ /^\s*$/ )
{
$ return = "$name|$local|present|$devname" ;
}
else
{
$ return = "$name|$local|absent" ;
}
2013-02-01 19:10:25 +00:00
}
else
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|error|no hcitool binary found. Please check that the bluez-package is properly installed" ;
2013-02-01 19:10:25 +00:00
}
return $ return ;
}
2013-04-12 21:31:49 +00:00
sub
PRESENCE_DoLocalShellScriptScan ( $ )
{
2013-02-01 19:10:25 +00:00
2013-04-12 21:31:49 +00:00
my ( $ string ) = @ _ ;
my ( $ name , $ call , $ local ) = split ( "\\|" , $ string ) ;
2013-02-01 19:10:25 +00:00
2013-04-12 21:31:49 +00:00
my $ ret ;
my $ return ;
2014-01-10 21:26:50 +00:00
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - execute local shell script: $string" ;
2013-04-12 21:31:49 +00:00
$ ret = qx( $call ) ;
2014-01-10 21:26:50 +00:00
2013-04-12 21:31:49 +00:00
chomp $ ret ;
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - script output: $ret" ;
2014-01-10 21:26:50 +00:00
2013-04-12 21:31:49 +00:00
if ( not defined ( $ ret ) )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|error|scriptcall doesn't return any output" ;
2013-04-12 21:31:49 +00:00
}
elsif ( $ ret eq "1" )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|present" ;
2013-04-12 21:31:49 +00:00
}
elsif ( $ ret eq "0" )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|absent" ;
2013-04-12 21:31:49 +00:00
}
else
{
2014-01-10 21:26:50 +00:00
$ ret =~ s/\n/<<line-break>>/g ;
$ return = "$name|$local|error|unexpected script output (expected 0 or 1): $ret" ;
2013-04-12 21:31:49 +00:00
}
2014-01-10 21:26:50 +00:00
2013-04-12 21:31:49 +00:00
return $ return ;
}
2013-02-01 19:10:25 +00:00
2013-04-12 21:31:49 +00:00
sub
PRESENCE_DoLocalFunctionScan ( $ )
{
my ( $ string ) = @ _ ;
my ( $ name , $ call , $ local ) = split ( "\\|" , $ string ) ;
my $ ret ;
my $ return ;
2014-01-10 21:26:50 +00:00
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - execute perl function: $string" ;
2013-04-12 21:31:49 +00:00
$ ret = AnalyzeCommandChain ( undef , $ call ) ;
2014-01-10 21:26:50 +00:00
2013-04-12 21:31:49 +00:00
chomp $ ret ;
2014-08-01 21:24:14 +00:00
Log3 $ name , 5 , "PRESENCE ($name) - function returned with: $ret" ;
2013-04-12 21:31:49 +00:00
if ( not defined ( $ ret ) )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|error|function call doesn't return any output" ;
2013-04-12 21:31:49 +00:00
}
elsif ( $ ret eq "1" )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|present" ;
2013-04-12 21:31:49 +00:00
}
elsif ( $ ret eq "0" )
{
2014-01-10 21:26:50 +00:00
$ return = "$name|$local|absent" ;
2013-04-12 21:31:49 +00:00
}
else
{
2014-01-10 21:26:50 +00:00
$ ret =~ s/\n/<<line-break>>/g ;
$ return = "$name|$local|error|unexpected function output (expected 0 or 1): $ret" ;
2013-04-12 21:31:49 +00:00
}
2014-01-10 21:26:50 +00:00
2013-04-12 21:31:49 +00:00
return $ return ;
}
2013-02-01 19:10:25 +00:00
sub
PRESENCE_ProcessLocalScan ( $ )
{
2014-01-10 21:26:50 +00:00
my ( $ string ) = @ _ ;
return unless ( defined ( $ string ) ) ;
my @ a = split ( "\\|" , $ string ) ;
my $ hash = $ defs { $ a [ 0 ] } ;
2014-09-19 10:20:15 +00:00
2014-01-10 21:26:50 +00:00
my $ local = $ a [ 1 ] ;
2014-08-01 21:24:14 +00:00
my $ name = $ hash - > { NAME } ;
Log3 $ hash - > { NAME } , 5 , "PRESENCE ($name) - blocking scan result: $string" ;
2014-01-10 21:26:50 +00:00
2014-09-19 10:20:15 +00:00
delete ( $ hash - > { helper } { RUNNING_PID } ) ;
if ( $ hash - > { helper } { DISABLED } )
{
Log3 $ hash - > { NAME } , 5 , "PRESENCE ($name) - don't process the scan result, as $name is disabled" ;
return ;
}
2014-01-10 21:26:50 +00:00
if ( defined ( $ hash - > { helper } { RETRY_COUNT } ) )
{
2014-08-01 21:24:14 +00:00
Log3 $ hash - > { NAME } , 2 , "PRESENCE ($name) - check returned a valid result after " . $ hash - > { helper } { RETRY_COUNT } . " unsuccesful " . ( $ hash - > { helper } { RETRY_COUNT } > 1 ? "retries" : "retry" ) ;
2014-01-10 21:26:50 +00:00
delete ( $ hash - > { helper } { RETRY_COUNT } ) ;
}
2014-09-19 10:20:15 +00:00
if ( $ hash - > { MODE } eq "fritzbox" and defined ( $ a [ 3 ] ) and $ a [ 3 ] ne "" )
2014-01-10 21:26:50 +00:00
{
$ hash - > { helper } { cachednr } = $ a [ 3 ] if ( ( $ a [ 2 ] eq "present" ) || ( $ a [ 2 ] eq "absent" ) ) ;
}
elsif ( $ hash - > { MODE } eq "fritzbox" and defined ( $ hash - > { helper } { cachednr } ) )
{
delete ( $ hash - > { helper } { cachednr } ) ;
}
readingsBeginUpdate ( $ hash ) ;
if ( $ a [ 2 ] eq "present" )
{
readingsBulkUpdate ( $ hash , "state" , "present" ) ;
2015-01-09 16:16:07 +00:00
readingsBulkUpdate ( $ hash , "presence" , "present" ) ;
2014-01-10 21:26:50 +00:00
readingsBulkUpdate ( $ hash , "device_name" , $ a [ 3 ] ) if ( defined ( $ a [ 3 ] ) and $ hash - > { MODE } =~ /^(lan-bluetooth|local-bluetooth)$/ ) ;
2014-09-19 10:20:15 +00:00
if ( $ hash - > { MODE } eq "fritzbox" and defined ( $ a [ 4 ] ) )
{
readingsBulkUpdate ( $ hash , "speed" , $ a [ 4 ] ) ;
}
2014-01-10 21:26:50 +00:00
}
elsif ( $ a [ 2 ] eq "absent" )
{
readingsBulkUpdate ( $ hash , "state" , "absent" ) ;
2015-01-09 16:16:07 +00:00
readingsBulkUpdate ( $ hash , "presence" , "absent" ) ;
2014-09-19 10:20:15 +00:00
if ( $ hash - > { MODE } eq "fritzbox" and defined ( $ a [ 4 ] ) )
{
readingsBulkUpdate ( $ hash , "speed" , $ a [ 4 ] ) ;
}
2014-01-10 21:26:50 +00:00
}
elsif ( $ a [ 2 ] eq "error" )
{
$ a [ 3 ] =~ s/<<line-break>>/\n/g ;
2014-08-01 21:24:14 +00:00
Log3 $ hash - > { NAME } , 2 , "PRESENCE ($name) - error while processing check: " . $ a [ 3 ] ;
2014-08-01 21:56:21 +00:00
readingsBulkUpdate ( $ hash , "state" , "error" ) ;
2014-01-10 21:26:50 +00:00
}
readingsEndUpdate ( $ hash , 1 ) ;
2014-09-19 10:20:15 +00:00
2014-01-10 21:26:50 +00:00
#Schedule the next check withing $timeout if it is a regular run
2014-08-01 21:56:21 +00:00
if ( $ local eq "0" )
2014-01-10 21:26:50 +00:00
{
2014-08-01 21:56:21 +00:00
my $ seconds = ( $ a [ 2 ] eq "present" ? $ hash - > { TIMEOUT_PRESENT } : $ hash - > { TIMEOUT_NORMAL } ) ;
Log3 $ hash - > { NAME } , 4 , "PRESENCE ($name) - rescheduling next check in $seconds seconds" ;
2014-01-10 21:26:50 +00:00
RemoveInternalTimer ( $ hash ) ;
2014-08-01 21:56:21 +00:00
InternalTimer ( gettimeofday ( ) + $ seconds , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
2014-01-10 21:26:50 +00:00
}
2013-02-01 19:10:25 +00:00
}
2013-04-09 21:15:38 +00:00
sub
PRESENCE_ProcessAbortedScan ( $ )
{
2014-01-10 21:26:50 +00:00
my ( $ hash ) = @ _ ;
2014-08-01 21:24:14 +00:00
my $ name = $ hash - > { NAME } ;
2014-01-10 21:26:50 +00:00
delete ( $ hash - > { helper } { RUNNING_PID } ) ;
RemoveInternalTimer ( $ hash ) ;
if ( defined ( $ hash - > { helper } { RETRY_COUNT } ) )
{
if ( $ hash - > { helper } { RETRY_COUNT } >= 3 )
{
2014-08-01 21:24:14 +00:00
Log3 $ hash - > { NAME } , 2 , "PRESENCE ($name) - device could not be checked after " . $ hash - > { helper } { RETRY_COUNT } . " " . ( $ hash - > { helper } { RETRY_COUNT } > 1 ? "retries" : "retry" ) . " (resuming normal operation)" if ( $ hash - > { helper } { RETRY_COUNT } == 3 ) ;
2014-01-10 21:26:50 +00:00
InternalTimer ( gettimeofday ( ) + 10 , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
$ hash - > { helper } { RETRY_COUNT } + + ;
}
else
{
2014-08-01 21:24:14 +00:00
Log3 $ hash - > { NAME } , 2 , "PRESENCE ($name) - device could not be checked after " . $ hash - > { helper } { RETRY_COUNT } . " " . ( $ hash - > { helper } { RETRY_COUNT } > 1 ? "retries" : "retry" ) . " (retrying in 10 seconds)" ;
2014-01-10 21:26:50 +00:00
InternalTimer ( gettimeofday ( ) + 10 , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
$ hash - > { helper } { RETRY_COUNT } + + ;
}
}
else
{
$ hash - > { helper } { RETRY_COUNT } = 1 ;
InternalTimer ( gettimeofday ( ) + 10 , "PRESENCE_StartLocalScan" , $ hash , 0 ) unless ( $ hash - > { helper } { DISABLED } ) ;
2014-08-01 21:24:14 +00:00
Log 2 , "PRESENCE ($name) - device could not be checked (retrying in 10 seconds)"
2014-01-10 21:26:50 +00:00
}
2014-08-01 21:56:21 +00:00
readingsSingleUpdate ( $ hash , "state" , "timeout" , 1 ) ;
2013-04-09 21:15:38 +00:00
}
2013-02-01 19:10:25 +00:00
1 ;
= pod
= begin html
< a name = "PRESENCE" > </a>
<h3> PRESENCE </h3>
<ul>
The PRESENCE module provides several possibilities to check the presence of mobile phones or similar mobile devices such as tablets .
<br> <br>
This module provides several operational modes to serve your needs . These are: <br> <br>
<ul>
<li> <b> lan - ping </b> - A presence check of a device via network ping in your LAN /WLAN</ li >
2013-02-18 17:49:27 +00:00
<li> <b> fritzbox </b> - A presence check by requesting the device state from the FritzBox internals ( only available when running FHEM on a FritzBox ! ) </li>
2013-02-01 19:10:25 +00:00
<li> <b> local - bluetooth </b> - A presence check by searching directly for a given bluetooth device nearby </li>
2013-05-20 11:31:38 +00:00
<li> <b> function </b> - A presence check by using your own perl function which returns a presence state </li>
<li> <b> shellscript </b> - A presence check by using an self - written script or binary which returns a presence state </li>
2013-02-01 19:10:25 +00:00
<li> <b> lan - bluetooth </b> - A presence check of a bluetooth device via LAN network by connecting to a presenced or collectord instance </li>
</ul>
2013-10-27 16:55:51 +00:00
<br>
Each mode can be optionally configured with a specific check interval and a present check interval . <br> <br>
<ul>
<li> check - interval - The interval in seconds between each presence check . Default value: 30 seconds </li>
<li> present - check - interval - The interval in seconds between each presence check in case the device is <i> present </i> . Otherwise the normal check - interval will be used . </li>
</ul>
2013-02-01 19:10:25 +00:00
<br> <br>
< a name = "PRESENCEdefine" > </a>
<b> Define </b> <br> <br>
<ul> <b> Mode: lan - ping </b> <br> <br>
2013-03-02 13:34:34 +00:00
<code> define & lt ; name & gt ; PRESENCE lan - ping & lt ; ip - address & gt ; [ & lt ; check - interval & gt ; [ & lt ; present - check - interval & gt ; ] ] </code> <br>
2013-02-01 19:10:25 +00:00
<br>
2013-05-20 11:31:38 +00:00
Checks for a network device via PING requests and reports its presence state . <br> <br>
<u> Example </u> <br> <br>
<code> define iPhone PRESENCE lan - ping 192.168 .179 .21 </code> <br>
2013-02-01 19:10:25 +00:00
<br>
2013-02-03 00:28:15 +00:00
<b> Mode: fritzbox </b> <br> <br>
2014-09-19 10:20:15 +00:00
<code> define & lt ; name & gt ; PRESENCE fritzbox & lt ; device - name /mac-address> [ <check-interval> [ <present-check-interval> ] ]</co de > <br>
2013-02-03 00:28:15 +00:00
<br>
2014-09-19 10:20:15 +00:00
Checks for a network device by requesting the internal state on a FritzBox via ctlmgr_ctl . The device - name must be the same as shown in the network overview of the FritzBox or can be substituted by the MAC address with the format XX:XX:XX:XX:XX:XX <br> <br>
<i> This check is only applicable when FHEM is running on a FritzBox ! The detection of absence can take about 10 - 15 minutes ! </i> <br> <br>
2013-05-20 11:31:38 +00:00
<u> Example </u> <br> <br>
2014-09-19 10:20:15 +00:00
<code> define iPhone PRESENCE fritzbox iPhone - 6 </code> <br>
<code> define iPhone PRESENCE fritzbox 00 : 06 : 08 : 05 : 0 D:00 </code> <br> <br>
2013-02-01 19:10:25 +00:00
<b> Mode: local - bluetooth </b> <br> <br>
2013-03-02 13:34:34 +00:00
<code> define & lt ; name & gt ; PRESENCE local - bluetooth & lt ; bluetooth - address & gt ; [ & lt ; check - interval & gt ; [ & lt ; present - check - interval & gt ; ] ] </code> <br>
2013-02-01 19:10:25 +00:00
<br>
Checks for a bluetooth device and reports its presence state . For this mode the shell command "hcitool" is required ( provided with a < a href = "http://www.bluez.org" target = "_new" > bluez </a> installation under Debian via APT ) , as well
as a functional bluetooth device directly attached to your machine . <br> <br>
2013-05-20 11:31:38 +00:00
<u> Example </u> <br> <br>
<code> define iPhone PRESENCE local - bluetooth 0 a:8d:4f:51:3c:8f </code> <br> <br>
2013-04-16 16:27:27 +00:00
<b> Mode: function </b> <br> <br>
<code> define & lt ; name & gt ; PRESENCE function { ... } [ & lt ; check - interval & gt ; [ & lt ; present - check - interval & gt ; ] ] </code> <br>
<br>
Checks for a presence state via perl - code . You can use a self - written perl function to obtain the presence state of a specific device ( e . g . via SNMP check ) . <br> <br>
2013-05-20 11:31:38 +00:00
The function must return 0 ( absent ) or 1 ( present ) . An example can be found in the < a href = "http://www.fhemwiki.de/wiki/Anwesenheitserkennung" target = "_new" > FHEM - Wiki </a> . <br> <br>
<u> Example </u> <br> <br>
<code> define iPhone PRESENCE function { snmpCheck ( "10.0.1.1" , "0x44d77429f35c" ) } </code> <br> <br>
<b> Mode: shellscript </b> <br> <br>
<code> define & lt ; name & gt ; PRESENCE shellscript "<path> [<arg1>] [<argN>]..." [ & lt ; check - interval & gt ; [ & lt ; present - check - interval & gt ; ] ] </code> <br>
<br>
Checks for a presence state via shell script . You can use a self - written script or binary in any language to obtain the presence state of a specific device ( e . g . via SNMP check ) . <br> <br>
The shell must return 0 ( absent ) or 1 ( present ) on <u> console ( STDOUT ) </u> . Any other values will be treated as an error <br> <br>
<u> Example </u> <br> <br>
<code> define iPhone PRESENCE shellscript "/opt/check_device.sh iPhone" </code> <br> <br>
2013-02-01 19:10:25 +00:00
<b> Mode: lan - bluetooth </b> <br> <br>
Checks for a bluetooth device with the help of presenced or collectord . They can be installed where - ever you like , just must be accessible via network .
The given device will be checked for presence status . <br>
<br>
2013-08-12 21:57:24 +00:00
<code> define & lt ; name & gt ; PRESENCE lan - bluetooth & lt ; bluetooth - address & gt ; & lt ; ip - address & gt ; [ : port ] [ & lt ; check - interval & gt ; ] </code> <br>
2013-02-01 19:10:25 +00:00
<br>
The default port is 5111 ( presenced ) . Alternatly you can use port 5222 ( collectord ) <br>
<br>
2013-05-20 11:31:38 +00:00
<u> Example </u> <br> <br>
2013-08-12 21:57:24 +00:00
<code> define iPhone PRESENCE lan - bluetooth 0 a:4f:36:d8:f9:89 127.0 .0 .1 : 5222 </code> <br> <br>
2013-02-01 19:10:25 +00:00
<u> presenced </u> <br> <br>
<ul> The presence is a perl network daemon , which provides presence checks of multiple bluetooth devices over network .
It listens on TCP port 5111 for incoming connections from a FHEM PRESENCE instance or a running collectord . <br>
<PRE>
Usage:
2013-02-02 13:16:38 +00:00
presenced - d [ - p & lt ; port & gt ; ] [ - P & lt ; filename & gt ; ]
2013-02-01 19:10:25 +00:00
presenced [ - h | - - help ]
Options:
- p , - - port
TCP Port which should be used ( Default: 5111 )
- P , - - pid - file
PID file for storing the local process id ( Default: /var/ run / presenced . pid )
- d , - - daemon
detach from terminal and run as background daemon
- v , - - verbose
Print detailed log output
- h , - - help
Print detailed help screen
</PRE>
It uses the hcitool command ( provided by a < a href = "http://www.bluez.org" target = "_new" > bluez </a> installation )
to make a paging request to the given bluetooth address ( like 01 : B4:5E:AD:F6:D3 ) . The devices must not be visible , but
still activated to receive bluetooth requests . <br> <br>
If a device is present , this is send to FHEM , as well as the device name as reading . <br> <br>
The presenced is available as: <br> <br>
<ul>
2013-07-17 20:32:47 +00:00
<li> direct perl script file: < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/presenced" target = "_new" > presenced </a> </li>
2013-10-08 19:03:41 +00:00
<li> . deb package for Debian ( noarch ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/presenced-1.3.deb" target = "_new" > presenced - 1.3 . deb </a> </li>
<li> . deb package for Raspberry Pi ( raspbian ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/presenced-rpi-1.3.deb" target = "_new" > presenced - rpi - 1.3 . deb </a> </li>
2013-02-01 19:10:25 +00:00
</ul>
</ul> <br> <br>
<u> collectord </u> <br> <br>
<ul>
The collectord is a perl network daemon , which handles connections to several presenced installations to search for multiple bluetooth devices over network . <br> <br>
It listens on TCP port 5222 for incoming connections from a FHEM presence instance .
<PRE>
Usage:
2013-02-03 00:28:15 +00:00
collectord - c & lt ; configfile & gt ; [ - d ] [ - p & lt ; port & gt ; ] [ - P & lt ; pidfile & gt ; ]
2013-02-01 19:10:25 +00:00
collectord [ - h | - - help ]
Options:
2013-02-02 13:16:38 +00:00
- c , - - configfile & lt ; configfile & gt ;
2013-02-01 19:10:25 +00:00
The config file which contains the room and timeout definitions
- p , - - port
TCP Port which should be used ( Default: 5222 )
- P , - - pid - file
PID file for storing the local process id ( Default: /var/ run / collectord . pid )
- d , - - daemon
detach from terminal and run as background daemon
- v , - - verbose
Print detailed log output
2013-02-02 13:16:38 +00:00
- l , - - logfile & lt ; logfile & gt ;
2013-02-01 19:10:25 +00:00
log to the given logfile
- h , - - help
Print detailed help screen
</PRE>
Before the collectord can be used , it needs a config file , where all different rooms , which have a presenced detector , will be listed . This config file looks like:
<br> <br>
<PRE>
# room definition
# ===============
#
[ room - name ] # name of the room
address = 192.168 .0 .10 # ip-address or hostname
port = 5111 # tcp port which should be used (5111 is default)
presence_timeout = 120 # timeout in seconds for each check when devices are present
absence_timeout = 20 # timeout in seconds for each check when devices are absent
[ living room ]
address = 192.168 .0 .11
port = 5111
presence_timeout = 180
absence_timeout = 20
</PRE>
If a device is present in any of the configured rooms , this is send to FHEM , as well as the device name as reading and the room which has detected the device . <br> <br>
The collectord is available as: <br> <br>
<ul>
2013-07-17 20:32:47 +00:00
<li> direct perl script file: < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/collectord" target = "_new" > collectord </a> </li>
2015-11-29 13:55:53 +00:00
<li> . deb package for Debian ( noarch ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/collectord-1.5.deb" target = "_new" > collectord - 1.5 . deb </a> </li>
2013-02-01 19:10:25 +00:00
</ul>
</ul> <br> <br>
</ul>
<br>
< a name = "PRESENCEset" > </a>
<b> Set </b>
<ul>
2013-12-08 09:39:25 +00:00
<li> <b> statusRequest </b> - Schedules an immediatly check . </li>
2014-07-14 20:58:50 +00:00
<li> <b> power </b> - Executes the given power command which is set as attribute to power ( on or off ) the device ( only when attribute "powerCmd" is set ) </li>
2013-02-01 19:10:25 +00:00
</ul>
<br>
< a name = "PRESENCEget" > </a>
<b> Get </b>
<ul>
N / A
</ul>
<br>
< a name = "PRESENCEattr" > </a>
<b> Attributes </b> <br> <br>
<ul>
<li> < a href = "#do_not_notify" > do_not_notify </a> </li>
<li> < a href = "#readingFnAttributes" > readingFnAttributes </a> </li> <br>
<li> <a> disable </a> </li>
If this attribute is activated , an active check will be disabled . <br> <br>
Possible values : 0 = > not disabled , 1 = > disabled <br>
Default Value is 0 ( not disabled ) <br> <br>
2015-10-14 17:01:10 +00:00
<li> <a> ping_count </a> </li> ( Only in Mode "ping" on Linux based OS applicable ) <br>
2013-05-18 11:57:34 +00:00
Changes the count of the used ping packets to recognize a present state . Depending on your network performance sometimes a packet can be lost or blocked . <br> <br>
Default Value is 4 ( packets ) <br> <br>
2014-09-19 10:20:15 +00:00
<li> <a> fritzbox_speed </a> </li> ( only for mode "fritzbox" ) <br>
When this attribute is enabled , the network speed is checked in addition to the device state . <br>
This only makes sense for wireless devices connected directly to the FritzBox .
2013-03-01 22:19:58 +00:00
<br> <br>
2014-09-19 10:20:15 +00:00
Possible values : 0 = > do not check speed , 1 = > check speed when device is active <br>
Default value is 0 ( no speed check )
2013-03-01 22:19:58 +00:00
<br> <br>
2014-07-14 20:58:50 +00:00
<li> <a> powerCmd </a> </li> <br>
Define a FHEM command , which powers on or off the device . <br> <br>
2014-07-12 22:00:35 +00:00
2014-07-14 20:58:50 +00:00
When executing the powerCmd ( set command: power ) following placeholders will be replaced by there corresponding values : <br> <br>
2014-07-12 22:00:35 +00:00
<ul>
2015-11-22 14:14:42 +00:00
<li> <code> $ NAME </code> - name of the PRESENCE definition </li>
<li> <code> $ ADDRESS </code> - the address of the PRESENCE definition as given in the define statement </li>
<li> <code> $ ARGUMENT </code> - the argument given to the power set command ( e . g . "on" or " off ) </li>
2014-07-12 22:00:35 +00:00
</ul>
<br>
2014-07-14 20:58:50 +00:00
Example FHEM commands: <br> <br>
<ul>
<li> <code> set PowerSwitch_1 on </code> </li>
<li> <code> set PowerSwitch_1 % ARGUMENT </code> </li>
<li> <code> "/opt/power_on.sh %ADDRESS" </code> </li>
<li> <code> { powerOn ( "%ADDRESS" , "username" , "password" ) } </code> </li>
2013-02-01 19:10:25 +00:00
</ul>
2014-07-14 20:58:50 +00:00
</ul>
2013-02-01 19:10:25 +00:00
<br>
< a name = "PRESENCEevents" > </a>
<b> Generated Events: </b> <br> <br>
<ul>
<u> General Events: </u> <br> <br>
<ul>
2015-01-09 16:16:07 +00:00
<li> <b> state </b> : ( absent | present | disabled | error | timeout ) - The state of the device or "disabled" when the disable attribute is enabled </li>
<li> <b> presence </b> : ( absent | present ) - The state of the device </li>
2014-07-14 20:58:50 +00:00
<li> <b> powerCmd </b> : ( executed | failed ) - power command was executed or has failed </li>
2013-02-01 19:10:25 +00:00
</ul> <br> <br>
<u> Bluetooth specific events: </u> <br> <br>
<ul>
2013-02-02 14:06:46 +00:00
<li> <b> device_name </b> : $ name - The name of the Bluetooth device in case it ' s present </li>
2013-02-01 19:10:25 +00:00
</ul> <br> <br>
<u> presenced /collectord specific events:</ u > <br> <br>
<ul>
2013-02-02 14:06:46 +00:00
<li> <b> command_accepted </b> : $ command_accepted ( yes | no ) - Was the last command acknowleged and accepted by the presenced or collectord ? </li>
2013-02-01 19:10:25 +00:00
<li> <b> room </b> : $ room - If the module is connected with a collector daemon this event shows the room , where the device is located ( as defined in the collectord config file ) </li>
</ul>
</ul>
</ul>
= end html
2013-02-03 14:22:22 +00:00
= begin html_DE
< a name = "PRESENCE" > </a>
<h3> PRESENCE </h3>
<ul>
Das PRESENCE Module bietet mehrere M & ouml ; glichkteiten um die Anwesenheit von Handys / Smartphones oder anderen mobilen Ger & auml ; ten ( z . B . Tablets ) zu erkennen .
<br> <br>
Dieses Modul bietet dazu mehrere Modis an um Anwesenheit zu erkennen . Diese sind: <br> <br>
<ul>
<li> <b> lan - ping </b> - Eine Erkennung auf Basis von Ping - Tests im lokalen LAN /WLAN</ li >
<li> <b> fritzbox </b> - Eine Erkennung aufgrund der internen Abfrage des Status auf der FritzBox ( nur m & ouml ; glich , wenn FHEM auf einer FritzBox l & auml ; uft ) </li>
<li> <b> local - bluetooth </b> - Eine Erkennung auf Basis von Bluetooth - Abfragen durch den FHEM Server . Das Ger & auml ; t muss dabei in Empfangsreichweite sein , aber nicht sichtbar sein </li>
2013-04-16 16:27:27 +00:00
<li> <b> function </b> - Eine Erkennung mithilfe einer selbst geschriebenen Perl - Funktion , welche den Anwesenheitsstatus ermittelt . </li>
2013-05-20 11:31:38 +00:00
<li> <b> shellscript </b> - Eine Erkennung mithilfe eines selbst geschriebenen Skriptes oder Programm ( egal in welcher Sprache ) . </li>
2013-02-03 14:22:22 +00:00
<li> <b> lan - bluetooth </b> - Eine Erkennung durch Bluetooth - Abfragen via Netzwerk ( LAN /WLAN) in ein oder mehreren Räumen</ li >
</ul>
2013-10-27 16:55:51 +00:00
<br>
Jeder Modus kann optional mit spezifischen Pr & uuml ; f - Intervallen ausgef & uuml ; hrt werden . <br> <br>
<ul>
<li> check - interval - Das normale Pr & uuml ; finterval in Sekunden für eine Anwesenheitspr & uuml ; fung . Standardwert: 30 Sekunden </li>
<li> present - check - interval - Das Pr & uuml ; finterval in Sekunden , wenn ein Ger & auml ; t anwesend ( <i> present </i> ) ist . Falls nicht angegeben , wird der Wert aus check - interval verwendet </li>
</ul>
2013-02-03 14:22:22 +00:00
<br> <br>
< a name = "PRESENCEdefine" > </a>
<b> Define </b> <br> <br>
<ul> <b> Modus: lan - ping </b> <br> <br>
2013-03-02 13:34:34 +00:00
<code> define & lt ; name & gt ; PRESENCE lan - ping & lt ; IP - Addresse oder Hostname & gt ; [ & lt ; Interval & gt ; [ & lt ; Anwesend - Interval & gt ; ] ] </code> <br>
2013-02-03 14:22:22 +00:00
<br>
2013-05-20 11:31:38 +00:00
Pr & uuml ; ft ob ein Ger & auml ; t & uuml ; ber Netzwerk ( & uuml ; blicherweise WLAN ) auf Ping - Anfragen reagiert und setzt entsprechend den Anwesenheitsstatus . <br> <br>
<u> Beispiel </u> <br> <br>
<code> define iPhone PRESENCE lan - ping 192.168 .179 .21 </code> <br> <br>
2013-02-03 14:22:22 +00:00
<b> Modus: fritzbox </b> <br> <br>
2014-09-19 10:20:15 +00:00
<code> define & lt ; name & gt ; PRESENCE fritzbox & lt ; Ger & auml ; tename /MAC-Adresse> [ <Interval> [ <Anwesend-Interval> ] ]</co de > <br>
2013-02-03 14:22:22 +00:00
<br>
Pr & uuml ; ft ob ein Ger & auml ; t welches per WLAN mit der FritzBox verbunden ist , erreichbar durch Abfrage des Status mit dem Befehl ctlmgr_ctl .
2014-09-19 10:20:15 +00:00
Der Ger & auml ; tename ( Parameter: & lt ; Ger & auml ; tename & gt ; ) muss dem Namen entsprechen , welcher im Men & uuml ; punkt "Heimnetz" auf der FritzBox - Oberfl & auml ; che angezeigt wird oder kann durch die MAC - Adresse im Format XX:XX:XX:XX:XX:XX ersetzt werden . <br> <br>
<i> Dieser Modus ist nur verwendbar , wenn FHEM auf einer FritzBox l & auml ; uft ! Die Erkennung einer Abwesenheit kann ca . 10 - 15 Minuten dauern ! </i> <br> <br>
2013-05-20 11:31:38 +00:00
<u> Beispiel </u> <br> <br>
2014-09-19 10:20:15 +00:00
<code> define iPhone PRESENCE fritzbox iPhone - 6 </code> <br>
<code> define iPhone PRESENCE fritzbox 00 : 06 : 08 : 05 : 0 D:00 </code> <br> <br>
2013-02-03 14:22:22 +00:00
<b> Modus: local - bluetooth </b> <br> <br>
2013-03-02 13:34:34 +00:00
<code> define & lt ; name & gt ; PRESENCE local - bluetooth & lt ; Bluetooth - Adresse & gt ; [ & lt ; Interval & gt ; [ & lt ; Anwesend - Interval & gt ; ] ] </code> <br>
2013-02-03 14:22:22 +00:00
<br>
Pr & uuml ; ft ob ein Bluetooth - Ger & auml ; t abgefragt werden kann und meldet dies als Anwesenheit . F & uuml ; r diesen Modus wird der Shell - Befehl "hcitool" ben & ouml ; tigt
( wird durch das Paket < a href = "http://www.bluez.org" target = "_new" > bluez </a> bereitgestellt ) , sowie ein funktionierender Bluetooth - Empf & auml ; nger ( intern oder als USB - Stick ) <br> <br>
2013-05-20 11:31:38 +00:00
<u> Beispiel </u> <br> <br>
<code> define iPhone PRESENCE local - bluetooth 0 a:4f:36:d8:f9:8 </code> <br> <br>
2013-04-16 16:27:27 +00:00
<b> Modus: function </b> <br> <br>
<code> define & lt ; name & gt ; PRESENCE function { ... } [ & lt ; Interval & gt ; [ & lt ; Anwesend - Interval & gt ; ] ] </code> <br>
<br>
Pr & uuml ; ft den Anwesenheitsstatus mithilfe einer selbst geschriebenen Perl - Funktion ( z . B . SNMP Abfrage ) . <br> <br>
2013-05-20 11:31:38 +00:00
Diese Funktion muss 0 ( Abwesend ) oder 1 ( Anwesend ) zurückgeben . Ein entsprechendes Beispiel findet man im < a href = "http://www.fhemwiki.de/wiki/Anwesenheitserkennung" target = "_new" > FHEM - Wiki </a> . <br> <br>
<u> Beispiel </u> <br> <br>
<code> define iPhone PRESENCE function { snmpCheck ( "10.0.1.1" , "0x44d77429f35c" ) </code> <br> <br>
<b> Mode: shellscript </b> <br> <br>
<code> define & lt ; name & gt ; PRESENCE shellscript "<Skript-Pfad> [<arg1>] [<argN>]..." [ & lt ; Interval & gt ; [ & lt ; Anwesend - Interval & gt ; ] ] </code> <br>
<br>
Pr & uuml ; ft den Anwesenheitsstatus mithilfe eines selbst geschrieben Skripts oder Programmes ( egal in welcher Programmier - / Skriptsprache ) <br> <br>
Der Aufruf dieses Skriptes muss eine 0 ( Abwesend ) oder 1 ( Anwesend ) auf der <u> Kommandozeile ( STDOUT ) </u> ausgeben . Alle anderen Werte / Ausgaben werden als Fehler behandelt . <br> <br>
<u> Beispiel </u> <br> <br>
<code> define iPhone PRESENCE shellscript "/opt/check_device.sh iPhone" </code> <br> <br>
2013-02-03 14:22:22 +00:00
<b> Modus: lan - bluetooth </b> <br> <br>
Pr & uuml ; ft ein Bluetooth - Ger & auml ; t auf Anwesenheit & uuml ; ber Netzwerk mit Hilfe von presenced oder collectord . Diese k & ouml ; nnen auf jeder Maschine installiert werden ,
welche eine Standard - Perl - Umgebung bereitstellt und & uuml ; ber Netzwerk erreichbar ist .
<br>
<br>
2013-08-12 21:57:24 +00:00
<code> define & lt ; name & gt ; PRESENCE lan - bluetooth & lt ; Bluetooth - Adresse & gt ; & lt ; IP - Adresse & gt ; [ : Port ] [ & lt ; Interval & gt ; ] </code> <br>
2013-02-03 14:22:22 +00:00
<br>
2013-05-20 11:31:38 +00:00
Der Standardport ist 5111 ( presenced ) . Alternativ kann man den Port 5222 ( collectord ) nutzen . Generell ist der Port aber frei w & auml ; hlbar . <br> <br>
<u> Beispiel </u> <br> <br>
2013-08-12 21:57:24 +00:00
<code> define iPhone PRESENCE lan - bluetooth 0 a:4f:36:d8:f9:89 127.0 .0 .1 : 5222 </code> <br> <br>
2013-02-03 14:22:22 +00:00
<u> presenced </u> <br> <br>
<ul> Der presenced ist ein Perl Netzwerk Dienst , welcher eine Bluetooth - Anwesenheitserkennung von ein oder mehreren Ger & auml ; ten & uuml ; ber Netzwerk bereitstellt .
Dieser lauscht standardm & auml ; & szlig ; ig auf TCP Port 5111 nach eingehenden Verbindungen von dem PRESENCE Modul oder einem collectord . <br>
<PRE>
Usage:
presenced - d [ - p & lt ; port & gt ; ] [ - P & lt ; filename & gt ; ]
presenced [ - h | - - help ]
Options:
- p , - - port
TCP Port which should be used ( Default: 5111 )
- P , - - pid - file
PID file for storing the local process id ( Default: /var/ run / presenced . pid )
- d , - - daemon
detach from terminal and run as background daemon
- v , - - verbose
Print detailed log output
- h , - - help
Print detailed help screen
</PRE>
Zur Bluetooth - Abfrage wird der Shell - Befehl "hcitool" verwendet ( Paket: < a href = "http://www.bluez.org" target = "_new" > bluez </a> )
um sogenannte "Paging-Request" an die gew & uuml ; nschte Bluetooth Adresse ( z . B . 01 : B4:5E:AD:F6:D3 ) durchzuf & uuml ; hren . Das Ger & auml ; t muss dabei nicht sichtbar sein , allerdings st & auml ; ndig aktiviert sein
um Bluetooth - Anfragen zu beantworten .
<br> <br>
Wenn ein Ger & auml ; t anwesend ist , wird dies an FHEM & uuml ; bermittelt zusammen mit dem Ger & auml ; tenamen als Reading . <br> <br>
Der presenced ist zum Download verf & uuml ; gbar als: <br> <br>
<ul>
2013-07-17 20:32:47 +00:00
<li> Perl Skript: < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/presenced" target = "_new" > presenced </a> </li>
2013-10-08 19:03:41 +00:00
<li> . deb Paket f & uuml ; r Debian ( architekturunabh & auml ; ngig ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/presenced-1.3.deb" target = "_new" > presenced - 1.3 . deb </a> </li>
<li> . deb Paket f & uuml ; r Raspberry Pi ( raspbian ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/presenced-rpi-1.3.deb" target = "_new" > presenced - rpi - 1.3 . deb </a> </li>
2013-02-03 14:22:22 +00:00
</ul>
</ul> <br> <br>
<u> collectord </u> <br> <br>
<ul>
Der collectord ist ein Perl Netzwerk Dienst , welcher Verbindungen zu mehreren presenced - Instanzen verwaltet um eine koordinierte Suche nach ein oder mehreren Bluetooth - Ger & auml ; ten & uuml ; ber Netzwerk durchzuf & uuml ; hren . <br> <br>
Er lauscht auf TCP port 5222 nach eingehenden Verbindungen von einem PRESENCE Modul .
<PRE>
Usage:
collectord - c & lt ; configfile & gt ; [ - d ] [ - p & lt ; port & gt ; ] [ - P & lt ; pidfile & gt ; ]
collectord [ - h | - - help ]
Options:
- c , - - configfile & lt ; configfile & gt ;
The config file which contains the room and timeout definitions
- p , - - port
TCP Port which should be used ( Default: 5222 )
- P , - - pid - file
PID file for storing the local process id ( Default: /var/ run / collectord . pid )
- d , - - daemon
detach from terminal and run as background daemon
- v , - - verbose
Print detailed log output
- l , - - logfile & lt ; logfile & gt ;
log to the given logfile
- h , - - help
Print detailed help screen
</PRE>
Bevor der collectord verwendet werden kann , ben & ouml ; tigt er eine Konfigurationsdatei in welcher alle R & auml ; ume mit einem presenced - Agenten eingetragen sind . Diese Datei sieht wie folgt aus:
<br> <br>
<PRE>
# Raum Definitionen
# =================
#
[ Raum - Name ] # Name des Raumes
address = 192.168 .0 .10 # IP-Adresse oder Hostname
port = 5111 # TCP Port welcher benutzt werden soll (standardmäßig 5111)
presence_timeout = 120 # Prüfinterval in Sekunden für jede Abfrage eines Gerätes, welches anwesend ist
absence_timeout = 20 # Prüfinterval in Sekunden für jede Abfrage eines Gerätes, welches abwesend ist
[ Wohnzimmer ]
address = 192.168 .0 .11
port = 5111
presence_timeout = 180
absence_timeout = 20
</PRE>
<br>
Wenn ein Ger & auml ; t in irgend einem Raum anwesend ist , wird dies an FHEM & uuml ; bermittelt , zusammen mit dem Ger & auml ; tenamen und dem Raum , in welchem das Ger & auml ; t erkannt wurde . <br> <br>
Der collectord ist zum Download verf & uuml ; gbar als: <br> <br>
<ul>
2013-07-17 20:32:47 +00:00
<li> Perl Skript: < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/collectord" target = "_new" > collectord </a> </li>
2015-11-29 13:55:53 +00:00
<li> . deb Paket f & uuml ; r Debian ( architekturunabh & auml ; ngig ) : < a href = "http://svn.code.sf.net/p/fhem/code/trunk/fhem/contrib/PRESENCE/deb/collectord-1.5.deb" target = "_new" > collectord - 1.5 . deb </a> </li>
2013-02-03 14:22:22 +00:00
</ul>
</ul>
</ul>
<br>
< a name = "PRESENCEset" > </a>
<b> Set </b>
<ul>
2013-02-18 17:49:27 +00:00
2013-12-08 09:39:25 +00:00
<li> <b> statusRequest </b> - Startet einen sofortigen Check . </li>
2014-07-14 20:58:50 +00:00
<li> <b> power </b> - Startet den powerCmd - Befehl welche durch den Parameter powerCmd angegeben ist ( Nur wenn das Attribut "powerCmd" definiert ist ) </li>
2013-02-03 14:22:22 +00:00
</ul>
<br>
< a name = "PRESENCEget" > </a>
<b> Get </b>
<ul>
N / A
</ul>
<br>
< a name = "PRESENCEattr" > </a>
<b> Attributes </b> <br> <br>
<ul>
<li> < a href = "#do_not_notify" > do_not_notify </a> </li>
<li> < a href = "#readingFnAttributes" > readingFnAttributes </a> </li> <br>
<li> <a> disable </a> </li>
Wenn dieses Attribut aktiviert ist , wird die Anwesenheitserkennung nicht mehr durchgef & uuml ; hrt . <br> <br>
M & ouml ; gliche Werte: 0 = > Erkennung durchf & uuml ; hren , 1 = > Keine Erkennungen durchf & uuml ; hren <br>
Standardwert ist 0 ( Erkennung durchf & uuml ; hren ) <br> <br>
2015-10-14 17:01:10 +00:00
<li> <a> ping_count </a> </li> ( Nur im Modus "ping" anwendbar auf Linux - basierten Betriebssystemen ) <br>
2013-05-18 11:57:34 +00:00
Verändert die Anzahl der Ping - Pakete die gesendet werden sollen um die Anwesenheit zu erkennen .
Je nach Netzwerkstabilität können erste Pakete verloren gehen oder blockiert werden . <br> <br>
Standartwert ist 4 ( Versuche ) <br> <br>
2014-09-19 10:20:15 +00:00
<li> <a> fritzbox_speed </a> </li> ( Nur im Modus "fritzbox" ) <br>
Zus & auml ; tzlich zum Status des Ger & auml ; ts wird die aktuelle Verbindungsgeschwindigkeit ausgegeben <br>
Das macht nur bei WLAN Geräten Sinn , die direkt mit der FritzBox verbunden sind . Bei abwesenden Ger & auml ; ten wird als Geschwindigkeit 0 ausgegeben .
2013-03-01 22:19:58 +00:00
<br> <br>
2014-09-19 10:20:15 +00:00
M & ouml ; gliche Werte: 0 = > Geschwindigkeit nicht pr & uuml ; fen , 1 = > Geschwindigkeit pr & uuml ; fen <br>
Standardwert ist 0 ( Keine Geschwindigkeitspr & uuml ; fung )
2013-03-01 22:19:58 +00:00
<br> <br>
2014-07-14 20:58:50 +00:00
<li> <a> powerCmd </a> </li> <br>
Ein FHEM - Befehl , welcher das Ger & auml ; t schalten kann . <br> <br>
2014-07-12 22:00:35 +00:00
2014-07-14 20:58:50 +00:00
Wenn der power - Befehl ausgef & uuml ; hrt wird ( set - Befehl: power ) werden folgende Platzhalter durch ihre entsprechenden Werte ersetzt: <br> <br>
2014-07-12 22:00:35 +00:00
<ul>
2015-11-22 14:14:42 +00:00
<li> <code> $ NAME </code> - Name der PRESENCE - Definition </li>
<li> <code> $ ADDRESS </code> - Die & uuml ; berwachte Addresse der PRESENCE Definition , wie sie im define - Befehl angegeben wurde . </li>
<li> <code> $ ARGUMENT </code> - Das Argument , was dem Set - Befehl "power" & uuml ; bergeben wurde . ( z . B . "on" oder "off" ) </li>
2014-07-12 22:00:35 +00:00
</ul>
<br>
2014-07-14 20:58:50 +00:00
Beispielhafte FHEM - Befehle: <br> <br>
<ul>
<li> <code> set PowerSwitch_1 on </code> </li>
<li> <code> set PowerSwitch_1 % ARGUMENT </code> </li>
<li> <code> "/opt/power_on.sh %ADDRESS" </code> </li>
<li> <code> { powerOn ( "%ADDRESS" , "username" , "password" ) } </code> </li>
</ul>
2013-02-03 14:22:22 +00:00
</ul>
<br>
< a name = "PRESENCEevents" > </a>
<b> Generierte Events: </b> <br> <br>
<ul>
<u> Generelle Events: </u> <br> <br>
<ul>
2015-01-09 16:16:07 +00:00
<li> <b> state </b> : ( absent | present | disabled | error | timeout ) - Der Anwesenheitsstatus eine Ger & auml ; tes ( absent = abwesend ; present = anwesend ) oder "disabled" wenn das disable - Attribut aktiviert ist </li>
<li> <b> presence </b> : ( absent | present ) - Der Anwesenheitsstatus eine Ger & auml ; tes ( absent = abwesend ; present = anwesend ) </li>
2014-07-14 20:58:50 +00:00
<li> <b> powerCmd </b> : ( executed | failed ) - Ausf & uuml ; hrung des power - Befehls war erfolgreich . </li>
2013-02-03 14:22:22 +00:00
</ul> <br> <br>
<u> Bluetooth - spezifische Events: </u> <br> <br>
<ul>
<li> <b> device_name </b> : $ name - Der Name des Bluetooth - Ger & auml ; tes , wenn es anwesend ( Status: present ) ist </li>
</ul> <br> <br>
<u> presenced - /collectord-spezifische Events:</ u > <br> <br>
<ul>
<li> <b> command_accepted </b> : $ command_accepted ( yes | no ) - Wurde das letzte Kommando an den presenced /collectord akzeptiert (yes = ja, no = nein)?</ li >
<li> <b> room </b> : $ room - Wenn das Modul mit einem collectord verbunden ist , zeigt dieses Event den Raum an , in welchem dieses Ger & auml ; t erkannt wurde ( Raumname entsprechend der Konfigurationsdatei des collectord ) </li>
</ul>
</ul>
</ul>
= end html_DE
2013-02-07 22:08:38 +00:00
= cut