From 5caa5fd5fb9e89d999b5f6d04eac1067801fbdd2 Mon Sep 17 00:00:00 2001 From: markusbloch <> Date: Tue, 26 Sep 2017 09:20:09 +0000 Subject: [PATCH] my modules: remove unneccessary whitespaces at the end of the line git-svn-id: https://svn.fhem.de/fhem/trunk@15140 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/70_Pushsafer.pm | 70 ++--- fhem/FHEM/71_YAMAHA_BD.pm | 216 ++++++------- fhem/FHEM/72_FB_CALLLIST.pm | 590 ++++++++++++++++++------------------ fhem/FHEM/73_PRESENCE.pm | 346 ++++++++++----------- fhem/FHEM/82_LGTV_IP12.pm | 172 +++++------ fhem/FHEM/98_version.pm | 44 +-- 6 files changed, 719 insertions(+), 719 deletions(-) diff --git a/fhem/FHEM/70_Pushsafer.pm b/fhem/FHEM/70_Pushsafer.pm index 2ff0e27ee..a0ecb391a 100755 --- a/fhem/FHEM/70_Pushsafer.pm +++ b/fhem/FHEM/70_Pushsafer.pm @@ -5,8 +5,8 @@ # Sents messages to your Pushsafer accout which will be delivered to # any configured device (e.g. iOS, Andriod, Windows). # -# This module is based on the Pushsafer API description -# which is available at https://www.pushsafer.com/en/pushapi: +# This module is based on the Pushsafer API description +# which is available at https://www.pushsafer.com/en/pushapi: # # Copyright by Markus Bloch # e-mail: Notausstieg0309@googlemail.com @@ -71,23 +71,23 @@ sub Pushsafer_Define($$) my ($hash, $def) = @_; my @args = split("[ \t]+", $def); - + if(!@args == 3) { return "wrong define syntax: define Pushsafer "; } - + my $privatekey = @args[2]; return "invalid private key: ".$privatekey if ($privatekey !~ /^[a-z\d]{20}$/i); - + $hash->{PrivateKey} = $privatekey; $hash->{helper}{URL} = "https://www.pushsafer.com/api"; Log3 $hash, 4, "Pushsafer ($name) - defined with private key: ".$privatekey; $hash->{STATE} = "Initialized"; - + return undef; } @@ -129,11 +129,11 @@ sub Pushsafer_Set($$$@) my ($err, $data) = Pushsafer_createBody($hash, $h); return $err if(defined($err)); - + my $data_scrambled = $data; - + $data_scrambled =~ s/k=[^&]+/k=HIDDEN/g; # remove private key from log output - + Log3 $name, 5, "Pushsafer ($name) - sending data: $data_scrambled"; Pushsafer_Send($hash, $data); @@ -158,7 +158,7 @@ sub Pushsafer_createBody($$) { my ($hash, $args) = @_; my $name = $hash->{NAME}; - + my @urlParts; my @errs; @@ -168,7 +168,7 @@ sub Pushsafer_createBody($$) { my $key; my $val; - + if(exists($Pushsaver_Params{$item})) { if(exists($Pushsaver_Params{$item}{check}) and $args->{$item} !~ $Pushsaver_Params{$item}{check}) @@ -200,23 +200,23 @@ sub Pushsafer_createBody($$) push @errs, "unsupported parameter: $item"; next; } - + if($key =~/^p\d?$/) { if($val =~ /^IPCAM:(\S+)$/) { my $ipcam = $1; - + if(!exists($defs{$ipcam}) or !exists($defs{$ipcam}{TYPE}) or $defs{$ipcam}{TYPE} ne "IPCAM") { Log3 $name, 3, "Pushsafer ($name) - no such IPCAM device: $ipcam. sending message without a picture..."; next; } - + my $path = AttrVal($ipcam, "storage",AttrVal("global", "modpath", ".")."/www/snapshots"); $path .= "/" unless($path =~ m,/$,); $path .= ReadingsVal($ipcam, "last", ""); - + $val = Pushsafer_createDataUrl($hash, $path); next unless(defined($val)); } @@ -231,7 +231,7 @@ sub Pushsafer_createBody($$) next; } } - + push @urlParts, $key."=".urlEncode($val); } @@ -242,7 +242,7 @@ sub Pushsafer_createBody($$) ##################################### # determine the image file format (reused from IPCAM module by Martin Fischer) -sub Pushsafer_guessFileFormat($) +sub Pushsafer_guessFileFormat($) { my ($src) = shift; my $header; @@ -255,7 +255,7 @@ sub Pushsafer_guessFileFormat($) return undef if(!$reading); local($_) = $srcHeader; - + return "image/jpeg" if /^\xFF\xD8/; return "image/png" if /^\x89PNG\x0d\x0a\x1a\x0a/; return "image/gif" if /^GIF8[79]a/; @@ -267,7 +267,7 @@ sub Pushsafer_createDataUrl($$) { my ($hash, $file) = @_; my $name = $hash->{NAME}; - + Log3 $name, 4, "Pushsafer ($name) - open image file: $file"; my ($err, @content) = FileRead({FileName => $file, ForceType => "file"}); @@ -281,21 +281,21 @@ sub Pushsafer_createDataUrl($$) { my $image = join($/, @content); my $mime_type = Pushsafer_guessFileFormat(\$image); - + if(defined($mime_type)) { Log3 $name, 5, "Pushsafer ($name) - found image of type: $mime_type"; - + my $base_64 = encode_base64($image); - + return "data:$mime_type;base64,".$base_64; } else { Log3 $name, 3, "Pushsafer ($name) - unsupported image type for $file - see commandref for supported image formats"; - } + } } - + return undef; } @@ -304,7 +304,7 @@ sub Pushsafer_createDataUrl($$) sub Pushsafer_Send($$) { my ($hash, $body) = @_; - + my $params = { url => $hash->{helper}{URL}, timeout => 10, @@ -363,7 +363,7 @@ sub Pushsafer_Callback($$$) { readingsBulkUpdate($hash, "lastSuccess", $1); } - + if($data =~ /available"?\s*:\s*{(.+)\s*}\s*}\s*$/gcs) { my %devices = grep { defined($_) } map { /^"?(\d+)"?:({.+})$/ ? ($1 => $2) : undef } split(",", $1); @@ -373,28 +373,28 @@ sub Pushsafer_Callback($$$) if(defined($devices{$dev}) and $devices{$dev} =~ /^{\s*"?([^":]+)"?\s*:\s*"?([^":]+)"?\s*}$/) { my ($devname, $available) = ($1, $2); - + $devname =~ s/\s+//g; - + readingsBulkUpdate($hash, "availableMessages-$dev-$devname", $available); } } } - + readingsEndUpdate($hash, 1); } return undef; } - + 1; =pod =item device -=item summary sents text message notifications via pushsafer.com -=item summary_DE verschickt Texnachrichten zur Benachrichtigung via Pushsafer +=item summary sents text message notifications via pushsafer.com +=item summary_DE verschickt Texnachrichten zur Benachrichtigung via Pushsafer =begin html @@ -540,12 +540,12 @@ sub Pushsafer_Callback($$$) vibration - Kurzform: - Typ: Ganzzahl - Die Anzahl, wie oft das Zielgerät vibrieren soll beim Empfang der Nachricht (maximal 3 mal; nur für iOS-/Android-Geräte nutzbar). Falls nicht benutzt, wird die geräteinterne Einstellung verwendet.
url       - Kurzform: - Typ: Text - Eine URL, welche der Nachricht angehangen werden soll. Dies kann eine normale http:// bzw. https:// URL sein, es sind jedoch auch weitere spezielle Schemas möglich. Eine Liste aller möglichen URL-Schemas gibt es unter pushsafer.com .
urlText   - Kurzform: ut - Typ: Text - Der Text, welcher zum Anzeigen der URL benutzt werden soll anstatt der Zieladresse.
- key       - Kurzform: - Typ: Text - Übersteuert den zu nutzenden Schlüssel zur Identifikation aus dem define-Kommando. Es kann hierbei auch ein Email-Alias-Schlüssel benutzt werden.
- ttl       - Kurzform: - Typ: Ganzzahl - Die Lebensdauer der Nachricht in Minuten. Sobald die Lebensdauer erreicht ist, wird die Nachricht selbstständig auf allen Geräten gelöscht. Der mögliche Wertebereich liegt zwischen 1 - 43200 Minuten (entspricht 30 Tagen).
+ key       - Kurzform: - Typ: Text - Übersteuert den zu nutzenden Schlüssel zur Identifikation aus dem define-Kommando. Es kann hierbei auch ein Email-Alias-Schlüssel benutzt werden.
+ ttl       - Kurzform: - Typ: Ganzzahl - Die Lebensdauer der Nachricht in Minuten. Sobald die Lebensdauer erreicht ist, wird die Nachricht selbstständig auf allen Geräten gelöscht. Der mögliche Wertebereich liegt zwischen 1 - 43200 Minuten (entspricht 30 Tagen).
picture   - Kurzform: - Typ: Text - Anhängen eines Bildes zur Nachricht. Dies kann ein Dateipfad zu einer Bilddatei sein (z.B. picture=/home/user/Bild.jpg) oder der Name einer IPCAM-Instanz (im Format: picture=IPCAM:<Name>) um die letzte Aufnahme zu senden (Bsp. picture=IPCAM:IpKamera_Einganstuer). Es werden die Dateiformate JPG, PNG und GIF unterstüzt.
picture2  - Kurzform: p2 - Typ: Text - Gleiche Syntax wie die Option "picture".
picture3  - Kurzform: p3 - Typ: Text - Gleiche Syntax wie die Option "picture".
- +
Beispiele:

diff --git a/fhem/FHEM/71_YAMAHA_BD.pm b/fhem/FHEM/71_YAMAHA_BD.pm index 88c639f72..801de6d75 100755 --- a/fhem/FHEM/71_YAMAHA_BD.pm +++ b/fhem/FHEM/71_YAMAHA_BD.pm @@ -33,7 +33,7 @@ use strict; use warnings; use Time::HiRes qw(gettimeofday); use HttpUtils; - + sub YAMAHA_BD_Get($@); sub YAMAHA_BD_Define($$); sub YAMAHA_BD_GetStatus($;$); @@ -54,7 +54,7 @@ YAMAHA_BD_Initialize($) $hash->{UndefFn} = "YAMAHA_BD_Undefine"; $hash->{AttrList} = "do_not_notify:0,1 disable:0,1 request-timeout:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 model ". $readingFnAttributes; - + $data{RC_layout}{YAMAHA_BluRay} = "YAMAHA_BD_RClayout"; $data{RC_makenotify}{YAMAHA_BD} = "YAMAHA_BD_RCmakenotify"; } @@ -66,7 +66,7 @@ YAMAHA_BD_Define($$) my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $name = $hash->{NAME}; - + if(! @a >= 3) { my $msg = "wrong syntax: define YAMAHA_BD [] []"; @@ -75,9 +75,9 @@ YAMAHA_BD_Define($$) } my $address = $a[2]; - + $hash->{helper}{ADDRESS} = $address; - + # if an update interval was given which is greater than zero, use it. if(defined($a[3]) and $a[3] > 0) { @@ -87,7 +87,7 @@ YAMAHA_BD_Define($$) { $hash->{helper}{OFF_INTERVAL}=30; } - + # if a second update interval is given, use this as ON_INTERVAL, otherwise use OFF_INTERVAL instead. if(defined($a[4]) and $a[4] > 0) { @@ -96,15 +96,15 @@ YAMAHA_BD_Define($$) else { $hash->{helper}{ON_INTERVAL}=$hash->{helper}{OFF_INTERVAL}; - } + } $hash->{helper}{CMD_QUEUE} = (); delete($hash->{helper}{HTTP_CONNECTION}) if(exists($hash->{helper}{HTTP_CONNECTION})); - + # start the status update timer $hash->{helper}{DISABLED} = 0 unless(exists($hash->{helper}{DISABLED})); YAMAHA_BD_ResetTimer($hash, 2); - + return undef; } @@ -115,11 +115,11 @@ YAMAHA_BD_Get($@) my ($hash, @a) = @_; my $what; my $return; - + return "argument is missing" if(int(@a) != 2); - + $what = $a[1]; - + if(exists($hash->{READINGS}{$what})) { YAMAHA_BD_GetStatus($hash, 1); @@ -136,12 +136,12 @@ YAMAHA_BD_Get($@) else { $return = "unknown argument $what, choose one of"; - + foreach my $reading (keys %{$hash->{READINGS}}) { $return .= " $reading:noArg"; } - + return $return; } } @@ -154,9 +154,9 @@ YAMAHA_BD_Set($@) my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; my $result = ""; - - return "No Argument given" if(!defined($a[1])); - + + return "No Argument given" if(!defined($a[1])); + my $what = $a[1]; my $usage = "Unknown argument $what, choose one of on:noArg ". "off:noArg ". @@ -171,7 +171,7 @@ YAMAHA_BD_Set($@) "trickPlay:normal,repeatChapter,repeatTitle,repeatFolder,repeat-AB,randomChapter,randomTitle,randomAll,shuffleChapter,shuffleTitle,shuffleAll,setApoint"; if($what eq "on") - { + { YAMAHA_BD_SendCommand($hash, "On","on",undef); } elsif($what eq "off") @@ -279,11 +279,11 @@ YAMAHA_BD_Set($@) elsif($a[2] eq "setup") { YAMAHA_BD_SendCommand($hash,"SETUP","remoteControl","setup"); - } + } elsif($a[2] eq "home") { YAMAHA_BD_SendCommand($hash,"HOME","remoteControl","home"); - } + } elsif($a[2] eq "clear") { YAMAHA_BD_SendCommand($hash,"CLEAR","remoteControl","clear"); @@ -409,7 +409,7 @@ YAMAHA_BD_Set($@) elsif($a[2] eq "close") { YAMAHA_BD_SendCommand($hash, "Close","tray","close"); - } + } } elsif($what eq "skip") { @@ -420,7 +420,7 @@ YAMAHA_BD_Set($@) elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","skip","reverse"); - } + } } elsif($what eq "fast") { @@ -431,7 +431,7 @@ YAMAHA_BD_Set($@) elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","fast","reverse"); - } + } } elsif($what eq "slow") { @@ -442,7 +442,7 @@ YAMAHA_BD_Set($@) elsif($a[2] eq "reverse") { YAMAHA_BD_SendCommand($hash, "Rev","slow","reverse"); - } + } } elsif($what eq "play") { @@ -464,7 +464,7 @@ YAMAHA_BD_Set($@) { return $usage; } - + return undef; } @@ -495,7 +495,7 @@ YAMAHA_BD_Attr(@) # Start/Stop Timer according to new disabled-Value YAMAHA_BD_ResetTimer($hash); - + return undef; } @@ -504,7 +504,7 @@ sub YAMAHA_BD_Undefine($$) { my($hash, $name) = @_; - + # Stop the internal GetStatus-Loop and exit RemoveInternalTimer($hash); return undef; @@ -527,7 +527,7 @@ YAMAHA_BD_GetStatus($;$) my $name = $hash->{NAME}; my $power; my $return; - + $local = 0 unless(defined($local)); return "" if(!defined($hash->{helper}{ADDRESS}) or !defined($hash->{helper}{ON_INTERVAL}) or !defined($hash->{helper}{OFF_INTERVAL})); @@ -540,16 +540,16 @@ YAMAHA_BD_GetStatus($;$) Log3 $name, 4, "YAMAHA_BD ($name) - Requesting system status"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","systemStatus"); - + Log3 $name, 4, "YAMAHA_BD ($name) - Requesting input info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","inputInfo"); Log3 $name, 4, "YAMAHA_BD ($name) - Requesting power state"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","powerStatus"); - + Log3 $name, 4, "YAMAHA_BD ($name) - Requesting playing info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","playInfo"); - + Log3 $name, 4, "YAMAHA_BD ($name) - Requesting trickPlay info"; YAMAHA_BD_SendCommand($hash, "GetParam", "statusRequest","trickPlayInfo"); @@ -564,21 +564,21 @@ YAMAHA_BD_SendCommand($$$$) { my ($hash, $data,$cmd,$arg) = @_; my $name = $hash->{NAME}; - + my $response; - + Log3 $name, 4, "YAMAHA_BD ($name) - append to queue \"$cmd".(defined($arg) ? " ".$arg : "")."\": $data"; - + # In case any URL changes must be made, this part is separated in this function". - + my $param = { data => "".$data, cmd => $cmd, arg => $arg, }; - - push @{$hash->{helper}{CMD_QUEUE}}, $param; - + + push @{$hash->{helper}{CMD_QUEUE}}, $param; + YAMAHA_BD_HandleCmdQueue($hash); } @@ -590,7 +590,7 @@ YAMAHA_BD_HandleCmdQueue($) my ($hash) = @_; my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; - + if(not($hash->{helper}{RUNNING_REQUEST}) and @{$hash->{helper}{CMD_QUEUE}}) { my $params = { @@ -603,12 +603,12 @@ YAMAHA_BD_HandleCmdQueue($) hash => $hash, callback => \&YAMAHA_BD_ParseResponse }; - + my $request = pop @{$hash->{helper}{CMD_QUEUE}}; map {$hash->{helper}{HTTP_CONNECTION}{$_} = $params->{$_}} keys %{$params}; map {$hash->{helper}{HTTP_CONNECTION}{$_} = $request->{$_}} keys %{$request}; - + $hash->{helper}{RUNNING_REQUEST} = 1; Log3 $name, 4, "YAMAHA_BD ($name) - send command \"$request->{cmd}".(defined($request->{arg}) ? " ".$request->{arg} : "")."\": $request->{data}"; HttpUtils_NonblockingGet($hash->{helper}{HTTP_CONNECTION}); @@ -621,25 +621,25 @@ sub YAMAHA_BD_ParseResponse($$$) { - my ( $param, $err, $data ) = @_; - + my ( $param, $err, $data ) = @_; + my $hash = $param->{hash}; my $name = $hash->{NAME}; - + my $cmd = $param->{cmd}; my $arg = $param->{arg}; - + $data = "" unless(defined($data)); $err = "" unless(defined($err)); - + $hash->{helper}{RUNNING_REQUEST} = 0; - + delete($hash->{helper}{HTTP_CONNECTION}) unless($param->{keepalive}); - + if($err ne "") { Log3 $name, 4, "YAMAHA_BD ($name) - error while executing \"$cmd".(defined($arg) ? " ".$arg : "")."\": $err"; - + if((not exists($hash->{helper}{AVAILABLE})) or (exists($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} eq 1)) { Log3 $name, 3, "YAMAHA_BD ($name) - could not execute command on device $name. Please turn on your device in case of deactivated network standby or check for correct hostaddress: $err"; @@ -650,21 +650,21 @@ YAMAHA_BD_ParseResponse($$$) elsif($data ne "") { Log3 $name, 5, "YAMAHA_BD ($name) - got HTTP response for \"$cmd".(defined($arg) ? " ".$arg : "")."\": $data"; - + if (defined($hash->{helper}{AVAILABLE}) and $hash->{helper}{AVAILABLE} == 0) { Log3 $name, 3, "YAMAHA_BD: device $name reappeared"; - readingsSingleUpdate($hash, "presence", "present", 1); + readingsSingleUpdate($hash, "presence", "present", 1); } - + readingsBeginUpdate($hash); - + if(not $data =~ /RC="0"/) { # if the returncode isn't 0, than the command was not successful Log3 $name, 3, "YAMAHA_BD ($name) - Could not execute \"$cmd".(defined($arg) ? " ".$arg : "")."\""; } - + if($cmd eq "statusRequest" and $arg eq "systemStatus") { if($data =~ /(.+?)<\/Error_Info>/) @@ -678,34 +678,34 @@ YAMAHA_BD_ParseResponse($$$) { $hash->{MODEL} = $1; $hash->{FIRMWARE} = $2; - + $hash->{MODEL} =~ s/\s*YAMAHA\s*//g; $attr{$name}{"model"} = $hash->{MODEL}; } - } + } elsif($cmd eq "statusRequest" and $arg eq "powerStatus") { if($data =~ /(.+?)<\/Power>/) - { + { my $power = $1; - + if($power eq "Standby" or $power eq "Network Standby") - { + { $power = "off"; } - + readingsBulkUpdate($hash, "power", lc($power)); readingsBulkUpdate($hash, "state", lc($power)); } } elsif($cmd eq "on") { - if($data =~ /RC="0"/ and $data =~ /<\/Power>/) + if($data =~ /RC="0"/ and $data =~ /<\/Power>/) { # As the player startup takes about 5 seconds, the status will be already set, if the return code of the command is 0. readingsBulkUpdate($hash, "power", "on"); - readingsBulkUpdate($hash, "state","on"); + readingsBulkUpdate($hash, "state","on"); } else { @@ -716,14 +716,14 @@ YAMAHA_BD_ParseResponse($$$) { if($data =~ /(.+?)<\/Trick_Play>/) { - readingsBulkUpdate($hash, "trickPlay", $1); - } + readingsBulkUpdate($hash, "trickPlay", $1); + } } elsif($cmd eq "statusRequest" and $arg eq "inputInfo") { if($data =~ /(.+?)<\/Status><\/Input_Info/) { - readingsBulkUpdate($hash, "input", $1); + readingsBulkUpdate($hash, "input", $1); } elsif($data =~ /(.+?)<\/Input_Info/) { @@ -736,67 +736,67 @@ YAMAHA_BD_ParseResponse($$$) { readingsBulkUpdate($hash, "playStatus", lc($1)); } - + if($data =~ /.*?(.+?)<\/Chapter>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentChapter", $1); } - + if($data =~ /.*?(.+?)<\/Track>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentTrack", $1); } - + if($data =~ /.*?(.+?)<\/Title>.*?<\/Contents>/) { readingsBulkUpdate($hash, "currentTitle", $1); } - + if($data =~ /<Disc_Info>.*?<Track_Num>(.+?)<\/Track_Num>.*?<\/Disc_Info>/) { readingsBulkUpdate($hash, "totalTracks", $1); } - + if($data =~ /<Contents>.*?<Type>(.+?)<\/Type>.*?<\/Contents>/) { readingsBulkUpdate($hash, "contentType", lc($1)); } - + if($data =~ /<File_Name>(.+?)<\/File_Name>/) { readingsBulkUpdate($hash, "currentMedia", $1); } - + if($data =~ /<Disc_Type>(.+?)<\/Disc_Type>/) { readingsBulkUpdate($hash, "discType", $1); } - + if($data =~ /<Tray>(.+?)<\/Tray>/) { readingsBulkUpdate($hash, "trayStatus", lc($1)); } - + if($data =~ /<Current_PlayTime>(.+?)<\/Current_PlayTime>/) { readingsBulkUpdate($hash, "playTimeCurrent", YAMAHA_BD_formatTimestamp($1)); - } - + } + if($data =~ /<Total_Time>(.+?)<\/Total_Time>/) { readingsBulkUpdate($hash, "playTimeTotal", YAMAHA_BD_formatTimestamp($1)); } } - + readingsEndUpdate($hash, 1); - + YAMAHA_BD_GetStatus($hash, 1) if($cmd ne "statusRequest" and $cmd ne "on"); YAMAHA_BD_ResetTimer($hash, 10) if($cmd eq "on"); } - + $hash->{helper}{AVAILABLE} = ($err ne "" ? 0 : 1); - YAMAHA_BD_HandleCmdQueue($hash); + YAMAHA_BD_HandleCmdQueue($hash); } ############################# @@ -805,9 +805,9 @@ sub YAMAHA_BD_ResetTimer($;$) { my ($hash, $interval) = @_; - + RemoveInternalTimer($hash); - + if($hash->{helper}{DISABLED} == 0) { if(defined($interval)) @@ -827,7 +827,7 @@ YAMAHA_BD_ResetTimer($;$) ############################# # define the layout for module 95_remotecontrol.pm -sub YAMAHA_BD_RClayout() +sub YAMAHA_BD_RClayout() { my @row; @@ -857,11 +857,11 @@ sub YAMAHA_BD_RClayout() ##################################### # Callback from 95_remotecontrol for command makenotify. -sub YAMAHA_BD_RCmakenotify($$) +sub YAMAHA_BD_RCmakenotify($$) { my ($name, $dev) = @_; my $new_name="notify_$name"; - + fhem("define $new_name notify $name set $dev ".'$EVENT',1); Log3 undef, 2, "[remotecontrol:YAMAHA_BD] Notify created: $new_name"; return "Notify created by YAMAHA_BD: $new_name"; @@ -869,14 +869,14 @@ sub YAMAHA_BD_RCmakenotify($$) ############################# # formats a 3 byte Hex Value into human readable time duration -sub YAMAHA_BD_formatTimestamp($) +sub YAMAHA_BD_formatTimestamp($) { my ($hex) = @_; - + my ($hour) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 0, 2)))); my ($min) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 2, 2)))); my ($sec) = sprintf("%02d", unpack("s", pack "s", hex(substr($hex, 4, 2)))); - + return "$hour:$min:$sec"; } @@ -911,22 +911,22 @@ sub YAMAHA_BD_formatTimestamp($) seconds), which periodically reads the status of the player (power state, current disc, tray status,...) and triggers notify/filelog commands. <br><br> - Different status update intervals depending on the power state can be given also. - If two intervals are given to the define statement, the first interval statement represents the status update - interval in seconds in case the device is off, absent or any other non-normal state. The second + Different status update intervals depending on the power state can be given also. + If two intervals are given to the define statement, the first interval statement represents the status update + interval in seconds in case the device is off, absent or any other non-normal state. The second interval statement is used when the device is on. - + Example:<br><br> <ul><code> define BD_Player YAMAHA_BD 192.168.0.10 <br><br> # With custom status interval of 60 seconds<br> - define BD_Player YAMAHA_BD 192.168.0.10 60 + define BD_Player YAMAHA_BD 192.168.0.10 60 <br><br> # With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br> define BD_Player YAMAHA_BD 192.168.0.10 60 10 </code></ul> - + </ul> <br><br> <a name="YAMAHA_BDset"></a> @@ -968,7 +968,7 @@ sub YAMAHA_BD_formatTimestamp($) ...<br> remoteControl 9<br> </code></ul><br><br> - + <u>Cursor Selection:</u><br><br> <ul><code> remoteControl up<br> @@ -989,7 +989,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl home<br> remoteControl clear<br> </code></ul><br><br> - + <u>Color Buttons:</u><br><br> <ul><code> remoteControl red<br> @@ -997,7 +997,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl yellow<br> remoteControl blue<br> </code></ul><br><br> - + <u>Play Control Buttons:</u><br><br> <ul><code> remoteControl program<br> @@ -1012,7 +1012,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl secondVideo<br> </code></ul><br><br> The button names are the same as on your remote control.<br><br> - + </ul> <a name="YAMAHA_BDget"></a> @@ -1061,7 +1061,7 @@ sub YAMAHA_BD_formatTimestamp($) <br> <b>Implementator's note</b><br> <ul> - <li>Some older models (e.g. BD-S671) cannot be controlled over networked by delivery. A <u><b>firmware update is neccessary</b></u> to control these models via FHEM. In general it is always recommended to use the latest firmware.</li> + <li>Some older models (e.g. BD-S671) cannot be controlled over networked by delivery. A <u><b>firmware update is neccessary</b></u> to control these models via FHEM. In general it is always recommended to use the latest firmware.</li> <li>The module is only usable if you activate "Network Control" on your player. Otherwise it is not possible to communicate with the player.</li> </ul> <br> @@ -1088,13 +1088,13 @@ sub YAMAHA_BD_formatTimestamp($) Es bietet die Möglichkeit den Player an-/auszuschalten, die Schublade zu öffnen und schließen, die Wiedergabe beeinflussen, sämtliche Fernbedieungs-Befehle zu senden, sowie den aktuellen Status abzufragen. <br><br> - Bei der Definition eines YAMAHA_BD-Moduls wird eine interne Routine in Gang gesetzt, welche regelmäßig + Bei der Definition eines YAMAHA_BD-Moduls wird eine interne Routine in Gang gesetzt, welche regelmäßig (einstellbar durch den optionalen Parameter <code><Status_Interval></code>; falls nicht gesetzt ist der Standardwert 30 Sekunden) den Status des Players abfragt und entsprechende Notify-/FileLog-Definitionen triggert. <br><br> Sofern 2 Interval-Argumente übergeben werden, wird der erste Parameter <code><Off_Interval></code> genutzt - sofern der Player ausgeschaltet oder nicht erreichbar ist. Der zweiter Parameter <code><On_Interval></code> - wird verwendet, sofern der Player eingeschaltet ist. + sofern der Player ausgeschaltet oder nicht erreichbar ist. Der zweiter Parameter <code><On_Interval></code> + wird verwendet, sofern der Player eingeschaltet ist. <br><br> Beispiel:<br><br> <ul><code> @@ -1147,7 +1147,7 @@ sub YAMAHA_BD_formatTimestamp($) ...<br> remoteControl 9<br> </code></ul><br><br> - + <u>Cursor Steuerung:</u><br><br> <ul><code> remoteControl up<br> @@ -1168,7 +1168,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl home<br> remoteControl clear<br> </code></ul><br><br> - + <u>Farbtasten:</u><br><br> <ul><code> remoteControl red<br> @@ -1176,7 +1176,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl yellow<br> remoteControl blue<br> </code></ul><br><br> - + <u>Wiedergabetasten:</u><br><br> <ul><code> remoteControl program<br> @@ -1190,7 +1190,7 @@ sub YAMAHA_BD_formatTimestamp($) remoteControl secondAudio<br> remoteControl secondVideo<br> </code></ul><br><br> - + Die Befehlsnamen entsprechen den Tasten auf der Fernbedienung.<br><br> </ul> @@ -1205,7 +1205,7 @@ sub YAMAHA_BD_formatTimestamp($) <a name="YAMAHA_BDattr"></a> <b>Attribute</b> <ul> - + <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a name="disable">disable</a></li> @@ -1241,7 +1241,7 @@ sub YAMAHA_BD_formatTimestamp($) <br> <b>Hinweise des Autors</b> <ul> - <li>Einige ältere Player-Modelle (z.B. BD-S671) können im Auslieferungszustand nicht via Netzwerk gesteuert werden. Um eine Steuerung via FHEM zu ermöglichen ist ein <u><b>Firmware-Update notwending</b></u>!</li> + <li>Einige ältere Player-Modelle (z.B. BD-S671) können im Auslieferungszustand nicht via Netzwerk gesteuert werden. Um eine Steuerung via FHEM zu ermöglichen ist ein <u><b>Firmware-Update notwending</b></u>!</li> <li>Dieses Modul ist nur nutzbar, wenn die Option "Netzwerksteuerung" am Player aktiviert ist. Ansonsten ist die Steuerung nicht möglich.</li> </ul> <br> diff --git a/fhem/FHEM/72_FB_CALLLIST.pm b/fhem/FHEM/72_FB_CALLLIST.pm index afe0f7549..412254848 100755 --- a/fhem/FHEM/72_FB_CALLLIST.pm +++ b/fhem/FHEM/72_FB_CALLLIST.pm @@ -33,10 +33,10 @@ use MIME::Base64; use Data::Dumper; use HttpUtils; -sub +sub FB_CALLLIST_Initialize($) { - my ($hash) = @_; + my ($hash) = @_; $hash->{SetFn} = "FB_CALLLIST_Set"; $hash->{DefFn} = "FB_CALLLIST_Define"; @@ -56,7 +56,7 @@ FB_CALLLIST_Initialize($) "list-type:all,incoming,outgoing,missed-calls,completed,active " . "time-format-string ". "list-order:ascending,descending ". - "answMachine-is-missed-call:0,1 ". + "answMachine-is-missed-call:0,1 ". "language:de,en ". "disable:0,1 ". "number-cmd ". @@ -70,7 +70,7 @@ FB_CALLLIST_Initialize($) $hash->{FW_detailFn} = "FB_CALLLIST_makeTable"; $hash->{FW_summaryFn} = "FB_CALLLIST_makeTable"; $hash->{FW_atPageEnd} = 1; -} +} ##################################### # Define function @@ -81,26 +81,26 @@ sub FB_CALLLIST_Define($$) my $retval = undef; my $name = $a[0]; my $callmonitor = $a[2]; - + return "wrong define syntax: you must specify a device name for using FB_CALLLIST" if(!defined($callmonitor)); return "wrong define syntax: define <name> FB_CALLLIST <name>" if(@a != 3); - + if($init_done) { return "define error: the selected device $callmonitor does not exist." unless(defined($defs{$callmonitor})); Log3 $name, 3, "FB_CALLLIST ($name) - WARNING - selected device $callmonitor ist not of type FB_CALLMONITOR" unless($defs{$callmonitor}->{TYPE} eq "FB_CALLMONITOR"); } - + $hash->{FB} = $callmonitor; $hash->{NOTIFYDEV} = "global,".$callmonitor; $hash->{STATE} = 'Initialized'; $hash->{helper}{DEFAULT_COLUMN_ORDER} = "row,state,timestamp,name,number,internal,external,connection,duration"; - + FB_CALLLIST_loadList($hash); - + return undef; -} +} ##################################### # AttrFn for importing filter expressions and cleanup list when user set an attribute @@ -108,101 +108,101 @@ sub FB_CALLLIST_Attr($@) { my ($cmd, $name, $attrib, $value) = @_; my $hash = $defs{$name}; - + if($cmd eq "set") - { + { if($attrib eq "internal-number-filter") { - if( $value =~ m/^{.*}$/ ) + if( $value =~ m/^{.*}$/ ) { my $table = eval $value; - + if($table and (ref($table) eq 'HASH')) { $hash->{helper}{INTERNAL_FILTER} = $table; Log3 $name, 4, "FB_CALLLIST ($name) - filter stored as hash: $value"; - } + } else { return "(line-filter) is not a valid hash: $value"; - } + } } - else + else { delete($hash->{helper}{INTERNAL_FILTER}) if(exists($hash->{helper}{INTERNAL_FILTER})); - + foreach my $item (split("[ \t,][ \t,]*",$value)) { - $hash->{helper}{INTERNAL_FILTER}{$item} = $item; + $hash->{helper}{INTERNAL_FILTER}{$item} = $item; } - + Log3 $name, 4, "FB_CALLLIST ($name) - filter stored as list $value"; - } + } } elsif($attrib eq "connection-mapping") { - if($value and $value =~ m/^{.*}$/ ) + if($value and $value =~ m/^{.*}$/ ) { my $table = eval $value; - + if($table and ref($table) eq 'HASH') { $hash->{helper}{CONNECTION_MAP} = $table; Log3 $name, 4, "FB_CALLLIST ($name) - connection map stored as hash: $value"; - } + } else { return "invalid connection mapping table: $value"; - } + } } - else + else { return "invalid connection mapping table: $value"; - } - } + } + } elsif($attrib eq "icon-mapping") { - if($value and $value =~ m/^{.*}$/ ) + if($value and $value =~ m/^{.*}$/ ) { $value =~ s/"/'/g; # workaround for array variable interpretation - + my $table = eval $value; - + if($table and ref($table) eq 'HASH') { $hash->{helper}{ICON_MAP} = $table; Log3 $name, 4, "FB_CALLLIST ($name) - icon map stored as hash: $value"; - } + } else { return "invalid icon mapping table: $value"; - } + } } - else + else { return "invalid icon mapping table: $value"; - } - } + } + } elsif($attrib eq "external-mapping") { - if($value and $value =~ m/^{.*}$/ ) + if($value and $value =~ m/^{.*}$/ ) { my $table = eval $value; - + if($table and ref($table) eq 'HASH') { $hash->{helper}{EXTERNAL_MAP} = $table; Log3 $name, 4, "FB_CALLLIST ($name) - external map stored as hash: $value"; - } + } else { return "invalid external mapping table: $value"; - } + } } - else + else { return "invalid external mapping table: $value"; - } + } } elsif($attrib eq "expire-calls-after") { @@ -217,7 +217,7 @@ sub FB_CALLLIST_Attr($@) { return "not a valid positive integer value"; } - } + } } elsif($cmd eq "del") { @@ -247,29 +247,29 @@ sub FB_CALLLIST_Set($@) my ($hash, $name, $cmd, $value) = @_; my $usage = "Unknown argument $cmd, choose one of clear:noArg"; - + if($cmd eq "clear") { delete($hash->{helper}{DATA}) if(exists($hash->{helper}{DATA})); - + if(AttrVal($name, "create-readings", "0") eq "1") { readingsBeginUpdate($hash); readingsBulkUpdate($hash, "numberOfCalls", 0, 1); - + for my $reading (keys %{$hash->{READINGS}}) { readingsBulkUpdate($hash, $reading, ""); } - + readingsEndUpdate($hash, 1); - + CommandDeleteReading($hash->{CL}, $name.' \d+-.*'); } - + # Inform all FHEMWEB clients FB_CALLLIST_updateFhemWebClients($hash); - + # Delete stored list FB_CALLLIST_saveList($hash); } @@ -284,7 +284,7 @@ sub FB_CALLLIST_Set($@) sub FB_CALLLIST_Delete($) { my ($hash, $name) = @_; - + my $err = setKeyValue("FB_CALLLIST-$name", undef); Log3 $name, 3, "FB_CALLLIST ($name) - error while deleting the current call list: $err" if(defined($err)); @@ -297,12 +297,12 @@ sub FB_CALLLIST_Rename($$) my ($new,$old) = @_; my (undef, $data) = getKeyValue("FB_CALLLIST-".$old); - + return undef unless(defined($data)); - + setKeyValue("FB_CALLLIST-".$new, $data); setKeyValue("FB_CALLLIST-".$old, undef); - + return undef; } @@ -311,7 +311,7 @@ sub FB_CALLLIST_Rename($$) sub FB_CALLLIST_Undef($$) { my ($hash, $name) = @_; - + RemoveInternalTimer($name, "FB_CALLLIST_deleteExpiredCalls"); } @@ -320,16 +320,16 @@ sub FB_CALLLIST_Undef($$) sub FB_CALLLIST_Notify($$) { my ($hash,$dev) = @_; - + return undef if(!defined($hash) or !defined($dev)); my $name = $hash->{NAME}; my $events = deviceEvents($dev,0); - + if($dev->{NAME} eq "global") { my $callmonitor = $hash->{FB}; - + if(grep(m/^(?:ATTR $name .*|DELETEATTR $name .*|INITIALIZED|REREADCFG)$/, @{$events})) { Log3 $name, 3, "FB_CALLLIST ($name) - WARNING - the selected device $callmonitor does not exist" unless(defined($defs{$callmonitor})); @@ -340,16 +340,16 @@ sub FB_CALLLIST_Notify($$) # Inform all FHEMWEB clients FB_CALLLIST_updateFhemWebClients($hash) if(grep(m/^(?:ATTR|DELETEATTR)/, @{$events})); - + # save current list state to file/configDB FB_CALLLIST_saveList($hash); } - + # detect renaming of attached FB_CALLMONITOR if(defined($callmonitor) and grep(/^RENAMED $callmonitor \S+$/, @{$events})) - { + { my ($new) = map((/^RENAMED $callmonitor (\S+)$/ ? $1 : () ), @{$events}); - + if(defined($new)) { Log3 $name, 3, "FB_CALLLIST ($name) - configured callmonitor definition $callmonitor was renamed to $new"; @@ -358,21 +358,21 @@ sub FB_CALLLIST_Notify($$) $hash->{FB} = $new; } } - + return undef; } my $fb = $dev->{NAME}; - - return undef if(IsDisabled($name)); + + return undef if(IsDisabled($name)); return undef if($fb ne $hash->{FB}); return undef if(!grep(m/^event:/,@{$events})); - + my $event = ReadingsVal($fb, "event", undef); - my $call_id = ReadingsVal($fb, "call_id", undef); - + my $call_id = ReadingsVal($fb, "call_id", undef); + Log3 $name, 4, "FB_CALLLIST ($name) - start processing event $event for Call-ID $call_id"; - + if(exists($hash->{helper}{LAST_EVENT}) and exists($hash->{helper}{LAST_CALL_ID}) and $event eq $hash->{helper}{LAST_EVENT} and $call_id eq $hash->{helper}{LAST_CALL_ID}) { Log3 $name, 4, "FB_CALLLIST ($name) - already processed event $event for Call-ID $call_id, skipping..."; @@ -383,11 +383,11 @@ sub FB_CALLLIST_Notify($$) $hash->{helper}{LAST_EVENT} = $event; $hash->{helper}{LAST_CALL_ID} = $call_id; } - + if(exists($hash->{helper}{INTERNAL_FILTER})) { Log3 $name, 5, "FB_CALLLIST ($name) - internal-number-filter is defined, checking if internal number is allowed"; - + my $line_number = ReadingsVal($fb, "internal_number", undef); if(defined($line_number) and not exists($hash->{helper}{INTERNAL_FILTER}{$line_number})) @@ -395,12 +395,12 @@ sub FB_CALLLIST_Notify($$) Log3 $name, 5, "FB_CALLLIST ($name) - internal number $line_number does not match the current internal-number-filter. skipping call."; return undef; } - + Log3 $name, 5, "FB_CALLLIST ($name) - call passed the internal-number-filter. proceeding..."; } - + my $data; - + if($event =~ /^call|ring$/) { # end running calls with same call-id (Forum: #62468) @@ -412,7 +412,7 @@ sub FB_CALLLIST_Notify($$) $old_data->{finished} = gettimeofday(); $old_data->{call_duration} = 0; } - + my $timestamp = gettimeofday(); $hash->{helper}{DATA}{$timestamp} = undef; @@ -422,63 +422,63 @@ sub FB_CALLLIST_Notify($$) $data->{external_number} = ReadingsVal($fb, "external_number", undef); $data->{external_name} = ReadingsVal($fb, "external_name", undef); $data->{external_connection} = ReadingsVal($fb, "external_connection", undef); - $data->{internal_number} = ReadingsVal($fb, "internal_number", undef); + $data->{internal_number} = ReadingsVal($fb, "internal_number", undef); $data->{direction} = ReadingsVal($fb, "direction", undef); $data->{running_call} = 1; $data->{call_id} = $call_id; - + if($data->{direction} eq "outgoing") { $data->{internal_connection} = ReadingsVal($fb, "internal_connection", undef); } - + Log3 $name, 5, "FB_CALLLIST ($name) - created new data hashcreated new data hash: $data"; } - else + else { $data = FB_CALLLIST_getDataReference($hash, $call_id); Log3 $name, 5, "FB_CALLLIST ($name) - found old data hash: $data" if($data); } - + if(!$data) { Log3 $name, 4, "FB_CALLLIST ($name) - no data for this call in list. seams to be filtered out. skipping further processing..."; return undef; } - + if($event eq "connect") { $data->{internal_connection} = ReadingsVal($fb, "internal_connection", undef) if($data->{direction} eq "incoming"); - + Log3 $name, 5, "FB_CALLLIST ($name) - processed connect event for call id $call_id"; } - + if($event eq "disconnect" ) { $data->{call_duration} = ReadingsVal($fb, "call_duration", undef); $data->{finished} = gettimeofday(); - + if($data->{last_event} =~ /^call|ring$/) { $data->{missed_call} = 1; } - + delete($data->{running_call}) if(defined($data->{running_call})); - + Log3 $name, 5, "FB_CALLLIST ($name) - processed disconnect event for call id $call_id"; } $data->{last_event} = $event; - - # clean up the list + + # clean up the list FB_CALLLIST_cleanupList($hash); - + # Inform all FHEMWEB clients FB_CALLLIST_updateFhemWebClients($hash); - + # save current list state to file/configDB FB_CALLLIST_saveList($hash); -} +} ############################################################################################################ # @@ -492,11 +492,11 @@ sub FB_CALLLIST_Notify($$) sub FB_CALLLIST_getDataReference($$) { my ($hash, $call_id) = @_; - + my @result = grep {$hash->{helper}{DATA}{$_}{call_id} eq $call_id and defined($hash->{helper}{DATA}{$_}{running_call}) and $hash->{helper}{DATA}{$_}{running_call} == 1} keys %{$hash->{helper}{DATA}}; return \%{$hash->{helper}{DATA}{$result[0]}} if(defined($result[0])); - return undef; + return undef; } ##################################### @@ -504,30 +504,30 @@ sub FB_CALLLIST_getDataReference($$) sub FB_CALLLIST_cleanupList($) { my ($hash) = @_; - + my $name = $hash->{NAME}; my $limit = int(AttrVal($name, "number-of-calls", 5)); my $listtype = AttrVal($name, "list-type", "all"); my $count = 0; my $index; - + my @list; - + if(exists($hash->{helper}{DATA}) and (scalar keys %{$hash->{helper}{DATA}}) > 0) { Log3 $name, 4, "FB_CALLLIST ($name) - cleaning up call list"; - + # delete calls which not matched the configured list-type and number-of-calls if($listtype ne "all") { @list = grep { ($hash->{helper}{DATA}{$_}{direction} ne "incoming") or ($hash->{helper}{DATA}{$_}{direction} eq "incoming" and ++$count > $limit) } sort {$b <=> $a} keys %{$hash->{helper}{DATA}} if($listtype eq "incoming"); - + @list = grep { ($hash->{helper}{DATA}{$_}{direction} ne "outgoing") or ($hash->{helper}{DATA}{$_}{direction} eq "outgoing" and ++$count > $limit) } sort {$b <=> $a} keys %{$hash->{helper}{DATA}} if($listtype eq "outgoing"); - + @list = grep { ($hash->{helper}{DATA}{$_}{direction} eq "outgoing") or (!$hash->{helper}{DATA}{$_}{running_call} and not (((!$hash->{helper}{DATA}{$_}{missed_call} and AttrVal($name, "answMachine-is-missed-call", "0") eq "1" and $hash->{helper}{DATA}{$_}{internal_connection} =~ /^Answering_Machine/) or $hash->{helper}{DATA}{$_}{missed_call}) and not ++$count > $limit)) } sort {$b <=> $a} keys %{$hash->{helper}{DATA}} if($listtype eq "missed-calls"); - + @list = grep { (not $hash->{helper}{DATA}{$_}{running_call}) and ++$count > $limit } sort {$b <=> $a} keys %{$hash->{helper}{DATA}} if($listtype eq "completed"); - + @list = grep { (not $hash->{helper}{DATA}{$_}{running_call}) or ($hash->{helper}{DATA}{$_}{running_call} and ++$count > $limit)} sort {$b <=> $a} keys %{$hash->{helper}{DATA}} if($listtype eq "active"); } else @@ -540,7 +540,7 @@ sub FB_CALLLIST_cleanupList($) { push @list, grep { not FB_CALLLIST_checkForInternalNumberFilter($hash, $hash->{helper}{DATA}{$_}{internal_number}) } keys %{$hash->{helper}{DATA}}; } - + # delete the collected list of unwanted calls foreach $index (@list) { @@ -561,27 +561,27 @@ sub FB_CALLLIST_cleanupList($) sub FB_CALLLIST_deleteExpiredCalls($;$) { my ($hash, $inform) = @_; - + if(ref($hash) ne "HASH") { - ($hash, $inform) = ($defs{$hash}, 1); + ($hash, $inform) = ($defs{$hash}, 1); } - + my $name = $hash->{NAME}; my $expireCallSeconds = AttrVal($name, "expire-calls-after", 0); RemoveInternalTimer($name, "FB_CALLLIST_deleteExpiredCalls"); - + if($expireCallSeconds !~ /^\d+(?:\.\d+)?$/) { if($expireCallSeconds =~ /^\s*(\d+(?:\.\d+)?)\s+minutes?\s*$/i) { $expireCallSeconds = $1 * 60; - } + } elsif($expireCallSeconds =~ /^\s*(\d+(?:\.\d+)?)\s+hours?\s*$/i) { $expireCallSeconds = $1 * 3600; - } + } elsif($expireCallSeconds =~ /^\s*(\d+(?:\.\d+)?)\s+days?\s*$/i) { $expireCallSeconds = $1 * 86400; @@ -608,7 +608,7 @@ sub FB_CALLLIST_deleteExpiredCalls($;$) if($expireCallSeconds =~ /^\d+(?:\.\d+)?$/ and $expireCallSeconds > 0) { my @list = grep { !($hash->{helper}{DATA}{$_}{running_call}) and ((exists($hash->{helper}{DATA}{$_}{finished}) ? $hash->{helper}{DATA}{$_}{finished} : $_) < (gettimeofday - $expireCallSeconds)) } keys %{$hash->{helper}{DATA}}; - + if(@list) { # delete the collected list of expired calls @@ -616,30 +616,30 @@ sub FB_CALLLIST_deleteExpiredCalls($;$) { Log3 $name, 5, "FB_CALLLIST ($name) - deleting expired call $index"; delete($hash->{helper}{DATA}{$index}) if(exists($hash->{helper}{DATA}{$index})); - } - } + } + } my ($oldest) = sort {$b <=> $a} map {(exists($hash->{helper}{DATA}{$_}{finished}) ? $hash->{helper}{DATA}{$_}{finished} : $_) } grep { !$hash->{helper}{DATA}{$_}{running_call} } keys %{$hash->{helper}{DATA}}; - + if(defined($oldest)) { my $diff = $expireCallSeconds - (gettimeofday() - $oldest); - + if($diff > 0) { - Log3 $name, 4, "FB_CALLLIST ($name) - oldest call $oldest expires in $diff seconds, scheduling timer..."; + Log3 $name, 4, "FB_CALLLIST ($name) - oldest call $oldest expires in $diff seconds, scheduling timer..."; InternalTimer(gettimeofday()+$diff+1, "FB_CALLLIST_deleteExpiredCalls", $name); } } - + if($inform) { # Inform all FHEMWEB clients FB_CALLLIST_updateFhemWebClients($hash); - + # save current list state to file/configDB FB_CALLLIST_saveList($hash); - } + } } } @@ -648,31 +648,31 @@ sub FB_CALLLIST_deleteExpiredCalls($;$) sub FB_CALLLIST_returnIcon($$$) { my ($hash, $icon, $text) = @_; - + my $icon_name; - + my %standard = ( - + "incoming.connected" => 'phone_ring_in@blue', "outgoing.connected" => 'phone_ring_out@green', - + "incoming.ring" => 'phone_ring@blue', "outgoing.ring" => 'phone_ring@green', - + "incoming.missed" => 'phone_missed_in@red', "outgoing.missed" => 'phone_missed_out@green', - + "incoming.done" => 'phone_call_end_in@blue', "outgoing.done" => 'phone_call_end_out@green', - + "incoming.tam" => 'phone_answering@blue' ); - + $icon_name = $standard{$icon} if(exists($standard{$icon})); $icon_name = $hash->{helper}{ICON_MAP}{$icon} if(exists($hash->{helper}{ICON_MAP}{$icon})); my $result = FW_makeImage($icon_name); - + return $result if($result ne $icon_name); return $text; } @@ -682,14 +682,14 @@ sub FB_CALLLIST_returnIcon($$$) sub FB_CALLLIST_returnCallState($$;$) { my ($hash, $index, $icons) = @_; - + return undef unless(exists($hash->{helper}{DATA}{$index})); - + my $data = $hash->{helper}{DATA}{$index}; my $state; - + $icons = AttrVal($hash->{NAME}, "show-icons", 1) unless(defined($icons)); - + if($data->{running_call}) { if($data->{direction} eq "incoming" and $data->{last_event} eq "connect" ) @@ -718,7 +718,7 @@ sub FB_CALLLIST_returnCallState($$;$) if($data->{direction} eq "incoming" and ((not exists($data->{internal_connection}) ) or (exists($data->{internal_connection}) and not $data->{internal_connection} =~ /Answering_Machine/))) { $state = "=>".($data->{missed_call} ? " X" : ""); - $state = FB_CALLLIST_returnIcon($hash, "incoming.done", $state) if($icons and not $data->{missed_call}); + $state = FB_CALLLIST_returnIcon($hash, "incoming.done", $state) if($icons and not $data->{missed_call}); $state = FB_CALLLIST_returnIcon($hash, "incoming.missed", $state) if($icons and $data->{missed_call}); } elsif($data->{direction} eq "incoming" and exists($data->{internal_connection}) and $data->{internal_connection} =~ /^Answering_Machine/) @@ -733,7 +733,7 @@ sub FB_CALLLIST_returnCallState($$;$) $state = FB_CALLLIST_returnIcon($hash, "outgoing.missed", $state) if($icons and $data->{missed_call}); } } - + return $state; } @@ -744,7 +744,7 @@ sub FB_CALLLIST_makeTable($$$$) my ($FW_wname, $devname, $room, $extPage) = @_; my $hash = $defs{$devname}; - + return FB_CALLLIST_list2html($hash) } @@ -753,16 +753,16 @@ sub FB_CALLLIST_makeTable($$$$) sub FB_CALLLIST_getListItems($) { my ($hash) = @_; - + my $name = $hash->{NAME}; my @result; - + if(exists($hash->{helper}{DATA}) and (scalar keys %{$hash->{helper}{DATA}}) > 0) { my $count = 0; - + my @list = sort { (AttrVal($name, "list-order","descending") eq "descending") ? $b <=> $a : $a <=> $b } keys %{$hash->{helper}{DATA}}; - + if(AttrVal($hash->{NAME}, "list-type", "all") eq "missed-calls") { @list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list; @@ -772,15 +772,15 @@ sub FB_CALLLIST_getListItems($) { @list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list; } - + foreach my $index (@list) { $count++; my $data = \%{$hash->{helper}{DATA}{$index}}; - + my $number = $data->{external_number}; - - my $line = { + + my $line = { index => $index, line => $count, # internal line identifier for JavaScript, must be present row => $count, # column "row" to display or not @@ -793,12 +793,12 @@ sub FB_CALLLIST_getListItems($) connection => ($data->{internal_connection} ? ((exists($hash->{helper}{CONNECTION_MAP}) and exists($hash->{helper}{CONNECTION_MAP}{$data->{internal_connection}})) ? $hash->{helper}{CONNECTION_MAP}{$data->{internal_connection}} : $data->{internal_connection} ) : "-"), duration => FB_CALLLIST_formatDuration($hash, $index) }; - + push @result, $line; } } - - return @result; + + return @result; } ##################################### @@ -806,17 +806,17 @@ sub FB_CALLLIST_getListItems($) sub FB_CALLLIST_list2html($) { my ($hash) = @_; - + return undef if( !$hash ); - + my $name = $hash->{NAME}; my $alias = AttrVal($hash->{NAME}, "alias", $hash->{NAME}); my $create_readings = AttrVal($hash->{NAME}, "create-readings","0"); my $td_style = 'style="padding-left:6px;padding-right:6px;"'; my $line; - + my $old_locale = setlocale(LC_ALL); - + if(AttrVal($name, "language", "en") eq "de") { setlocale(LC_ALL, "de_DE.utf8"); @@ -825,63 +825,63 @@ sub FB_CALLLIST_list2html($) { setlocale(LC_ALL, "en_US.utf8"); } - + my $ret .= "<table>"; - + if(AttrVal($name, "no-heading", "0") eq "0" and defined($FW_ME) and defined($FW_subdir)) { $ret .=" <tr><td>"; $ret .= '<div class="devType"><a href="'.$FW_ME.$FW_subdir.'?detail='.$name.'">'.$alias.'</a>'.(IsDisabled($name) ? " (disabled)" : "").'</div>' unless($FW_webArgs{"detail"}); $ret .= "</td></tr>"; } - + $ret .= "<tr><td>"; $ret .= '<div class="fhemWidget" informId="'.$name.'" cmd="" arg="fbcalllist" dev="'.$name.'">'; # div tag to support inform updates $ret .= '<table class="block fbcalllist">'; - + $ret .= FB_CALLLIST_returnOrderedHTMLOutput($hash, FB_CALLLIST_returnTableHeader($hash), 'class="fbcalllist header"','') if(AttrVal($name, "no-table-header", "0") eq "0"); - + my @item_list = FB_CALLLIST_getListItems($hash); - + if(@item_list > 0) - { + { foreach $line (@item_list) { if(defined(my $cmd = AttrVal($name, "number-cmd", undef))) { $cmd =~ s/\$NUMBER/$line->{number}/g; - + $line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>"; } - + $ret .= FB_CALLLIST_returnOrderedHTMLOutput($hash, $line, 'number="'.$line->{line}.'" class="fbcalllist '.($line->{line} % 2 == 1 ? "odd" : "even").'"', 'class="fbcalllist" '.$td_style); - } + } } else { my $string; - + if(AttrVal($name, "language", "en") eq "de") { $string = "leer"; - } + } else { $string = "empty"; } - + my @columns = split(",",AttrVal($name, "visible-columns", $hash->{helper}{DEFAULT_COLUMN_ORDER})); my $additional_columns = scalar(@columns); - + $ret .= '<tr align="center" name="empty"><td style="padding:10px;" colspan="'.$additional_columns.'"><i>'.$string.'</i></td></tr>'; } - + $ret .= "</table></div>"; - $ret .= "</td></tr></table>"; - + $ret .= "</td></tr></table>"; + setlocale(LC_ALL, $old_locale); - - + + return $ret; } @@ -891,15 +891,15 @@ sub FB_CALLLIST_list2html($) sub FB_CALLLIST_list2json($) { my ($hash) = @_; - + return undef if( !$hash ); - + my $name = $hash->{NAME}; my $create_readings = AttrVal($hash->{NAME}, "create-readings","0"); my @json_output = (); - + my $old_locale = setlocale(LC_ALL); - + if(AttrVal($name, "language", "en") eq "de") { setlocale(LC_ALL, "de_DE.utf8"); @@ -908,48 +908,48 @@ sub FB_CALLLIST_list2json($) { setlocale(LC_ALL, "en_US.utf8"); } - + my @item_list = FB_CALLLIST_getListItems($hash); - + readingsBeginUpdate($hash) if($create_readings eq "1"); - + if(@item_list > 0) - { + { foreach my $line (@item_list) { FB_CALLLIST_updateReadings($hash, $line) if($create_readings eq "1"); - + if(defined(my $cmd = AttrVal($name, "number-cmd", undef))) { $cmd =~ s/\$NUMBER/$line->{number}/g; - + $line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>"; } - + push @json_output, FB_CALLLIST_returnOrderedJSONOutput($hash, $line); - } + } } - + setlocale(LC_ALL, $old_locale); - + # delete old readings if($create_readings eq "1") { readingsBulkUpdate($hash, "numberOfCalls", scalar @item_list, 1); - + my @delete_readings; - + for my $reading (grep { /^(\d+)-/ and ($1 > @item_list) } keys %{$hash->{READINGS}}) { readingsBulkUpdate($hash, $reading, ""); push @delete_readings, $reading; } - + readingsEndUpdate($hash, 1) if($create_readings eq "1"); - + map { delete($hash->{READINGS}{$_}) } @delete_readings; } - + return @json_output; } @@ -959,40 +959,40 @@ sub FB_CALLLIST_list2json($) sub FB_CALLLIST_formatDuration($$) { my ($hash, $index) = @_; - + my $data = \%{$hash->{helper}{DATA}{$index}}; - + if($data->{running_call}) { if(AttrVal($hash->{NAME}, "language", "en") eq "de") { return "<i>läuft</i>"; - } + } else { return "<i>ongoing</i>"; } - } - + } + my $hour = int($data->{call_duration} / (60 * 60)); my $minute = ($data->{call_duration} / 60) % 60; my $seconds = int($data->{call_duration} % 60); - + return "-" if($data->{missed_call}); return sprintf("%02d:%02d:%02d", $hour, $minute, $seconds); } ##################################### -# save the current call list to file or configDB +# save the current call list to file or configDB sub FB_CALLLIST_saveList($) { my ($hash) = @_; my $name = $hash->{NAME}; - + if(exists($hash->{helper}{DATA})) { Log3 $name, 5, "FB_CALLLIST ($name) - start dumping of list to file"; - + my $dumper = Data::Dumper->new([$hash->{helper}{DATA}], [qw($hash->{helper}{DATA})] ); $dumper->Purity(1); $dumper->Terse(0); @@ -1000,15 +1000,15 @@ sub FB_CALLLIST_saveList($) my $dump = $dumper->Dump; eval { require Compress::Zlib; }; - - unless($@) + + unless($@) { Log3 $name, 5, "FB_CALLLIST ($name) - found Compress::Zlib module, compressing dump"; $dump = Compress::Zlib::compress($dump); $dump = "compressed:".encode_base64($dump, ""); } else - { + { Log3 $name, 5, "FB_CALLLIST ($name) - unable to load Compress::Zlib module: $@"; Log3 $name, 5, "FB_CALLLIST ($name) - using just plain base64 encoding for dump"; $dump = encode_base64($dump, ""); @@ -1034,33 +1034,33 @@ sub FB_CALLLIST_loadList($) { my ($hash) = @_; my $name = $hash->{NAME}; - + Log3 $name, 5, "FB_CALLLIST ($name) - loading old call list from file"; - + delete($hash->{helper}{DATA}) if(exists($hash->{helper}{DATA})); - + my ($err, $dump) = getKeyValue("FB_CALLLIST-$name"); - + if(defined($err)) { Log3 $name, 3, "FB_CALLLIST ($name) - error while loading the old call list state: $err"; return undef; } - + if(defined($dump)) { if($dump =~ /^compressed:(.+)$/) { Log3 $name, 5, "FB_CALLLIST ($name) - found compressed list dump in file"; - + $dump = $1; - + eval { require Compress::Zlib; }; - - unless($@) + + unless($@) { $dump = decode_base64($dump); - $dump = Compress::Zlib::uncompress($dump); + $dump = Compress::Zlib::uncompress($dump); } else { @@ -1072,12 +1072,12 @@ sub FB_CALLLIST_loadList($) { $dump = decode_base64($dump); } - + Log3 $name, 5, "FB_CALLLIST ($name) - importing list...\n$dump"; - + eval($dump); - - Log3 $name, 3, "FB_CALLLIST ($name) - error while importing old call list state: $@" if($@); + + Log3 $name, 3, "FB_CALLLIST ($name) - error while importing old call list state: $@" if($@); } else { @@ -1091,20 +1091,20 @@ sub FB_CALLLIST_returnOrderedHTMLOutput($$$$) { my ($hash,$line, $tr_additions, $td_additions) = @_; - + my $name = $hash->{NAME}; - + my @order = split(",", AttrVal($name, "visible-columns",$hash->{helper}{DEFAULT_COLUMN_ORDER})); - + my @ret = (); - + push @ret, '<tr align="center" '.$tr_additions.'>'; - + foreach my $col (@order) { push @ret, '<td name="'.$col.'" '.$td_additions.'>'.$line->{$col}.'</td>' if(defined($line->{$col})); } - + return join("",@ret)."</tr>"; } @@ -1113,15 +1113,15 @@ sub FB_CALLLIST_returnOrderedHTMLOutput($$$$) sub FB_CALLLIST_returnOrderedJSONOutput($$) { my ($hash,$line) = @_; - + my $name = $hash->{NAME}; - + my @order = split(",", AttrVal($name, "visible-columns",$hash->{helper}{DEFAULT_COLUMN_ORDER})); - + my @ret = (); - + push @ret, '"line":"'.$line->{line}.'"'; - + foreach my $col (@order) { if($line->{$col}) @@ -1131,7 +1131,7 @@ sub FB_CALLLIST_returnOrderedJSONOutput($$) push @ret, '"'.$col.'":"'.$val.'"'; } } - + return "{".join(",",@ret)."}"; } @@ -1140,16 +1140,16 @@ sub FB_CALLLIST_returnOrderedJSONOutput($$) sub FB_CALLLIST_updateReadings($$) { my ($hash,$line) = @_; - + my $name = $hash->{NAME}; - + my %line_tmp = %{$line}; - + my @order = split(",", AttrVal($name, "visible-columns",$hash->{helper}{DEFAULT_COLUMN_ORDER})); - + $line_tmp{state} = FB_CALLLIST_returnCallState($hash, $line->{index}, 0); - - + + foreach my $col (@order) { readingsBulkUpdate($hash, $line_tmp{line}."-$col", $line_tmp{$col}) if($line->{$col}); @@ -1162,7 +1162,7 @@ sub FB_CALLLIST_checkForInternalNumberFilter($$) { my ($hash, $line_number) = @_; my $name = $hash->{NAME}; - + if(exists($hash->{helper}{INTERNAL_FILTER})) { Log3 $name, 5, "FB_CALLLIST ($name) - internal-number-filter is defined, checking if internal number $line_number is allowed"; @@ -1177,7 +1177,7 @@ sub FB_CALLLIST_checkForInternalNumberFilter($$) Log3 $name, 5, "FB_CALLLIST ($name) - call passed the internal-number-filter. proceeding..."; } } - + return 1; } @@ -1187,13 +1187,13 @@ sub FB_CALLLIST_updateFhemWebClients($) { my ($hash) = @_; my $name = $hash->{NAME}; - + return undef unless($init_done); if(my @list = FB_CALLLIST_list2json($hash)) { Log3 $name, 5, "FB_CALLLIST ($name) - inform all FHEMWEB clients"; - + # inform all FHEMWEB clients about changes my $count = 0; foreach my $line (@list) @@ -1201,28 +1201,28 @@ sub FB_CALLLIST_updateFhemWebClients($) FW_directNotify($name, $line, 1); $count++; } - + # send the current row count to ensure all other rows are deleted via JS FW_directNotify($name,"max-lines,$count", 1); } else { Log3 $name, 5, "FB_CALLLIST ($name) - list is empty, sending a clear command to all FHEMWEB clients"; - + # inform all FHEMWEB clients about empty list my @columns = split(",",AttrVal($name, "visible-columns", $hash->{helper}{DEFAULT_COLUMN_ORDER})); my $additional_columns = scalar(@columns); my $string; - + if(AttrVal($name, "language", "en") eq "de") { $string = "leer"; - } + } else { $string = "empty"; } - + FW_directNotify($name, "clear,$additional_columns,$string", 1); } } @@ -1237,7 +1237,7 @@ sub FB_CALLLIST_returnTableHeader($) if(AttrVal($name, "language", "en") eq "de") { - $line = { + $line = { row => "", state => "Status", timestamp => "Zeitpunkt", @@ -1251,7 +1251,7 @@ sub FB_CALLLIST_returnTableHeader($) } else { - $line = { + $line = { row => "", state => "State", timestamp => "Timestamp", @@ -1263,7 +1263,7 @@ sub FB_CALLLIST_returnTableHeader($) duration => "Duration" }; } - + return $line; } @@ -1311,7 +1311,7 @@ sub FB_CALLLIST_returnTableHeader($) The default icon mapping for all states can be changed by the corresponding attribute. <br> <br> - + <a name="FB_CALLLIST_define"></a> <b>Define</b> <ul> @@ -1337,45 +1337,45 @@ sub FB_CALLLIST_returnTableHeader($) <ul> <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li> - + <br> - + <li><a name="FB_CALLLIST_answMachine-is-missed-call">answMachine-is-missed-call</a> 0,1</li> If activated, a incoming call, which is answered by an answering machine, will be treated as a missed call. This is only relevant if <a href="#FB_CALLLIST_list-type">list-type</a> is set to "missed-call". <br><br> Possible values: 0 => disabled, 1 => enabled (answering machine calls will be treated as "missed call").<br> Default Value is 0 (disabled)<br><br> - + <li><a name="FB_CALLLIST_connection-mapping">connection-mapping</a> <hash></li> Defines a custom mapping of connection names to custom values. The mapping is performed in a hash table.<br><br> e.g.<br> <ul> <code>attr <name> connection-mapping {'DECT_1' => 'Mobile Kitchen', 'FON1' => 'Fax'}</code> - </ul><br> + </ul><br> The mapped name will be displayed in the table instead of the original value from FB_CALLMONITOR. <br><br> Default Value: <i>empty</i> (no mapping is performed) <br><br> - + <li><a name="FB_CALLLIST_create-readings">create-readings</a> 0,1</li> If enabled, for all visible calls in the list, readings and events will be created. It is recommended to set the attribute <a href="#event-on-change-reading">event-on-change-reading</a> to <code>.*</code> (all readings), to reduce the amount of generated readings for certain call events.<br><br> Possible values: 0 => no readings will be created, 1 => readings and events will be created.<br> Default Value is 0 (no readings will be created)<br><br> - + <li><a name="FB_CALLLIST_disable">disable</a> 0,1</li> Optional attribute to disable the call list update. When disabled, call events will be processed and the list wouldn't be updated accordingly. <br><br> Possible values: 0 => FB_CALLLIST is activated, 1 => FB_CALLLIST is deactivated.<br> Default Value is 0 (activated)<br><br> - + <li><a name="FB_CALLLIST_disabledForIntervals">disabledForIntervals</a> HH:MM-HH:MM HH:MM-HH-MM...</li> Optional attribute to disable the call list update during a specific time interval. The attribute contains a space separated list of HH:MM tupels. If the current time is between any of these time specifications, the callist will be disabled and no longer updated. - Instead of HH:MM you can also specify HH or HH:MM:SS. + Instead of HH:MM you can also specify HH or HH:MM:SS. <br><br>To specify an interval spawning midnight, you have to specify two intervals, e.g.: <pre>23:00-24:00 00:00-01:00</pre> Default Value is <i>empty</i> (no intervals defined, calllist is always active)<br><br> - + <li><a name="FB_CALLLIST_expire-calls-after">expire-calls-after</a> <time frame></li> Optional attribute to automatically delete finished calls which are older than a given time frame. If a finished call is older than this time frame, it will be deleted from the list. <br><br>A time frame can be specified as follows: @@ -1388,24 +1388,24 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br> <b>IMPORTANT:</b> In this case, the ending time of each call is checked, not the beginning time.<br><br> - - If no unit is given, the given number ist interpreted as seconds. Float values can also be used (e.g. <code>0.5 day</code>). + + If no unit is given, the given number ist interpreted as seconds. Float values can also be used (e.g. <code>0.5 day</code>). The value <code>0</code> means no expiry of calls, so no calls will be deleted because of expiry.<br><br> Default Value is 0 (no calls will be deleted because of expiry)<br><br> - + <li><a name="FB_CALLLIST_external-mapping">external-mapping</a> <hash></li> Defines a custom mapping of external connection values (reading: external_connection) to custom values. The mapping is performed in a hash table.<br><br> e.g.<br> <ul> <code>attr <name> external-mapping {'ISDN' => 'Fixed Network', 'SIP0' => 'Operator A', 'SIP1' => 'Operator B'}</code> </ul><br> - + <li><a name="FB_CALLLIST_icon-mapping">icon-mapping</a> <hash></li> Defines a custom mapping of call states to custom icons. The mapping is performed in a hash table.<br><br> e.g.<br> <ul> <code>attr <name> icon-mapping {'incoming.connected' => 'phone_ring_in@yellow', 'outgoing.missed' => 'phone_missed_out@red'}</code> - </ul><br> + </ul><br> The mapped name will be displayed in the table instead of the original value from FB_CALLMONITOR. If you use SVG-based icons, you can set the desired color as name or HTML color code via an optional "@<i>color</i>". <br><br> Possible values and their default icon are:<br><br> @@ -1414,7 +1414,7 @@ sub FB_CALLLIST_returnTableHeader($) <li><b>outgoing.ring</b> => phone_ring@green</li> <li><b>incoming.connected</b> => phone_ring_in@blue</li> <li><b>outgoing.connected</b> => phone_ring_in@green</li> - + <li><b>incoming.missed</b> => phone_missed_in@red</li> <li><b>outgoing.missed</b> => phone_missed_out@green</li> <li><b>incoming.done</b> => phone_call_end_in@blue</li> @@ -1423,7 +1423,7 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br><br> Default Value: <i>empty</i> (no mapping is performed)<br><br> - + <li><a name="FB_CALLLIST_internal-number-filter">internal-number-filter</a> <hash></li> This attribute accepts a list of comma seperated internal numbers for filtering incoming or outgoing calls by a specific list of internal numbers @@ -1442,30 +1442,30 @@ sub FB_CALLLIST_returnTableHeader($) <br><br> Default Value: <i>empty</i> (all internal numbers should be used, no exclusions and no mapping is performed) <br><br> - + <li><a name="FB_CALLLIST_language">language</a> en,de</li> Defines the language of the table header, some keywords and the timestamp format. You need to have the selected locale installed and available in your operating system.<br><br> Possible values: en => English , de => German<br> Default Value is en (English)<br><br> - + <li><a name="FB_CALLLIST_list-type">list-type</a> all,incoming,outgoing,missed-calls,completed,active</li> Defines what type of calls should be displayed in the list.<br><br> Default Value is "all"<br><br> - + <li><a name="FB_CALLLIST_list-order">list-order</a> descending,ascending</li> Defines whether the newest call should be on top of the list (descending) or on the bottom of the list (ascending).<br><br> Default Value is descending (first call at top of the list)<br><br> - + <li><a name="FB_CALLLIST_no-heading">no-heading</a> 0,1</li> If activated the headline with a link to the detail page of the current definition will be hidden.<br><br> Possible values: 0 => the heading line will be shown , 1 => the heading line will not be shown<br> Default Value is 0 (the heading line will be shown)<br><br> - + <li><a name="FB_CALLLIST_no-table-header">no-table-header</a> 0,1</li> If activated the table header containing the name of each column for the current definition will be hidden.<br><br> Possible values: 0 => the table header will be shown , 1 => the table header will not be shown<br> Default Value is 0 (the table header will be shown)<br><br> - + <li><a name="FB_CALLLIST_number-cmd">number-cmd</a> <command></li> Can be set, to execute a specific FHEM command, when clicking on a number in the list. The value can be any valid FHEM command or Perl code (in curly brackets: { ... } ). The placeholder <code>$NUMBER</code> will be replaced with the current external number of each row. @@ -1478,18 +1478,18 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br> If not set, no link will be shown in the list.<br><br> - + <li><a name="FB_CALLLIST_number-of-calls">number-of-calls</a> 1..20</li> Defines the maximum number of displayed call entries in the list.<br><br> Default Value is 5 calls<br><br> - + <li><a name="FB_CALLLIST_show-icons">show-icons</a> 0,1</li> Normally the call state is shown with icons (used from the openautomation icon set). You need to have openautomation in your iconpath attribute of your appropriate FHEMWEB definition to use this icons. If you don't want to use icons you can deactivate them with this attribute.<br><br> Possible values: 0 => no icons , 1 => use icons<br> Default Value is 1 (use icons)<br><br> - + <li><a name="FB_CALLLIST_time-format-string">time-format-string</a> <string></li> Defines a format string which should be used to format the timestamp values. It contains several placeholders for different elements of a date/time. @@ -1508,7 +1508,7 @@ sub FB_CALLLIST_returnTableHeader($) Please consult the manpage of <code>strftime()</code> or the documentation of your perl interpreter to find out more. <br><br> Default value is "%a, %d %b %Y %H:%M:%S" ( = "Sun, 07 Jun 2015 12:50:09")<br><br> - + <li><a name="FB_CALLLIST_visible-columns">visible-columns</a> row,state,timestamp,name,number,internal,external,connection,duration</li> Defines the visible columns, as well as the order in which these columns are displayed in the call list (from left to right). Not all columns must be displayed, you can select only a subset of columns which will be displayed. @@ -1548,7 +1548,7 @@ sub FB_CALLLIST_returnTableHeader($) <br> Falls keine Icons verwendet werden sollen (siehe Attribut <a href="#FB_CALLLIST_show-icons">show-icons</a>), wird der Status wie folgt angezeigt:<br><br> <ul> - + <li><code><b><= ((o))</b></code></td><td> - Ausgehender Anruf (klingelt)</li> <li><code><b>=> ((o))</b></code></td><td> - Eingehender Anruf (klingelt)</li> <br> @@ -1589,38 +1589,38 @@ sub FB_CALLLIST_returnTableHeader($) <ul> <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li> - + <br> - + <li><a name="FB_CALLLIST_answMachine-is-missed-call">answMachine-is-missed-call</a> 0,1</li> Sofern aktiviert, werden Anrufe, welche durch einen internen Anrufbeantworter beantwortet werden, als "verpasster Anruf" gewertet. Diese Funktionalität ist nur relevant, wenn <a href="#FB_CALLLIST_list-type">list-type</a> auf "missed-call" gesetzt ist. <br><br> Mögliche Werte: 0 => deaktiviert, 1 => aktiviert (Anrufbeantworter gilt als "verpasster Anruf").<br> Standardwert ist 0 (deaktiviert)<br><br> - + <li><a name="FB_CALLLIST_create-readings">create-readings</a> 0,1</li> Sofern aktiviert, werden für alle sichtbaren Anrufe in der Liste entsprechende Readings und Events erzeugt. Es wird empfohlen das Attribut <a href="#event-on-change-reading">event-on-change-reading</a> auf den Wert <code>.*</code> zu stellen um die hohe Anzahl an Events in bestimmten Fällen zu minimieren.<br><br> Mögliche Werte: 0 => keine Readings erstellen, 1 => Readings und Events werden erzeugt.<br> Standardwert ist 0 (keine Readings erstellen)<br><br> - + <li><a name="FB_CALLLIST_connection-mapping">connection-mapping</a> <hash></li> Definiert eine eigene Zuordnung der Endgeräte (Reading: internal_connection) zu eigenen Bezeichnungen. Die Zuordnung erfolgt über eine Hash-Struktur.<br><br> z.B.<br> <ul> <code>attr <name> connection-mapping {'DECT_1' => 'Mobilteil Küche', 'FON1' => 'Fax', 'Answering_Machine_1' => 'Anrufbeantworter'}</code> - </ul><br> + </ul><br> Die jeweils zugeordnete Bezeichnung wird in der Anrufliste dann entsprechend angezeigt anstatt des originalen Werten von FB_CALLMONITOR. <br><br> Standardwert ist <i>nicht gesetzt</i> (Keine Zuordnung, es werden die Originalwerte verwendet) <br><br> - + <li><a name="FB_CALLLIST_disable">disable</a> 0,1</li> Optionales Attribut zur Deaktivierung der Anrufliste. Es werden dann keine Anruf-Events mehr verarbeitet und die Liste nicht weiter aktualisiert. <br><br> Mögliche Werte: 0 => Anrufliste ist aktiv, 1 => Anrufliste ist deaktiviert.<br> Standardwert ist 0 (aktiv)<br><br> - + <li><a name="FB_CALLLIST_disabledForIntervals">disabledForIntervals</a> HH:MM-HH:MM HH:MM-HH-MM...</li> Optionales Attribut zur Deaktivierung der Anrufliste innerhalb von bestimmten Zeitintervallen. Das Argument ist eine Leerzeichen-getrennte Liste von Minuszeichen-getrennten HH:MM Paaren (Stunde : Minute). @@ -1629,7 +1629,7 @@ sub FB_CALLLIST_returnTableHeader($) Um einen Intervall um Mitternacht zu spezifizieren, muss man zwei einzelne Intervalle angeben, z.Bsp.: <pre>23:00-24:00 00:00-01:00</pre> Standardwert ist <i>nicht gesetzt</i> (dauerhaft aktiv)<br><br> - + <li><a name="FB_CALLLIST_expire-calls-after">expire-calls-after</a> <Zeitfenster></li> Optionales Attribut um beendete Anrufe nach einem angegeben Zeitfenster automatisch aus der Anrufliste zu löschen. Sobald ein beendetes Gespräch älter ist als das angegebene Zeitfenster, wird es automatisch aus der Liste entfernt. @@ -1643,28 +1643,28 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br> <b>WICHTIG:</b> Es wird hierbei der Endezeitpunkt eines Gesprächs betrachtet, nicht der Beginn des Gesprächs.<br><br> - - Wenn keine Einheit angegeben ist, wird die angegebene Zahl als Sekunden interpretiert. Es können auch Fliesskommazahlen mit einem Punkt als Kommastelle angegeben werden (z.B. <code>0.5 day</code>). + + Wenn keine Einheit angegeben ist, wird die angegebene Zahl als Sekunden interpretiert. Es können auch Fliesskommazahlen mit einem Punkt als Kommastelle angegeben werden (z.B. <code>0.5 day</code>). Der Wert <code>0</code> bedeutet, das keine Gespräche nach einem gewissen Zeitfenster gelöscht werden.<br><br> Standardwert ist 0 (keine Gespräche werden nach einem Zeitfenster gelöscht)<br><br> - + <li><a name="FB_CALLLIST_external-mapping">external-mapping</a> <hash></li> Definiert eine eigene Zuordnung der externen Anschlussbezeichnung (Reading: external_connection) zu eigenen Bezeichnungen. Die Zuordnung erfolgt über eine Hash-Struktur.<br><br> z.B.<br> <ul> <code>attr <name> external-mapping {'ISDN' => 'Festnetz', 'SIP0' => 'Anbieter A', 'SIP1' => 'Anbieter B'}</code> - </ul><br> + </ul><br> Die jeweils zugeordnete Bezeichnung wird in der Anrufliste dann entsprechend angezeigt anstatt des originalen Werten von FB_CALLMONITOR. <br><br> Standardwert ist <i>nicht gesetzt</i> (Keine Zuordnung, es werden die Originalwerte verwendet) <br><br> - + <li><a name="FB_CALLLIST_icon-mapping">icon-mapping</a> <hash></li> Definiert eine eigene Zuordnung eines Anrufstatus zu einem Icon. Die Zuordnung erfolgt über eine Hash-Struktur.<br><br> z.B.<br> <ul> <code>attr <name> icon-mapping {'incoming.connected' => 'phone_ring_in@yellow', 'outgoing.missed' => 'phone_missed_out@red'}</code> - </ul><br> + </ul><br> Das entsprechende Icon wird an Stelle des Original-Icons bzw. Text verwendet. Sofern SVG-basierte Icons verwendet werden, kann man die Farbe optional definieren durch das Anfügen via @ mit Name oder einem HTML Farbcode. <br><br> Mögliche Werte und ihre Standard-Icons sind:<br><br> @@ -1682,7 +1682,7 @@ sub FB_CALLLIST_returnTableHeader($) <br><br> Standardwert ist <i>nicht gesetzt</i> (Keine Zuordnung, es werden die Standard-Icons verwendet, sofern Icons akitivert sind) <br><br> - + <li><a name="FB_CALLLIST_internal-number-filter">internal-number-filter</a> <hash></li> Dieses Attribut ermöglicht das Filtern der angezeigten Anrufe auf bestimmte interne Rufnummern sowie das Zuordnen von Namen zu den internen Rufnummern.<br><br> Es ist möglich eine kommaseparierte Liste an internen Rufnummern anzugeben oder eine Hash-Tabelle in der man den internen Rufnummern eine eigene Bezeichnung zuweist. @@ -1695,15 +1695,15 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br> <b>Wichtig:</b> Je nach Telefonanbieter kann der Wert die Ortsvorwahl enthalten. Die Rufnummer muss genauso angegeben werden, wie sie ohne eine Zuordnung in der Anrufliste auftaucht.<br><br> - Wenn dieses Attribut gesetzt ist, werden nur die eingestellten Rufnummern in der Liste angezeigt. + Wenn dieses Attribut gesetzt ist, werden nur die eingestellten Rufnummern in der Liste angezeigt. <br><br> Standardwert ist <i>nicht gesetzt</i> (alle internen Rufnummern werden angezeigt) <br><br> - + <li><a name="FB_CALLLIST_list-order">list-order</a> descending,ascending</li> Gibt an ob der neueste Anruf in der ersten Zeile (aufsteigend => descending) oder in der letzten Zeile (absteigend => ascending) in der Liste angezeigt werden soll. Dementsprechend rollt die Liste dann nach oben oder unten durch.<br><br> Standardwert ist "descending" (absteigend, neuester Anruf in der ersten Zeile)<br><br> - + <li><a name="FB_CALLLIST_list-type">list-type</a> all,incoming,outgoing,missed-calls,completed,active</li> Ist dieses Attribut gesetzt, werden nur bestimmte Typen von Anrufen in der Liste angezeigt:<br><br> <ul> @@ -1715,17 +1715,17 @@ sub FB_CALLLIST_returnTableHeader($) <li><code>active</code> - Alle aktuell laufenden Anrufe werden angezeigt (eingehend und ausgehend)</li> </ul><br> Standardwert ist "all" (alle Anrufe anzeigen)<br><br> - + <li><a name="FB_CALLLIST_no-heading">no-heading</a> 0,1</li> Sofern aktiviert, wird die Überschriftenzeile ausserhalb der Liste inkl. Link auf die Detail-Seite der aktuellen Definition ausgeblendet.<br><br> Mögliche Werte: 0 => Überschriftenzeile wird angezeigt , 1 => Überschriftenzeile wird ausgeblendet<br> Standardwert ist 1 (Überschriftenzeile wird angezeigt)<br><br> - + <li><a name="FB_CALLLIST_no-table-header">no-table-header</a> 0,1</li> Sofern aktiviert, wird die Kopfzeile der Tabelle für die aktuelle Definition ausgeblendet.<br><br> Mögliche Werte: 0 => Kopfzeile wird angezeigt , 1 => Kopfzeile wird ausgeblendet<br> Standardwert ist 1 (Kopfzeile wird angezeigt)<br><br> - + <li><a name="FB_CALLLIST_number-cmd">number-cmd</a> <Befehl></li> Kann gesetzt werden, um ein FHEM-Befehl oder Perl-Code (in geschweiften Klammern: { ... } ) auszuführen, wenn man auf eine Rufnummer in der Anrufliste klickt. Der Platzhalter <code>$NUMBER</code> wird dabei mit der entsprechenden Rufnummer der jeweiligen Zeile ersetzt. @@ -1738,16 +1738,16 @@ sub FB_CALLLIST_returnTableHeader($) </ul> <br> Sofern nicht gesetzt, wird kein Link angezeigt.<br><br> - + <li><a name="FB_CALLLIST_number-of-calls">number-of-calls</a> 1..20</li> Setzt die maximale Anzahl an Einträgen in der Anrufliste. Sollte die Anrufliste voll sein, wird das älteste Gespräch gelöscht.<br><br> Standardwert sind 5 Einträge<br><br> - + <li><a name="FB_CALLLIST_show-icons">show-icons</a> 0,1</li> Im Normalfall wird der Status eines jeden Anrufs mit einem Icon angezeigt. Dazu muss das openautomation Icon-Set im iconpath-Attribut der entsprechenden FHEMWEB Instanz konfiguriert sein. Sollte man keine Icons wünschen, so kann man diese hiermit abschalten. Der Status wird dann mittels Textzeichen dargestellt.<br><br> Mögliche Werte: 0 => keine Icons , 1 => benutze Icons<br> Standardwert ist 1 (benutze Icons)<br><br> - + <li><a name="FB_CALLLIST_time-format-string">time-format-string</a> <string></li> Definiert einen Formatierungs-String welcher benutzt wird um die Zeitangaben in der Anrufliste nach eigenen Wünschen anzupassen. Es stehen hier eine ganze Reihe an Platzhaltern zur Verfügung um die einzelnen Elemente einer Datums-/Zeitangabe einzeln zu setzen. Die möglichen Werte sind alle Standard POSIX strftime() Platzhalter. Gängige Platzhalter sind:<br><br> <ul> @@ -1767,7 +1767,7 @@ sub FB_CALLLIST_returnTableHeader($) Definiert die Sprache in der die Anrufliste angezeigt werden soll (Tabellenkopf, Datum). Die entsprechende Sprache muss auch im Betriebssystem installiert und unterstützt werden.<br><br> Mögliche Werte: en => Englisch , de => Deutsch<br> Standardwert ist en (Englisch)<br><br> - + <li><a name="FB_CALLLIST_visible-columns">visible-columns</a> row,state,timestamp,name,number,internal,external,connection,duration</li> Legt fest, welche Spalten in welcher Reihenfolge (von links nach rechts) in der Anrufliste angezeigt werden sollen. Es müssen nicht alle verfügbaren Spalten angezeigt werden. diff --git a/fhem/FHEM/73_PRESENCE.pm b/fhem/FHEM/73_PRESENCE.pm index 29f546c33..7d7be08db 100755 --- a/fhem/FHEM/73_PRESENCE.pm +++ b/fhem/FHEM/73_PRESENCE.pm @@ -39,7 +39,7 @@ PRESENCE_Initialize($) my ($hash) = @_; # Provider - $hash->{ReadFn} = "PRESENCE_Read"; + $hash->{ReadFn} = "PRESENCE_Read"; $hash->{ReadyFn} = "PRESENCE_Ready"; $hash->{SetFn} = "PRESENCE_Set"; $hash->{DefFn} = "PRESENCE_Define"; @@ -71,7 +71,7 @@ PRESENCE_Define($$) my $name = $hash->{NAME}; $hash->{NOTIFYDEV} = "global"; - + if(defined($a[2]) and defined($a[3])) { if($a[2] eq "local-bluetooth") @@ -82,16 +82,16 @@ PRESENCE_Define($$) Log 2, "PRESENCE ($name) - ".$msg; return $msg } - + $hash->{MODE} = "local-bluetooth"; $hash->{ADDRESS} = $a[3]; $hash->{TIMEOUT_NORMAL} = (defined($a[4]) ? $a[4] : 30); - $hash->{TIMEOUT_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{TIMEOUT_NORMAL}); + $hash->{TIMEOUT_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{TIMEOUT_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; @@ -103,9 +103,9 @@ PRESENCE_Define($$) Log 2, "PRESENCE ($name) - ".$msg; return $msg; } - + $hash->{MODE} = "fritzbox"; - $hash->{ADDRESS} = $a[3]; + $hash->{ADDRESS} = $a[3]; $hash->{TIMEOUT_NORMAL} = (defined($a[4]) ? $a[4] : 30); $hash->{TIMEOUT_PRESENT} = (defined($a[5]) ? $a[5] : $hash->{TIMEOUT_NORMAL}); } @@ -133,7 +133,7 @@ PRESENCE_Define($$) $hash->{TIMEOUT_PRESENT} = ($5 ne "" ? $5 : $hash->{TIMEOUT_NORMAL}); delete($hash->{helper}{ADDRESS}); - + if($hash->{helper}{call} =~ /\|/) { my $msg = "The command contains a pipe ( | ) symbol, which is not allowed."; @@ -173,18 +173,18 @@ PRESENCE_Define($$) 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"; - + InternalTimer(gettimeofday(), "PRESENCE_setNotfiyDev", $hash); } else @@ -233,7 +233,7 @@ PRESENCE_Define($$) } delete($hash->{helper}{cachednr}); - + readingsSingleUpdate($hash,"model",$hash->{MODE},0); return undef; @@ -252,7 +252,7 @@ PRESENCE_Undef($$) BlockingKill($hash->{helper}{RUNNING_PID}); } - DevIo_CloseDev($hash); + DevIo_CloseDev($hash); return undef; } @@ -261,16 +261,16 @@ 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})) @@ -278,7 +278,7 @@ PRESENCE_Notify($$) $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})); @@ -295,21 +295,21 @@ PRESENCE_Notify($$) 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$/) + 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$/) + 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); @@ -326,20 +326,20 @@ 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)); - + 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 @@ -350,20 +350,20 @@ PRESENCE_Set($@) } else { - return "PRESENCE Definition \"$name\" is not connected to ".$hash->{DeviceName}; + return "PRESENCE Definition \"$name\" is not connected to ".$hash->{DeviceName}; } - } + } } - elsif(defined($powerCmd) && $a[1] eq "power") + 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); @@ -412,7 +412,7 @@ PRESENCE_Attr(@) $hash->{helper}{DISABLED} = 0; DevIo_OpenDev($hash, 0, "PRESENCE_DoInit"); } - } + } else { $hash->{helper}{DISABLED} = 0; @@ -424,7 +424,7 @@ PRESENCE_Attr(@) elsif($a[3] eq "1") { if(defined($hash->{FD})) - { + { DevIo_SimpleWrite($hash, "stop\n", 2); } @@ -441,7 +441,7 @@ PRESENCE_Attr(@) if(defined($hash->{DeviceName})) { $hash->{helper}{DISABLED} = 0; - + if(defined($hash->{FD})) { PRESENCE_DoInit($hash) if(exists($hash->{helper}{DISABLED})); @@ -460,10 +460,10 @@ PRESENCE_Attr(@) 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"; @@ -482,7 +482,7 @@ PRESENCE_Attr(@) 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."; @@ -491,13 +491,13 @@ PRESENCE_Attr(@) 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; } @@ -516,10 +516,10 @@ PRESENCE_Read($) readingsBeginUpdate($hash); - for my $line (split /^/, $buf) + 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->{TIMEOUT_NORMAL} != $hash->{TIMEOUT_PRESENT}) @@ -528,11 +528,11 @@ PRESENCE_Read($) Log3 $name, 4 , "PRESENCE ($name) - changing to normal timeout every ".$hash->{TIMEOUT_NORMAL}." seconds"; DevIo_SimpleWrite($hash, $hash->{ADDRESS}."|".$hash->{TIMEOUT_NORMAL}."\n", 2); } - + unless($hash->{helper}{DISABLED}) { PRESENCE_ProcessState($hash, "absent"); - + if($line=~ /^[^;]+;(.+)$/) { PRESENCE_ProcessAddonData($hash, $1); @@ -547,12 +547,12 @@ PRESENCE_Read($) Log3 $name, 4 , "PRESENCE ($name) - changing to present timeout every ".$hash->{TIMEOUT_PRESENT}." seconds"; DevIo_SimpleWrite($hash, $hash->{ADDRESS}."|".$hash->{TIMEOUT_PRESENT}."\n", 2); } - + unless($hash->{helper}{DISABLED}) { PRESENCE_ProcessState($hash, "present"); my $data = $1; - + if($data =~ /\S=\S/) { PRESENCE_ProcessAddonData($hash, $data); @@ -596,7 +596,7 @@ PRESENCE_Read($) Log3 $name, 3, "PRESENCE ($name) - presenced cannot execute hcitool to check device "; } } - + readingsEndUpdate($hash, 1); } @@ -605,7 +605,7 @@ sub PRESENCE_Ready($) { my ($hash) = @_; - + return DevIo_OpenDev($hash, 1, "PRESENCE_DoInit") if($hash->{MODE} eq "lan-bluetooth"); } @@ -622,9 +622,9 @@ 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; @@ -665,7 +665,7 @@ sub PRESENCE_StartLocalScan($;$) 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}); @@ -677,23 +677,23 @@ sub PRESENCE_StartLocalScan($;$) 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->{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}); } - + return "another check is currently running"; } } @@ -710,7 +710,7 @@ sub PRESENCE_DoLocalPingScan($) my $retcode; my $return; my $temp; - + $SIG{CHLD} = 'IGNORE'; if($^O =~ m/(Win|cygwin)/) @@ -724,7 +724,7 @@ sub PRESENCE_DoLocalPingScan($) $return = "$name|$local|".($temp =~ /TTL=\d+/ ? "present" : "absent"); } else - { + { $return = "$name|$local|error|Could not execute ping command: \"ping -n $count -4 $device\""; } } @@ -739,7 +739,7 @@ sub PRESENCE_DoLocalPingScan($) $return = "$name|$local|".($temp =~ /is alive/ ? "present" : "absent"); } else - { + { $return = "$name|$local|error|Could not execute ping command: \"ping -n $count -4 $device\""; } @@ -755,7 +755,7 @@ sub PRESENCE_DoLocalPingScan($) $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\""; } } @@ -772,7 +772,7 @@ sub PRESENCE_ExecuteFritzBoxCMD($$) 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; @@ -798,35 +798,35 @@ sub PRESENCE_DoLocalFritzBoxScan($) 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})) + + 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"); + + $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"); @@ -834,9 +834,9 @@ sub PRESENCE_DoLocalFritzBoxScan($) 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)"; @@ -870,14 +870,14 @@ sub PRESENCE_DoLocalFritzBoxScan($) $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"); @@ -885,9 +885,9 @@ sub PRESENCE_DoLocalFritzBoxScan($) 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; } @@ -908,11 +908,11 @@ sub PRESENCE_DoLocalBluetoothScan($) 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"; @@ -923,7 +923,7 @@ sub PRESENCE_DoLocalBluetoothScan($) 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"; @@ -947,7 +947,7 @@ sub PRESENCE_DoLocalBluetoothScan($) $wait = 0; } } - + Log3 $name, 5, "PRESENCE ($name) - executing: hcitool name $device"; $devname = qx(hcitool $options name $device); @@ -982,20 +982,20 @@ sub PRESENCE_DoLocalShellScriptScan($) 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; + chomp $ret; Log3 $name, 5, "PRESENCE ($name) - script output: $ret"; } - + if(not defined($ret)) { - $return = "$name|$local|error|scriptcall doesn't return any output"; + $return = "$name|$local|error|scriptcall doesn't return any output"; } elsif($ret eq "1") { @@ -1009,7 +1009,7 @@ sub PRESENCE_DoLocalShellScriptScan($) { $ret =~ s/\n/<<line-break>>/g; - $return = "$name|$local|error|unexpected script output (expected 0 or 1): $ret"; + $return = "$name|$local|error|unexpected script output (expected 0 or 1): $ret"; } return $return; @@ -1026,18 +1026,18 @@ sub PRESENCE_DoLocalFunctionScan($) 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"; + $return = "$name|$local|error|function call doesn't return any output"; } elsif($ret eq "1") { @@ -1051,9 +1051,9 @@ sub PRESENCE_DoLocalFunctionScan($) { $ret =~ s/\n/<<line-break>>/g; - $return = "$name|$local|error|unexpected function output (expected 0 or 1): $ret"; + $return = "$name|$local|error|unexpected function output (expected 0 or 1): $ret"; } - + return $return; } @@ -1065,21 +1065,21 @@ sub PRESENCE_ProcessLocalScan($) return unless(defined($string)); my @a = split("\\|",$string); - my $hash = $defs{$a[0]}; - + 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"); @@ -1088,7 +1088,7 @@ sub PRESENCE_ProcessLocalScan($) 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")); + $hash->{helper}{cachednr} = $a[3] if(($a[2] eq "present") || ($a[2] eq "absent")); } elsif($hash->{MODE} eq "fritzbox" and defined($hash->{helper}{cachednr})) { @@ -1096,13 +1096,13 @@ sub PRESENCE_ProcessLocalScan($) } readingsBeginUpdate($hash); - + PRESENCE_ProcessState($hash, $a[2]) unless($hash->{helper}{DISABLED}); - + if($a[2] eq "present") { readingsBulkUpdate($hash, "device_name", $a[3]) if(defined($a[3]) and $hash->{MODE} =~ /^(lan-bluetooth|local-bluetooth)$/ ); - + if($hash->{MODE} eq "fritzbox" and defined($a[4])) { readingsBulkUpdate($hash, "speed", $a[4]); @@ -1128,9 +1128,9 @@ sub PRESENCE_ProcessLocalScan($) if($local eq "0") { my $seconds = ($a[2] 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) unless($hash->{helper}{DISABLED}); } @@ -1166,7 +1166,7 @@ sub PRESENCE_ProcessAbortedScan($) InternalTimer(gettimeofday()+10, "PRESENCE_StartLocalScan", $hash, 0) unless($hash->{helper}{DISABLED}); Log3 $hash->{NAME}, 2, "PRESENCE ($name) - device could not be checked (retrying in 10 seconds)" } - + readingsSingleUpdate($hash, "state", "timeout",1); } @@ -1200,17 +1200,17 @@ sub PRESENCE_DoInit($) 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; @@ -1228,22 +1228,22 @@ sub PRESENCE_calculateThreshold($) 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}); } } @@ -1253,22 +1253,22 @@ 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") @@ -1282,7 +1282,7 @@ sub PRESENCE_ProcessState($$) { readingsBulkUpdate($hash, "state", "absent"); readingsBulkUpdate($hash, "presence", "absent"); - + $hash->{helper}{CURRENT_STATE} = "absent"; delete($hash->{helper}{NEW_STATE}); } @@ -1299,7 +1299,7 @@ sub PRESENCE_ProcessState($$) else { $hash->{helper}{ABSENT_COUNT} = $count; - + readingsBulkUpdate($hash, ".presenceThresholdCounter", 0); readingsBulkUpdate($hash, ".absenceThresholdCounter", $count); readingsBulkUpdate($hash, "state", "maybe absent"); @@ -1308,14 +1308,14 @@ sub PRESENCE_ProcessState($$) 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") @@ -1329,7 +1329,7 @@ sub PRESENCE_ProcessState($$) { readingsBulkUpdate($hash, "state", "present"); readingsBulkUpdate($hash, "presence", "present"); - + $hash->{helper}{CURRENT_STATE} = "present"; delete($hash->{helper}{NEW_STATE}); } @@ -1342,13 +1342,13 @@ sub PRESENCE_ProcessState($$) 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"); @@ -1357,7 +1357,7 @@ sub PRESENCE_ProcessState($$) 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 @@ -1370,14 +1370,14 @@ sub PRESENCE_ProcessState($$) 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; } @@ -1385,7 +1385,7 @@ sub PRESENCE_ProcessAddonData($$) sub PRESENCE_setNotfiyDev($) { my ($hash) = @_; - + notifyRegexpChanged($hash,"(global|".$hash->{EVENT_PRESENT}."|".$hash->{EVENT_ABSENT}.")"); } @@ -1475,7 +1475,7 @@ sub PRESENCE_setNotfiyDev($) <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. + <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: @@ -1495,13 +1495,13 @@ Options: -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) + + 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> @@ -1520,22 +1520,22 @@ Options: 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> @@ -1545,7 +1545,7 @@ Examples: <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: @@ -1568,7 +1568,7 @@ Options: log to the given logfile -h, --help Print detailed help screen -</PRE> +</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> @@ -1583,15 +1583,15 @@ Options: [living room] address=192.168.0.11 - port=5111 + port=5111 presence_timeout=180 - absence_timeout=20 + 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.7.deb" target="_new">collectord-1.7.deb</a></li> @@ -1662,7 +1662,7 @@ Options: <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> @@ -1679,7 +1679,7 @@ Options: </ul> </ul> <br> - + <a name="PRESENCEevents"></a> <b>Generated Events:</b><br><br> <ul> @@ -1739,7 +1739,7 @@ Options: <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. + 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> @@ -1769,7 +1769,7 @@ Options: <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. + 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> @@ -1785,7 +1785,7 @@ Options: <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. + <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: @@ -1805,14 +1805,14 @@ Options: -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>) + + 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> @@ -1832,22 +1832,22 @@ Options: 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> @@ -1857,7 +1857,7 @@ Examples: <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: @@ -1880,7 +1880,7 @@ Options: log to the given logfile -h, --help Print detailed help screen -</PRE> +</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> @@ -1895,15 +1895,15 @@ Options: [Wohnzimmer] address=192.168.0.11 - port=5111 + port=5111 presence_timeout=180 - absence_timeout=20 + 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.7.deb" target="_new">collectord-1.7.deb</a></li> @@ -1915,8 +1915,8 @@ Options: <a name="PRESENCEset"></a> <b>Set</b> <ul> - - <li><b>statusRequest</b> - Startet einen sofortigen Check.</li> + + <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> </ul> <br> @@ -1962,7 +1962,7 @@ Options: 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_ping_count">ping_count</a></li> (Nur im Modus "ping" anwendbar)<br> - Verändert die Anzahl der Ping-Pakete die gesendet werden sollen um die Anwesenheit zu erkennen. + 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_bluetooth_hci_device">bluetooth_hci_device</a></li> (Nur im Modus "local-bluetooth" anwendbar)<br> @@ -1977,7 +1977,7 @@ Options: <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> @@ -1994,7 +1994,7 @@ Options: </ul> </ul> <br> - + <a name="PRESENCEevents"></a> <b>Generierte Events:</b><br><br> <ul> diff --git a/fhem/FHEM/82_LGTV_IP12.pm b/fhem/FHEM/82_LGTV_IP12.pm index 2d69c1f42..03eb74529 100755 --- a/fhem/FHEM/82_LGTV_IP12.pm +++ b/fhem/FHEM/82_LGTV_IP12.pm @@ -114,7 +114,7 @@ sub LGTV_IP12_Initialize($) { my ($hash) = @_; - + $hash->{DefFn} = "LGTV_IP12_Define"; $hash->{DeleteFn} = "LGTV_IP12_Delete"; $hash->{UndefFn} = "LGTV_IP12_Undef"; @@ -137,10 +137,10 @@ LGTV_IP12_Define($$) return "LGTV_IP12: not enough arguments. Usage: " . "define <name> LGTV_IP12 <HOST>"; } - + $hash->{HOST} = $args[2]; $hash->{PORT} = "8080"; - + # if an update interval was given which is greater than zero, use it. if(defined($args[3]) and $args[3] > 0) { @@ -150,7 +150,7 @@ LGTV_IP12_Define($$) { $hash->{helper}{OFF_INTERVAL} = 30; } - + if(defined($args[4]) and $args[4] > 0) { $hash->{ON_INTERVAL} = $args[4]; @@ -161,11 +161,11 @@ LGTV_IP12_Define($$) { $hash->{INTERVAL} = $hash->{helper}{OFF_INTERVAL}; $hash->{helper}{ON_INTERVAL} = $hash->{helper}{OFF_INTERVAL}; - } - + } + $hash->{STATE} = 'defined'; $hash->{NOTIFYDEV} = "global"; - + return undef; } @@ -176,22 +176,22 @@ LGTV_IP12_Get($@) my ($hash, @a) = @_; my $what; my $return; - + return "argument is missing" if(int(@a) != 2); - + $what = $a[1]; - + return ReadingsVal($hash->{NAME}, $what, "") if(defined(ReadingsVal($hash->{NAME}, $what, undef))); - + $return = "unknown argument $what, choose one of"; - + foreach my $reading (keys %{$hash->{READINGS}}) { $return .= " $reading:noArg"; } - + return $return; - + } ################################# @@ -200,9 +200,9 @@ LGTV_IP12_Notify($$) { my ($hash,$dev) = @_; my $name = $hash->{NAME}; - + return unless(exists($dev->{NAME}) and $dev->{NAME} eq "global"); - + if(grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})) { if(defined(AttrVal($name, "pairingcode", undef)) and AttrVal($name, "pairingcode", undef) =~/^\d{6}$/) @@ -210,7 +210,7 @@ LGTV_IP12_Notify($$) Log3 $name, 3, "LGTV_IP12 ($name) - try pairing with pairingcode ".AttrVal($name, "pairingcode", undef); LGTV_IP12_Pair($hash, AttrVal($name, "pairingcode", undef)); } - + LGTV_IP12_ResetTimer($hash, 0); } elsif(grep(m/^(?:ATTR $name disable.*|DELETEATTR $name disable.*)$/, @{$dev->{CHANGED}})) @@ -251,19 +251,19 @@ LGTV_IP12_Set($@) { LGTV_IP12_ResetTimer($hash, 0); } - + my $new_channel; - + if($what eq "channelUp" or $what eq "channelDown") { my $current_channel = ReadingsVal($name, "channel", undef); - + if(defined($current_channel) and $current_channel =~ /^\d+$/ and $current_channel > 0) { my $found = 0; - - $new_channel = (grep { $found++ < 1; } grep { ($what eq "channelUp" ? $_ > $current_channel : $_ < $current_channel ) } sort { ($what eq "channelUp" ? $a <=> $b : $b <=> $a) } grep { defined($_) and /^\d+$/ } keys %{$hash->{helper}{CHANNEL_LIST}})[0]; - + + $new_channel = (grep { $found++ < 1; } grep { ($what eq "channelUp" ? $_ > $current_channel : $_ < $current_channel ) } sort { ($what eq "channelUp" ? $a <=> $b : $b <=> $a) } grep { defined($_) and /^\d+$/ } keys %{$hash->{helper}{CHANNEL_LIST}})[0]; + } } elsif($what eq "channel" and exists($hash->{helper}{CHANNEL_LIST}) and exists($hash->{helper}{CHANNEL_LIST}{$arg})) @@ -274,18 +274,18 @@ LGTV_IP12_Set($@) { return $usage; } - + if(defined($new_channel)) { - Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - set new channel: $new_channel"; - + Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - set new channel: $new_channel"; + my $xml = "<api type=\"command\"><name>HandleChannelChange</name>"; $xml .= "<major>".$hash->{helper}{CHANNEL_LIST}{$new_channel}{major}."</major>"; $xml .= "<minor>".$hash->{helper}{CHANNEL_LIST}{$new_channel}{minor}."</minor>"; $xml .= "<sourceIndex>".$hash->{helper}{CHANNEL_LIST}{$new_channel}{sourceIndex}."</sourceIndex>"; - $xml .= "<physicalNum>".$hash->{helper}{CHANNEL_LIST}{$new_channel}{physicalNum}."</physicalNum>"; + $xml .= "<physicalNum>".$hash->{helper}{CHANNEL_LIST}{$new_channel}{physicalNum}."</physicalNum>"; $xml .= "</api>"; - + LGTV_IP12_HttpGet($hash, "/udap/api/command", "channel", $new_channel, $xml); } } @@ -340,7 +340,7 @@ LGTV_IP12_Attr(@) elsif($a[0] eq "del" && $a[2] eq "disable") { LGTV_IP12_ResetTimer($hash, 0); - } + } return undef; } @@ -350,7 +350,7 @@ sub LGTV_IP12_Delete($$) { my ($hash, $name) = @_; - # unpairing + # unpairing LGTV_IP12_HttpGet($hash, "/udap/api/pairing", "removePairing", undef, "<api type=\"pairing\"><name>byebye</name><port>8080</port></api>") if(exists($hash->{helper}{PAIRED}) and $hash->{helper}{PAIRED} == 1); } @@ -373,7 +373,7 @@ LGTV_IP12_Undef($$) ################################# # start a status request by starting the neccessary requests -sub +sub LGTV_IP12_GetStatus($) { my ($hash) = @_; @@ -382,12 +382,12 @@ LGTV_IP12_GetStatus($) { LGTV_IP12_HttpGet($hash, "/udap/api/data?target=channel_list", "statusRequest", "channelList", undef); } - + unless(exists($hash->{helper}{APP_LIST}) and ReadingsVal($hash->{NAME}, "state", "off") eq "on") { LGTV_IP12_HttpGet($hash, "/udap/api/data?target=applist_get&type=1&index=0&number=0", "statusRequest", "appList", undef); } - + LGTV_IP12_HttpGet($hash, "/udap/api/data?target=cur_channel", "statusRequest", "currentChannel"); LGTV_IP12_HttpGet($hash, "/udap/api/data?target=volume_info", "statusRequest", "volumeInfo"); @@ -403,16 +403,16 @@ sub LGTV_IP12_ParseHttpResponse($$$) { - my ( $param, $err, $data ) = @_; - + my ( $param, $err, $data ) = @_; + my $hash = $param->{hash}; my $name = $hash->{NAME}; my $cmd = $param->{cmd}; my $arg = $param->{arg}; - + $err = "" unless(defined($err)); $data = "" unless(defined($data)); - + # we successfully received a HTTP status code in the response if($data eq "" and exists($param->{code})) { @@ -420,7 +420,7 @@ LGTV_IP12_ParseHttpResponse($$$) if($param->{code} eq 401) { Log3 $name, 3, "LGTV_IP12 ($name) - failed to execute \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\": Device is not paired"; - + if(exists($hash->{helper}{PAIRED})) { if($hash->{helper}{PAIRED} == 1) @@ -428,7 +428,7 @@ LGTV_IP12_ParseHttpResponse($$$) $hash->{helper}{PAIRED} = 0; } } - + # If a pairing code is set as attribute, try one repair (when $hash->{helper}{PAIRED} == -1) if(defined(AttrVal($name, "pairingcode", undef)) and AttrVal($name, "pairingcode", undef) =~/^\d{6}$/) { @@ -437,7 +437,7 @@ LGTV_IP12_ParseHttpResponse($$$) return; } } - + if($cmd eq "channel" and $param->{code} == 200) { readingsSingleUpdate($hash, $cmd, $arg, 1); @@ -445,18 +445,18 @@ LGTV_IP12_ParseHttpResponse($$$) return; } } - + readingsBeginUpdate($hash); - + # if an error was occured, raise a log entry if($err ne "") { Log3 $name, 5, "LGTV_IP12 ($name) - could not execute command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" - $err"; - + readingsBulkUpdate($hash, "state", "off"); readingsBulkUpdate($hash, "power", "off"); } - + # if the response contains data, examine it. if($data ne "") { @@ -464,7 +464,7 @@ LGTV_IP12_ParseHttpResponse($$$) readingsBulkUpdate($hash, "state", "on"); readingsBulkUpdate($hash, "power", "on"); - + if($cmd eq "statusRequest") { if($arg eq "volumeInfo") @@ -473,41 +473,41 @@ LGTV_IP12_ParseHttpResponse($$$) { readingsBulkUpdate($hash, "volume", $1); } - + if($data =~ /<mute>(.+?)<\/mute>/) { readingsBulkUpdate($hash, "mute", ($1 eq "true" ? "on" : "off")); } } - + if($arg eq "currentChannel") { if($data =~ /<inputSourceName>(.+?)<\/inputSourceName>/) { readingsBulkUpdate($hash, "input", LGTV_IP12_html2txt($1)); } - + if($data =~ /<labelName>(.+?)<\/labelName>/) { readingsBulkUpdate($hash, "inputLabel", LGTV_IP12_html2txt($1)); } - + if($data =~ /<chname>(.+?)<\/chname>/) { readingsBulkUpdate($hash, "channelName", LGTV_IP12_html2txt($1)); } - + if($data =~ /<major>(.+?)<\/major>/) { readingsBulkUpdate($hash, "channel", $1); } - + if($data =~ /<progName>(.+?)<\/progName>/) { readingsBulkUpdate($hash, "currentProgram", LGTV_IP12_html2txt($1)); } } - + if($arg eq "is3d") { if($data =~ /<is3D>(.+?)<\/is3D>/) @@ -515,7 +515,7 @@ LGTV_IP12_ParseHttpResponse($$$) readingsBulkUpdate($hash, "3D", $1); } } - + if($arg eq "appList") { while($data =~ /<data><auid>([0-9a-f]+)<\/auid><name>\s*([^<]+?)\s*<\/name><type>(\d+)<\/type><cpid>([\w\d_-]*)<\/cpid>.*?<\/data>/gci) @@ -530,11 +530,11 @@ LGTV_IP12_ParseHttpResponse($$$) $hash->{helper}{APP_LIST}{$index}{cpid} = $fields[3]; } } - + if($arg eq "channelList") { delete($hash->{helper}{CHANNEL_LIST}) if(exists($hash->{helper}{CHANNEL_LIST})); - + while($data =~ /<data>(.+?)<\/data>/gc) { my $channel = $1; @@ -542,22 +542,22 @@ LGTV_IP12_ParseHttpResponse($$$) { my $channel_major = $1; $hash->{helper}{CHANNEL_LIST}{$channel_major}{major} = $channel_major; - + if($channel =~ /<minor>(\d+?)<\/minor>/) { $hash->{helper}{CHANNEL_LIST}{$channel_major}{minor} = $1; } - + if($channel =~ /<sourceIndex>(\d+?)<\/sourceIndex>/) { $hash->{helper}{CHANNEL_LIST}{$channel_major}{sourceIndex} = $1; } - + if($channel =~ /<physicalNum>(\d+?)<\/physicalNum>/) { $hash->{helper}{CHANNEL_LIST}{$channel_major}{physicalNum} = $1; } - + if($channel =~ /<chname>(.+?)<\/chname>/) { Log3 $name, 5 , "LGTV_IP12 ($name) - adding channel ".LGTV_IP12_html2txt($1); @@ -568,7 +568,7 @@ LGTV_IP12_ParseHttpResponse($$$) } } } - + readingsEndUpdate($hash, 1); } @@ -581,7 +581,7 @@ LGTV_IP12_HttpGet($$$$;$) if(defined($data)) { - Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - sending POST request for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" to url $path: $data"; + Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - sending POST request for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" to url $path: $data"; # start a HTTP POST on the given url with content data HttpUtils_NonblockingGet({ url => "http://".$hash->{HOST}.":8080".$path, @@ -599,8 +599,8 @@ LGTV_IP12_HttpGet($$$$;$) } else { - Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - sending GET request for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" to url $path"; - + Log3 $hash->{NAME}, 5 , "LGTV_IP12 (".$hash->{NAME}.") - sending GET request for command \"$cmd".(defined($arg) ? " ".(split("\\|", $arg))[0] : "")."\" to url $path"; + # start a HTTP GET on the given url HttpUtils_NonblockingGet({ url => "http://".$hash->{HOST}.":8080".$path, @@ -623,8 +623,8 @@ sub LGTV_IP12_Pair($$) { my ($hash, $code) = @_; - - LGTV_IP12_HttpGet($hash, "/udap/api/pairing", "pairing", $code, "<api type=\"pairing\"><name>hello</name><value>$code</value><port>8080</port></api>"); + + LGTV_IP12_HttpGet($hash, "/udap/api/pairing", "pairing", $code, "<api type=\"pairing\"><name>hello</name><value>$code</value><port>8080</port></api>"); } @@ -633,9 +633,9 @@ LGTV_IP12_Pair($$) sub LGTV_IP12_ResetTimer($;$) { my ($hash, $interval) = @_; - + RemoveInternalTimer($hash); - + unless(IsDisabled($hash->{NAME})) { if(defined($interval)) @@ -651,7 +651,7 @@ sub LGTV_IP12_ResetTimer($;$) InternalTimer(gettimeofday()+$hash->{helper}{OFF_INTERVAL}, "LGTV_IP12_GetStatus", $hash, 0); } } - + return undef; } ############################# @@ -671,7 +671,7 @@ sub LGTV_IP12_html2txt($) $string =~ s/(\xfc|ü)/ü/g; $string =~ s/(\xdc|Ü)/Ü/g; $string =~ s/(\xdf|ß)/ß/g; - + $string =~ s/<.+?>//g; $string =~ s/(^\s+|\s+$)//g; @@ -683,7 +683,7 @@ sub LGTV_IP12_html2txt($) =pod =item device =item summary controls LG SmartTV's build between 2012-2014 via LAN connection -=item summary_DE steuert LG SmartTV's, welche zwischen 2012-2014 hergestellt wurden, via LAN-Verbindung +=item summary_DE steuert LG SmartTV's via LAN, welche zwischen 2012-2014 hergestellt wurden =begin html <a name="LGTV_IP12"></a> @@ -703,31 +703,31 @@ sub LGTV_IP12_html2txt($) define <name> LGTV_IP12 <ip-address> [<off_status_interval>] [<on_status_interval>] </code> <br><br> - + Defining a LGTV_IP12 device will schedule an internal task (interval can be set with optional parameter <status_interval> in seconds, if not set, the value is 30 seconds), which periodically reads the status of the TV (power state, current channel, input, ...) and triggers notify/FileLog commands. <br><br> - Different status update intervals depending on the power state can be given also. - If two intervals are given to the define statement, the first interval statement represents the status update - interval in seconds in case the device is off. The second + Different status update intervals depending on the power state can be given also. + If two intervals are given to the define statement, the first interval statement represents the status update + interval in seconds in case the device is off. The second interval statement is used when the device is on. - + Example:<br><br> <ul><code> define TV LGTV_IP12 192.168.0.10 <br><br> # With custom status interval of 60 seconds<br> - define TV LGTV_IP12 192.168.0.10 60 + define TV LGTV_IP12 192.168.0.10 60 <br><br> # With custom "off"-interval of 60 seconds and "on"-interval of 10 seconds<br> define TV LGTV_IP12 192.168.0.10 60 10 </code></ul> - + </ul> <br><br> - + <a name="LGTV_IP12_set"></a> <b>Set </b> <ul> @@ -769,7 +769,7 @@ sub LGTV_IP12_html2txt($) <li><a name="LGTV_IP12_disabledForIntervals">disabledForIntervals</a> HH:MM-HH:MM HH:MM-HH-MM...</li> Optional attribute to disable the internal cyclic status update of the TV during a specific time interval. The attribute contains a space separated list of HH:MM tupels. If the current time is between any of these time specifications, the cyclic update will be disabled. - Instead of HH:MM you can also specify HH or HH:MM:SS. + Instead of HH:MM you can also specify HH or HH:MM:SS. <br><br>To specify an interval spawning midnight, you have to specify two intervals, e.g.: <pre>23:00-24:00 00:00-01:00</pre> Default Value is <i>empty</i> (no intervals defined, cyclic update is always active)<br><br> @@ -815,13 +815,13 @@ sub LGTV_IP12_html2txt($) define <name> LGTV_IP12 <IP-Addresse> [<Off_Interval>] [<On_Interval>] </code> <br><br> - Bei der Definition eines LGTV_IP12-Moduls wird eine interne Routine in Gang gesetzt, welche regelmäßig + Bei der Definition eines LGTV_IP12-Moduls wird eine interne Routine in Gang gesetzt, welche regelmäßig (einstellbar durch den optionalen Parameter <code><Status_Interval></code>; falls nicht gesetzt ist der Standardwert 30 Sekunden) den Status des TV abfragt und entsprechende Notify-/FileLog-Definitionen triggert. <br><br> Sofern 2 Interval-Argumente übergeben werden, wird der erste Parameter <code><Off_Interval></code> genutzt - sofern der TV ausgeschaltet ist. Der zweiter Parameter <code><On_Interval></code> - wird verwendet, sofern der TV eingeschaltet ist. + sofern der TV ausgeschaltet ist. Der zweiter Parameter <code><On_Interval></code> + wird verwendet, sofern der TV eingeschaltet ist. <br><br> Beispiel:<br><br> <ul><code> @@ -847,9 +847,9 @@ sub LGTV_IP12_html2txt($) <li><b>channelUp</b>   -   schaltet auf den nächsten Kanal um </li> <li><b>channelDown</b>   -   schaltet auf den vorherigen Kanal um </li> <li><b>removePairing</b>   -   löscht das Pairing zwischen FHEM und dem TV</li> - <li><b>showPairCode</b>   -   zeigt den Pair-Code auf dem TV-Bildschirm an. Dieser Code muss im Attribut <a href="#LGTV_IP12_pairingcode">pairingcode</a> gesetzt werden, damit FHEM mit dem TV kommunizieren kann.</li> - <li><b>startApp</b> <Name>  -   startet eine installierte App</li> - <li><b>stopApp</b> <Name>  -   stoppt eine laufende App</li> + <li><b>showPairCode</b>   -   zeigt den Pair-Code auf dem TV-Bildschirm an. Dieser Code muss im Attribut <a href="#LGTV_IP12_pairingcode">pairingcode</a> gesetzt werden, damit FHEM mit dem TV kommunizieren kann.</li> + <li><b>startApp</b> <Name>  -   startet eine installierte App</li> + <li><b>stopApp</b> <Name>  -   stoppt eine laufende App</li> <li><b>statusRequest</b>   -   fragt den aktuellen Status ab</li> <li><b>remoteControl</b> up,down,...   -   sendet Fernbedienungsbefehle</li> </ul> @@ -866,7 +866,7 @@ sub LGTV_IP12_html2txt($) <a name="LGTV_IP12_attr"></a> <b>Attribute</b> <ul> - + <li><a href="#do_not_notify">do_not_notify</a></li> <li><a href="#readingFnAttributes">readingFnAttributes</a></li><br> <li><a name="LGTV_IP12_disable">disable</a></li> diff --git a/fhem/FHEM/98_version.pm b/fhem/FHEM/98_version.pm index b973302cc..5839757c4 100755 --- a/fhem/FHEM/98_version.pm +++ b/fhem/FHEM/98_version.pm @@ -15,14 +15,14 @@ sub CommandVersion($$) { my ($cl, $param) = @_; - + my $noheader = ($param =~ s/(?:^\s*|\s+)noheader\s*$//); eval { "test" =~ /$param/ }; return "invalid filter regexp" if($@); - + my @ret; - my $max = 0; + my $max = 0; my $modpath = (exists($attr{global}{modpath}) ? $attr{global}{modpath} : ""); my @files = map {$INC{$_}} keys %INC; push @files, $0; # path to fhem.pl @@ -30,7 +30,7 @@ CommandVersion($$) @files = () if($param && $param eq "revision"); foreach my $fn (@files) { next unless($fn); - next unless($fn =~ /^(?:$modpath.?)?FHEM/ or $fn =~ /fhem.pl$/); # configDB + next unless($fn =~ /^(?:$modpath.?)?FHEM/ or $fn =~ /fhem.pl$/); # configDB my $mod_name = ($fn=~ /[\/\\]([^\/\\]+)$/ ? $1 : $fn); next if($param ne "" && $mod_name !~ /$param/); next if(grep(/$mod_name/, @ret)); @@ -39,7 +39,7 @@ CommandVersion($$) $max = length($mod_name) if($max < length($mod_name)); my $line; - + if(!open(FH, $fn)) { $line = "$fn: $!"; if(configDBUsed()){ @@ -59,12 +59,12 @@ CommandVersion($$) $line = "No Id found for $mod_name" unless($line); push @ret, $line; } - + my $fhem_revision = version_getRevFromControls(); - + $fhem_revision = "Latest Revision: $fhem_revision\n\n" if(defined($fhem_revision) && !$noheader); - - @ret = map {/\$Id\: (\S+?) (\d+?) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}Z \S+?) \$/ ? sprintf("%-".$max."s %5d %s",$1,$2,$3) : $_} @ret; + + @ret = map {/\$Id\: (\S+?) (\d+?) (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}Z \S+?) \$/ ? sprintf("%-".$max."s %5d %s",$1,$2,$3) : $_} @ret; @ret = sort {version_sortModules($a, $b)} grep {($param ne "" ? /$param/ : 1)} @ret; return "no loaded modules found that match: $param" if($param ne "" && $param ne "revision" && !@ret); return (((!$param && !$noheader) || $param eq "revision") ? $fhem_revision : ""). @@ -81,14 +81,14 @@ sub version_sortModules($$) $a =~ s/^(?:No Id found for |#\s*\$Id\: )//; $b =~ s/^(?:No Id found for |#\s*\$Id\: )//; - + my @a_vals = split(' ', $a); my @b_vals = split(' ', $b); # fhem.pl always at top - return -1 if($a_vals[0] eq "fhem.pl"); + return -1 if($a_vals[0] eq "fhem.pl"); return 1 if($b_vals[0] eq "fhem.pl"); - + $a_vals[0] =~ s/^\d\d_//; $b_vals[0] =~ s/^\d\d_//; @@ -130,7 +130,7 @@ sub version_getRevFromControls(;$) <code>version [<filter>|revision] [noheader]</code> <br><br> List the version of fhem.pl and all loaded modules. The optional parameter - can be used to filter the ouput. The special filter value "revision" shows + can be used to filter the ouput. The special filter value "revision" shows only the latest revision number since the last update.<br><br> The optional flag <code>noheader</code> disables the output of the header lines (Latest Revision, File, Rev, Last Change). <br><br> @@ -152,16 +152,16 @@ sub version_getRevFromControls(;$) <br> Example output of <code>version fhem.pl</code>: <ul> - <code><br> + <code><br> File             Rev   Last Change<br><br> - fhem.pl          10397 2016-01-07 08:36:49Z rudolfkoenig<br> + fhem.pl          10397 2016-01-07 08:36:49Z rudolfkoenig<br> </code> </ul> <br> Example output of <code>version fhem.pl noheader</code>: <ul> - <code><br> - fhem.pl 10397 2016-01-07 08:36:49Z rudolfkoenig<br> + <code><br> + fhem.pl 10397 2016-01-07 08:36:49Z rudolfkoenig<br> </code> </ul> </ul> @@ -185,7 +185,7 @@ sub version_getRevFromControls(;$) <br><br> Beispiel der Ausgabe von <code>version</code>: <ul> - <code><br> + <code><br> Latest Revision: 10814<br><br> File             Rev   Last Change<br><br> fhem.pl          10769 2016-02-08 12:11:51Z rudolfkoenig<br> @@ -199,16 +199,16 @@ sub version_getRevFromControls(;$) <br> Beispiel der Ausgabe von <code>version fhem</code>: <ul> - <code><br> + <code><br> File             Rev   Last Change<br><br> - fhem.pl          10769 2016-02-08 12:11:51Z rudolfkoenig<br> + fhem.pl          10769 2016-02-08 12:11:51Z rudolfkoenig<br> </code> </ul> <br> Beispiel der Ausgabe von <code>version fhem.pl noheader</code>: <ul> - <code><br> - fhem.pl 10769 2016-02-08 12:11:51Z rudolfkoenig<br> + <code><br> + fhem.pl 10769 2016-02-08 12:11:51Z rudolfkoenig<br> </code> </ul> </ul>