| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079 |
- # $Id: 73_PRESENCE.pm 16177 2018-02-14 08:58:43Z markusbloch $
- ##############################################################################
- #
- # 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.
- #
- # 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;
- use Time::HiRes qw(gettimeofday usleep sleep);
- use DevIo;
- sub
- PRESENCE_Initialize($)
- {
- my ($hash) = @_;
- # Provider
- $hash->{ReadFn} = "PRESENCE_Read";
- $hash->{ReadyFn} = "PRESENCE_Ready";
- $hash->{SetFn} = "PRESENCE_Set";
- $hash->{DefFn} = "PRESENCE_Define";
- $hash->{NotifyFn} = "PRESENCE_Notify";
- $hash->{UndefFn} = "PRESENCE_Undef";
- $hash->{AttrFn} = "PRESENCE_Attr";
- $hash->{AttrList} = "do_not_notify:0,1 ".
- "disable:0,1 ".
- "disabledForIntervals ".
- "fritzboxCheckSpeed:0,1 ".
- "pingCount:1,2,3,4,5,6,7,8,9,10 ".
- "bluetoothHciDevice ".
- "absenceThreshold ".
- "presenceThreshold ".
- "absenceTimeout ".
- "presenceTimeout ".
- "powerCmd ".
- $readingFnAttributes;
-
- $hash->{AttrRenameMap} = { "ping_count" => "pingCount",
- "bluetooth_hci_device" => "bluetoothHciDevice",
- "fritzbox_speed" => "fritzboxCheckSpeed"
- };
- }
- #####################################
- sub
- PRESENCE_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t]+", $def);
- my $dev;
- my $username = getlogin || getpwuid($<) || "[unknown]";
- my $name = $hash->{NAME};
- $hash->{NOTIFYDEV} = "global";
- 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";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg
- }
- $hash->{MODE} = "local-bluetooth";
- $hash->{ADDRESS} = $a[3];
- $hash->{INTERVAL_NORMAL} = (defined($a[4]) ? $a[4] : 30);
- $hash->{INTERVAL_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{INTERVAL_NORMAL});
- }
- 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";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- unless($username eq "root")
- {
- my $msg = "FHEM is not running under root (currently $username) This check can only performed with root access to the FritzBox";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- $hash->{MODE} = "fritzbox";
- $hash->{ADDRESS} = $a[3];
- $hash->{INTERVAL_NORMAL} = (defined($a[4]) ? $a[4] : 30);
- $hash->{INTERVAL_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{INTERVAL_NORMAL});
- }
- elsif($a[2] eq "lan-ping")
- {
- if(-X "/usr/bin/ctlmgr_ctl" and not $username eq "root")
- {
- my $msg = "FHEM is not running under root (currently $username) This check can only performed with root access to the FritzBox";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- $hash->{MODE} = "lan-ping";
- $hash->{ADDRESS} = $a[3];
- $hash->{INTERVAL_NORMAL} = (defined($a[4]) ? $a[4] : 30);
- $hash->{INTERVAL_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{INTERVAL_NORMAL});
- }
- 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->{INTERVAL_NORMAL} = ($4 ne "" ? $4 : 30);
- $hash->{INTERVAL_PRESENT} = ($5 ne "" ? $5 : $hash->{INTERVAL_NORMAL});
- delete($hash->{helper}{ADDRESS});
- if($hash->{helper}{call} =~ /\|/)
- {
- my $msg = "The command contains a pipe ( | ) symbol, which is not allowed.";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- if($hash->{MODE} eq "function" and not $hash->{helper}{call} =~ /^\{.+\}$/)
- {
- my $msg = "The function call must be encapsulated by brackets ( {...} ).";
- Log 2, "PRESENCE ($name) - ".$msg;
- 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";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg
- }
- DevIo_CloseDev($hash);
- $hash->{MODE} = "lan-bluetooth";
- $hash->{ADDRESS} = $a[3];
- $hash->{INTERVAL_NORMAL} = (defined($a[5]) ? $a[5] : 30);
- $hash->{INTERVAL_PRESENT} = (defined($a[6]) ? $a[6] : $hash->{INTERVAL_NORMAL});
- $dev = $a[4];
- $dev .= ":5222" if($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
- $hash->{DeviceName} = $dev;
- }
- elsif($a[2] eq "event")
- {
- return "missing arguments for mode event. You need to provide two event regexp" unless(defined($a[4]));
- eval { qr/^$a[3]$/ };
- return "invalid absent regexp: $@" if($@);
- eval { qr/^$a[4]$/ };
- return "invalid present regexp: $@" if($@);
- $hash->{MODE} = "event";
- $hash->{EVENT_ABSENT} = $a[3];
- $hash->{EVENT_PRESENT} = $a[4];
- $hash->{STATE} = "Initialized" if($init_done);
- InternalTimer(gettimeofday(), "PRESENCE_setNotfiyDev", $hash);
- }
- else
- {
- my $msg = "unknown mode \"".$a[2]."\" in define statement: Please use lan-ping, lan-bluetooth, local-bluetooth, fritzbox, shellscript, function or event";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg
- }
- }
- else
- {
- my $msg = "wrong syntax for define statement: define <name> PRESENCE <mode> <device-address> [ <check-interval> [ <present-check-interval> ] ]";
- Log 2, "PRESENCE ($name) - $msg";
- return $msg;
- }
- my $timeout = $hash->{INTERVAL_NORMAL};
- my $presence_timeout = $hash->{INTERVAL_PRESENT};
- if(defined($timeout) and not $timeout =~ /^\d+$/)
- {
- my $msg = "check-interval must be a number";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- if(defined($timeout) and not $timeout > 0)
- {
- my $msg = "check-interval must be greater than zero";
- Log 2, "PRESENCE ($name) -".$msg;
- return $msg;
- }
- if(defined($presence_timeout) and not $presence_timeout =~ /^\d+$/)
- {
- my $msg = "presence-check-interval must be a number";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- if(defined($presence_timeout) and not $presence_timeout > 0)
- {
- my $msg = "presence-check-interval must be greater than zero";
- Log 2, "PRESENCE ($name) - ".$msg;
- return $msg;
- }
- delete($hash->{helper}{cachednr});
- readingsSingleUpdate($hash,"model",$hash->{MODE},0);
- return undef;
- }
- #####################################
- sub
- PRESENCE_Undef($$)
- {
- my ($hash, $arg) = @_;
- RemoveInternalTimer($hash);
- if(defined($hash->{helper}{RUNNING_PID}))
- {
- BlockingKill($hash->{helper}{RUNNING_PID});
- }
- DevIo_CloseDev($hash);
- return undef;
- }
- #####################################
- sub
- PRESENCE_Notify($$)
- {
- my ($hash,$dev) = @_;
- return undef if(!defined($hash) or !defined($dev));
- my $name = $hash->{NAME};
- my $dev_name = $dev->{NAME};
- return undef if(!defined($dev_name) or !defined($name));
- my $events = deviceEvents($dev,0);
- if($dev_name eq "global" and grep(m/^(?:DEFINED $name|MODIFIED $name|INITIALIZED|REREADCFG)$/, @{$events}))
- {
- if(grep(m/^(?:INITIALIZED|REREADCFG)$/, @{$events}))
- {
- $hash->{helper}{ABSENT_COUNT} = int(ReadingsVal($name, ".absenceThresholdCounter", 0));
- $hash->{helper}{PRESENT_COUNT} = int(ReadingsVal($name, ".presenceThresholdCounter", 0));
- }
- if($hash->{MODE} =~ /(lan-ping|local-bluetooth|fritzbox|shellscript|function)/)
- {
- delete $hash->{helper}{RUNNING_PID} if(defined($hash->{helper}{RUNNING_PID}));
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday(), "PRESENCE_StartLocalScan", $hash, 0) unless($hash->{helper}{DISABLED});
- return undef;
- }
- elsif($hash->{MODE} eq "lan-bluetooth")
- {
- delete($hash->{NEXT_OPEN}) if(exists($hash->{NEXT_OPEN}));
- return DevIo_OpenDev($hash, 0, "PRESENCE_DoInit");
- }
- }
- elsif($hash->{MODE} eq "event")
- {
- return undef if($hash->{helper}{DISABLED});
- my $re_present = $hash->{EVENT_PRESENT};
- my $re_absent = $hash->{EVENT_ABSENT};
- Log3 $name, 5, "PRESENCE ($name) - processing events from $dev_name";
- foreach my $event (@{$events})
- {
- if($dev_name =~ m/^$re_present$/ or "$dev_name:$event" =~ m/^$re_present$/)
- {
- Log3 $name, 5, "PRESENCE ($name) - $dev_name:$event matched present regexp";
- readingsBeginUpdate($hash);
- PRESENCE_ProcessState($hash, "present");
- readingsEndUpdate($hash, 1);
- }
- elsif($dev_name =~ m/^$re_absent$/ or "$dev_name:$event" =~ m/^$re_absent$/)
- {
- Log3 $name, 5, "PRESENCE ($name) - $dev_name:$event matched absent regexp";
- readingsBeginUpdate($hash);
- PRESENCE_ProcessState($hash, "absent");
- readingsEndUpdate($hash, 1);
- }
- }
- }
- }
- #####################################
- sub
- PRESENCE_Set($@)
- {
- my ($hash, @a) = @_;
- my $name = $hash->{NAME};
- return "No Argument given" if(!defined($a[1]));
- my $usage = "Unknown argument ".$a[1].", choose one of statusRequest";
- my $powerCmd = AttrVal($name, "powerCmd", undef);
- $usage .= " power" if(defined($powerCmd));
- $usage .= " overrideInterval" if($hash->{MODE} !~ /^event|lan-bluetooth$/);
- $usage .= " clearOverride:noArg" if($hash->{INTERVAL_OVERRIDED});
- if($a[1] eq "statusRequest")
- {
- if($hash->{MODE} ne "lan-bluetooth")
- {
- Log3 $name, 5, "PRESENCE ($name) - starting local scan";
- return PRESENCE_StartLocalScan($hash, 1);
- }
- else
- {
- if(exists($hash->{FD}))
- {
- DevIo_SimpleWrite($hash, "now\n", 2);
- }
- else
- {
- return "PRESENCE Definition \"$name\" is not connected to ".$hash->{DeviceName};
- }
- }
- }
- elsif(defined($powerCmd) && $a[1] eq "power")
- {
- my %specials= (
- '%NAME' => $name,
- '%ADDRESS' => (defined($hash->{ADDRESS}) ? $hash->{ADDRESS} : ""),
- '%ARGUMENT' => (defined($a[2]) ? $a[2] : "")
- );
- $powerCmd = EvalSpecials($powerCmd, %specials);
- Log3 $name, 5, "PRESENCE ($name) - executing powerCmd: $powerCmd";
- my $return = AnalyzeCommandChain(undef, $powerCmd);
- if($return)
- {
- Log3 $name, 3, "PRESENCE ($name) - executed powerCmd failed: ".$return;
- readingsSingleUpdate($hash, "powerCmd", "failed",1);
- return "executed powerCmd failed: ".$return;
- }
- else
- {
- readingsSingleUpdate($hash, "powerCmd", "executed",1);
- }
- }
- elsif($a[1] eq "overrideInterval")
- {
- if($a[2] and $a[2] =~ /^\d+$/)
- {
- Log3 $name, 3, "PRESENCE ($name) - overriding regular check intervals to ".$a[2]." seconds";
- $hash->{INTERVAL_OVERRIDED} = $a[2];
- }
- else
- {
- return "invalid override interval given (must be a positive integer)"
- }
- }
- elsif($a[1] eq "clearOverride")
- {
- delete($hash->{INTERVAL_OVERRIDED});
- }
- else
- {
- return $usage;
- }
- return undef;
- }
- ##########################
- sub
- PRESENCE_Attr(@)
- {
- 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", 2);
- }
- 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}))
- {
- $hash->{helper}{DISABLED} = 0;
- 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);
- }
- }
- 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";
- }
- }
- elsif($a[0] eq "set" and $a[2] eq "absenceThreshold")
- {
- return $a[2]." must be a valid integer number" if($a[3] !~ /^\d+$/);
- return $a[2]." is not applicable for mode 'event'" if($hash->{MODE} eq "event");
- }
- elsif($a[0] eq "set" and $a[2] eq "presenceThreshold")
- {
- return $a[2]." must be a valid integer number" if($a[3] !~ /^\d+$/);
- return $a[2]." is not applicable for mode 'event'" if($hash->{MODE} eq "event");
- }
- elsif($a[0] eq "set" and $a[2] eq "absenceTimeout")
- {
- return $a[2]." is only applicable for mode 'event'" if($hash->{MODE} ne "event");
- if($a[3] !~ /^\d?\d(?::\d\d){0,2}$/)
- {
- return "not a valid time frame value. See commandref for the correct syntax.";
- }
- }
- elsif($a[0] eq "set" and $a[2] eq "presenceTimeout")
- {
- return $a[2]." is only applicable for mode 'event'" if($hash->{MODE} ne "event");
- if($a[3] !~ /^\d?\d(?::\d\d){0,2}$/)
- {
- return "not a valid time frame value. See commandref for the correct syntax.";
- }
- }
- return undef;
- }
- #####################################
- # Receives an event and creates several readings for event triggering
- sub
- PRESENCE_Read($)
- {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- my $buf = DevIo_SimpleRead($hash);
- return "" if(!defined($buf));
- chomp $buf;
- readingsBeginUpdate($hash);
- for my $line (split /^/, $buf)
- {
- Log3 $name, 5, "PRESENCE ($name) - received data: $line";
- if($line =~ /^absence|absent/)
- {
- if(!$hash->{helper}{DISABLED} and $hash->{helper}{CURRENT_TIMEOUT} eq "present" and $hash->{INTERVAL_NORMAL} != $hash->{INTERVAL_PRESENT})
- {
- $hash->{helper}{CURRENT_TIMEOUT} = "normal";
- Log3 $name, 4 , "PRESENCE ($name) - changing to normal timeout every ".$hash->{INTERVAL_NORMAL}." seconds";
- DevIo_SimpleWrite($hash, $hash->{ADDRESS}."|".$hash->{INTERVAL_NORMAL}."\n", 2);
- }
- unless($hash->{helper}{DISABLED})
- {
- PRESENCE_ProcessState($hash, "absent");
- if($line=~ /^[^;]+;(.+)$/)
- {
- PRESENCE_ProcessAddonData($hash, $1);
- }
- }
- }
- elsif($line =~ /present;(.+?)$/)
- {
- if(!$hash->{helper}{DISABLED} and $hash->{helper}{CURRENT_TIMEOUT} eq "normal" and $hash->{INTERVAL_NORMAL} != $hash->{INTERVAL_PRESENT})
- {
- $hash->{helper}{CURRENT_TIMEOUT} = "present";
- Log3 $name, 4 , "PRESENCE ($name) - changing to present timeout every ".$hash->{INTERVAL_PRESENT}." seconds";
- DevIo_SimpleWrite($hash, $hash->{ADDRESS}."|".$hash->{INTERVAL_PRESENT}."\n", 2);
- }
- unless($hash->{helper}{DISABLED})
- {
- PRESENCE_ProcessState($hash, "present");
- my $data = $1;
- if($data =~ /\S=\S/)
- {
- PRESENCE_ProcessAddonData($hash, $data);
- }
- else
- {
- if($1 =~ /^(.*);(.+)$/)
- {
- readingsBulkUpdate($hash, "room", $2);
- readingsBulkUpdate($hash, "device_name", $1);
- }
- else
- {
- readingsBulkUpdate($hash, "device_name", $1);
- }
- }
- }
- }
- elsif($line eq "command accepted")
- {
- readingsBulkUpdate($hash, "command_accepted", "yes");
- }
- elsif($line eq "command rejected")
- {
- readingsBulkUpdate($hash, "command_accepted", "no");
- }
- elsif($line =~ /socket_closed;(?:room='?)?(.+?)'?$/)
- {
- Log3 $name, 3, "PRESENCE ($name) - collectord lost connection to room $1";
- }
- elsif($line =~ /socket_reconnected;(?:room='?)?(.+?)'?$/)
- {
- Log3 $name , 3, "PRESENCE ($name) - collectord reconnected to room $1";
- }
- elsif($line =~ /error;(?:room='?)?(.+?)'?$/)
- {
- Log3 $name, 3, "PRESENCE ($name) - room $1 cannot execute hcitool to check device";
- }
- elsif($line =~ /error$/)
- {
- Log3 $name, 3, "PRESENCE ($name) - presenced cannot execute hcitool to check device ";
- }
- }
- readingsEndUpdate($hash, 1);
- }
- #####################################
- sub
- PRESENCE_Ready($)
- {
- my ($hash) = @_;
- return DevIo_OpenDev($hash, 1, "PRESENCE_DoInit") if($hash->{MODE} eq "lan-bluetooth");
- }
- ##########################################################################################################################
- #
- # Functions for local testing with Blocking.pm to ensure a smooth FHEM processing
- #
- ##########################################################################################################################
- #####################################
- sub PRESENCE_StartLocalScan($;$)
- {
- my ($hash, $local) = @_;
- my $name = $hash->{NAME};
- my $mode = $hash->{MODE};
- $local = 0 unless(defined($local));
- if(not (exists($hash->{ADDRESS}) or exists($hash->{helper}{call})))
- {
- return undef;
- }
- unless(exists($hash->{helper}{RUNNING_PID}))
- {
- $hash->{STATE} = "active" if($hash->{STATE} eq "???" or $hash->{STATE} eq "defined");
- 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."|".AttrVal($name, "bluetoothHciDevice", ""), "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, "pingCount", "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, "fritzboxCheckSpeed", "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);
- }
- if(!$hash->{helper}{RUNNING_PID} and $mode =~ /^local-bluetooth|lan-ping|fritzbox|shellscript|function$/)
- {
- delete($hash->{helper}{RUNNING_PID});
- my $seconds = (ReadingsVal($name, "state", "absent") eq "present" ? $hash->{INTERVAL_PRESENT} : $hash->{INTERVAL_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});
- }
- return undef;
- }
- else
- {
- 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->{INTERVAL_PRESENT} : $hash->{INTERVAL_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});
- }
- return "another check is currently running";
- }
- }
- #####################################
- sub PRESENCE_DoLocalPingScan($)
- {
- my ($string) = @_;
- my ($name, $device, $local, $count) = split("\\|", $string);
- Log3 $name, 5, "PRESENCE ($name) - starting ping scan: $string";
- my $retcode;
- my $return;
- my $temp;
- $SIG{CHLD} = 'IGNORE';
- if($^O =~ m/(Win|cygwin)/)
- {
- $temp = qx(ping -n $count -4 $device);
- if(defined($temp) and $temp ne "")
- {
- chomp $temp;
- Log3 $name, 5, "PRESENCE ($name) - ping command returned with output:\n$temp";
- $return = "$name|$local|".($temp =~ /TTL=\d+/ ? "present" : "absent");
- }
- else
- {
- $return = "$name|$local|error|Could not execute ping command: \"ping -n $count -4 $device\"";
- }
- }
- elsif($^O =~ m/solaris/)
- {
- $temp = qx(ping $device 4);
- if(defined($temp) and $temp ne "")
- {
- chomp $temp;
- 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\"";
- }
- }
- else
- {
- $temp = qx(ping -c $count $device 2>&1);
- if(defined($temp) and $temp ne "")
- {
- chomp $temp;
- Log3 $name, 5, "PRESENCE ($name) - ping command returned with output:\n$temp";
- $return = "$name|$local|".(($temp =~ /\d+ [Bb]ytes (from|von)/ and not $temp =~ /[Uu]nreachable/) ? "present" : "absent");
- }
- else
- {
- $return = "$name|$local|error|Could not execute ping command: \"ping -c $count $device\"";
- }
- }
- return $return;
- }
- #####################################
- sub PRESENCE_ExecuteFritzBoxCMD($$)
- {
- my ($name, $cmd) = @_;
- my $status;
- my $wait;
- 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;
- Log3 $name, 5, "PRESENCE ($name) - ctlmgr_ctl is locked. waiting $wait seconds...";
- $wait = 1000000*$wait;
- usleep $wait;
- }
- unlink("/var/tmp/fhem-PRESENCE-cmd-lock.tmp") if(-e "/var/tmp/fhem-PRESENCE-cmd-lock.tmp");
- qx(touch /var/tmp/fhem-PRESENCE-cmd-lock.tmp);
- Log3 $name, 5, "PRESENCE ($name) - executing ctlmgr_ctl: $cmd";
- $status = qx($cmd);
- usleep 200000;
- unlink("/var/tmp/fhem-PRESENCE-cmd-lock.tmp") if(-e "/var/tmp/fhem-PRESENCE-cmd-lock.tmp");
- return $status;
- }
- #####################################
- sub PRESENCE_DoLocalFritzBoxScan($)
- {
- my ($string) = @_;
- my ($name, $device, $local, $speedcheck) = split("\\|", $string);
- Log3 $name, 5, "PRESENCE ($name) - starting fritzbox scan: $string";
- my $number = 0;
- my $status = 0;
- my $speed;
- $SIG{CHLD} = 'IGNORE';
- 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}))
- {
- $number = $defs{$name}{helper}{cachednr};
- Log3 $name, 5, "PRESENCE ($name) - try checking $name as device $device with cached number $number";
- my $cached_name = "";
- $cached_name = PRESENCE_ExecuteFritzBoxCMD($name, "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/$check_command");
- chomp $cached_name;
- # only use the cached $number if it has still the correct device name
- if($cached_name eq $device)
- {
- 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");
- 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");
- }
- 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)";
- }
- return ($status == 0 ? "$name|$local|absent|$number" : "$name|$local|present|$number").($speedcheck == 1 and defined($speed) ? "|$speed" :"");
- }
- else
- {
- Log3 $name, 5, "PRESENCE ($name) - cached device ($cached_name) does not match expected device ($device). perform a full scan";
- }
- }
- my $max = PRESENCE_ExecuteFritzBoxCMD($name, "/usr/bin/ctlmgr_ctl r landevice settings/landevice/count");
- chomp $max;
- Log3 $name, 5, "PRESENCE ($name) - ctlmgr_ctl (getting device count) returned: $max";
- if(not $max =~ /^\s*\d+\s*$/)
- {
- return "$name|$local|error|could not execute ctlmgr_ctl";
- }
- my $net_device;
- $number = 0;
- while($number <= $max)
- {
- $net_device = PRESENCE_ExecuteFritzBoxCMD($name, "/usr/bin/ctlmgr_ctl r landevice settings/landevice$number/$check_command");
- chomp $net_device;
- Log3 $name, 5, "PRESENCE ($name) - checking device number $number ($net_device)";
- if($net_device eq $device)
- {
- $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");
- }
- Log3 $name, 5, "PRESENCE ($name) - state for device number $net_device is $status";
- last;
- }
- $number++;
- }
- return ($status == 0 ? "$name|$local|absent" : "$name|$local|present").($number <= $max ? "|$number" : "|").($speedcheck == 1 and defined($speed) ? "|$speed" : "");
- }
- #####################################
- sub PRESENCE_DoLocalBluetoothScan($)
- {
- my ($string) = @_;
- my ($name, $device, $local, $btdevice) = split("\\|", $string);
- my $devname;
- my $return;
- my $wait = 1;
- my $ps;
- my $psargs = "ax";
- Log3 $name, 5, "PRESENCE ($name) - starting bluetooth scan: $string";
- $SIG{CHLD} = 'IGNORE';
- if(qx(ps --help 2>&1) =~ /BusyBox/g)
- {
- Log3 $name, 5, "PRESENCE ($name) - found busybox variant of ps command, using \"w\" as parameter";
- $psargs = "w";
- }
- else
- {
- Log3 $name, 5, "PRESENCE ($name) - found standard variant of ps command, using \"ax\" as parameter";
- $psargs = "ax";
- }
- Log3 $name, 4, "PRESENCE ($name) - executing: which hcitool";
- my $hcitool = qx(which hcitool);
- Log3 $name, 4, "PRESENCE ($name) - 'which hcitool' returns: $hcitool";
- chomp $hcitool;
- if(-x $hcitool)
- {
- my $options = ($btdevice ? "-i $btdevice" : "");
- while($wait)
- { # check if another hcitool process is running
- $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;
- }
- }
- Log3 $name, 5, "PRESENCE ($name) - executing: hcitool name $device";
- $devname = qx(hcitool $options 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";
- }
- }
- else
- {
- $return = "$name|$local|error|no hcitool binary found. Please check that the bluez-package is properly installed";
- }
- return $return;
- }
- #####################################
- sub PRESENCE_DoLocalShellScriptScan($)
- {
- my ($string) = @_;
- my ($name, $call, $local) = split("\\|", $string);
- my $ret;
- my $return;
- Log3 $name, 5, "PRESENCE ($name) - starting local shell script scan: $string";
- $SIG{CHLD} = 'IGNORE';
- $ret = qx($call 2>&1);
- if(defined($ret))
- {
- chomp $ret;
- Log3 $name, 5, "PRESENCE ($name) - script output: $ret";
- }
- if(not defined($ret))
- {
- $return = "$name|$local|error|scriptcall doesn't return any output";
- }
- elsif($ret eq "1")
- {
- $return = "$name|$local|present";
- }
- elsif($ret eq "0")
- {
- $return = "$name|$local|absent";
- }
- else
- {
- $ret =~ s/\n/<<line-break>>/g;
- $return = "$name|$local|error|unexpected script output (expected 0 or 1): $ret";
- }
- return $return;
- }
- #####################################
- sub PRESENCE_DoLocalFunctionScan($)
- {
- my ($string) = @_;
- my ($name, $call, $local) = split("\\|", $string);
- my $ret;
- my $return;
- Log3 $name, 5, "PRESENCE ($name) - execute perl function: $string";
- $SIG{CHLD} = 'IGNORE';
- $ret = AnalyzeCommandChain(undef, $call);
- chomp $ret;
- Log3 $name, 5, "PRESENCE ($name) - function returned with: $ret";
- if(not defined($ret))
- {
- $return = "$name|$local|error|function call doesn't return any output";
- }
- elsif($ret eq "1")
- {
- $return = "$name|$local|present";
- }
- elsif($ret eq "0")
- {
- $return = "$name|$local|absent";
- }
- else
- {
- $ret =~ s/\n/<<line-break>>/g;
- $return = "$name|$local|error|unexpected function output (expected 0 or 1): $ret";
- }
- return $return;
- }
- #####################################
- sub PRESENCE_ProcessLocalScan($)
- {
- my ($string) = @_;
- return unless(defined($string));
- my @a = split("\\|",$string);
- my $hash = $defs{$a[0]};
- my $local = $a[1];
- my $name = $hash->{NAME};
- Log3 $hash->{NAME}, 5, "PRESENCE ($name) - blocking scan result: $string";
- 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;
- }
- if(defined($hash->{helper}{RETRY_COUNT}))
- {
- Log3 $hash->{NAME}, 2, "PRESENCE ($name) - check returned a valid result after ".$hash->{helper}{RETRY_COUNT}." unsuccesful ".($hash->{helper}{RETRY_COUNT} > 1 ? "retries" : "retry");
- delete($hash->{helper}{RETRY_COUNT});
- }
- if($hash->{MODE} eq "fritzbox" and defined($a[3]) and $a[3] ne "")
- {
- $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);
- PRESENCE_ProcessState($hash, $a[2]) unless($hash->{helper}{DISABLED});
- if($a[2] eq "present")
- {
- readingsBulkUpdate($hash, "device_name", $a[3]) if($hash->{MODE} =~ /^(lan-bluetooth|local-bluetooth)$/ and defined($a[3]));
- readingsBulkUpdate($hash, "speed", $a[4]) if($hash->{MODE} eq "fritzbox" and defined($a[4]));
- }
- elsif($a[2] eq "absent")
- {
- readingsBulkUpdate($hash, "speed", $a[4]) if($hash->{MODE} eq "fritzbox" and defined($a[4]));
- }
- elsif($a[2] eq "error")
- {
- $a[3] =~ s/<<line-break>>/\n/g;
- Log3 $hash->{NAME}, 2, "PRESENCE ($name) - error while processing check: ".$a[3];
- }
- readingsEndUpdate($hash, 1);
- #Schedule the next check within $timeout if it is a regular run
- if($local eq "0")
- {
- my $seconds = (($a[2] eq "present") ? $hash->{INTERVAL_PRESENT} : $hash->{INTERVAL_NORMAL});
- $seconds = $hash->{INTERVAL_OVERRIDED} if($hash->{INTERVAL_OVERRIDED});
- Log3 $hash->{NAME}, 4, "PRESENCE ($name) - rescheduling next check in $seconds seconds";
- RemoveInternalTimer($hash);
- InternalTimer(gettimeofday()+$seconds, "PRESENCE_StartLocalScan", $hash) unless($hash->{helper}{DISABLED});
- }
- }
- #####################################
- sub PRESENCE_ProcessAbortedScan($)
- {
- my ($hash, $msg) = @_;
- my $name = $hash->{NAME};
- delete($hash->{helper}{RUNNING_PID});
- RemoveInternalTimer($hash);
- my $retry_interval = AttrVal($name,"retryInterval",10);
- if(defined($hash->{helper}{RETRY_COUNT}))
- {
- if($hash->{helper}{RETRY_COUNT} >= AttrVal($name, "retryCount", 3))
- {
- 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): $msg" if($hash->{helper}{RETRY_COUNT} == 3);
- InternalTimer(gettimeofday()+$hash->{INTERVAL_NORMAL}, "PRESENCE_StartLocalScan", $hash, 0) unless($hash->{helper}{DISABLED});
- $hash->{helper}{RETRY_COUNT}++;
- }
- else
- {
- 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 $retry_interval seconds): $msg";
- InternalTimer(gettimeofday()+$retry_interval, "PRESENCE_StartLocalScan", $hash, 0) unless($hash->{helper}{DISABLED});
- $hash->{helper}{RETRY_COUNT}++;
- }
- }
- else
- {
- $hash->{helper}{RETRY_COUNT} = 1;
- InternalTimer(gettimeofday()+$retry_interval, "PRESENCE_StartLocalScan", $hash, 0) unless($hash->{helper}{DISABLED});
- Log3 $hash->{NAME}, 2, "PRESENCE ($name) - device could not be checked (retrying in $retry_interval seconds): $msg"
- }
- readingsSingleUpdate($hash, "state", "timeout",1);
- }
- ##########################################################################################################################
- #
- # Helper Functions
- #
- ##########################################################################################################################
- #####################################
- sub PRESENCE_DoInit($)
- {
- my ($hash) = @_;
- if(not exists($hash->{helper}{DISABLED}) or (exists($hash->{helper}{DISABLED}) and $hash->{helper}{DISABLED} == 0))
- {
- readingsSingleUpdate($hash, "state", "active",0);
- $hash->{helper}{CURRENT_TIMEOUT} = "normal";
- DevIo_SimpleWrite($hash, $hash->{ADDRESS}."|".$hash->{INTERVAL_NORMAL}."\n", 2);
- }
- else
- {
- readingsSingleUpdate($hash, "state", "disabled",0);
- }
- return undef;
- }
- #####################################
- sub PRESENCE_calculateThreshold($)
- {
- my ($value) = @_;
- if(defined($value) and $value ne "")
- {
- if($value =~ /^(\d?\d):(\d\d)$/)
- {
- $value = $1 * 60 + $2;
- }
- elsif($value =~ /^(\d?\d):(\d\d):(\d\d)$/)
- {
- $value = $1 * 3600 + $2 * 60 + $3;
- }
- elsif($value !~ /^\d?\d+$/)
- {
- $value = 0;
- }
- }
- else
- {
- $value = 0;
- }
- return $value;
- }
- #####################################
- sub PRESENCE_ThresholdTrigger($)
- {
- my ($hash) = @_;
- if($hash->{helper}{DISABLED})
- {
- delete($hash->{helper}{NEW_STATE});
- return undef;
- }
- if($hash->{helper}{NEW_STATE})
- {
- readingsBeginUpdate($hash);
- readingsBulkUpdateIfChanged($hash, "state", $hash->{helper}{NEW_STATE});
- readingsBulkUpdateIfChanged($hash, "presence", $hash->{helper}{NEW_STATE});
- readingsEndUpdate($hash, 1);
- $hash->{helper}{CURRENT_STATE} = $hash->{helper}{NEW_STATE};
- delete($hash->{helper}{NEW_STATE});
- }
- }
- #####################################
- sub PRESENCE_ProcessState($$)
- {
- my ($hash, $state) = @_;
- my $name = $hash->{NAME};
- my $current_state = $hash->{helper}{CURRENT_STATE} ? $hash->{helper}{CURRENT_STATE} : "";
- my $new_state = $hash->{helper}{NEW_STATE} ? $hash->{helper}{NEW_STATE} : "";
- my $absenceThreshold = AttrVal($name, "absenceThreshold", 1);
- my $presenceThreshold = AttrVal($name, "presenceThreshold", 1);
- my $absenceTimeout = PRESENCE_calculateThreshold(AttrVal($name, "absenceTimeout", ""));
- my $presenceTimeout = PRESENCE_calculateThreshold(AttrVal($name, "presenceTimeout", ""));
- if($state eq "absent")
- {
- RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
- my $count = ($hash->{helper}{ABSENT_COUNT} ? $hash->{helper}{ABSENT_COUNT} : 0);
- if($hash->{MODE} eq "event")
- {
- if($absenceTimeout > 0 and $current_state ne "absent" and $new_state ne "absent")
- {
- readingsBulkUpdate($hash, "state", "maybe absent");
- readingsBulkUpdate($hash, "presence", "maybe absent");
- $hash->{helper}{NEW_STATE} = "absent";
- InternalTimer(gettimeofday()+$absenceTimeout, "PRESENCE_ThresholdTrigger", $hash);
- }
- else
- {
- readingsBulkUpdate($hash, "state", "absent");
- readingsBulkUpdate($hash, "presence", "absent");
- $hash->{helper}{CURRENT_STATE} = "absent";
- delete($hash->{helper}{NEW_STATE});
- }
- }
- else
- {
- if(++$count >= $absenceThreshold)
- {
- readingsBulkUpdate($hash, ".presenceThresholdCounter", 0);
- readingsBulkUpdate($hash, ".absenceThresholdCounter", ($count-1));
- readingsBulkUpdate($hash, "state", "absent");
- readingsBulkUpdate($hash, "presence", "absent");
- }
- else
- {
- $hash->{helper}{ABSENT_COUNT} = $count;
- readingsBulkUpdate($hash, ".presenceThresholdCounter", 0);
- readingsBulkUpdate($hash, ".absenceThresholdCounter", $count);
- readingsBulkUpdate($hash, "state", "maybe absent");
- readingsBulkUpdate($hash, "presence", "maybe absent");
- Log3 $name, 4, "PRESENCE ($name) - device is absent after $count check".($count == 1 ? "" : "s").". ".($absenceThreshold-$count)." check".(($absenceThreshold-$count) == 1 ? "" : "s")." left before going absent";
- }
- }
- delete($hash->{helper}{PRESENT_COUNT});
- }
- elsif($state eq "present")
- {
- RemoveInternalTimer($hash, "PRESENCE_ThresholdTrigger");
- my $count = ($hash->{helper}{PRESENT_COUNT} ? $hash->{helper}{PRESENT_COUNT} : 0);
- if($hash->{MODE} eq "event")
- {
- if($presenceTimeout > 0 and $current_state ne "present" and $new_state ne "present")
- {
- readingsBulkUpdate($hash, "state", "maybe present");
- readingsBulkUpdate($hash, "presence", "maybe present");
- $hash->{helper}{NEW_STATE} = "present";
- InternalTimer(gettimeofday()+$presenceTimeout, "PRESENCE_ThresholdTrigger", $hash);
- }
- else
- {
- readingsBulkUpdate($hash, "state", "present");
- readingsBulkUpdate($hash, "presence", "present");
- $hash->{helper}{CURRENT_STATE} = "present";
- delete($hash->{helper}{NEW_STATE});
- }
- }
- else
- {
- if(++$count >= $presenceThreshold)
- {
- readingsBulkUpdate($hash, ".absenceThresholdCounter", 0);
- readingsBulkUpdate($hash, ".presenceThresholdCounter", ($count-1));
- readingsBulkUpdate($hash, "state", "present");
- readingsBulkUpdate($hash, "presence", "present");
- $hash->{helper}{CURRENT_STATE} = "present";
- }
- else
- {
- $hash->{helper}{PRESENT_COUNT} = $count;
- readingsBulkUpdate($hash, ".absenceThresholdCounter", 0);
- readingsBulkUpdate($hash, ".presenceThresholdCounter", $count);
- readingsBulkUpdate($hash, "state", "maybe present");
- readingsBulkUpdate($hash, "presence", "maybe present");
- Log3 $name, 4, "PRESENCE ($name) - device is present after $count check".($count == 1 ? "" : "s").". ".($presenceThreshold-$count)." check".(($presenceThreshold-$count) == 1 ? "" : "s")." left before going present";
- }
- }
- delete($hash->{helper}{ABSENT_COUNT});
- }
- else
- {
- readingsBulkUpdate($hash, "state", $state);
- }
- }
- #####################################
- sub PRESENCE_ProcessAddonData($$)
- {
- my ($hash, $data) = @_;
- my ($a, $h) = parseParams($data, ";");
- foreach my $key (sort keys %{$h})
- {
- readingsBulkUpdate($hash, $key, $h->{$key}) if(defined($h->{$key}));
- }
- return undef;
- }
- #####################################
- sub PRESENCE_setNotfiyDev($)
- {
- my ($hash) = @_;
- notifyRegexpChanged($hash,"(global|".$hash->{EVENT_PRESENT}."|".$hash->{EVENT_ABSENT}.")");
- }
- 1;
- =pod
- =item helper
- =item summary provides presence detection checks
- =item summary_DE stellt eine Anwesenheitserkennung zur Verfügung
- =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>
- <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>
- <li><b>local-bluetooth</b> - A presence check by searching directly for a given bluetooth device nearby.</li>
- <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>
- <li><b>event</b> - A presence check by listening to FHEM events of other definitions.</li>
- <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>
- <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>
- <br><br>
- <a name="PRESENCE_define"></a>
- <b>Define</b><br><br>
- <ul><b>Mode: lan-ping</b><br><br>
- <code>define <name> PRESENCE lan-ping <ip-address> [ <check-interval> [ <present-check-interval> ] ]</code><br>
- <br>
- 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>
- <br>
- <b>Mode: fritzbox</b><br><br>
- <code>define <name> PRESENCE fritzbox <device-name/mac-address> [ <check-interval> [ <present-check-interval> ] ]</code><br>
- <br>
- 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>
- <u>Example</u><br><br>
- <code>define iPhone PRESENCE fritzbox iPhone-6</code><br>
- <code>define iPhone PRESENCE fritzbox 00:06:08:05:0D:00</code><br><br>
- <b>Mode: local-bluetooth</b><br><br>
- <code>define <name> PRESENCE local-bluetooth <bluetooth-address> [ <check-interval> [ <present-check-interval> ] ]</code><br>
- <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>
- <u>Example</u><br><br>
- <code>define iPhone PRESENCE local-bluetooth 0a:8d:4f:51:3c:8f</code><br><br>
- <b>Mode: function</b><br><br>
- <code>define <name> PRESENCE function {...} [ <check-interval> [ <present-check-interval> ] ]</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>
- 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 <name> PRESENCE shellscript "<path> [<arg1>] [<argN>]..." [ <check-interval> [ <present-check-interval> ] ]</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>
- <b>Mode: event</b><br><br>
- <code>define <name> PRESENCE evemt <absent-regexp> <present-regexp></code><br>
- <br>
- Listens for events of other FHEM definitions to determine a presence state. You must provide two event regexp's in the same style as for the <a href="#notify">notify</a> module.<br><br>
- If an event matches one of the provides regexps, the presence state will be changed.<br><br>
- <u>Example</u><br><br>
- <code>define Presence_John PRESENCE event Door_Switch:off Door_Switch:on</code><br><br>
- <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>
- <code>define <name> PRESENCE lan-bluetooth <bluetooth-address> <ip-address>[:port] [ <check-interval> ]</code><br>
- <br>
- The default port is 5111 (presenced). Alternatly you can use port 5222 (collectord)<br>
- <br>
- <u>Example</u><br><br>
- <code>define iPhone PRESENCE lan-bluetooth 0a:4f:36:d8:f9:89 127.0.0.1:5222</code><br><br>
- <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:
- presenced [-d] [-p <port>] [-P <filename>]
- 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
- -n, --no-timestamps
- do not output timestamps in log messages
- -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>
- <li>direct perl script file: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/presenced" target="_new">presenced</a></li>
- <li>.deb package for Debian/Raspbian (noarch): <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/presenced-1.5.deb" target="_new">presenced-1.5.deb</a></li>
- </ul>
- </ul><br><br>
- <u>lepresenced</u><br><br>
- <ul>lepresenced is a Perl network daemon that provides presence checks of
- multiple bluetooth devices over network. In contrast to presenced,
- lepresenced covers <u>Bluetooth 4.0 (low energy) devices, i. e.
- Gigaset G-Tags, FitBit Charges.</u>
- lepresenced listens on TCP port 5333 for connections of a PRESENCE definition
- or collectord.<br>
- <PRE>
- Usage:
- lepresenced --bluetoothdevice <bluetooth device> --listenaddress <listen address> --listenport <listen port> --loglevel <log level> --daemon
- lepresenced -b <bluetooth device> -a <listen address> -p <listen port> -l <log level> -d
- valid log levels:
- LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG. Default: LOG_INFO
- Examples:
- lepresenced --bluetoothdevice hci0 --listenaddress 127.0.0.1 --listenport 5333 --daemon
- lepresenced --loglevel LOG_DEBUG --daemon
- </PRE>
- To detect the presence of a device, it uses the command <i>hcitool lescan</i> (package:
- <a href="http://www.bluez.org" target="_new">bluez</a>) to continuously listen to
- beacons of Bluetooth LE devices.
- <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>
- <li>Perl script: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/lepresenced" target="_new">lepresenced</a></li>
- <li>.deb package (noarch): <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/" target="_new">contrib/PRESENCE/deb/</a></li>
- </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:
- collectord -c <configfile> [-d] [-p <port>] [-P <pidfile>]
- collectord [-h | --help]
- Options:
- -c, --configfile <configfile>
- 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
- -n, --no-timestamps
- do not output timestamps in log messages
- -v, --verbose
- Print detailed log output
- -l, --logfile <logfile>
- 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>
- <li>direct perl script file: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/collectord" target="_new">collectord</a></li>
- <li>.deb package for Debian (noarch): <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/collectord-1.8.1.deb" target="_new">collectord-1.8.1.deb</a></li>
- </ul>
- </ul><br><br>
- </ul>
- <br>
- <a name="PRESENCE_set"></a>
- <b>Set</b>
- <ul>
- <li><b>statusRequest</b> - Schedules an immediatly check.</li>
- <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>
- <li><b>overrideInterval</b> - Override the check interval to the given number of seconds. (not applicable in mode "event" and "lan-bluetooth")</li>
- <li><b>clearOverride</b> - clear an active check interval override (only if set command overrideInterval was executed before)</li>
- </ul>
- <br>
- <a name="PRESENCE_get"></a>
- <b>Get</b>
- <ul>
- N/A
- </ul>
- <br>
- <a name="PRESENCE_attr"></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 name="PRESENCE_disable">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>
- <li><a name="PRESENCE_absenceThreshold">absenceThreshold</a></li><br> <i>(not applicable in mode "event" )</i><br>
- The number of checks that have to result in "absent" before the state of the PRESENCE definition is changed to "absent".
- This can be used to verify the absence of a device with multiple check runs before the state is finally changed to "absent".
- If this attribute is set to a value >1, the reading state and presence will be set to "maybe absent" during the absence verification.<br><br>
- Default Value is 1 (no absence verification)<br><br>
- <li><a name="PRESENCE_presenceThreshold">presenceThreshold</a></li><br> <i>(not applicable in mode "event" )</i><br>
- The number of checks that have to result in "present" before the state of the PRESENCE definition is changed to "present".
- This can be used to verify the permanent presence of a device with multiple check runs before the state is finally changed to "present".
- If this attribute is set to a value >1, the reading state and presence will be set to "maybe present" during the presence verification.<br><br>
- Default Value is 1 (no presence verification)<br><br>
- <li><a name="PRESENCE_absenceTimeout">absenceTimeout</a></li><br> <i>(only in mode "event" applicable)</i><br>
- The timeout after receiving an "absent" event, before the state of the PRESENCE definition is switched to "absent".
- This can be used to verify the permanent absence by waiting a specific time frame to not receive an "present" event.
- If this timeout is reached with no "present" event received in the meantime, the presence state will finally be set to "absent".
- The timeout is given in HH:MM:SS format, where hours and minutes are optional.
- If this attribute is set to a valid value, the reading state and presence will be set to "maybe absent" during the absence verification.<br><br>
- Default Value is 0 (no absence verification)<br><br>
- <li><a name="PRESENCE_presenceTimeout">presenceTimeout</a></li><br> <i>(only in mode "event" applicable)</i><br>
- The timeout after receiving an "present" event, before the state of the PRESENCE definition is switched to "present".
- This can be used to verify the permanent presence by waiting a specific time frame to not receive an "absent" event.
- If this timeout is reached with no "absent" event received in the meantime, the presence state will finally be set to "present".
- The timeout is given in HH:MM:SS format, where hours and minutes are optional.
- If this attribute is set to a valid value, the reading state and presence will be set to "maybe present" during the presence verification.<br><br>
- Default Value is 0 (no presence verification)<br><br>
- <li><a name="PRESENCE_retryInterval">retryInterval</a></li><br> <i>(Not applicable in mode "event" or "lan-bluetooth")</i><br>
- The check interval in case a check is prematurely aborted and was unable to check the presence. In this case, PRESENCE reschedules
- the next check as retry within the given retry interval in seconds (usually lower than the regular check interval).
- <br><br>
- Default Value is 10 seconds<br><br>
- <li><a name="PRESENCE_retryCount">retryCount</a></li><br> <i>(Not applicable in mode "event" or "lan-bluetooth")</i><br>
- The maximum number of checks to perform within the retryInterval in case a check is prematurely aborted and was unable to check the presence.
- PRESENCE will try to retry after a failed check to a maximum of the given number of tries. If all retries fails also, it will uses afterwards
- the regular check interval.
- <br><br>
- Default Value is 3 (number of check retries)<br><br>
- <li><a name="PRESENCE_pingCount">pingCount</a></li> (Only in mode "ping" applicable)<br>
- 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>
- <li><a name="PRESENCE_bluetoothHciDevice">bluetoothHciDevice</a></li> (Only in Mode "local-bluetooth" applicable)<br>
- Set a specific bluetooth HCI device to use for scanning. If you have multiple bluetooth modules connected, you can select a specific one to use for scanning (e.g. hci0, hci1, ...).<br><br>
- <li><a name="PRESENCE_fritzboxCheckSpeed">fritzboxCheckSpeed</a></li> (Only in Mode "fritzbox" applicable)<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.
- <br><br>
- Possible values: 0 => do not check speed, 1 => check speed when device is active<br>
- Default value is 0 (no speed check)
- <br><br>
- <li><a name="PRESENCE_powerCmd">powerCmd</a></li><br>
- Define a FHEM command, which powers on or off the device.<br><br>
- When executing the powerCmd (set command: power) following placeholders will be replaced by there corresponding values:<br><br>
- <ul>
- <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>
- </ul>
- <br>
- 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>
- </ul>
- </ul>
- <br>
- <a name="PRESENCE_events"></a>
- <b>Generated readings/events:</b><br><br>
- <ul>
- <u>General readings/events:</u><br><br>
- <ul>
- <li><b>state</b>: (absent|maybe absent|present|maybe present|disabled|error|timeout) - The state of the device, check errors or "disabled" when the <a href="#PRESENCE_disable">disable</a> attribute is enabled</li>
- <li><b>presence</b>: (absent|maybe absent|present|maybe present) - The presence state of the device. The value "maybe absent" only occurs if <a href="#PRESENCE_absenceThreshold">absenceThreshold</a> is activated. The value "maybe present" only occurs if <a href="#PRESENCE_presenceThreshold">presenceThreshold</a> is activated.</li>
- <li><b>powerCmd</b>: (executed|failed) - power command was executed or has failed</li>
- </ul><br><br>
- <u>Bluetooth specific readings/events:</u><br><br>
- <ul>
- <li><b>device_name</b>: $name - The name of the Bluetooth device in case it's present</li>
- </ul><br><br>
- <u>FRITZ!Box specific readings/events:</u><br><br>
- <ul>
- <li><b>speed</b>: $speed - The current speed of the checked device if attribute <a href="#PRESENCE_fritzboxCheckSpeed">fritzboxCheckSpeed</a> is activated</li>
- </ul><br><br>
- <u>presenced/collectord specific readings/events:</u><br><br>
- <ul>
- <li><b>command_accepted</b>: $command_accepted (yes|no) - Was the last command acknowleged and accepted by the presenced or collectord?</li>
- <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
- =begin html_DE
- <a name="PRESENCE"></a>
- <h3>PRESENCE</h3>
- <ul>
- Das PRESENCE Module bietet mehrere Möglichkteiten um die Anwesenheit von Handys/Smartphones oder anderen mobilen Gerä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öglich, wenn FHEM auf einer FritzBox läuft)</li>
- <li><b>local-bluetooth</b> - Eine Erkennung auf Basis von Bluetooth-Abfragen durch den FHEM Server. Das Gerät muss dabei in Empfangsreichweite sein, aber nicht sichtbar sein</li>
- <li><b>function</b> - Eine Erkennung mithilfe einer selbst geschriebenen Perl-Funktion, welche den Anwesenheitsstatus ermittelt.</li>
- <li><b>shellscript</b> - Eine Erkennung mithilfe eines selbst geschriebenen Skriptes oder Programm (egal in welcher Sprache).</li>
- <li><b>event</b> - Eine Erkennung basierend auf Events einer anderen Definition in FHEM. </li>
- <li><b>lan-bluetooth</b> - Eine Erkennung durch Bluetooth-Abfragen via Netzwerk (LAN/WLAN) in ein oder mehreren Räumen</li>
- </ul>
- <br>
- Jeder Modus kann optional mit spezifischen Prüf-Intervallen ausgeführt werden.<br><br>
- <ul>
- <li>check-interval - Das normale Prüfinterval in Sekunden für eine Anwesenheitsprüfung. Standardwert: 30 Sekunden</li>
- <li>present-check-interval - Das Prüfinterval in Sekunden, wenn ein Gerät anwesend (<i>present</i>) ist. Falls nicht angegeben, wird der Wert aus check-interval verwendet</li>
- </ul>
- <br><br>
- <a name="PRESENCE_define"></a>
- <b>Define</b><br><br>
- <ul><b>Modus: lan-ping</b><br><br>
- <code>define <name> PRESENCE lan-ping <IP-Addresse oder Hostname> [ <Interval> [ <Anwesend-Interval> ] ]</code><br>
- <br>
- Prüft ob ein Gerät über Netzwerk (ü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>
- <b>Modus: fritzbox</b><br><br>
- <code>define <name> PRESENCE fritzbox <Gerätename/MAC-Adresse> [ <Interval> [ <Anwesend-Interval> ] ]</code><br>
- <br>
- Prüft ob ein Gerät welches per WLAN mit der FritzBox verbunden ist, erreichbar durch Abfrage des Status mit dem Befehl ctlmgr_ctl.
- Der Gerätename (Parameter: <Gerätename>) muss dem Namen entsprechen, welcher im Menüpunkt "Heimnetz" auf der FritzBox-Oberflä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äuft! Die Erkennung einer Abwesenheit kann ca. 10-15 Minuten dauern!</i><br><br>
- <u>Beispiel</u><br><br>
- <code>define iPhone PRESENCE fritzbox iPhone-6</code><br>
- <code>define iPhone PRESENCE fritzbox 00:06:08:05:0D:00</code><br><br>
- <b>Modus: local-bluetooth</b><br><br>
- <code>define <name> PRESENCE local-bluetooth <Bluetooth-Adresse> [ <Interval> [ <Anwesend-Interval> ] ]</code><br>
- <br>
- Prüft ob ein Bluetooth-Gerät abgefragt werden kann und meldet dies als Anwesenheit. Für diesen Modus wird der Shell-Befehl "hcitool" benötigt
- (wird durch das Paket <a href="http://www.bluez.org" target="_new">bluez</a> bereitgestellt), sowie ein funktionierender Bluetooth-Empfänger (intern oder als USB-Stick)<br><br>
- <u>Beispiel</u><br><br>
- <code>define iPhone PRESENCE local-bluetooth 0a:4f:36:d8:f9:8</code><br><br>
- <b>Modus: function</b><br><br>
- <code>define <name> PRESENCE function {...} [ <Interval> [ <Anwesend-Interval> ] ]</code><br>
- <br>
- Prüft den Anwesenheitsstatus mithilfe einer selbst geschriebenen Perl-Funktion (z.B. SNMP Abfrage).<br><br>
- 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 <name> PRESENCE shellscript "<Skript-Pfad> [<arg1>] [<argN>]..." [ <Interval> [ <Anwesend-Interval> ] ]</code><br>
- <br>
- Prü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>
- <b>Mode: event</b><br><br>
- <code>define <name> PRESENCE event <Abwesend-Regexp> <Anwesend-Regexp></code><br>
- <br>
- Lauscht auf Events von anderen Definitionen innerhalb von FHEM um die Anwesenheit darzustellen.
- Die regulären Ausdrücke für An- und Abwesenheit entsprechen dabei der Syntax von <a href="#notify">notify</a>.<br><br>
- Sobald innerhalb von FHEM ein Event gefeuert wird, welches auf die Abwesend-Regexp bzw. Anwesend-Regexp passt, wird der Status entsprechend in PRESENCE gesetzt.<br><br>
- <u>Beispiel</u><br><br>
- <code>define Anwesenheit PRESENCE event Tuerschalter:off Tuerschalter:on</code><br><br>
- <b>Modus: lan-bluetooth</b><br><br>
- Prüft ein Bluetooth-Gerät auf Anwesenheit über Netzwerk mit Hilfe von presenced oder collectord. Diese können auf jeder Maschine installiert werden,
- welche eine Standard-Perl-Umgebung bereitstellt und über Netzwerk erreichbar ist.
- <br>
- <br>
- <code>define <name> PRESENCE lan-bluetooth <Bluetooth-Adresse> <IP-Adresse>[:Port] [ <Interval> ]</code><br>
- <br>
- Der Standardport ist 5111 (presenced). Alternativ kann man den Port 5222 (collectord) nutzen. Generell ist der Port aber frei wählbar.<br><br>
- <u>Beispiel</u><br><br>
- <code>define iPhone PRESENCE lan-bluetooth 0a:4f:36:d8:f9:89 127.0.0.1:5222</code><br><br>
- <u>presenced</u><br><br>
- <ul>Der presenced ist ein Perl Netzwerkdienst, welcher eine Bluetooth-Anwesenheitserkennung von ein oder mehreren Geräten über Netzwerk bereitstellt.
- Dieser lauscht standardmäßig auf TCP Port 5111 nach eingehenden Verbindungen von dem PRESENCE Modul oder einem collectord.<br>
- <PRE>
- Usage:
- presenced -d [-p <port>] [-P <filename>]
- 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ünschte Bluetooth Adresse (z.B. 01:B4:5E:AD:F6:D3) durchzuführen. Das Gerät muss dabei nicht sichtbar sein, allerdings ständig aktiviert sein
- um Bluetooth-Anfragen zu beantworten.
- <br><br>
- Wenn ein Gerät anwesend ist, wird dies an FHEM übermittelt zusammen mit dem Gerätenamen als Reading.<br><br>
- Der presenced ist zum Download verfügbar als:<br><br>
- <ul>
- <li>Perl Skript: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/presenced" target="_new">presenced</a></li>
- <li>.deb Paket für Debian/Raspbian (architekturunabhängig): <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/presenced-1.5.deb" target="_new">presenced-1.5.deb</a></li>
- </ul>
- </ul><br><br>
- <u>lepresenced</u><br><br>
- <ul>lepresenced ist ein Perl Netzwerkdienst, der analog zu presenced eine
- Bluetooth-Anwesenheitserkennung von ein oder mehreren Geräten
- über Netzwerk bereitstellt. Im Gegensatz zu presenced unterstützt
- lepresenced <u>Bluetooth 4.0 (Low Energy) Geräte wie z. B. Gigaset G-Tags,
- FitBit Charges.</u>
- lepresenced lauscht standardmäßig auf TCP Port 5333 und wartet
- auf eingehende Verbindungen des PRESENCE-Moduls bzw. von collectord.<br>
- <PRE>
- Usage:
- lepresenced --bluetoothdevice <bluetooth device> --listenaddress <listen address> --listenport <listen port> --loglevel <log level> --daemon
- lepresenced -b <bluetooth device> -a <listen address> -p <listen port> -l <log level> -d
- valid log levels:
- LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG. Default: LOG_INFO
- Examples:
- lepresenced --bluetoothdevice hci0 --listenaddress 127.0.0.1 --listenport 5333 --daemon
- lepresenced --loglevel LOG_DEBUG --daemon
- </PRE>
- Zur Bluetooth-Abfrage wird der Befehl <i>hcitool lescan</i> (Paket:
- <a href="http://www.bluez.org" target="_new">bluez</a>) verwendet, der
- fortwährend auf die Beacons der Bluetooth-LE-Geräte lauscht.
- <br><br>
- Wenn ein Gerät anwesend ist, wird dies an FHEM übermittelt zusammen mit dem Gerätenamen als Reading.<br><br>
- Der le presenced ist zum Download verfügbar als:<br><br>
- <ul>
- <li>Perl Skript: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/lepresenced" target="_new">lepresenced</a></li>
- <li>.deb Paket (architekturunabhängig) unter <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/" target="_new">contrib/PRESENCE/deb/</a></li>
- </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äten über Netzwerk durchzuführen.<br><br>
- Er lauscht auf TCP port 5222 nach eingehenden Verbindungen von einem PRESENCE Modul.
- <PRE>
- Usage:
- collectord -c <configfile> [-d] [-p <port>] [-P <pidfile>]
- collectord [-h | --help]
- Options:
- -c, --configfile <configfile>
- 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 <logfile>
- log to the given logfile
- -h, --help
- Print detailed help screen
- </PRE>
- Bevor der collectord verwendet werden kann, benötigt er eine Konfigurationsdatei in welcher alle Rä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ät in irgend einem Raum anwesend ist, wird dies an FHEM übermittelt, zusammen mit dem Gerätenamen und dem Raum, in welchem das Gerät erkannt wurde.<br><br>
- Der collectord ist zum Download verfügbar als:<br><br>
- <ul>
- <li>Perl Skript: <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/collectord" target="_new">collectord</a></li>
- <li>.deb Paket für Debian (architekturunabhängig): <a href="https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/collectord-1.8.1.deb" target="_new">collectord-1.8.1.deb</a></li>
- </ul>
- </ul>
- </ul>
- <br>
- <a name="PRESENCE_set"></a>
- <b>Set</b>
- <ul>
- <li><b>statusRequest</b> - Startet einen sofortigen Check.</li>
- <li><b>power</b> - Startet den powerCmd-Befehl welche durch den Parameter powerCmd angegeben ist (Nur wenn das Attribut "powerCmd" definiert ist)</li>
- <li><b>overrideInterval</b> - Übersteuert das Prüfinterval auf die übergebene Dauer in Sekunden (Nicht im Modus "event" und "lan-bluetooth" anwendbar)</li>
- <li><b>clearOverride</b> - Entfernt eine zuvor gesetzte Übersteuerung des Prüfintervals (Nur anwendbar, wenn zuvor eine Übersteuerung mit dem Set-Befehl overrideInterval stattgefunden hat)</li>
- </ul>
- <br>
- <a name="PRESENCE_get"></a>
- <b>Get</b>
- <ul>
- N/A
- </ul>
- <br>
- <a name="PRESENCE_attr"></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 name="PRESENCE_disable">disable</a></li>
- Wenn dieses Attribut aktiviert ist, wird die Anwesenheitserkennung nicht mehr durchgeführt.<br><br>
- Mögliche Werte: 0 => Erkennung durchführen , 1 => Keine Erkennungen durchführen<br>
- Standardwert ist 0 (Erkennung durchführen)<br><br>
- <li><a name="PRESENCE_absenceThreshold">absenceThreshold</a></li> <i>(Nicht im Modus "event" anwendbar)</i><br>
- Die Anzahl an Checks, welche in "absent" resultieren müssen, bevor der Status der PRESENCE-Definition auf "absent" wechselt.
- Mit dieser Funktion kann man die Abwesenheit eines Gerätes verifizieren bevor der Status final auf "absent" geändert wird.
- Wenn dieses Attribut auf einen Wert >1 gesetzt ist, werden die Readings "state" und "presence" auf den Wert "maybe absent" gesetzt,
- bis der Status final auf "absent" wechselt.<br><br>
- Standardwert ist 1 (keine Abwesenheitsverifizierung)<br><br>
- <li><a name="PRESENCE_presenceThreshold">presenceThreshold</a></li> <i>(Nicht im Modus "event" anwendbar)</i><br>
- Die Anzahl an Checks, welche in "present" resultieren müssen, bevor der Status der PRESENCE-Definition auf "present" wechselt.
- Mit dieser Funktion kann man die Anwesenheit eines Gerätes verifizieren bevor der Status final auf "present" geändert wird.
- Wenn dieses Attribut auf einen Wert >1 gesetzt ist, werden die Readings "state" und "presence" auf den Wert "maybe present" gesetzt,
- bis der Status final auf "present" wechselt.<br><br>
- Standardwert ist 1 (keine Anwesenheitsverifizierung)<br><br>
- <li><a name="PRESENCE_absenceTimeout">absenceTimeout</a></li> <i>(Nur im Modus "event" anwendbar)</i><br>
- Die Dauer, die nach einem "absent"-Event gewartet werden soll, bis der Status der PRESENCE-Definition tatsächlich auf "absent" geändert werden soll.
- Die Dauer kann dabei im Format HH:MM:SS angegeben werden, wobei Stunden und Minuten optional sind.
- Wenn dieses Attribut auf einen gültigen Wert gesetzt ist, werden die Readings "state" und "presence" bei einem "absent"-Event zunächst auf den Wert "maybe absent" gesetzt.
- Sobald das parametrisierte Zeitfenster um ist, wird der Status final auf "absent" gesetzt.<br><br>
- Standardwert ist 0 Sekunden (keine Statusverzögerung)<br><br>
- <li><a name="PRESENCE_presenceTimeout">presenceTimeout</a></li> <i>(Nur im Modus "event" anwendbar)</i><br>
- Die Dauer, die nach einem "present"-Event gewartet werden soll, bis der Status der PRESENCE-Definition tatsächlich auf "present" geändert werden soll.
- Die Dauer kann dabei im Format HH:MM:SS angegeben werden, wobei Stunden und Minuten optional sind.
- Wenn dieses Attribut auf einen gültigen Wert gesetzt ist, werden die Readings "state" und "presence" bei einem "present"-Event zunächst auf den Wert "maybe present" gesetzt.
- Sobald das parametrisierte Zeitfenster um ist, wird der Status final auf "present" gesetzt.<br><br>
- Standardwert ist 0 Sekunden (keine Statusverzögerung)<br><br>
- <li><a name="PRESENCE_retryInterval">retryInterval</a></li> <i>(Nicht im Modus "event" oder "lan-bluetooth" anwendbar)</i><br>
- Das Prüfinterval, welches im Falle eines vorzeitig abgebrochenen Checks genutzt wird, um eine Wiederholung auszuführen. Dazu wird im Falle eines abgebrochenen
- Checks der nächste Check nach der übergebenen Dauer in Sekunden ausgeführt. Diese sollte geringer sein als das reguläre Prüfinterval.
- <br><br>
- Standardwert ist 10 Sekunden<br><br>
- <li><a name="PRESENCE_retryCount">retryCount</a></li> <i>(Nicht im Modus "event" oder "lan-bluetooth" anwendbar)</i><br>
- Die maximale Anzahl an Wiederholungen, sollte ein Check vorzeitig abgebrochen werden. Sobald ein Check vorzeitigabbricht, werden maximal die übergebene Anzahl an Wiederholung
- innerhalb des in retryInterval konfigurierten Interval ausgeführt um in kürzerer Zeit ein valides Ergebnis zu erhalten.
- <br><br>
- Standardwert ist 3 Wiederholungen<br><br>
- <li><a name="PRESENCE_pingCount">pingCount</a></li> (Nur im Modus "ping" anwendbar)<br>
- 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>
- Standardwert ist 4 (Versuche)<br><br>
- <li><a name="PRESENCE_bluetoothHciDevice">bluetoothHciDevice</a></li> (Nur im Modus "local-bluetooth" anwendbar)<br>
- Sofern man mehrere Bluetooth-Empfänger verfügbar hat, kann man mit diesem Attribut ein bestimmten Empfänger auswählen, welcher zur Erkennung verwendet werden soll (bspw. hci0, hci1, ...). Es muss dabei ein vorhandener HCI-Gerätename angegeben werden wie z.B. <code>hci0</code>.
- <br><br>
- <li><a name="PRESENCE_fritzboxCheckSpeed">fritzboxCheckSpeed</a></li> (Nur im Modus "fritzbox")<br>
- Zusätzlich zum Status des Gerä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äten wird als Geschwindigkeit 0 ausgegeben.
- <br><br>
- Mögliche Werte: 0 => Geschwindigkeit nicht prüfen, 1 => Geschwindigkeit prüfen<br>
- Standardwert ist 0 (Keine Geschwindigkeitsprüfung)
- <br><br>
- <li><a name="PRESENCE_powerCmd">powerCmd</a></li><br>
- Ein FHEM-Befehl, welcher das Gerät schalten kann.<br><br>
- Wenn der power-Befehl ausgeführt wird (set-Befehl: power) werden folgende Platzhalter durch ihre entsprechenden Werte ersetzt:<br><br>
- <ul>
- <li><code>$NAME</code> - Name der PRESENCE-Definition</li>
- <li><code>$ADDRESS</code> - Die überwachte Addresse der PRESENCE Definition, wie sie im define-Befehl angegeben wurde.</li>
- <li><code>$ARGUMENT</code> - Das Argument, was dem Set-Befehl "power" übergeben wurde. (z.B. "on" oder "off")</li>
- </ul>
- <br>
- 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>
- </ul>
- <br>
- <a name="PRESENCE_events"></a>
- <b>Generierte Readings/Events:</b><br><br>
- <ul>
- <u>Generelle ReadingsEvents:</u><br><br>
- <ul>
- <li><b>state</b>: (absent|maybe absent|present|maybe present|disabled|error|timeout) - Der Anwesenheitsstatus eine Gerätes (absent = abwesend; present = anwesend) oder "disabled" wenn das <a href="#PRESENCE_disable">disable</a>-Attribut aktiviert ist</li>
- <li><b>presence</b>: (absent|maybe absent|present|maybe present) - Der Anwesenheitsstatus eine Gerätes (absent = abwesend; present = anwesend). Der Wert "maybe absent" (vielleicht abwesend) tritt nur auf, sofern das Attribut <a href="#PRESENCE_absenceThreshold">absenceThreshold</a> aktiviert ist. Der Wert "maybe present" (vielleicht anwesend) tritt nur auf, sofern das Attribut <a href="#PRESENCE_presenceThreshold">presenceThreshold</a> aktiviert ist.</li>
- <li><b>powerCmd</b>: (executed|failed) - Ausführung des power-Befehls war erfolgreich.</li>
- </ul><br><br>
- <u>Bluetooth-spezifische Readings/Events:</u><br><br>
- <ul>
- <li><b>device_name</b>: $name - Der Name des Bluetooth-Gerätes, wenn es anwesend (Status: present) ist</li>
- </ul><br><br>
- <u>FRITZ!Box-spezifische Readings/Events:</u><br><br>
- <ul>
- <li><b>speed</b>: $speed - Die Netzwerkdeschwindigkeit des Gerätes, sofern das Attribut <a href="#PRESENCE_fritzboxCheckSpeed">fritzboxCheckSpeed</a> aktiviert ist.</li>
- </ul><br><br>
- <u>presenced-/collectord-spezifische Readings/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ät erkannt wurde (Raumname entsprechend der Konfigurationsdatei des collectord)</li>
- </ul>
- </ul>
- </ul>
- =end html_DE
- =cut
|