diff --git a/fhem/CHANGED b/fhem/CHANGED index 6b6a59386..f813bc3c8 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - changed: 70_BRAVIA: optimized command queue, + introduced own package, + new reading application - feature: 93_Log2Syslog: parseProfile = Automatic for automatic protocol detection (default) if a collector is defined - feature: 93_DbRep: attribute "sqlCmdVars" to set SQL variables or PRAGMA diff --git a/fhem/FHEM/70_BOTVAC.pm b/fhem/FHEM/70_BOTVAC.pm index 3b6fb566e..25aa60f12 100755 --- a/fhem/FHEM/70_BOTVAC.pm +++ b/fhem/FHEM/70_BOTVAC.pm @@ -165,7 +165,7 @@ sub GetStatus($;$) { my $name = $hash->{NAME}; my $interval = $hash->{INTERVAL}; my @successor = (); - + Log3($name, 5, "BOTVAC $name: called function GetStatus()"); # use actionInterval if state is busy or paused @@ -260,7 +260,7 @@ sub Set($@) { $usage .= " findMe:noArg" if ( GetServiceVersion($hash, "findMe") eq "basic-1" ); $usage .= " startManual:noArg" if ( GetServiceVersion($hash, "manualCleaning") ne "" ); $usage .= " statusRequest:noArg schedule:on,off syncRobots:noArg"; - + # house cleaning $usage .= " nextCleaningMode:eco,turbo" if ($houseCleaningSrv =~ /basic-\d/); $usage .= " nextCleaningNavigationMode:normal,extra#care" if ($houseCleaningSrv eq "minimal-2"); @@ -442,7 +442,7 @@ sub Set($@) { Log3($name, 2, "BOTVAC Can't set robot, run 'syncRobots' before"); } } - + # reloadMaps elsif ( $a[1] eq "reloadMaps" ) { Log3($name, 2, "BOTVAC set $name $arg"); @@ -490,7 +490,7 @@ sub Set($@) { readingsSingleUpdate($hash, $a[1], $a[2], 0); } - + # wsCommand || wsCommand elsif ( $a[1] =~ /wsCombo|wsCommand/) { Log3($name, 2, "BOTVAC set $name $arg"); @@ -500,7 +500,7 @@ sub Set($@) { my $cmd = ($a[1] eq "wsCombo" ? "combo" : "command"); wsEncode($hash, "{ \"$cmd\": \"$a[2]\" }"); } - + # password elsif ( $a[1] eq "password") { Log3($name, 2, "BOTVAC set $name " . $a[1]); @@ -619,7 +619,7 @@ sub SendCommand($$;$$@) { my $URL = "https://"; my $response; my $return; - + my %sslArgs; if ($service ne "sessions" && $service ne "dashboard") { @@ -687,7 +687,7 @@ sub SendCommand($$;$$@) { $data .= "\"category\":2"; $data .= ",\"mode\":"; $data .= (GetCleaningParameter($hash, "cleaningMode", "eco") eq "eco" ? "1" : "2"); - $data .= ",\"modifier\":1"; + $data .= ",\"modifier\":1"; } elsif ($version eq "minimal-2") { $data .= "\"category\":2"; $data .= ",\"navigationMode\":"; @@ -711,7 +711,7 @@ sub SendCommand($$;$$@) { my $zone = GetCleaningParameter($hash, "cleaningZone", ""); $data .= ",\"boundaryId\":\"".$zone."\"" if ($zone ne ""); } - } + } $data .= "}"; } elsif ($cmd eq "startSpot") { @@ -724,7 +724,7 @@ sub SendCommand($$;$$@) { $data .= (GetCleaningParameter($hash, "cleaningMode", "eco") eq "eco" ? "1" : "2"); } if ($version eq "basic-1" or $version eq "minimal-2") { - $data .= ",\"modifier\":"; + $data .= ",\"modifier\":"; $data .= (GetCleaningParameter($hash, "cleaningModifier", "normal") eq "normal" ? "1" : "2"); } if ($version eq "micro-2" or $version eq "minimal-2") { @@ -732,14 +732,14 @@ sub SendCommand($$;$$@) { $data .= (GetCleaningParameter($hash, "cleaningNavigationMode", "normal") eq "normal" ? "1" : "2"); } if ($version eq "basic-1" or $version eq "basic-3") { - $data .= ",\"spotWidth\":"; + $data .= ",\"spotWidth\":"; $data .= GetCleaningParameter($hash, "cleaningSpotWidth", "200"); - $data .= ",\"spotHeight\":"; + $data .= ",\"spotHeight\":"; $data .= GetCleaningParameter($hash, "cleaningSpotHeight", "200"); - } + } $data .= "}"; } - elsif ($cmd eq "setMapBoundaries" or $cmd eq "getMapBoundaries") { + elsif ($cmd eq "setMapBoundaries" or $cmd eq "getMapBoundaries") { if (defined($option) and ref($option) eq "HASH") { $data .= ",\"params\":{"; foreach( keys %$option ) { @@ -749,7 +749,7 @@ sub SendCommand($$;$$@) { $data .= "}"; } } - + $data .= "}"; my $now = time(); @@ -804,7 +804,7 @@ sub ReceiveCommand($$$) { my @successor = @{$param->{successor}}; my $rc = ( $param->{buf} ) ? $param->{buf} : $param; - + my $loadMap; my $return; my $reqId = 0; @@ -824,7 +824,7 @@ sub ReceiveCommand($$$) { # keep last state #readingsBulkUpdateIfChanged( $hash, "state", "Error" ); - + # stop pulling for current interval Log3($name, 4, "BOTVAC $name: drop successors"); LogSuccessors($hash, @successor); @@ -833,7 +833,7 @@ sub ReceiveCommand($$$) { # data received elsif ($data) { - + if ( !defined($cmd) ) { Log3($name, 4, "BOTVAC $name: RCV $service"); } else { @@ -945,13 +945,13 @@ sub ReceiveCommand($$$) { } } } - + #remove outdated calendar information foreach ( keys %currentEvents ) { delete( $hash->{READINGS}{$_} ); } } - } + } elsif ( $cmd eq "getMapBoundaries" ) { if ( ref($return->{data}) eq "HASH" ) { $reqId = $return->{reqId}; @@ -997,7 +997,7 @@ sub ReceiveCommand($$$) { readingsBulkUpdateIfChanged($hash, "floorplan_".$reqId."_zones", $zonesList); } } - } + } elsif ( $cmd eq "getGeneralInfo" ) { if ( ref($return->{data}) eq "HASH" ) { my $generalInfo = $return->{data}; @@ -1017,11 +1017,11 @@ sub ReceiveCommand($$$) { # sendToBase, setMapBoundaries, getRobotManualCleaningInfo if ( ref($return) eq "HASH" ) { push(@successor , ["robots", "maps"]) - if ($cmd eq "setMapBoundaries" or + if ($cmd eq "setMapBoundaries" or (defined($return->{state}) and ($return->{state} == 1 or $return->{state} == 4) and # Idle or Error $return->{state} != ReadingsNum($name, "stateId", $return->{state}))); - + #readingsBulkUpdateIfChanged($hash, "version", $return->{version}); #readingsBulkUpdateIfChanged($hash, "data", $return->{data}); readingsBulkUpdateIfChanged($hash, "result", $return->{result}) if (defined($return->{result})); @@ -1090,14 +1090,14 @@ sub ReceiveCommand($$$) { } } } - + # Sessions elsif ( $service eq "sessions" ) { if ( ref($return) eq "HASH" and defined($return->{access_token})) { readingsBulkUpdateIfChanged($hash, ".accessToken", $return->{access_token}); } } - + # dashboard elsif ( $service eq "dashboard" ) { if ( ref($return) eq "HASH" ) { @@ -1121,7 +1121,7 @@ sub ReceiveCommand($$$) { $hash->{helper}{ROBOTS} = \@robotList; SetRobot($hash, ReadingsNum($name, "robot", 0)); - + push(@successor , ["robots", "maps"]); } } @@ -1167,7 +1167,7 @@ sub ReceiveCommand($$$) { } } } - + # loadmap elsif ( $service eq "loadmap" ) { readingsBulkUpdate($hash, ".map_cache", $data) @@ -1181,12 +1181,12 @@ sub ReceiveCommand($$$) { } readingsEndUpdate( $hash, 1 ); - + if ($loadMap) { my $url = ReadingsVal($name, ".map_url", ""); push(@successor , ["loadmap", $url]) if ($url ne ""); } - + if (@successor) { my @nextCmd = @{shift(@successor)}; my $cmdLength = @nextCmd; @@ -1279,13 +1279,13 @@ sub StorePassword($$) { $key = Digest::MD5::md5_hex(unpack "H*", $key); $key .= Digest::MD5::md5_hex($key); } - + for my $char (split //, $password) { my $encode=chop($key); $enc_pwd.=sprintf("%.2x",ord($char)^ord($encode)); $key=$encode.$key; } - + my $err = setKeyValue($index, $enc_pwd); return "error while saving the password - $err" if(defined($err)); @@ -1298,16 +1298,16 @@ sub ReadPassword($) { my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd"; my $key = getUniqueId().$index; my ($password, $err); - + Log3($name, 4, "BOTVAC $name: Read password from file"); - + ($err, $password) = getKeyValue($index); if ( defined($err) ) { Log3($name, 3, "BOTVAC $name: unable to read password from file: $err"); - return undef; + return undef; } - + if ( defined($password) ) { if ( eval "use Digest::MD5;1" ) { $key = Digest::MD5::md5_hex(unpack "H*", $key); @@ -1333,22 +1333,22 @@ sub CheckRegistration($$$$$) { if (ReadingsVal($name, ".secretKey", "") eq "") { my @nextCmd = ($service, $cmd, $option); unshift(@successor, [$service, $cmd, $option]); - - my @succ_item; - my $msg = " successor:"; - for (my $i = 0; $i < @successor; $i++) { - @succ_item = @{$successor[$i]}; - $msg .= " $i: "; - $msg .= join(",", map { defined($_) ? $_ : '' } @succ_item); - } - Log3($name, 4, "BOTVAC created".$msg); - + + my @succ_item; + my $msg = " successor:"; + for (my $i = 0; $i < @successor; $i++) { + @succ_item = @{$successor[$i]}; + $msg .= " $i: "; + $msg .= join(",", map { defined($_) ? $_ : '' } @succ_item); + } + Log3($name, 4, "BOTVAC created".$msg); + SendCommand($hash, "sessions", undef, undef, @successor) if (ReadingsVal($name, ".accessToken", "") eq ""); SendCommand($hash, "dashboard", undef, undef, @successor) if (ReadingsVal($name, ".accessToken", "") ne ""); - + return 1; } - + return; } @@ -1557,15 +1557,14 @@ sub LogSuccessors($@) { my ($hash,@successor) = @_; my $name = $hash->{NAME}; - my $msg = "BOTVAC $name: RCV successors"; + my $msg = "BOTVAC $name: successors"; my @succ_item; for (my $i = 0; $i < @successor; $i++) { @succ_item = @{$successor[$i]}; $msg .= " $i: "; $msg .= join(",", map { defined($_) ? $_ : '' } @succ_item); } - Log3($name, 4, $msg); - + Log3($name, 4, $msg) if (@successor > 0); } sub ShowMap($;$$) { @@ -1575,23 +1574,23 @@ sub ShowMap($;$$) { $img .= ' width="'.$width.'"' if (defined($width)); $img .= ' width="'.$height.'"' if (defined($height)); $img .= ' alt="Map currently not available">'; - + return $img; } sub GetMap() { my ($request) = @_; - + if ($request =~ /^\/BOTVAC\/(\w+)\/map/) { my $name = $1; my $width = $3; my $height = $5; - + return ("image/png", ReadingsVal($name, ".map_cache", "")); } return ("text/plain; charset=utf-8", "No BOTVAC device for webhook $request"); - + } ####################################### @@ -1604,7 +1603,7 @@ sub wsOpen($$$) { Log3($name, 4, "BOTVAC(ws) $name: Establishing socket connection"); $hash->{DeviceName} = join(':', $ip_address, $port); - ::DevIo_CloseDev($hash) if(::DevIo_IsOpen($hash)); + ::DevIo_CloseDev($hash) if(::DevIo_IsOpen($hash)); if (::DevIo_OpenDev($hash, 0, "BOTVAC::wsHandshake")) { Log3($name, 2, "BOTVAC(ws) $name: ERROR: Can't open websocket to $hash->{DeviceName}"); @@ -1640,7 +1639,7 @@ sub wsHandshake($) { my $date = FmtDateTimeRFC1123($now); my $message = lc($serial) . "\n" . $date . "\n"; my $hmac = hmac_sha256_hex($message, ReadingsVal($name, ".secretKey", "")); - + my $wsHandshakeCmd = "GET $path HTTP/1.1\r\n"; $wsHandshakeCmd .= "Host: $host:$port\r\n"; $wsHandshakeCmd .= "Sec-WebSocket-Key: $wsKey\r\n"; @@ -1650,13 +1649,13 @@ sub wsHandshake($) { $wsHandshakeCmd .= "Date: $date\r\n"; $wsHandshakeCmd .= "Authorization: NEATOAPP $hmac\r\n"; $wsHandshakeCmd .= "Connection: Upgrade\r\n"; - $wsHandshakeCmd .= "\r\n"; - + $wsHandshakeCmd .= "\r\n"; + Log3($name, 4, "BOTVAC(ws) $name: Starting Websocket Handshake"); wsWrite($hash,$wsHandshakeCmd); - + $hash->{HELPER}{wsKey} = $wsKey; - + return undef; } @@ -1696,7 +1695,7 @@ sub wsCheckHandshake($$) { sub wsWrite($@) { my ($hash,$string) = @_; my $name = $hash->{NAME}; - + Log3($name, 4, "BOTVAC(ws) $name: WriteFn called:\n$string"); ::DevIo_SimpleWrite($hash, $string, 0); @@ -1728,7 +1727,7 @@ sub wsCallback(@) { my ($param, $err, $data) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; - + if($err){ Log3($name, 3, "received callback with error:\n$err"); } elsif($data){ @@ -1793,10 +1792,10 @@ sub wsEncode($$;$$) { $wsString .= pack 'N', $len >> 32; $wsString .= pack 'N', ($len & 0xffffffff); } - if ($masked) { + if ($masked) { my $mask = pack 'N', int(rand(2**32)); $wsString .= $mask; - $wsString .= wsMasking($payload, $mask); + $wsString .= wsMasking($payload, $mask); } else { $wsString .= $payload; } @@ -1815,9 +1814,9 @@ sub wsPong($) { sub wsDecode($$) { my ($hash,$wsString) = @_; my $name = $hash->{NAME}; - + Log3($name, 5, "BOTVAC(ws) $name: String:\n" . $wsString); - + while (length $wsString) { my $FIN = (ord(substr($wsString,0,1)) & 0b10000000) >> 7; my $OPCODE = (ord(substr($wsString,0,1)) & 0b00001111); @@ -2050,7 +2049,7 @@ sub wsMasking($$) {
diff --git a/fhem/FHEM/70_BRAVIA.pm b/fhem/FHEM/70_BRAVIA.pm index f111a613e..dd0645cf0 100644 --- a/fhem/FHEM/70_BRAVIA.pm +++ b/fhem/FHEM/70_BRAVIA.pm @@ -27,70 +27,163 @@ package main; -use 5.012; use strict; use warnings; + +################################### +sub BRAVIA_Initialize($) { + my ($hash) = @_; + + Log3($hash, 5, "BRAVIA_Initialize: Entering"); + + $hash->{GetFn} = "BRAVIA::Get"; + $hash->{SetFn} = "BRAVIA::Set"; + $hash->{DefFn} = "BRAVIA::Define"; + $hash->{UndefFn} = "BRAVIA::Undefine"; + + $hash->{AttrList} = "disable:0,1 macaddr:textField channelsMax:textField " . $::readingFnAttributes; + + $::data{RC_layout}{BRAVIA_SVG} = "BRAVIA::RClayout_SVG"; + $::data{RC_layout}{BRAVIA} = "BRAVIA::RClayout"; + + $::data{RC_makenotify}{BRAVIA} = "BRAVIA::RCmakenotify"; + + return; +} + +package BRAVIA; + +use strict; +use warnings; +use POSIX; + +use GPUtils qw(:all); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt + use Data::Dumper; use Time::HiRes qw(gettimeofday); use Time::Local; -use HttpUtils; -use SetExtensions; use Encode; use JSON qw(decode_json); use MIME::Base64; use XML::Simple qw(:strict); use IO::Socket; -sub BRAVIA_Set($@); -sub BRAVIA_Get($@); -sub BRAVIA_GetStatus($;$); -sub BRAVIA_Define($$); -sub BRAVIA_Undefine($$); +require "HttpUtils.pm"; -######################### -# Forward declaration for remotecontrol module -#sub BRAVIA_RClayout_TV(); -#sub BRAVIA_RCmakenotify($$); +## Import der FHEM Funktionen +BEGIN { + GP_Import(qw( + AttrVal + createUniqueId + fhem + fhemTimeLocal + InternalTimer + InternalVal + readingsSingleUpdate + readingsBulkUpdate + readingsBulkUpdateIfChanged + readingsBeginUpdate + readingsDelete + readingsEndUpdate + ReadingsNum + ReadingsTimestamp + ReadingsVal + RemoveInternalTimer + Log3 + )) +}; + +sub Set($@); +sub Get($@); +sub GetStatus($;$); +sub Define($$); +sub Undefine($$); ################################### -sub BRAVIA_Initialize($) { - my ($hash) = @_; +sub Define($$) { + my ( $hash, $def ) = @_; + my @a = split( "[ \t][ \t]*", $def ); + my $name = $hash->{NAME}; - Log3 $hash, 5, "BRAVIA_Initialize: Entering"; + Log3($name, 5, "BRAVIA $name: called function Define()"); - $hash->{GetFn} = "BRAVIA_Get"; - $hash->{SetFn} = "BRAVIA_Set"; - $hash->{DefFn} = "BRAVIA_Define"; - $hash->{UndefFn} = "BRAVIA_Undefine"; + if ( int(@a) < 3 ) { + my $msg = + "Wrong syntax: define BRAVIA []"; + Log3($name, 4, $msg); + return $msg; + } - $hash->{AttrList} = "disable:0,1 macaddr:textField channelsMax:textField " . $readingFnAttributes; + $hash->{TYPE} = "BRAVIA"; - $data{RC_layout}{BRAVIA_SVG} = "BRAVIA_RClayout_SVG"; - $data{RC_layout}{BRAVIA} = "BRAVIA_RClayout"; + my $address = $a[2]; + $hash->{helper}{ADDRESS} = $address; - $data{RC_makenotify}{BRAVIA} = "BRAVIA_RCmakenotify"; + # use interval of 45 sec if not defined + my $interval = $a[3] || 45; + $hash->{INTERVAL} = $interval; + + # number of channels read from channellist, maximum 50 + my $channelCount = 50; + $hash->{CHANNELCOUNT} = $channelCount; + + $hash->{helper}{PORT} = { + 'IRCC' => "80", + 'SERVICE' => "80", + 'UPNP' => "52323", + }; + + $hash->{helper}{HEADER} = 'X-CERS-DEVICE-ID: fhem_remote'; + + unless ( defined( AttrVal( $name, "webCmd", undef ) ) ) { + $::attr{$name}{webCmd} = 'volume:channelUp:channelDown'; + } + unless ( defined( AttrVal( $name, "devStateIcon", undef ) ) ) { + $::attr{$name}{devStateIcon} = + 'on:rc_GREEN:off off:rc_YELLOW:on absent:rc_STOP:on'; + } + unless ( defined( AttrVal( $name, "icon", undef ) ) ) { + $::attr{$name}{icon} = 'it_television'; + } + + # start the status update timer + RemoveInternalTimer($hash); + InternalTimer( gettimeofday() + 2, "BRAVIA::GetStatus", $hash, 1 ); + + return; +} + +################################### +sub Undefine($$) { + my ( $hash, $arg ) = @_; + my $name = $hash->{NAME}; + + Log3($name, 5, "BRAVIA $name: called function Undefine()"); + + # Stop the internal GetStatus-Loop and exit + RemoveInternalTimer($hash); return; } ##################################### -sub BRAVIA_GetStatus($;$) { +sub GetStatus($;$) { my ( $hash, $update ) = @_; my $name = $hash->{NAME}; my $interval = $hash->{INTERVAL}; - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_GetStatus()"; + Log3($name, 5, "BRAVIA $name: called function GetStatus()"); RemoveInternalTimer($hash); - InternalTimer( gettimeofday() + $interval, "BRAVIA_GetStatus", $hash, 0 ); + InternalTimer( gettimeofday() + $interval, "BRAVIA::GetStatus", $hash, 0 ); return if ( AttrVal($name, "disable", 0) == 1 ); # check device availability if (!$update) { - BRAVIA_SendCommand( $hash, "getStatus", "xml" ) + SendCommand( $hash, "getStatus", "xml" ) if (ReadingsVal($name, "requestFormat", "xml") eq "xml"); - BRAVIA_SendCommand( $hash, "getStatus", "json" ) + SendCommand( $hash, "getStatus", "json" ) if (ReadingsVal($name, "requestFormat", "json") eq "json"); } @@ -98,12 +191,12 @@ sub BRAVIA_GetStatus($;$) { } ################################### -sub BRAVIA_Get($@) { +sub Get($@) { my ( $hash, @a ) = @_; my $name = $hash->{NAME}; my $what; - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_Get()"; + Log3($name, 5, "BRAVIA $name: called function Get()"); return "argument is missing" if ( int(@a) < 2 ); @@ -121,12 +214,12 @@ sub BRAVIA_Get($@) { else { return -"Unknown argument $what, choose one of power:noArg presence:noArg input:noArg channel:noArg volume:noArg mute:noArg"; + "Unknown argument $what, choose one of power:noArg presence:noArg input:noArg channel:noArg volume:noArg mute:noArg"; } } ################################### -sub BRAVIA_Set($@) { +sub Set($@) { my ( $hash, @a ) = @_; my $name = $hash->{NAME}; my $power = ReadingsVal($name, "power", ""); @@ -146,7 +239,7 @@ sub BRAVIA_Set($@) { my $input = $hash->{helper}{lastInput}; - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_Set()"; + Log3($name, 5, "BRAVIA $name: called function Set()"); return "No Argument given" if ( !defined( $a[1] ) ); @@ -216,30 +309,30 @@ sub BRAVIA_Set($@) { # statusRequest if ( lc( $a[1] ) eq "statusrequest" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); delete $hash->{helper}{device} if ( defined( $hash->{helper}{device} ) ); - BRAVIA_GetStatus($hash); + GetStatus($hash); } # toggle elsif ( $a[1] eq "toggle" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "off" ) { - return BRAVIA_Set( $hash, $name, "on" ); + return Set( $hash, $name, "on" ); } else { - return BRAVIA_Set( $hash, $name, "off" ); + return Set( $hash, $name, "off" ); } } # on elsif ( $a[1] eq "on" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "off" ) { readingsSingleUpdate($hash, "state", "set_on", 1); @@ -251,18 +344,18 @@ sub BRAVIA_Set($@) { ($presence eq "absent" || ReadingsVal($name, "generation", "") eq "1.0.5" || ReadingsVal($name, "generation", "") eq "2.5.0") ) { - $result = BRAVIA_wake( $name, $macAddr ); + $result = wake( $name, $macAddr ); return "wake-up command sent"; } else { $cmd = "POWER"; - BRAVIA_SendCommand( $hash, "ircc", $cmd ); + SendCommand( $hash, "ircc", $cmd ); } } } # off elsif ( $a[1] eq "off" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $presence eq "present" ) { readingsSingleUpdate($hash, "state", "set_off", 1); @@ -271,7 +364,7 @@ sub BRAVIA_Set($@) { } else { $cmd = "POWER"; } - BRAVIA_SendCommand( $hash, "ircc", $cmd ); + SendCommand( $hash, "ircc", $cmd ); } else { return "Device needs to be reachable to toggle standby mode."; } @@ -279,7 +372,7 @@ sub BRAVIA_Set($@) { # volume elsif ( $a[1] eq "volume" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); return "No argument given" if ( !defined( $a[2] ) ); @@ -290,9 +383,9 @@ sub BRAVIA_Set($@) { } else { return -"Argument does not seem to be a valid integer between 1 and 100"; + "Argument does not seem to be a valid integer between 1 and 100"; } - BRAVIA_SendCommand( $hash, "upnp", $cmd ); + SendCommand( $hash, "upnp", $cmd ); readingsSingleUpdate( $hash, "volume", $a[2], 1 ) if ( ReadingsVal($name, "volume", "") ne $a[2] ); @@ -304,7 +397,7 @@ sub BRAVIA_Set($@) { # volumeUp/volumeDown elsif ( lc( $a[1] ) =~ /^(volumeup|volumedown)$/ ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $presence eq "present" ) { if ( lc( $a[1] ) eq "volumeup" ) { @@ -313,7 +406,7 @@ sub BRAVIA_Set($@) { else { $cmd = "VOLDOWN"; } - BRAVIA_SendCommand( $hash, "ircc", $cmd ); + SendCommand( $hash, "ircc", $cmd ); } else { return "Device needs to be ON to adjust volume."; @@ -323,26 +416,26 @@ sub BRAVIA_Set($@) { # mute elsif ( $a[1] eq "mute" ) { if ( defined( $a[2] ) ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); } else { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); } if ( $presence eq "present" ) { if ( !defined( $a[2] ) || $a[2] eq "toggle" ) { - $result = BRAVIA_SendCommand( $hash, "ircc", "MUTE" ); + $result = SendCommand( $hash, "ircc", "MUTE" ); readingsSingleUpdate( $hash, "mute", (ReadingsVal($name, "mute", "") eq "on" ? "off" : "on"), 1 ); } elsif ( $a[2] eq "off" ) { - #$result = BRAVIA_SendCommand( $hash, "MuteOff" ) - $result = BRAVIA_SendCommand( $hash, "upnp", "setMute:0" ); + #$result = SendCommand( $hash, "MuteOff" ) + $result = SendCommand( $hash, "upnp", "setMute:0" ); readingsSingleUpdate( $hash, "mute", $a[2], 1 ) if ( ReadingsVal($name, "mute", "") ne $a[2] ); } elsif ( $a[2] eq "on" ) { - #$result = BRAVIA_SendCommand( $hash, "MuteOn" ) - $result = BRAVIA_SendCommand( $hash, "upnp", "setMute:1" ); + #$result = SendCommand( $hash, "MuteOn" ) + $result = SendCommand( $hash, "upnp", "setMute:1" ); readingsSingleUpdate( $hash, "mute", $a[2], 1 ) if ( ReadingsVal($name, "mute", "") ne $a[2] ); } @@ -357,18 +450,12 @@ sub BRAVIA_Set($@) { # remoteControl elsif ( lc( $a[1] ) eq "remotecontrol" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); if ( $presence eq "present" ) { if ( !defined( $a[2] ) ) { my $commandKeys = ""; - for ( - sort keys %{ - BRAVIA_GetRemotecontrolCommand( - "GetRemotecontrolCommands") - } - ) - { + for (sort keys %{GetRemotecontrolCommand("GetRemotecontrolCommands")}) { $commandKeys = $commandKeys . " " . $_; } return "No argument given, choose one of" . $commandKeys; @@ -377,31 +464,25 @@ sub BRAVIA_Set($@) { $cmd = uc( $a[2] ); if ( $cmd eq "MUTE" ) { - BRAVIA_Set( $hash, $name, "mute" ); + Set( $hash, $name, "mute" ); } elsif ( $cmd eq "CHANUP" ) { - BRAVIA_Set( $hash, $name, "channelUp" ); + Set( $hash, $name, "channelUp" ); } elsif ( $cmd eq "CHANDOWN" ) { - BRAVIA_Set( $hash, $name, "channelDown" ); + Set( $hash, $name, "channelDown" ); } elsif ( $cmd eq "WOL" ) { my $macAddr = AttrVal( $name, "macaddr", "" ); $macAddr = ReadingsVal( $name, "macAddr", "") if ($macAddr eq ""); - BRAVIA_wake( $name, $macAddr ) if ( $macAddr ne "" && $macAddr ne "-" ); + wake( $name, $macAddr ) if ( $macAddr ne "" && $macAddr ne "-" ); } elsif ( $cmd ne "" ) { - BRAVIA_SendCommand( $hash, "ircc", $cmd ); + SendCommand( $hash, "ircc", $cmd ); } else { my $commandKeys = ""; - for ( - sort keys %{ - BRAVIA_GetRemotecontrolCommand( - "GetRemotecontrolCommands") - } - ) - { + for (sort keys %{GetRemotecontrolCommand("GetRemotecontrolCommands")}) { $commandKeys = $commandKeys . " " . $_; } return @@ -419,13 +500,13 @@ sub BRAVIA_Set($@) { # channel elsif ( $a[1] eq "channel" ) { if (defined($a[2]) && $presence eq "present" && $power ne "on" ) { - Log3 $name, 4, "BRAVIA $name: indirect switching request to ON"; - BRAVIA_Set( $hash, $name, "on" ); + Log3($name, 4, "BRAVIA $name: indirect switching request to ON"); + Set( $hash, $name, "on" ); } shift(@a); shift(@a); my $channelStr = join("#", @a); - Log3 $name, 2, "BRAVIA set $name channel " . $channelStr; + Log3($name, 2, "BRAVIA set $name channel " . $channelStr); return "No argument given, choose one of channel presetNumber channelName " @@ -435,15 +516,16 @@ sub BRAVIA_Set($@) { my $channelName = $channelStr; if ( defined($hash->{helper}{device}{channelPreset}) && $channelName =~ /^(\d+).*$/ ) { if ( defined($hash->{helper}{device}{channelPreset}{$1}{uri}) ) { - BRAVIA_SendCommand( $hash, "setPlayContent", $hash->{helper}{device}{channelPreset}{$1}{uri} ); + SendCommand( $hash, "setPlayContent", $hash->{helper}{device}{channelPreset}{$1}{uri} ); return; } } if ( $channelName =~ /^(\d)(\d?)(\d?)(\d?).*$/ ) { - BRAVIA_SendCommand( $hash, "ircc", $1, undef, "blocking" ); - BRAVIA_SendCommand( $hash, "ircc", $2, undef, "blocking" ) if (defined($2)); - BRAVIA_SendCommand( $hash, "ircc", $3, undef, "blocking" ) if (defined($3)); - BRAVIA_SendCommand( $hash, "ircc", $4, undef, "blocking" ) if (defined($4)); + my @successor = (); + push(@successor, ["ircc", $2]) if (defined($2)); + push(@successor, ["ircc", $3]) if (defined($3)); + push(@successor, ["ircc", $4]) if (defined($4)); + SendCommand( $hash, "ircc", $1, undef, @successor ); return; } return "Argument " . $channelName . " is not a valid channel name"; @@ -456,7 +538,7 @@ sub BRAVIA_Set($@) { # channelUp/channelDown elsif ( lc( $a[1] ) =~ /^(channelup|channeldown)$/ ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $presence eq "present" ) { if ( lc( $a[1] ) eq "channelup" ) { @@ -465,7 +547,7 @@ sub BRAVIA_Set($@) { else { $cmd = "CHANDOWN"; } - BRAVIA_SendCommand( $hash, "ircc", $cmd ); + SendCommand( $hash, "ircc", $cmd ); } else { return "Device needs to be ON to switch channel."; @@ -475,15 +557,15 @@ sub BRAVIA_Set($@) { # input elsif ( $a[1] eq "input" ) { if (defined($a[2]) && $presence eq "present" && $power ne "on" ) { - Log3 $name, 4, "BRAVIA $name: indirect switching request to ON"; - BRAVIA_Set( $hash, $name, "on" ); + Log3($name, 4, "BRAVIA $name: indirect switching request to ON"); + Set( $hash, $name, "on" ); } return "No 2nd argument given" if ( !defined( $a[2] ) ); shift(@a); shift(@a); my $inputStr = join("#", @a); - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $inputStr; + Log3($name, 2, "BRAVIA set $name input $inputStr"); # Resolve input uri my $input_uri; @@ -494,7 +576,7 @@ sub BRAVIA_Set($@) { } if ( $presence eq "present" ) { - BRAVIA_SendCommand( $hash, "setPlayContent", $input_uri ); + SendCommand( $hash, "setPlayContent", $input_uri ); if ( ReadingsVal($name, "input", "") ne $inputStr ) { readingsSingleUpdate( $hash, "input", $inputStr, 1 ); @@ -508,8 +590,8 @@ sub BRAVIA_Set($@) { # application elsif ( $a[1] eq "application" or $a[1] eq "app") { if (defined($a[2]) && $presence eq "present" && $power ne "on" ) { - Log3 $name, 4, "BRAVIA $name: indirect switching request to ON"; - BRAVIA_Set( $hash, $name, "on" ); + Log3($name, 4, "BRAVIA $name: indirect switching request to ON"); + Set( $hash, $name, "on" ); } return "No 2nd argument given" if ( !defined( $a[2] ) ); @@ -539,8 +621,8 @@ sub BRAVIA_Set($@) { return "Unknown app '" . $appStr . "' on that device." unless defined($app_uri); if ( $presence eq "present" ) { - Log3 $name, 2, "BRAVIA set $name " . $app_name . ($app_data ? " " . $app_data : ""); - BRAVIA_SendCommand( $hash, "setActiveApp", $app_uri, $app_data ); + Log3($name, 2, "BRAVIA set $name " . $app_name . ($app_data ? " " . $app_data : "")); + SendCommand( $hash, "setActiveApp", $app_uri, $app_data ); } else { return "Device needs to be reachable to start an app."; @@ -550,22 +632,22 @@ sub BRAVIA_Set($@) { # openUrl elsif ( $a[1] eq "openUrl") { if (defined($a[2]) && $presence eq "present" && $power ne "on" ) { - Log3 $name, 4, "BRAVIA $name: indirect switching request to ON"; - BRAVIA_Set( $hash, $name, "on" ); + Log3($name, 4, "BRAVIA $name: indirect switching request to ON"); + Set( $hash, $name, "on" ); } return "No 2nd argument given" if ( !defined( $a[2] ) ); if ( $presence eq "present" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); my $url = lc($a[2]); if ($url !~ /^https?:\/\/.*/) { $url = "http://$url"; } $url =~ s/([\x2F \x3A])/sprintf("%%%02X",ord($1))/eg; $url = "localapp://webappruntime?url=$url"; - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $url; - BRAVIA_SendCommand( $hash, "setActiveApp", $url ); + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $url); + SendCommand( $hash, "setActiveApp", $url ); } else { return "Device needs to be reachable to start an app."; @@ -574,10 +656,10 @@ sub BRAVIA_Set($@) { # tvpause elsif ( $a[1] eq "tvpause" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "on" ) { - BRAVIA_SendCommand( $hash, "ircc", "TVPAUSE" ); + SendCommand( $hash, "ircc", "TVPAUSE" ); } else { return "Device needs to be ON to pause tv."; @@ -586,10 +668,10 @@ sub BRAVIA_Set($@) { # pause elsif ( $a[1] eq "pause" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "on" ) { - BRAVIA_SendCommand( $hash, "ircc", "PAUSE" ); + SendCommand( $hash, "ircc", "PAUSE" ); } else { return "Device needs to be ON to pause video."; @@ -598,10 +680,10 @@ sub BRAVIA_Set($@) { # play elsif ( $a[1] eq "play" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "on" ) { - BRAVIA_SendCommand( $hash, "ircc", "PLAY" ); + SendCommand( $hash, "ircc", "PLAY" ); } else { return "Device needs to be ON to play video."; @@ -610,10 +692,10 @@ sub BRAVIA_Set($@) { # stop elsif ( $a[1] eq "stop" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "on" ) { - BRAVIA_SendCommand( $hash, "ircc", "STOP" ); + SendCommand( $hash, "ircc", "STOP" ); } else { return "Device needs to be ON to stop video."; @@ -622,10 +704,10 @@ sub BRAVIA_Set($@) { # record elsif ( $a[1] eq "record" ) { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; + Log3($name, 2, "BRAVIA set $name " . $a[1]); if ( $power eq "on" ) { - BRAVIA_SendCommand( $hash, "ircc", "RECORD" ); + SendCommand( $hash, "ircc", "RECORD" ); } else { return "Device needs to be ON to start instant recording."; @@ -635,11 +717,11 @@ sub BRAVIA_Set($@) { # register elsif ( $a[1] eq "register" ) { if (defined($a[2])) { - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; - BRAVIA_SendCommand( $hash, "register", $a[2] ); + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); + SendCommand( $hash, "register", $a[2] ); } else { - Log3 $name, 2, "BRAVIA set $name " . $a[1]; - BRAVIA_SendCommand( $hash, "register" ); + Log3($name, 2, "BRAVIA set $name " . $a[1]); + SendCommand( $hash, "register" ); } } @@ -647,7 +729,7 @@ sub BRAVIA_Set($@) { elsif ( $a[1] eq "requestFormat" ) { return "No 2nd argument given" if ( !defined( $a[2] ) ); - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); readingsSingleUpdate( $hash, "requestFormat", $a[2], 1 ) if ( ReadingsVal($name, "requestFormat", "") ne $a[2] ); } @@ -656,7 +738,7 @@ sub BRAVIA_Set($@) { elsif ( $a[1] eq "upnp" ) { return "No 2nd argument given" if ( !defined( $a[2] ) ); - Log3 $name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]; + Log3($name, 2, "BRAVIA set $name " . $a[1] . " " . $a[2]); readingsSingleUpdate( $hash, "upnp", $a[2], 1 ) if ( ReadingsVal($name, "upnp", "") ne $a[2] ); } @@ -667,9 +749,9 @@ sub BRAVIA_Set($@) { shift(@a); shift(@a); my $text = join(" ", @a); - Log3 $name, 2, "BRAVIA set $name text $text"; + Log3($name, 2, "BRAVIA set $name text $text"); - BRAVIA_SendCommand( $hash, "text", $text ); + SendCommand( $hash, "text", $text ); } # return usage hint @@ -680,60 +762,6 @@ sub BRAVIA_Set($@) { return; } -################################### -sub BRAVIA_Define($$) { - my ( $hash, $def ) = @_; - my @a = split( "[ \t][ \t]*", $def ); - my $name = $hash->{NAME}; - - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_Define()"; - - if ( int(@a) < 3 ) { - my $msg = - "Wrong syntax: define BRAVIA []"; - Log3 $name, 4, $msg; - return $msg; - } - - $hash->{TYPE} = "BRAVIA"; - - my $address = $a[2]; - $hash->{helper}{ADDRESS} = $address; - - # use interval of 45 sec if not defined - my $interval = $a[3] || 45; - $hash->{INTERVAL} = $interval; - - # number of channels read from channellist, maximum 50 - my $channelCount = 50; - $hash->{CHANNELCOUNT} = $channelCount; - - $hash->{helper}{PORT} = { - 'IRCC' => "80", - 'SERVICE' => "80", - 'UPNP' => "52323", - }; - - $hash->{helper}{HEADER} = 'X-CERS-DEVICE-ID: fhem_remote'; - - unless ( defined( AttrVal( $name, "webCmd", undef ) ) ) { - $attr{$name}{webCmd} = 'volume:channelUp:channelDown'; - } - unless ( defined( AttrVal( $name, "devStateIcon", undef ) ) ) { - $attr{$name}{devStateIcon} = - 'on:rc_GREEN:off off:rc_YELLOW:on absent:rc_STOP:on'; - } - unless ( defined( AttrVal( $name, "icon", undef ) ) ) { - $attr{$name}{icon} = 'it_television'; - } - - # start the status update timer - RemoveInternalTimer($hash); - InternalTimer( gettimeofday() + 2, "BRAVIA_GetStatus", $hash, 1 ); - - return; -} - ############################################################################################################ # # Begin of helper functions @@ -741,8 +769,8 @@ sub BRAVIA_Define($$) { ############################################################################################################ ################################### -sub BRAVIA_SendCommand($$;$$$) { - my ( $hash, $service, $cmd, $param, $type ) = @_; +sub SendCommand($$;$$@) { + my ( $hash, $service, $cmd, $param, @successor ) = @_; my $name = $hash->{NAME}; my $address = $hash->{helper}{ADDRESS}; my $port = $hash->{helper}{PORT}; @@ -751,21 +779,24 @@ sub BRAVIA_SendCommand($$;$$$) { my $data; my $timeout; - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_SendCommand()"; + Log3($name, 5, "BRAVIA $name: called function SendCommand()"); my $URL; my $response; my $return; my $requestFormat = ReadingsVal($name, "requestFormat", ""); - BRAVIA_CheckRegistration($hash) if ($service ne "register" && $service ne "getStatus"); + if ($service ne "register" && $service ne "getStatus") { + return if CheckRegistration($hash, $service, $cmd, $param, @successor); + } if ( !defined($cmd) ) { - Log3 $name, 4, "BRAVIA $name: REQ $service"; + Log3($name, 4, "BRAVIA $name: REQ $service"); } else { - Log3 $name, 4, "BRAVIA $name: REQ $service/" . urlDecode($cmd); + Log3($name, 4, "BRAVIA $name: REQ $service/" . ::urlDecode($cmd)); } + LogSuccessors($hash, @successor); $URL = "http://" . $address . ":"; $header .= "\r\nCookie: auth=".ReadingsVal($name, "authCookie", "") @@ -777,8 +808,8 @@ sub BRAVIA_SendCommand($$;$$$) { $URL .= "/IRCC"; $header .= "\r\nSoapaction: \"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC\""; $header .= "\r\nContent-Type: text/xml; charset=UTF-8"; - $cmd = BRAVIA_GetRemotecontrolCommand($cmd); - $data = BRAVIA_GetIrccRequest($cmd); + $cmd = GetRemotecontrolCommand($cmd); + $data = GetIrccRequest($cmd); } elsif ($service eq "upnp") { my $value; if ($cmd =~ m/^(.+):(\d+)$/) { @@ -791,7 +822,7 @@ sub BRAVIA_SendCommand($$;$$$) { $header .= ucfirst($cmd); $header .= "\""; $header .= "\r\nContent-Type: text/xml"; - $data = BRAVIA_GetUpnpRequest($cmd, $value); + $data = GetUpnpRequest($cmd, $value); } elsif ($service eq "register") { my $id = "Fhem Remote"; my $device = "fhem_remote"; @@ -924,88 +955,70 @@ sub BRAVIA_SendCommand($$;$$$) { } } - if ( defined( $attr{$name}{timeout} ) && $attr{$name}{timeout} =~ /^\d+$/ ) { - $timeout = $attr{$name}{timeout}; - } elsif ( $service eq "getStatus" ) { - $timeout = 10; - } else { - $timeout = 30; + $timeout = AttrVal($name, "timeout", 0); + if ($timeout !~ /^\d+$/ or $timeout == 0) { + if ( $service eq "getStatus" ) { + $timeout = 10; + } else { + $timeout = 30; + } } # send request via HTTP-POST method - Log3 $name, 5, "BRAVIA $name: POST " . $URL . " (" . urlDecode($data) . ")" + Log3($name, 5, "BRAVIA $name: POST " . $URL . " (" . ::urlDecode($data) . ")") if ( defined($data) ); - Log3 $name, 5, "BRAVIA $name: GET " . $URL + Log3($name, 5, "BRAVIA $name: GET " . $URL) if ( !defined($data) ); - Log3 $name, 5, "BRAVIA $name: header " . $header + Log3($name, 5, "BRAVIA $name: header " . $header) if ( defined($header) ); - if ( defined($type) && $type eq "blocking" ) { - my ($err, $data) = HttpUtils_BlockingGet( - { - url => $URL, - timeout => 4, - noshutdown => 1, - header => $header, - data => $data, - hash => $hash, - service => $service, - cmd => $cmd, - type => $type, - timestamp => $timestamp, - } - ); - Log3 $name, 5, "BRAVIA $name: REQ $service received err: $err data: $data "; - sleep 1; - } else { - HttpUtils_NonblockingGet( - { - url => $URL, - timeout => $timeout, - noshutdown => 1, - header => $header, - data => $data, - hash => $hash, - service => $service, - cmd => $cmd, - type => $type, - timestamp => $timestamp, - callback => \&BRAVIA_ReceiveCommand, - } - ); - } + ::HttpUtils_NonblockingGet( + { + url => $URL, + timeout => $timeout, + noshutdown => 1, + header => $header, + data => $data, + hash => $hash, + service => $service, + cmd => $cmd, + successor => \@successor, + timestamp => $timestamp, + callback => \&BRAVIA::ReceiveCommand, + } + ); return; } ################################### -sub BRAVIA_ReceiveCommand($$$) { +sub ReceiveCommand($$$) { my ( $param, $err, $data ) = @_; - my $hash = $param->{hash}; - my $name = $hash->{NAME}; - my $service = $param->{service}; - my $cmd = $param->{cmd}; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $service = $param->{service}; + my $cmd = $param->{cmd}; + my @successor = @{$param->{successor}}; my $newstate; my $rc = ( $param->{buf} ) ? $param->{buf} : $param; my $return; - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_ReceiveCommand() rc: $rc err: $err data: $data "; + Log3($name, 5, "BRAVIA $name: called function ReceiveCommand() rc: $rc err: $err data: $data "); # device not reachable if ($err) { if ( !defined($cmd) || ref($cmd) eq "HASH" || $cmd eq "" ) { - Log3 $name, 4, "BRAVIA $name: RCV TIMEOUT $service"; + Log3($name, 4, "BRAVIA $name: RCV TIMEOUT $service"); } else { - Log3 $name, 4, - "BRAVIA $name: RCV TIMEOUT $service/" . urlDecode($cmd); + Log3($name, 4, "BRAVIA $name: RCV TIMEOUT $service/" . ::urlDecode($cmd)); } # device is not reachable or # does not even support master command for status if ( $service eq "getStatus" ) { - BRAVIA_ClearContentInformation($hash); + ClearContentInformation($hash); $newstate = "absent"; if ( @@ -1018,6 +1031,11 @@ sub BRAVIA_ReceiveCommand($$$) { readingsSingleUpdate( $hash, "presence", "absent", 1 ); } } + + # stop pulling for current interval + Log3($name, 4, "BRAVIA $name: drop successors"); + LogSuccessors($hash, @successor); + return; } # data received @@ -1033,11 +1051,12 @@ sub BRAVIA_ReceiveCommand($$$) { } if ( !defined($cmd) ) { - Log3 $name, 4, "BRAVIA $name: RCV $service"; + Log3($name, 4, "BRAVIA $name: RCV $service"); } else { - Log3 $name, 4, "BRAVIA $name: RCV $service/" . urlDecode($cmd); + Log3($name, 4, "BRAVIA $name: RCV $service/" . ::urlDecode($cmd)); } + LogSuccessors($hash, @successor); if ( $data ne "" ) { if ( $data =~ /^<\?xml/ ) { @@ -1049,11 +1068,10 @@ sub BRAVIA_ReceiveCommand($$$) { ); if ( !defined($cmd) || ref($cmd) eq "HASH" || $cmd eq "" ) { - Log3 $name, 4, "BRAVIA $name: RES $service - $data"; + Log3($name, 4, "BRAVIA $name: RES $service - $data"); } else { - Log3 $name, 4, - "BRAVIA $name: RES $service/" . urlDecode($cmd) . " - $data"; + Log3($name, 4, "BRAVIA $name: RES $service/" . ::urlDecode($cmd) . " - $data"); } readingsSingleUpdate( $hash, "requestFormat", "xml", 1 ) @@ -1064,11 +1082,10 @@ sub BRAVIA_ReceiveCommand($$$) { elsif ( $data =~ /^{/ || $data =~ /^\[/ ) { if ( !defined($cmd) || ref($cmd) eq "HASH" || $cmd eq "" ) { - Log3 $name, 4, "BRAVIA $name: RES $service - $data"; + Log3($name, 4, "BRAVIA $name: RES $service - $data"); } else { - Log3 $name, 4, - "BRAVIA $name: RES $service/" . urlDecode($cmd) . " - $data"; + Log3($name, 4, "BRAVIA $name: RES $service/" . ::urlDecode($cmd) . " - $data"); } readingsSingleUpdate( $hash, "requestFormat", "json", 1 ) @@ -1079,11 +1096,10 @@ sub BRAVIA_ReceiveCommand($$$) { elsif ( $data eq "not foundnot found" ) { if ( !defined($cmd) || ref($cmd) eq "HASH" || $cmd eq "" ) { - Log3 $name, 4, "BRAVIA $name: RES $service - not found"; + Log3($name, 4, "BRAVIA $name: RES $service - not found"); } else { - Log3 $name, 4, - "BRAVIA $name: RES $service/" . urlDecode($cmd) . " - not found"; + Log3($name, 4, "BRAVIA $name: RES $service/" . ::urlDecode($cmd) . " - not found"); } $return = "not found"; @@ -1091,11 +1107,10 @@ sub BRAVIA_ReceiveCommand($$$) { elsif ( $data =~ /^ 1); + $cmdParam = $nextCmd[2] if ($cmdLength > 2); -################################### -sub BRAVIA_Undefine($$) { - my ( $hash, $arg ) = @_; - my $name = $hash->{NAME}; - - Log3 $name, 5, "BRAVIA $name: called function BRAVIA_Undefine()"; - - # Stop the internal GetStatus-Loop and exit - RemoveInternalTimer($hash); + SendCommand($hash, $cmdService, $cmdCmd, $cmdParam, @successor); + } return; } ################################### -sub BRAVIA_wake ($$) { +sub wake ($$) { my ( $name, $mac_addr ) = @_; my $address = '255.255.255.255'; my $port = 9; @@ -1195,9 +1206,7 @@ sub BRAVIA_wake ($$) { setsockopt( $sock, SOL_SOCKET, SO_BROADCAST, 1 ) or die "setsockopt : $!"; - Log3 $name, 4, - "BRAVIA $name: Waking up by sending Wake-On-Lan magic package to " - . $mac_addr; + Log3($name, 4, "BRAVIA $name: Waking up by sending Wake-On-Lan magic package to $mac_addr"); send( $sock, $packet, 0, $sock_addr ) or die "send : $!"; close($sock); @@ -1206,32 +1215,19 @@ sub BRAVIA_wake ($$) { ################################### # process return data -sub BRAVIA_ProcessCommandData ($$) { +sub ProcessCommandData ($$$) { - my ($param, $return) = @_; - my $hash = $param->{hash}; - my $name = $hash->{NAME}; - my $service = $param->{service}; - my $cmd = $param->{cmd}; - my $type = ( $param->{type} ) ? $param->{type} : ""; - my $header = $param->{httpheader}; + my ($param,$return,$successor) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + my $service = $param->{service}; + my $cmd = $param->{cmd}; + my $header = $param->{httpheader}; my $newstate; # ircc if ( $service eq "ircc" ) { - if ( ref($return) ne "HASH" && $return eq "ok" ) { - - # toggle standby - if ( defined($type) && $type eq "off" ) { - $newstate = "off"; - } - - # toggle standby - elsif ( defined($type) && $type eq "on" ) { - $newstate = "on"; - } - - } + # nothing to do } # upnp @@ -1272,8 +1268,7 @@ sub BRAVIA_ProcessCommandData ($$) { $input = $_->{value}; $setInput = "true"; } else { - readingsBulkUpdate( $hash, "s_".$_->{field}, $_->{value} ) - if (ReadingsVal($name, "s_".$_->{field}, "") ne $_->{value} ); + readingsBulkUpdateIfChanged( $hash, "s_".$_->{field}, $_->{value} ); } delete $statusKeys{"s_".$_->{field}}; } @@ -1284,17 +1279,14 @@ sub BRAVIA_ProcessCommandData ($$) { $input = $return->{status}{statusItem}{value}; $setInput = "true"; } else { - readingsBulkUpdate( $hash, $field, $return->{status}{statusItem}{value} ) - if (ReadingsVal($name, $field, "") ne $return->{status}{statusItem}{value} ); + readingsBulkUpdateIfChanged( $hash, $field, $return->{status}{statusItem}{value} ); } delete $statusKeys{$field}; } } } - readingsBulkUpdate( $hash, "input", $input ) - if ( defined($setInput) and - (ReadingsVal($name, "input", "") ne $input) ); + readingsBulkUpdateIfChanged( $hash, "input", $input ) if ( defined($setInput) ); #remove outdated content information - replaces by "-" foreach ( keys %statusKeys ) { @@ -1305,7 +1297,7 @@ sub BRAVIA_ProcessCommandData ($$) { # check for valid status if (ref $return eq ref {} && ref($return->{error}) eq "ARRAY" && $return->{error}[0] eq "404") { - BRAVIA_ClearContentInformation($hash); + ClearContentInformation($hash); return "off"; } @@ -1313,17 +1305,17 @@ sub BRAVIA_ProcessCommandData ($$) { # fetch other info # read system information if not existing - BRAVIA_SendCommand( $hash, "getSystemInformation" ) + push(@$successor, ["getSystemInformation"]) if ( ReadingsVal($name, "name", "0") eq "0" || ReadingsVal($name, "model", "0") eq "0" ); # read content information if ( ReadingsVal($name, "generation", "1.0") ne "1.0" ) { if (ref $return eq ref {} && ref($return->{result}) eq "ARRAY" && $return->{result}[0]{status} ne "active") { # current status is not active, don't need to fetch content information - BRAVIA_ClearContentInformation($hash); + ClearContentInformation($hash); $newstate = "off"; } else { - BRAVIA_SendCommand( $hash, "getContentInformation" ); + push(@$successor, ["getContentInformation"]); } } elsif (ref $return eq ref {}) { if (ref($return->{result}) eq "ARRAY") { @@ -1333,8 +1325,8 @@ sub BRAVIA_ProcessCommandData ($$) { } # get current system settings if ($newstate eq "on" && ReadingsVal($name, "upnp", "on") eq "on") { - BRAVIA_SendCommand( $hash, "upnp", "getVolume" ); - BRAVIA_SendCommand( $hash, "upnp", "getMute" ); + push(@$successor, ["upnp", "getVolume"]); + push(@$successor, ["upnp", "getMute"]); } } } @@ -1387,12 +1379,11 @@ sub BRAVIA_ProcessCommandData ($$) { } elsif ( $_->{field} eq "inputType" ) { $currentMedia = $_->{value}; } elsif ( $_->{field} eq "serviceName" ) { - $channelName = BRAVIA_GetNormalizedName($_->{value}); + $channelName = $_->{value}; } elsif ( $_->{field} eq "title" ) { $currentTitle = $_->{value}; } else { - readingsBulkUpdate( $hash, "ci_".$_->{field}, $_->{value} ) - if ( ReadingsVal($name, "ci_".$_->{field}, "") ne $_->{value} ); + readingsBulkUpdateIfChanged( $hash, "ci_".$_->{field}, $_->{value} ); delete $contentKeys{"ci_".$_->{field}}; } } @@ -1407,6 +1398,8 @@ sub BRAVIA_ProcessCommandData ($$) { } else { # json if ( ref($return->{result}[0]) eq "HASH" ) { + my $uri; + my $input; readingsBeginUpdate($hash); foreach ( keys %{$return->{result}[0]} ) { if ( $_ eq "dispNum" ) { @@ -1414,34 +1407,44 @@ sub BRAVIA_ProcessCommandData ($$) { } elsif ( $_ eq "programMediaType" ) { $currentMedia = $return->{result}[0]{$_}; } elsif ( $_ eq "title" ) { - $channelName = BRAVIA_GetNormalizedName($return->{result}[0]{$_}); + $channelName = $return->{result}[0]{$_}; } elsif ( $_ eq "programTitle" ) { $currentTitle = $return->{result}[0]{$_}; } elsif ( $_ eq "source" ) { - readingsBulkUpdate( $hash, "input", $return->{result}[0]{$_} ) - if ( ReadingsVal($name, "input", "") ne $return->{result}[0]{$_} ); + $input = $return->{result}[0]{$_}; } elsif ( $_ eq "uri" ) { - readingsBulkUpdate( $hash, "uri", $return->{result}[0]{$_} ) - if ( ReadingsVal($name, "uri", "") ne $return->{result}[0]{$_} ); + $uri = $return->{result}[0]{$_}; # set TV input uri to last tv-norm (tv:dvbt, tv:dvbs) $hash->{helper}{device}{inputPreset}{TV}{uri} = $return->{result}[0]{$_} if (defined($hash->{helper}{device}{inputPreset}) && $return->{result}[0]{$_} =~ /tv:.*/); } else { - readingsBulkUpdate( $hash, "ci_".$_, $return->{result}[0]{$_} ) - if ( ReadingsVal($name, "ci_".$_, "") ne $return->{result}[0]{$_} ); + readingsBulkUpdateIfChanged( $hash, "ci_".$_, $return->{result}[0]{$_} ); delete $contentKeys{"ci_".$_}; } } + if ($uri) { + readingsBulkUpdateIfChanged($hash, "uri", $uri); + foreach ( keys %{$hash->{helper}{device}{inputPreset}} ) { + if ($hash->{helper}{device}{inputPreset}{$_}{uri} eq $uri) { + $input = $_; + $input =~ s/#/ /g; + last; + } + } + } + readingsBulkUpdateIfChanged($hash, "input", $input) if ($input); + #reset application + readingsBulkUpdate( $hash, "application", "-" ) if (ReadingsVal($name, "application", "-") ne "-"); readingsEndUpdate( $hash, 1 ); } elsif ( ref($return->{error}) eq "ARRAY" && $return->{error}[0] eq "7" && $return->{error}[1] eq "Illegal State" ) { #could be timeshift mode or app mode - BRAVIA_SendCommand( $hash, "getScheduleList" ); - BRAVIA_FetchPresets( $hash ); + push(@$successor, ["getScheduleList"]); + FetchPresets($hash, $successor); return; } } } else { - if ( ReadingsVal($name, "input", "") eq "Others" || ReadingsVal($name, "input", "") eq "Broadcast" ) { + if (ReadingsVal($name, "input", "") eq "Others" || ReadingsVal($name, "input", "") eq "Broadcast" ) { $newstate = "off"; } else { $newstate = "on"; @@ -1450,14 +1453,10 @@ sub BRAVIA_ProcessCommandData ($$) { readingsBeginUpdate($hash); - readingsBulkUpdate( $hash, "channel", $channelName ) - if ( ReadingsVal($name, "channel", "") ne $channelName ); - readingsBulkUpdate( $hash, "channelId", $channelNo ) - if ( ReadingsVal($name, "channelId", "") ne $channelNo ); - readingsBulkUpdate( $hash, "currentTitle", $currentTitle ) - if ( ReadingsVal($name, "currentTitle", "") ne $currentTitle ); - readingsBulkUpdate( $hash, "currentMedia", $currentMedia ) - if ( ReadingsVal($name, "currentMedia", "") ne $currentMedia ); + readingsBulkUpdateIfChanged( $hash, "channel", $channelName ); + readingsBulkUpdateIfChanged( $hash, "channelId", $channelNo ); + readingsBulkUpdateIfChanged( $hash, "currentTitle", $currentTitle ); + readingsBulkUpdateIfChanged( $hash, "currentMedia", $currentMedia ); #remove outdated content information - replaces by "-" foreach ( keys %contentKeys ) { @@ -1467,7 +1466,7 @@ sub BRAVIA_ProcessCommandData ($$) { readingsEndUpdate( $hash, 1 ); if ($channelName ne "-" && $channelNo ne "-") { - BRAVIA_SendCommand( $hash, "getContentList", ReadingsVal($name, "input", "") ) + push(@$successor, ["getContentList", ReadingsVal($name, "input", "")]) if (ReadingsVal($name, "requestFormat", "") eq "json" && (!defined($hash->{helper}{device}{channelPreset}) || ReadingsVal($name, "state", "") ne "on")); $hash->{helper}{device}{channelPreset}{ $channelNo }{id} = $channelNo; @@ -1476,11 +1475,11 @@ sub BRAVIA_ProcessCommandData ($$) { # get current system settings if ($newstate eq "on" && ReadingsVal($name, "upnp", "on") eq "on") { - BRAVIA_SendCommand( $hash, "upnp", "getVolume" ); - BRAVIA_SendCommand( $hash, "upnp", "getMute" ); + push(@$successor, ["upnp", "getVolume"]); + push(@$successor, ["upnp", "getMute"]); } - BRAVIA_FetchPresets($hash) if ($newstate eq "on"); + FetchPresets($hash, $successor) if ($newstate eq "on"); } # getScheduleList @@ -1507,15 +1506,13 @@ sub BRAVIA_ProcessCommandData ($$) { foreach $key ( keys %{ $_ }) { if ( $key eq "type" ) { $currentMedia = $_->{$key}; - readingsBulkUpdate( $hash, "input", $_->{$key} ) - if ( ReadingsVal($name, "input", "") ne $_->{$key} ); + readingsBulkUpdateIfChanged( $hash, "input", $_->{$key} ); } elsif ( $key eq "channelName" ) { - $channelName = BRAVIA_GetNormalizedName($_->{$key}); + $channelName = $_->{$key}; } elsif ( $key eq "title" ) { $currentTitle = $_->{$key}; } else { - readingsBulkUpdate( $hash, "ci_".$key, $_->{$key} ) - if ( ReadingsVal($name, "ci_".$key, "") ne $_->{$key} ); + readingsBulkUpdateIfChanged( $hash, "ci_".$key, $_->{$key} ); delete $contentKeys{"ci_".$key}; } } @@ -1524,12 +1521,9 @@ sub BRAVIA_ProcessCommandData ($$) { } } } - readingsBulkUpdate( $hash, "channel", $channelName ) - if ( ReadingsVal($name, "channel", "") ne $channelName ); - readingsBulkUpdate( $hash, "currentTitle", $currentTitle ) - if ( ReadingsVal($name, "currentTitle", "") ne $currentTitle ); - readingsBulkUpdate( $hash, "currentMedia", $currentMedia ) - if ( ReadingsVal($name, "currentMedia", "") ne $currentMedia ); + readingsBulkUpdateIfChanged( $hash, "channel", $channelName ); + readingsBulkUpdateIfChanged( $hash, "currentTitle", $currentTitle ); + readingsBulkUpdateIfChanged( $hash, "currentMedia", $currentMedia ); #remove outdated content information - replaces by "-" foreach ( keys %contentKeys ) { @@ -1540,8 +1534,8 @@ sub BRAVIA_ProcessCommandData ($$) { # get current system settings if (ReadingsVal($name, "upnp", "on") eq "on") { - BRAVIA_SendCommand( $hash, "upnp", "getVolume" ); - BRAVIA_SendCommand( $hash, "upnp", "getMute" ); + push(@$successor, ["upnp", "getVolume"]); + push(@$successor, ["upnp", "getMute"]); } } @@ -1560,7 +1554,7 @@ sub BRAVIA_ProcessCommandData ($$) { if ( $key eq "dispNum" ) { $channelNo = $_->{$key}; } elsif ( $key eq "title" ) { - $channelName = BRAVIA_GetNormalizedName($_->{$key}); + $channelName = GetNormalizedName($_->{$key}); } elsif ( $key eq "index" ) { $channelIndex = $_->{$key}; } elsif ( $key eq "uri" ) { @@ -1577,7 +1571,7 @@ sub BRAVIA_ProcessCommandData ($$) { # increment index, because it starts with 0 if (++$channelIndex % InternalVal($name, "CHANNELCOUNT", 50) == 0) { # try next junk of channels - BRAVIA_SendCommand( $hash, "getContentList", ReadingsVal($name, "input", "")."|".$channelIndex ); + push(@$successor, ["getContentList", ReadingsVal($name, "input", "")."|".$channelIndex]); } } @@ -1596,9 +1590,9 @@ sub BRAVIA_ProcessCommandData ($$) { } if (defined($scheme)) { if ($scheme eq "extInput") { - BRAVIA_SendCommand( $hash, "getCurrentExternalInputsStatus" ); + push(@$successor, ["getCurrentExternalInputsStatus"]); } elsif ($scheme eq "tv") { - BRAVIA_SendCommand( $hash, "getSourceList", $scheme ); + push(@$successor, ["getSourceList", $scheme]); } } } @@ -1621,7 +1615,7 @@ sub BRAVIA_ProcessCommandData ($$) { } } if (defined($source) and $source =~ /tv:dvb(.)/) { - my $dvbName = BRAVIA_GetNormalizedName("TV / DVB-".uc($1)); + my $dvbName = GetNormalizedName("TV / DVB-".uc($1)); $hash->{helper}{device}{inputPreset}{$dvbName}{uri} = $source; } } @@ -1637,13 +1631,16 @@ sub BRAVIA_ProcessCommandData ($$) { foreach ( @{ $return->{result} } ) { foreach ( @{ $_ } ) { my $inputName; + my $inputLabel; my $inputUri; my $key; foreach $key ( keys %{ $_ }) { if ( $key eq "uri" ) { $inputUri = $_->{$key}; } elsif ( $key eq "title" ) { - $inputName = BRAVIA_GetNormalizedName($_->{$key}); + $inputName = GetNormalizedName($_->{$key}); + } elsif ( $key eq "label" ) { + $inputLabel = GetNormalizedName($_->{$key}); } } $hash->{helper}{device}{inputPreset}{$inputName}{uri} = $inputUri; @@ -1669,7 +1666,7 @@ sub BRAVIA_ProcessCommandData ($$) { if ( $key eq "uri" ) { $appUri = $_->{$key}; } elsif ( $key eq "title" ) { - $appName = BRAVIA_GetNormalizedName($_->{$key}); + $appName = GetNormalizedName($_->{$key}); } } $hash->{helper}{device}{appPreset}{$appName}{uri} = $appUri; @@ -1686,7 +1683,15 @@ sub BRAVIA_ProcessCommandData ($$) { # setActiveApp elsif ( $service eq "setActiveApp" ) { - # nothing to do + my $appName; + foreach ( keys %{$hash->{helper}{device}{appPreset}} ) { + if ($hash->{helper}{device}{appPreset}{$_}{uri} eq $cmd) { + $appName = $_; + $appName =~ s/#/ /g; + last; + } + } + readingsSingleUpdate( $hash, "application", $appName, 1 ) if ($appName); } # text @@ -1696,22 +1701,30 @@ sub BRAVIA_ProcessCommandData ($$) { # register elsif ( $service eq "register" ) { - readingsBeginUpdate($hash); - if ( $header =~ /auth=([A-Za-z0-9]+)/ ) { - readingsBulkUpdate( $hash, "authCookie", $1 ); + # check for error + if (ref $return eq ref {} && ref($return->{error}) eq "ARRAY" && $return->{error}[0] eq "401") { + # drop successors for current interval + Log3($name, 4, "BRAVIA $name: drop successors"); + LogSuccessors($hash, @$successor); + @$successor = (); + } else { + readingsBeginUpdate($hash); + if ( $header =~ /auth=([A-Za-z0-9]+)/ ) { + readingsBulkUpdate( $hash, "authCookie", $1 ); + } + if ( $header =~ /[Ee]xpires=([^;]+)/ ) { + readingsBulkUpdate( $hash, "authExpires", $1 ); + } + if ( $header =~ /[Mm]ax-[Aa]ge=(\d+)/ ) { + readingsBulkUpdateIfChanged( $hash, "authMaxAge", $1 ); + } + readingsEndUpdate( $hash, 1 ); } - if ( $header =~ /[Ee]xpires=([^;]+)/ ) { - readingsBulkUpdate( $hash, "authExpires", $1 ); - } - if ( $header =~ /[Mm]ax-[Aa]ge=(\d+)/ ) { - readingsBulkUpdate( $hash, "authMaxAge", $1 ) if (ReadingsVal($name, "authMaxAge", 0) != $1); - } - readingsEndUpdate( $hash, 1 ); } # all other command results else { - Log3 $name, 2, "BRAVIA $name: ERROR: method to handle response of $service not implemented"; + Log3($name, 2, "BRAVIA $name: ERROR: method to handle response of $service not implemented"); } return $newstate; @@ -1719,7 +1732,7 @@ sub BRAVIA_ProcessCommandData ($$) { } ##################################### -sub BRAVIA_ClearContentInformation ($) { +sub ClearContentInformation ($) { my ($hash) = @_; my $name = $hash->{NAME}; @@ -1728,51 +1741,60 @@ sub BRAVIA_ClearContentInformation ($) { #remove outdated content information - replaces by "-" foreach ( keys %{ $hash->{READINGS} } ) { - readingsBulkUpdate($hash, $_, "-") - if ( $_ =~ /^ci_.*/ and ReadingsVal($name, $_, "") ne "-" ); + readingsBulkUpdateIfChanged($hash, $_, "-") if ( $_ =~ /^ci_.*/ ); } - readingsBulkUpdate( $hash, "channel", "-" ) - if ( ReadingsVal($name, "channel", "") ne "-" ); - readingsBulkUpdate( $hash, "channelId", "-" ) - if ( ReadingsVal($name, "channelId", "") ne "-" ); - readingsBulkUpdate( $hash, "currentTitle", "-" ) - if ( ReadingsVal($name, "currentTitle", "") ne "-" ); - readingsBulkUpdate( $hash, "currentMedia", "-" ) - if ( ReadingsVal($name, "currentMedia", "") ne "-" ); - readingsBulkUpdate( $hash, "input", "-" ) - if ( ReadingsVal($name, "input", "") ne "-" ); + readingsBulkUpdateIfChanged( $hash, "channel", "-" ); + readingsBulkUpdateIfChanged( $hash, "channelId", "-" ); + readingsBulkUpdateIfChanged( $hash, "currentTitle", "-" ); + readingsBulkUpdateIfChanged( $hash, "currentMedia", "-" ); + readingsBulkUpdateIfChanged( $hash, "input", "-" ); + readingsBulkUpdateIfChanged( $hash, "uri", "-" ); readingsEndUpdate( $hash, 1 ); } -sub BRAVIA_FetchPresets { - my ($hash) = @_; +sub FetchPresets($$) { + my ($hash,$successor) = @_; my $name = $hash->{NAME}; if ( ReadingsVal( $name, "requestFormat", "" ) eq "json" ) { # load input - BRAVIA_SendCommand( $hash, "getSchemeList" ) + push(@$successor, ["getSchemeList"]) if ( ReadingsVal( $name, "state", "" ) ne "on" || !defined( $hash->{helper}{device}{inputPreset} ) || scalar( keys %{ $hash->{helper}{device}{inputPreset} } ) == 0 ); # load app - BRAVIA_SendCommand( $hash, "getApplicationList" ) + push(@$successor, ["getApplicationList"]) if ( ReadingsVal( $name, "state", "" ) ne "on" || !defined( $hash->{helper}{device}{appPreset} ) || scalar( keys %{ $hash->{helper}{device}{appPreset} } ) == 0 ); } } +sub LogSuccessors($@) { + my ($hash,@successor) = @_; + my $name = $hash->{NAME}; + + my $msg = "BRAVIA $name: successors"; + my @succ_item; + for (my $i = 0; $i < @successor; $i++) { + @succ_item = @{$successor[$i]}; + $msg .= " $i: "; + $msg .= join(",", map { defined($_) ? $_ : '' } @succ_item); + } + Log3($name, 4, $msg) if (@successor > 0); +} + ##################################### # Callback from 95_remotecontrol for command makenotify. -sub BRAVIA_RCmakenotify($$) { +sub RCmakenotify($$) { my ( $nam, $ndev ) = @_; my $nname = "notify_$nam"; fhem( "define $nname notify $nam set $ndev remoteControl " . '$EVENT', 1 ); - Log3 undef, 2, "[remotecontrol:BRAVIA] Notify created: $nname"; + Log3(undef, 2, "[remotecontrol:BRAVIA] Notify created: $nname"); return "Notify created by BRAVIA: $nname"; } @@ -1780,7 +1802,7 @@ sub BRAVIA_RCmakenotify($$) { # RC layouts # Sony TV with SVG -sub BRAVIA_RClayout_SVG() { +sub RClayout_SVG() { my @row; $row[0] = "SOURCE:rc_AV.svg,:rc_BLANK.svg,:rc_BLANK.svg,POWER:rc_POWER.svg"; @@ -1812,7 +1834,7 @@ sub BRAVIA_RClayout_SVG() { } # Sony TV with PNG -sub BRAVIA_RClayout() { +sub RClayout() { my @row; $row[0] = "SOURCE,:blank,:blank,POWER:POWEROFF"; @@ -1837,6 +1859,9 @@ sub BRAVIA_RClayout() { $row[17] = "MUTE,VOLUP:VOLUP2,CHANNELUP:CHUP2,AUDIO"; $row[18] = ":blank,VOLDOWN:VOLDOWN2,CHANNELDOWN:CHDOWN2"; + + $row[19] = "attr rc_iconpath icons/remotecontrol"; + $row[20] = "attr rc_iconprefix black_btn_"; return @row; } @@ -1941,7 +1966,7 @@ sub BRAVIA_RClayout() { # 755 # 755 # 755 -sub BRAVIA_GetRemotecontrolCommand($) { +sub GetRemotecontrolCommand($) { my ($command) = @_; my $commands = { 'POWER' => "AAAAAQAAAAEAAAAVAw==", @@ -2019,7 +2044,7 @@ sub BRAVIA_GetRemotecontrolCommand($) { } } -sub BRAVIA_GetModelYear($) { +sub GetModelYear($) { my ($command) = @_; my $commands = { '1.0' => "2011", @@ -2039,7 +2064,7 @@ sub BRAVIA_GetModelYear($) { } } -sub BRAVIA_GetIrccRequest($) { +sub GetIrccRequest($) { my ($cmd) = @_; my $data = ""; $data .= ""; @@ -2053,7 +2078,7 @@ sub BRAVIA_GetIrccRequest($) { return $data; } -sub BRAVIA_GetUpnpRequest($$) { +sub GetUpnpRequest($$) { my ($cmd,$value) = @_; my $data = ""; $data .= ""; @@ -2091,26 +2116,42 @@ sub BRAVIA_GetUpnpRequest($$) { return $data; } -sub BRAVIA_CheckRegistration($) { - my ( $hash ) = @_; +sub CheckRegistration($$$$@) { + my ( $hash, $service, $cmd, $param, @successor ) = @_; my $name = $hash->{NAME}; if (ReadingsVal($name, "authCookie", "") ne "" and - ReadingsTimestamp($name, "authCookie", "") =~ m/^(\d{4})-(\d{2})-(\d{2}) ([0-2]\d):([0-5]\d):([0-5]\d)$/) { + ReadingsTimestamp($name, "authCookie", "") =~ m/^(\d{4})-(\d{2})-(\d{2}) ([0-2]\d):([0-5]\d):([0-5]\d)$/) { - my $time = fhemTimeLocal($6, $5, $4, $3, $2 - 1, $1 - 1900); - # max age defaults to 14 days - my $maxAge = ReadingsNum($name, "authMaxAge", 1209600); + my $time = fhemTimeLocal($6, $5, $4, $3, $2 - 1, $1 - 1900); + # max age defaults to 14 days + my $maxAge = ReadingsNum($name, "authMaxAge", 1209600); + + # renew registration after half period of validity + if ($time + $maxAge/2 < time()) { + Log3($name, 3, "BRAVIA $name: renew registration"); + + my @nextCmd = ($service, $cmd, $param); + unshift(@successor, [$service, $cmd, $param]); - # renew registration after half period of validity - if ($time + $maxAge/2 < time()) { - Log3 $name, 3, "BRAVIA $name: renew registration"; - BRAVIA_SendCommand( $hash, "register", "renew" ); + my @succ_item; + my $msg = " successor:"; + for (my $i = 0; $i < @successor; $i++) { + @succ_item = @{$successor[$i]}; + $msg .= " $i: "; + $msg .= join(",", map { defined($_) ? $_ : '' } @succ_item); } + Log3($name, 4, "BOTVAC created".$msg); + + SendCommand( $hash, "register", "renew", undef, @successor ); + + return 1; + } } + return; } -sub BRAVIA_GetNormalizedName($) { +sub GetNormalizedName($) { my ( $name ) = @_; $name =~ s/^\s+//; $name =~ s/\s+$//; @@ -2139,7 +2180,7 @@ sub BRAVIA_GetNormalizedName($) { The default value is 45 seconds.

After definition of a device using this module it has to be registered as a remote control - (set register). + (set register).

As long as readings are not among the usual AV readings they are clustered: @@ -2158,65 +2199,65 @@ sub BRAVIA_GetNormalizedName($) {

Options:
    -
  • application
    +
  • application
    List of applications. Applications are available with models from 2013 and newer.
  • -
  • channel
    +
  • channel
    List of all known channels. The module collects all visited channels. Channels can be loaded automtically with models from 2013 and newer. - (number of channels, see channelsMax).
  • -
  • channelDown
    + (number of channels, see channelsMax).
  • +
  • channelDown
    Switches a channel back.
  • -
  • channelUp
    +
  • channelUp
    Switches a channel forward.
  • -
  • input
    +
  • input
    List of input channels. Imputs are available with models from 2013 and newer.
  • -
  • mute
    - Set mute if Upnp is activated.
  • -
  • off
    +
  • mute
    + Set mute if Upnp is activated.
  • +
  • off
    Switches TV to off. State of device will have been set to "set_off" for 60 seconds or until off-status is pulled from TV.
  • -
  • on
    +
  • on
    Switches TV to on, with models from 2013 using WOL. State of device will have been set to "set_on" for 60 seconds or until on-status is pulled from TV.
  • -
  • openUrl
    +
  • openUrl
    Opens an URL on the screen. This Feature is available on models from 2013 and newer.
  • -
  • pause
    +
  • pause
    Pauses a playing of a recording, of an internal App, etc.
  • -
  • play
    +
  • play
    Starts playing of a recording, of an internal App, etc.
  • -
  • record
    +
  • record
    Starts recording of current content.
  • -
  • register
    +
  • register
    One-time registration of Fhem as remote control in the TV.
    - With requestFormat = "xml" registration works without parameter.
    - With requestFormat = "json" registration has to be executed twice.
    + With requestFormat = "xml" registration works without parameter.
    + With requestFormat = "json" registration has to be executed twice.
    The register option offers an additional input field:
    1. Call with empty input. A PIN for registration has to be shown on the TV.
    2. Insert PIN into input field and register again.
  • -
  • requestFormat
    +
  • requestFormat
    "xml" for xml based communication (models from 2011 and 2012)
    "json" for communication with models from 2013 and newer
  • -
  • remoteControl
    +
  • remoteControl
    Sends command directly to TV.
  • -
  • statusRequest
    +
  • statusRequest
    Retrieves current status information from TV.
  • -
  • stop
    +
  • stop
    Stops recording, playing of an internal App, etc.
  • -
  • text
    +
  • text
    Includes the given text into an input field on display.
  • -
  • toggle
    +
  • toggle
    Toggles power status of TV.
  • -
  • tvpause
    +
  • tvpause
    Activates Timeshift mode.
  • -
  • upnp
    +
  • upnp
    Activates Upnp service used to control volume.
  • -
  • volume
    - Straight setting of volume. Upnp service has to be activated.
  • -
  • volumeDown
    +
  • volume
    + Straight setting of volume. Upnp service has to be activated.
  • +
  • volumeDown
    Decreases volume.
  • -
  • volumeUp
    +
  • volumeUp
    Increases volume.
@@ -2229,9 +2270,9 @@ sub BRAVIA_GetNormalizedName($) {

Attributes:
    -
  • channelsMax
    +
  • channelsMax
    Maximum amount of channels to be displayed, default is 50.
  • -
  • macaddr
    +
  • macaddr
    Enables power on of TV using WOL.
@@ -2256,7 +2297,7 @@ sub BRAVIA_GetNormalizedName($) { Ansonsten wird der Task mit 45 Sekunden als Intervall definiert.

Nach der Definition eines Gerätes muss dieses einmalig im TV als Fernbedienung - registriert werden (set register). + registriert werden (set register).

Soweit die Readings nicht den allgemeinen AV Readings entsprechen, sind sie gruppiert:
@@ -2275,65 +2316,65 @@ sub BRAVIA_GetNormalizedName($) {

Optionen:
    -
  • application
    +
  • application
    Liste der Anwendungen. Anwenungen sind ab Modelljahr 2013 verfügbar.
  • -
  • channel
    +
  • channel
    Liste aller bekannten Kanäle. Das Modul merkt sich alle aufgerufenen Kanäle. Ab Modelljahr 2013 werden die Kanäle automatisch geladen - (Anzahl siehe channelsMax).
  • -
  • channelDown
    + (Anzahl siehe channelsMax).
  • +
  • channelDown
    Einen Kanal zurück schalten.
  • -
  • channelUp
    +
  • channelUp
    Einen Kanal weiter schalten.
  • -
  • input
    +
  • input
    Liste der Eingänge. Eingänge sind ab Modelljahr 2013 verfügbar.
  • -
  • mute
    - Direkte Stummschaltung erfolgt nur per aktiviertem Upnp.
  • -
  • off
    +
  • mute
    + Direkte Stummschaltung erfolgt nur per aktiviertem Upnp.
  • +
  • off
    Schaltet den TV aus. Der State des Gerätes wird auf "set_off" gesetzt. Dieser Wert wird nach 60 Sekunden wieder überschrieben oder sobald der TV entsprechend "off" meldet.
  • -
  • on
    +
  • on
    Einschalten des TV, ab Modelljahr 2013 per WOL. Der State des Gerätes wird auf "set_on" gesetzt. Dieser Wert wird nach 60 Sekunden wieder überschrieben oder sobald der TV entsprechend "on" meldet.
  • -
  • openUrl
    +
  • openUrl
    Öffnet eine URL auf dem Bildschirm. Diese Funktion ist ab Modelljahr 2013 verfügbar.
  • -
  • pause
    +
  • pause
    Pausiert die Wiedergabe einer Aufnahme, einer internen App, etc.
  • -
  • play
    +
  • play
    Startet die Wiedergabe einer Aufnahme, einer internen App, etc.
  • -
  • record
    +
  • record
    Startet die Aufnahme des aktuellen Inhalts.
  • -
  • register
    +
  • register
    Einmalige Registrierung von FHEM als Fernbedienung im TV.
    - Bei requestFormat = "xml" erfolgt die Registrierung ohne Parameter.
    - Bei requestFormat = "json" ist die Registrierung zweistufig.
    + Bei requestFormat = "xml" erfolgt die Registrierung ohne Parameter.
    + Bei requestFormat = "json" ist die Registrierung zweistufig.
    Beim Aufruf des Setter gibt es ein Eingabefeld:
    1. Aufruf mit leerem Eingabefeld. Auf dem TV sollte eine PIN zur Registrierung erscheinen.
    2. PIN im Eingabefeld eintragen und Registrierung noch mal ausführen
  • -
  • requestFormat
    +
  • requestFormat
    "xml" für xml-basierte Kommunikation 2011er/2012er Geräte
    "json" für die Kommunikation seit der 2013er Generation
  • -
  • remoteControl
    +
  • remoteControl
    Direktes Senden von Kommandos an den TV.
  • -
  • statusRequest
    +
  • statusRequest
    Ruft die aktuellen Statusinformationen vom TV ab.
  • -
  • stop
    +
  • stop
    Stoppt die Wiedergabe einer Aufnahme, einer internen App, etc.
  • -
  • text
    +
  • text
    Überträgt den eingegebenen Text in ein Textfeld der Anzeige.
  • -
  • toggle
    +
  • toggle
    Wechselt den Einschaltstatus des TV.
  • -
  • tvpause
    +
  • tvpause
    Aktiviert den Timeshift-Modus.
  • -
  • upnp
    +
  • upnp
    Aktiviert Upnp zum Abfragen und Einstellen der Lautstärke.
  • -
  • volume
    - Direktes Setzen der Lautstärke erfolgt nur per aktiviertem Upnp.
  • -
  • volumeDown
    +
  • volume
    + Direktes Setzen der Lautstärke erfolgt nur per aktiviertem Upnp.
  • +
  • volumeDown
    Verringert die Lautstärke.
  • -
  • volumeUp
    +
  • volumeUp
    Erhöht die Lautstärke.
@@ -2346,9 +2387,9 @@ sub BRAVIA_GetNormalizedName($) {

Attribute:
    -
  • channelsMax
    +
  • channelsMax
    Maximale Anzahl der im FHEMWEB angezeigten Kanäle. Der Standartwert ist 50.
  • -
  • macaddr
    +
  • macaddr
    Ermöglicht das Einschalten des TV per WOL.