diff --git a/fhem/FHEM/70_XBMC.pm b/fhem/FHEM/70_XBMC.pm
index 4330b9684..8a49ab83c 100644
--- a/fhem/FHEM/70_XBMC.pm
+++ b/fhem/FHEM/70_XBMC.pm
@@ -16,9 +16,9 @@ use strict;
use warnings;
use POSIX;
use JSON;
-#use JSON::RPC::Client;
use Data::Dumper;
use DevIo;
+use IO::Socket::INET;
use MIME::Base64;
sub XBMC_Initialize($$)
@@ -29,7 +29,7 @@ sub XBMC_Initialize($$)
$hash->{ReadFn} = "XBMC_Read";
$hash->{ReadyFn} = "XBMC_Ready";
$hash->{UndefFn} = "XBMC_Undefine";
- $hash->{AttrList} = "fork:enable,disable offMode:quit,hibernate,shutdown,standby";
+ $hash->{AttrList} = "fork:enable,disable compatibilityMode:xbmc,plex offMode:quit,hibernate,shutdown,standby " . $readingFnAttributes;
$data{RC_makenotify}{XBMC} = "XBMC_RCmakenotify";
$data{RC_layout}{XBMC_RClayout} = "XBMC_RClayout";
@@ -75,22 +75,24 @@ sub XBMC_Define($$)
sub XBMC_Ready($)
{
my ($hash) = @_;
- if(AttrVal($hash->{NAME},'fork','disable') eq 'enable') {
- if($hash->{CHILDPID} && !(kill 0, $hash->{CHILDPID})) {
- $hash->{CHILDPID} = undef;
+ if($hash->{Protocol} eq 'tcp') {
+ if(AttrVal($hash->{NAME},'fork','disable') eq 'enable') {
+ if($hash->{CHILDPID} && !(kill 0, $hash->{CHILDPID})) {
+ $hash->{CHILDPID} = undef;
+ return DevIo_OpenDev($hash, 1, "XBMC_Init");
+ }
+ elsif(!$hash->{CHILDPID}) {
+ return if($hash->{CHILDPID} = fork);
+ my $ppid = getppid();
+ while(kill 0, $ppid) {
+ DevIo_OpenDev($hash, 1, "XBMC_ChildExit");
+ sleep(5);
+ }
+ exit(0);
+ }
+ } else {
return DevIo_OpenDev($hash, 1, "XBMC_Init");
}
- elsif(!$hash->{CHILDPID}) {
- return if($hash->{CHILDPID} = fork);
- my $ppid = getppid();
- while(kill 0, $ppid) {
- DevIo_OpenDev($hash, 1, "XBMC_ChildExit");
- sleep(5);
- }
- exit(0);
- }
- } else {
- return DevIo_OpenDev($hash, 1, "XBMC_Init");
}
return undef;
}
@@ -151,11 +153,12 @@ sub XBMC_PlayerUpdate($$)
my $obj = {
"method" => "Player.GetProperties",
"params" => {
- "properties" => ["partymode", "totaltime", "repeat", "shuffled", "speed" ]
+ "properties" => ["time","totaltime", "repeat", "shuffled", "speed" ]
#"canseek", "canchangespeed", "canmove", "canzoom", "canrotate", "canshuffle", "canrepeat"
}
};
- if($playerid) {
+ push(@{$obj->{params}->{properties}}, 'partymode') if(AttrVal($hash->{NAME},'compatibilityMode','xbmc') eq 'xbmc');
+ if($playerid >= 0) {
$obj->{params}->{playerid} = $playerid;
XBMC_Call($hash,$obj,1);
}
@@ -228,23 +231,16 @@ sub XBMC_ProcessNotification($$)
elsif($obj->{method} eq "Player.OnPlay") {
my $id = XBMC_CreateId();
my $type = $obj->{params}->{data}->{item}->{type};
- if(!defined($obj->{params}->{data}->{item}->{id}) || $type eq "picture" || $type eq "unknown") {
+ if(AttrVal($hash->{NAME},'compatibilityMode','xbmc') eq 'plex' || !defined($obj->{params}->{data}->{item}->{id}) || $type eq "picture" || $type eq "unknown") {
readingsBeginUpdate($hash);
readingsBulkUpdate($hash,'playStatus','playing');
readingsBulkUpdate($hash,'type',$type);
- if(defined($obj->{params}->{data}->{item}->{artist})) {
- my $artist = $obj->{params}->{data}->{item}->{artist};
- if(ref($artist) eq 'ARRAY') {
- if(int(@$artist)) {
- $artist = join(',',@$artist);
- }
+ if(defined($obj->{params}->{data}->{item})) {
+ foreach my $key (keys %{$obj->{params}->{data}->{item}}) {
+ my $value = $obj->{params}->{data}->{item}->{$key};
+ XBMC_CreateReading($hash,$key,$value);
}
- readingsBulkUpdate($hash,'currentArtist', $artist);
}
- readingsBulkUpdate($hash,'currentAlbum',$obj->{params}->{data}->{item}->{album}) if(defined($obj->{params}->{data}->{item}->{album}));
- readingsBulkUpdate($hash,'currentTitle',$obj->{params}->{data}->{item}->{title}) if(defined($obj->{params}->{data}->{item}->{title}));
- readingsBulkUpdate($hash,'currentTrack',$obj->{params}->{data}->{item}->{track}) if(defined($obj->{params}->{data}->{item}->{track}));
- readingsBulkUpdate($hash,'currentMedia',$obj->{params}->{data}->{item}->{file}) if(defined($obj->{params}->{data}->{item}->{file}));
readingsEndUpdate($hash, 1);
}
elsif($type eq "song") {
@@ -336,7 +332,6 @@ sub XBMC_ProcessResponse($$)
my $name = $event->{name};
my $type = $event->{type};
my $value = '';
- #include song details into the event details
my $base = '';
$base = $obj->{result}->{songdetails} if($type eq 'song');
$base = $obj->{result}->{episodedetails} if($type eq 'episode');
@@ -348,14 +343,7 @@ sub XBMC_ProcessResponse($$)
readingsBulkUpdate($hash,'type',$type);
foreach my $key (keys %$base) {
my $item = $base->{$key};
- if(ref($item) eq 'ARRAY') {
- if(int(@$item)) {
- readingsBulkUpdate($hash,$key,join(',',@$item));
- }
- }
- else {
- readingsBulkUpdate($hash,$key,$item);
- }
+ XBMC_CreateReading($hash,$key,$item);
}
readingsEndUpdate($hash, 1);
}
@@ -377,37 +365,7 @@ sub XBMC_ProcessResponse($$)
readingsBeginUpdate($hash);
foreach my $key (keys %$properties) {
my $value = $properties->{$key};
- if($key eq 'version') {
- $value = $value->{major} . '.' . $value->{minor} . '-' . $value->{revision} . ' ' . $value->{tag};
- }
- elsif($key eq 'skin') {
- $value = $value->{name} . '(' . $value->{id} . ')';
- }
- elsif($key eq 'totaltime') {
- $value = sprintf('%02d:%02d:%02d.%03d',$value->{hours},$value->{minutes},$value->{seconds},$value->{milliseconds});
- }
- elsif($key eq 'shuffled') {
- $key = 'shuffle';
- $value = ($value ? 'on' : 'off');
- }
- elsif($key eq 'muted') {
- $key = 'mute';
- $value = ($value ? 'on' : 'off');
- }
- elsif($key eq 'speed') {
- readingsBulkUpdate($hash,'playStatus','playing') if $value != 0;
- readingsBulkUpdate($hash,'playStatus','paused') if $value == 0;
- }
- elsif($key =~ /(fullscreen|partymode)/) {
- $value = ($value ? 'on' : 'off');
- }
- elsif($key eq 'file') {
- $key = 'currentMedia';
- }
- elsif($key =~ /(album|artist|track|title)/) {
- $key = 'current' . ucfirst($key);
- }
- readingsBulkUpdate($hash,$key,$value);
+ XBMC_CreateReading($hash,$key,$value);
}
readingsEndUpdate($hash, 1);
}
@@ -415,6 +373,53 @@ sub XBMC_ProcessResponse($$)
return undef;
}
+sub XBMC_CreateReading($$$) {
+ my $hash = shift;
+ my $key = shift;
+ my $value = shift;
+ if($key eq 'version') {
+ my $version = '';
+ $version = $value->{major};
+ $version .= '.' . $value->{minor} if(defined($value->{minor}));
+ $version .= '-' . $value->{revision} if(defined($value->{revision}));
+ $version .= ' ' . $value->{tag} if(defined($value->{tag}));
+ $value = $version;
+ }
+ elsif($key eq 'skin') {
+ $value = $value->{name} . '(' . $value->{id} . ')';
+ }
+ elsif($key eq 'totaltime' || $key eq 'time') {
+ $value = sprintf('%02d:%02d:%02d.%03d',$value->{hours},$value->{minutes},$value->{seconds},$value->{milliseconds});
+ }
+ elsif($key eq 'shuffled') {
+ $key = 'shuffle';
+ $value = ($value ? 'on' : 'off');
+ }
+ elsif($key eq 'muted') {
+ $key = 'mute';
+ $value = ($value ? 'on' : 'off');
+ }
+ elsif($key eq 'speed') {
+ readingsBulkUpdate($hash,'playStatus','playing') if $value != 0;
+ readingsBulkUpdate($hash,'playStatus','paused') if $value == 0;
+ }
+ elsif($key =~ /(fullscreen|partymode)/) {
+ $value = ($value ? 'on' : 'off');
+ }
+ elsif($key eq 'file') {
+ $key = 'currentMedia';
+ }
+ elsif($key =~ /(album|artist|track|title)/) {
+ $key = 'current' . ucfirst($key);
+ }
+ if(ref($value) eq 'ARRAY') {
+ if(int(@$value)) {
+ $value = join(',',@$value);
+ }
+ }
+ readingsBulkUpdate($hash,$key,$value);
+}
+
#Parses a given string and returns ($msg,$tail). If the string contains a complete message
#(equal number of curly brackets) the return value $msg will contain this message. The
#remaining string is return in form of the $tail variable.
@@ -630,7 +635,7 @@ sub XBMC_Set($@)
"msg " .
"mute:toggle,on,off volume:slider,0,1,100 quit:noArg " .
"eject:noArg hibernate:noArg reboot:noArg shutdown:noArg suspend:noArg " .
- "videolibrary:scan,clean audiolibrary:scan,clean";
+ "videolibrary:scan,clean audiolibrary:scan,clean statusRequest";
return $res ;
}
@@ -909,7 +914,8 @@ sub XBMC_HTTP_Call($$$)
my ($hash,$obj,$id) = @_;
my $uri = "http://" . $hash->{Host} . ":" . $hash->{Port} . "/jsonrpc";
my $ret = XBMC_HTTP_Request(0,$uri,undef,$obj,undef,$hash->{Username},$hash->{Password});
- if($ret =~ /^error:(\d){3}$/) {
+ return undef if(!$ret);
+ if($ret =~ /^error:(\d{3})$/) {
return "HTTP Error Code " . $1;
}
return XBMC_ProcessResponse($hash,decode_json($ret)) if($id);
@@ -1023,7 +1029,7 @@ sub XBMC_HTTP_Request($$@)
define <name> XBMC <ip[:port]> <http|tcp> [<username>] [<password>]
- This module allows you to control XBMC and receive events from XBMC.
+ This module allows you to control XBMC and receive events from XBMC. It can also be used to control Plex (see attribute compatibilityMode).
Prerequisites
apt-get install libjson-perl
cpan install JSON
cpan install JSON
+ To get it working on a Fritzbox the JSON module has to be installed manually.