MEDIAPORTAL ip[:port]';
MEDIAPORTAL_Log $hash->{NAME}, 2, $msg;
return $msg;
}
DevIo_CloseDev($hash);
my $name = $a[0];
my $dev = $a[2];
$dev .= ":8017" if ($dev !~ m/:/ && $dev ne "none" && $dev !~ m/\@/);
$hash->{DeviceName} = $dev;
$hash->{STATE} = 'disconnected';
my $ret = undef;
$ret = DevIo_OpenDev($hash, 0, 'MEDIAPORTAL_DoInit') if (!AttrVal($hash->{NAME}, 'disable', 0));
return $ret;
}
########################################################################################
#
# MEDIAPORTAL_Undef
#
########################################################################################
sub MEDIAPORTAL_Undef($$) {
my ($hash, $arg) = @_;
RemoveInternalTimer($hash);
DevIo_CloseDev($hash);
return undef;
}
########################################################################################
#
# MEDIAPORTAL_Attribute
#
########################################################################################
sub MEDIAPORTAL_Attribute($@) {
my ($mode, $devName, $attrName, $attrValue) = @_;
my $hash = $defs{$devName};
my $disableChange = 0;
if($mode eq 'set') {
if ($attrName eq 'disable') {
if ($attrValue && AttrVal($devName, $attrName, 0) != 1) {
MEDIAPORTAL_Log($devName, 5, 'Neu-Disabled');
$disableChange = 1;
}
if (!$attrValue && AttrVal($devName, $attrName, 0) != 0) {
MEDIAPORTAL_Log($devName, 5, 'Neu-Enabled');
$disableChange = 1;
}
}
} elsif ($mode eq 'del') {
if ($attrName eq 'disable') {
if (AttrVal($devName, $attrName, 0) != 0) {
MEDIAPORTAL_Log($devName, 5, 'Deleted-Disabled');
$disableChange = 1;
$attrValue = 0;
}
}
}
if ($disableChange) {
# Wenn die Verbindung beendet werden muss...
if ($attrValue) {
MEDIAPORTAL_Log $devName, 5, 'Call AttributeFn: Stop Connection...';
DevIo_CloseDev($hash);
}
# Wenn die Verbindung gestartet werden muss...
if (!$attrValue) {
MEDIAPORTAL_Log $devName, 5, 'Call AttributeFn: Start Connection...';
DevIo_OpenDev($hash, 1, 'MEDIAPORTAL_DoInit');
}
}
return undef;
}
########################################################################################
#
# MEDIAPORTAL_DoInit
#
########################################################################################
sub MEDIAPORTAL_DoInit($) {
my ($hash) = @_;
readingsSingleUpdate($hash, 'state', 'Connecting...', 1);
$hash->{helper}{buffer} = '';
$hash->{helper}{LastStatusTimestamp} = time();
$hash->{GraceRetries} = 0;
# Versuch, die MAC-Adresse des Ziels selber herauszufinden...
if (AttrVal($hash->{NAME}, 'macaddress', '') eq '') {
my $newmac = MEDIAPORTAL_GetMAC($hash);
if (defined($newmac)) {
CommandAttr(undef, $hash->{NAME}.' macaddress '.$newmac);
}
}
#RemoveInternalTimer($hash);
#InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval), 'MEDIAPORTAL_GetIntervalStatus', $hash, 0) if AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval);
return undef;
}
########################################################################################
#
# MEDIAPORTAL_Ready
#
########################################################################################
sub MEDIAPORTAL_Ready($) {
my ($hash) = @_;
MEDIAPORTAL_Log $hash->{NAME}, 4, "Ready-Call";
return DevIo_OpenDev($hash, 1, 'MEDIAPORTAL_DoInit');
}
########################################################################################
#
# MEDIAPORTAL_Get
#
########################################################################################
sub MEDIAPORTAL_Get($@) {
my ($hash, @a) = @_;
my $cname = $a[1];
my $cmd = '';
return 'Module disabled!' if AttrVal($hash->{NAME}, 'disable', 0);
if ($cname eq "status") {
$cmd = "{\"Type\":\"requeststatus\"}\r\n";
} elsif ($cname eq "nowplaying") {
$cmd = "{\"Type\":\"requestnowplaying\"}\r\n";
} elsif ($cname eq "notify") {
$cmd = '{"Type":"properties","Properties":["#Play.Current.Title","#TV.View.title"]}'."\r\n";
} elsif ($cname eq "plugins") {
$cmd = "{\"Type\":\"plugins\",\"SendIcons\":false}\r\n";
} else {
return "Unknown command '$cname', choose one of status:noArg nowplaying:noArg plugins:noArg";
}
DevIo_SimpleWrite($hash, $cmd, 0);
return undef;
}
########################################################################################
#
# MEDIAPORTAL_GetStatus
#
########################################################################################
sub MEDIAPORTAL_GetStatus($) {
my ($hash) = @_;
MEDIAPORTAL_Get($hash, ($hash->{NAME}, 'status'));
}
########################################################################################
#
# MEDIAPORTAL_GetIntervalStatus
#
########################################################################################
sub MEDIAPORTAL_GetIntervalStatus($) {
my ($hash) = @_;
# Heartbeat-Prüfung nur machen, wenn es auch gewünscht wurde...
return undef if (!AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval));
# Ein "Disconnected" wird erst nach einigen Fehlversuchen hingenommen...
if (ReadingsVal($hash->{NAME}, 'state', 'disconnected') eq 'disconnected') {
$hash->{GraceRetries}++;
return undef if ($hash->{GraceRetries} > $MEDIAPORTAL_MaxGraceRetries);
# Reconnect veranlassen...
MEDIAPORTAL_Set($hash, ($hash->{NAME}, 'reconnect'));
InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval), 'MEDIAPORTAL_GetIntervalStatus', $hash, 0);
}
# Prüfen, wann der letzte Status zugestellt wurde...
if (time() - $hash->{helper}{LastStatusTimestamp} > (2 * $MEDIAPORTAL_HeartbeatInterval + 5)) {
MEDIAPORTAL_Log $hash->{NAME}, 3, 'GetIntervalStatus hat festgestellt, dass Mediaportal sich seit '.(time() - $hash->{helper}{LastStatusTimestamp}).'s nicht zurückgemeldet hat. Die Verbindung wird neu aufgebaut!';
MEDIAPORTAL_Set($hash, ($hash->{NAME}, 'reconnect'));
InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval), 'MEDIAPORTAL_GetIntervalStatus', $hash, 0);
return undef;
}
# Status anfordern...
MEDIAPORTAL_Get($hash, ($hash->{NAME}, 'status'));
InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval), 'MEDIAPORTAL_GetIntervalStatus', $hash, 0);
}
########################################################################################
#
# MEDIAPORTAL_GetNowPlaying
#
########################################################################################
sub MEDIAPORTAL_GetNowPlaying($) {
my ($hash) = @_;
MEDIAPORTAL_Get($hash, ($hash->{NAME}, 'nowplaying'));
}
########################################################################################
#
# MEDIAPORTAL_GetPlugins
#
########################################################################################
sub MEDIAPORTAL_GetPlugins($) {
my ($hash) = @_;
MEDIAPORTAL_Get($hash, ($hash->{NAME}, 'plugins'));
}
########################################################################################
#
# MEDIAPORTAL_Set
#
########################################################################################
sub MEDIAPORTAL_Set($@) {
my ($hash, @a) = @_;
my $cname = $a[1];
my $cmd = '';
my $powermodes = 'logoff suspend hibernate reboot shutdown exit';
my $mpcommands = 'stop record pause play rewind forward replay skip back info menu up down left right ok volup voldown volmute chup chdown dvdmenu 0 1 2 3 4 5 6 7 8 9 0 clear enter teletext red blue yellow green home basichome nowplaying tvguide tvrecs dvd playlists first last fullscreen subtitles audiotrack screenshot';
my $playlistcommands = 'play loadlist loadlist_shuffle loadfrompath loadfrompath_shuffle';
# Legacy Volume writing...
$cname = 'Volume' if (lc($cname) eq 'volume');
return 'Module disabled!' if AttrVal($hash->{NAME}, 'disable', 0);
if ($cname eq "command") {
if (!MEDIAPORTAL_isInList($a[2], split(/ /, $mpcommands))) {
return "Unknown command '$a[2]'. Supported commands are: $mpcommands";
}
$cmd = "{\"Type\":\"command\",\"Command\":\"$a[2]\"}\r\n";
} elsif ($cname eq "wakeup") {
my $macaddress = AttrVal($hash->{NAME}, 'macaddress', '');
if ($macaddress ne '') {
MEDIAPORTAL_Wakeup($macaddress);
$hash->{GraceRetries} = 0;
#MEDIAPORTAL_Set($hash, ($hash->{NAME}, 'reconnect'));
#InternalTimer(gettimeofday() + AttrVal($hash->{NAME}, 'HeartbeatInterval', $MEDIAPORTAL_HeartbeatInterval), 'MEDIAPORTAL_GetIntervalStatus', $hash, 0);
return 'WakeUp-Signal sent!';
} else {
return 'No MacAddress set! No WakeUp-Signal sent!';
}
} elsif ($cname eq "sleep") {
return MEDIAPORTAL_Set($hash, ($hash->{NAME}, 'powermode', 'hibernate'));
} elsif ($cname eq "key") {
$cmd = "{\"Type\":\"key\",\"Key\":\"$a[2]\"}\r\n";
} elsif ($cname eq "Volume") {
if (($a[2] ne $a[2]+0) || ($a[2]<0) || ($a[2]>100)) {
return "the volume must be in the range 0..100";
}
$cmd = "{\"Type\":\"volume\",\"Volume\":$a[2]}\r\n";
} elsif ($cname eq "powermode") {
if (!MEDIAPORTAL_isInList($a[2], split(/ /, $powermodes))) {
return "Unknown powermode '$a[2]'. Supported powermodes are: $powermodes";
}
$cmd = "{\"Type\":\"powermode\",\"PowerMode\":\"$a[2]\"}\r\n";
} elsif ($cname eq "playfile") {
$cmd = "{\"Type\":\"playfile\",\"FileType\":\"$a[2]\",\"Filepath\":\"$a[3]\"}\r\n";
} elsif ($cname eq "playchannel") {
if ($a[2] ne $a[2]+0) {
return "playchannel needs a valid channelid of type int";
}
$cmd = "{\"Type\":\"playchannel\",\"ChannelId\":$a[2]}\r\n";
} elsif ($cname eq "playradiochannel") {
if ($a[2] ne $a[2]+0) {
return "playradiochannel needs a valid channelid of type int";
}
$cmd = "{\"Type\":\"playradiochannel\",\"ChannelId\":$a[2]}\r\n";
} elsif ($cname eq "playlist") {
if (!MEDIAPORTAL_isInList($a[2], split(/ /, $playlistcommands))) {
return "Unknown playlist command '$a[2]'. Supported commands are: $playlistcommands";
}
if ($a[2] eq "play") {
if ($a[3] ne $a[3]+0) {
return "playlist play needs a valid index to start of type int";
}
$cmd = "{\"Type\":\"playlist\",\"PlaylistAction\":\"play\",\"Index\":$a[3]}\r\n";
} elsif ($a[2] eq "loadlist") {
$cmd = "{\"Type\":\"playlist\",\"PlaylistAction\":\"load\",\"PlaylistName\":\"$a[3]\"}\r\n";
} elsif ($a[2] eq "loadlist_shuffle") {
$cmd = "{\"Type\":\"playlist\",\"PlaylistAction\":\"load\",\"PlaylistName\":\"$a[3]\",\"Shuffle\":true}\r\n";
} elsif ($a[2] eq "loadfrompath") {
$cmd = "{\"Type\":\"playlist\",\"PlaylistAction\":\"load\",\"PlaylistPath\":\"$a[3]\"}\r\n";
} elsif ($a[2] eq "loadfrompath_shuffle") {
$cmd = "{\"Type\":\"playlist\",\"PlaylistAction\":\"load\",\"PlaylistPath\":\"$a[3]\",\"Shuffle\":true}\r\n";
}
} elsif ($cname eq "connect") {
$hash->{NEXT_OPEN} = 0; # force NEXT_OPEN used in DevIO
return undef;
} elsif ($cname eq "reconnect") {
DevIo_CloseDev($hash);
select(undef, undef, undef, 0.2);
DevIo_OpenDev($hash, 1, 'MEDIAPORTAL_DoInit');
return undef;
} elsif ($cname eq "window") {
my $param = $a[2];
if (!looks_like_number($param)) {
my %plugins = %{eval(ReadingsVal($hash->{NAME}, 'Plugins', '()'))};
$param =~ s/\%20/ /g;
$param = $plugins{$param};
}
$cmd = "{\"Type\":\"window\",\"Window\":$param}\r\n";
} else {
my %plugins = ();
eval {
%plugins = %{eval(ReadingsVal($hash->{NAME}, 'Plugins', '()'))};
};
return "Unknown command '$cname', choose one of wakeup:noArg sleep:noArg connect:noArg reconnect:noArg command:".join(',', split(/ /, $mpcommands))." key Volume:slider,0,1,100 powermode:".join(',', split(/ /, $powermodes))." playfile playchannel playradiochannel playlist window".((scalar(keys(%plugins)) != 0) ? ':'.join(',', map { s/ /%20/g; $_; } sort(keys(%plugins))) : '');
}
DevIo_SimpleWrite($hash, $cmd, 0);
return undef;
}
########################################################################################
#
# MEDIAPORTAL_Read
# Receives an event and creates several readings for event triggering
#
########################################################################################
sub MEDIAPORTAL_Read($) {
my ($hash) = @_;
my $buf = DevIo_SimpleRead($hash);
if(!defined($buf)) {
MEDIAPORTAL_Log $hash->{NAME}, 3, 'DevIo_SimpleRead hat keine Daten geliefert, obwohl Read aufgerufen wurde! Setze Buffer und einige Readings zurück. Aktueller Buffer: '.$hash->{helper}{buffer};
$hash->{helper}{buffer} = '';
return undef;
}
return undef if AttrVal($hash->{NAME}, 'disable', 0);
$hash->{GraceRetries} = 0;
MEDIAPORTAL_Log $hash->{NAME}, 5, "RAW MSG: $buf";
# Zum Buffer hinzufügen
$hash->{helper}{buffer} .= $buf;
# Bereits vollständige JSON-Strings verarbeiten...
my @groups = $hash->{helper}{buffer} =~ m/({(?:[^{}]++|(?1))*})/xg;
for my $elem (@groups) {
MEDIAPORTAL_ProcessMessage($hash, $elem);
}
# Bereits verarbeitetes aus dem Buffer wieder entfernen...
$hash->{helper}{buffer} =~ s/[ \r\n]*({(?:[^{}]++|(?1))*})[ \r\n]*//xg;
return undef;
}
########################################################################################
#
# MEDIAPORTAL_ProcessMessage
#
########################################################################################
sub MEDIAPORTAL_ProcessMessage($$) {
my ($hash, $msg) = @_;
MEDIAPORTAL_Log $hash->{NAME}, 5, "Message received: $msg";
my $json = {};
eval {
$json = from_json($msg);
};
if ($@) {
MEDIAPORTAL_Log $hash->{NAME}, 5, "Error during JSON-Parser with 'from_json()'-call (but just keep trying another way): $@";
eval {
$json = decode_json(decode('iso8859-1', $msg));
};
if ($@) {
MEDIAPORTAL_Log $hash->{NAME}, 1, "Final Error during JSON-Parser: $@";
return;
}
}
if (defined($json->{Type})) {
if ($json->{Type} eq "welcome") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'WELCOME received. Sending identify message.';
DevIo_SimpleWrite($hash, MEDIAPORTAL_GetMSG_identify($hash), 0);
} elsif ($json->{Type} eq "authenticationresponse") {
MEDIAPORTAL_Log $hash->{NAME}, 4, "AUTHRESPONSE received. SUCCESS=$json->{Success}";
#readingsSingleUpdate($hash, 'state', 'Authenticated. Processing messages.', 1);
readingsSingleUpdate($hash, 'state', 'opened', 1);
InternalTimer(gettimeofday() + 1, 'MEDIAPORTAL_GetPlugins', $hash, 0);
} elsif ($json->{Type} eq "status") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'STATUS received.';
my $playStatus = 'Stopped';
$playStatus = 'Playing' if ($json->{IsPlaying});
$playStatus = 'Paused' if ($json->{IsPaused});
my $title = '';
$title = $json->{Title} if (defined($json->{Title}) && $json->{Title});
if (defined($json->{SelectedItem}) && $json->{SelectedItem} ne '' && $title eq '') {
$title = 'Auswahl: '.$json->{SelectedItem};
# Wenn der Titel während des Abspielens nicht mitgeliefert wurde, dann für später nochmal anfordern...
# Das ist ein Bug in Wifiremote, das den Titel beim Start nicht immer mitliefert.
if ($json->{IsPlaying}) {
InternalTimer(gettimeofday() + 5, 'MEDIAPORTAL_GetNowPlaying', $hash, 0);
}
}
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'IsPlaying', $json->{IsPlaying});
readingsBulkUpdate($hash, 'IsPaused', $json->{IsPaused});
readingsBulkUpdate($hash, 'playStatus', $playStatus);
readingsBulkUpdate($hash, 'CurrentModule', $json->{CurrentModule});
readingsBulkUpdate($hash, 'Title', $title);
# Wenn der Abspielstatus auf Stopped gewechselt hat, dann einige Readings löschen...
if ($json->{IsPlaying} eq 'false' && $json->{IsPaused} eq 'false') {
readingsBulkUpdate($hash, 'Title', '');
readingsBulkUpdate($hash, 'Description', '');
readingsBulkUpdate($hash, 'nextTitle', '');
readingsBulkUpdate($hash, 'nextDescription', '');
readingsBulkUpdate($hash, 'mediaType', '');
readingsBulkUpdate($hash, 'tvChannel', '');
readingsBulkUpdate($hash, 'tvCurrentProgramName', '');
readingsBulkUpdate($hash, 'tvNextProgramName', '');
readingsBulkUpdate($hash, 'movieTitle', '');
readingsBulkUpdate($hash, 'seriesName', '');
readingsBulkUpdate($hash, 'seriesSeason', '');
readingsBulkUpdate($hash, 'seriesEpisode', '');
readingsBulkUpdate($hash, 'seriesTitle', '');
readingsBulkUpdate($hash, 'recordingChannel', '');
readingsBulkUpdate($hash, 'recordingProgramName', '');
readingsBulkUpdate($hash, 'Position', '0:00:00');
readingsBulkUpdate($hash, 'PositionPercent', 0);
readingsBulkUpdate($hash, 'File', '');
readingsBulkUpdate($hash, 'Duration', '0:00:00');
}
readingsEndUpdate($hash, 1);
$hash->{helper}{LastStatusTitle} = $title;
$hash->{helper}{LastStatusTimestamp} = time();
} elsif ($json->{Type} eq "volume") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'VOLUME received.';
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'Volume', $json->{Volume});
readingsBulkUpdate($hash, 'IsMuted', $json->{IsMuted});
readingsEndUpdate($hash, 1);
} elsif ($json->{Type} eq "nowplaying") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'NOWPLAYING received.';
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'Duration', MEDIAPORTAL_ConvertSecondsToTime($json->{Duration}));
readingsBulkUpdate($hash, 'Position', MEDIAPORTAL_ConvertSecondsToTime($json->{Position}));
if ($json->{Duration}) {
readingsBulkUpdate($hash, 'PositionPercent', sprintf(AttrVal($hash->{NAME}, 'PositionPercentFormat', '%.1f'), 100 * $json->{Position} / $json->{Duration}));
} else {
readingsBulkUpdate($hash, 'PositionPercent', 0);
}
readingsBulkUpdate($hash, 'File', $json->{File});
readingsBulkUpdate($hash, 'Title', '');
readingsBulkUpdate($hash, 'Description', '');
readingsBulkUpdate($hash, 'nextTitle', '');
readingsBulkUpdate($hash, 'nextDescription', '');
# Special MediaInformations...
if ($json->{IsTv}) {
readingsBulkUpdate($hash, 'mediaType', 'tv');
} else {
readingsBulkUpdate($hash, 'mediaType', '');
}
readingsBulkUpdate($hash, 'tvChannel', '');
readingsBulkUpdate($hash, 'tvCurrentProgramName', '');
readingsBulkUpdate($hash, 'tvNextProgramName', '');
readingsBulkUpdate($hash, 'movieTitle', '');
readingsBulkUpdate($hash, 'seriesName', '');
readingsBulkUpdate($hash, 'seriesSeason', '');
readingsBulkUpdate($hash, 'seriesEpisode', '');
readingsBulkUpdate($hash, 'seriesTitle', '');
readingsBulkUpdate($hash, 'recordingChannel', '');
readingsBulkUpdate($hash, 'recordingProgramName', '');
if (defined($json->{MediaInfo})) {
readingsBulkUpdate($hash, 'mediaType', $json->{MediaInfo}{MediaType}) if ($json->{MediaInfo}{MediaType});
if ($json->{MediaInfo}{MediaType} eq 'tv') {
readingsBulkUpdate($hash, 'Title', $json->{MediaInfo}{ChannelName}.' - '.$json->{MediaInfo}{CurrentProgramName});
readingsBulkUpdate($hash, 'Description', $json->{MediaInfo}{CurrentProgramDescription});
readingsBulkUpdate($hash, 'tvChannel', $json->{MediaInfo}{ChannelName});
readingsBulkUpdate($hash, 'tvCurrentProgramName', $json->{MediaInfo}{CurrentProgramName});
if (defined($json->{MediaInfo}{NextProgramName})) {
readingsBulkUpdate($hash, 'nextTitle', $json->{MediaInfo}{ChannelName}.' - '.$json->{MediaInfo}{NextProgramName});
readingsBulkUpdate($hash, 'nextDescription', $json->{MediaInfo}{NextProgramDescription});
readingsBulkUpdate($hash, 'tvNextProgramName', $json->{MediaInfo}{NextProgramName});
}
} elsif ($json->{MediaInfo}{MediaType} eq 'movie') {
readingsBulkUpdate($hash, 'Title', $json->{MediaInfo}{Title});
readingsBulkUpdate($hash, 'Description', $json->{MediaInfo}{Summary});
readingsBulkUpdate($hash, 'movieTitle', $json->{MediaInfo}{Title});
} elsif ($json->{MediaInfo}{MediaType} eq 'series') {
readingsBulkUpdate($hash, 'Title', $json->{MediaInfo}{Series}.' S'.sprintf("%02d", $json->{MediaInfo}{Season}).'E'.sprintf("%02d", $json->{MediaInfo}{Episode}).' - '.$json->{MediaInfo}{Title});
readingsBulkUpdate($hash, 'Description', $json->{MediaInfo}{Plot});
readingsBulkUpdate($hash, 'seriesName', $json->{MediaInfo}{Series});
readingsBulkUpdate($hash, 'seriesSeason', $json->{MediaInfo}{Season});
readingsBulkUpdate($hash, 'seriesEpisode', $json->{MediaInfo}{Episode});
readingsBulkUpdate($hash, 'seriesTitle', $json->{MediaInfo}{Title});
} elsif ($json->{MediaInfo}{MediaType} eq 'recording') {
readingsBulkUpdate($hash, 'Title', $json->{MediaInfo}{ChannelName}.' - '.$json->{MediaInfo}{ProgramName});
readingsBulkUpdate($hash, 'Description', $json->{MediaInfo}{ProgramDescription});
readingsBulkUpdate($hash, 'recordingChannel', $json->{MediaInfo}{ChannelName});
readingsBulkUpdate($hash, 'recordingProgramName', $json->{MediaInfo}{ProgramName});
} else {
MEDIAPORTAL_Log $hash->{NAME}, 0, 'Unbekannte MediaInfo für "'.$json->{MediaInfo}{MediaType}.'" geliefert, aber nicht verarbeitet. Bitte diese komplette Information ins Forum einstellen: '.Dumper($json->{MediaInfo});
}
} else {
# Die MediaInfos wurden nicht mitgeliefert...
# Hier nochmal versuchen, den Titel zu extrahieren...
my $title = '';
$title = $json->{Title} if (defined($json->{Title}) && $json->{Title});
if ($title eq '') {
readingsBulkUpdate($hash, 'Title', $hash->{helper}{LastStatusTitle});
} else {
readingsBulkUpdate($hash, 'Title', $title);
}
}
readingsEndUpdate($hash, 1);
} elsif ($json->{Type} eq "nowplayingupdate") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'NOWPLAYINGUPDATE received.';
readingsBeginUpdate($hash);
readingsBulkUpdate($hash, 'Duration', MEDIAPORTAL_ConvertSecondsToTime($json->{Duration}));
readingsBulkUpdate($hash, 'Position', MEDIAPORTAL_ConvertSecondsToTime($json->{Position}));
if ($json->{Duration}) {
readingsBulkUpdate($hash, 'PositionPercent', sprintf(AttrVal($hash->{NAME}, 'PositionPercentFormat', '%.1f'), 100 * $json->{Position} / $json->{Duration}));
} else {
readingsBulkUpdate($hash, 'PositionPercent', 0);
}
readingsEndUpdate($hash, AttrVal($hash->{NAME}, 'generateNowPlayingUpdateEvents', 0));
} elsif ($json->{Type} eq "properties") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'PROPERTIES received.';
MEDIAPORTAL_Log undef, 4, 'JSON: '.Dumper($json);
} elsif ($json->{Type} eq "facadeinfo") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'FACADEINFO received.';
} elsif ($json->{Type} eq "dialog") {
MEDIAPORTAL_Log $hash->{NAME}, 4, 'DIALOG received.';
} elsif ($json->{Type} eq "plugins") {
MEDIAPORTAL_Log $hash->{NAME}, 1, 'Plugins received.';
eval {
my %plugins = ();
foreach (@{$json->{Plugins}}) {
$plugins{$_->{Name}} = $_->{WindowId};
}
readingsSingleUpdate($hash, 'Plugins', MEDIAPORTAL_Dumper(\%plugins), 1);
};
if ($@) {
MEDIAPORTAL_Log $hash->{NAME}, 1, "Error during processing of plugins: $@";
}
} else {
MEDIAPORTAL_Log $hash->{NAME}, 1, "Unhandled message received: MessageType '$json->{Type}'";
}
} else {
MEDIAPORTAL_Log $hash->{NAME}, 1, 'Unhandled message received without any Messagetype: '.$msg;
}
}
########################################################################################
#
# MEDIAPORTAL_GetMSG_identify
#
########################################################################################
sub MEDIAPORTAL_GetMSG_identify($) {
my ($hash) = @_;
my $authmethod=AttrVal($hash->{NAME}, 'authmethod', 'none');
my $uid = AttrVal($hash->{NAME}, 'username', '');
my $pwd = AttrVal($hash->{NAME}, 'password', '');
my $cmd = {
Type => 'identify',
Name => 'MP_Connector',
Application => 'FHEM',
Version => '1.0'
};
if ($authmethod ne "none") {
$cmd->{Authenticate}{AuthMethod} = $authmethod;
$cmd->{Authenticate}{User} = $uid;
$cmd->{Authenticate}{Password} = $pwd;
}
my $strcmd = encode_json($cmd)."\r\n";
return $strcmd;
}
########################################################################################
#
# MEDIAPORTAL_GetMAC
#
########################################################################################
sub MEDIAPORTAL_GetMAC($) {
my ($hash) = @_;
my $mac = undef;
eval {
my ($host, $port) = split(/:/, $hash->{DeviceName});
my $result = qx/arp -a $host/;
MEDIAPORTAL_Log undef, 5, 'ARP-SysCall: '.$result;
$mac = uc($1) if ($result =~ m/([0-9a-fA-F]{2}(:|-)[0-9a-fA-F]{2}(:|-)[0-9a-fA-F]{2}(:|-)[0-9a-fA-F]{2}(:|-)[0-9a-fA-F]{2}(:|-)[0-9a-fA-F]{2})/s);
$mac =~ s/-/:/g if (defined($mac)); # Korrektur für Windows-Rechner
if (defined($mac)) {
MEDIAPORTAL_Log undef, 5, 'Found Mac: '.$mac;
} else {
MEDIAPORTAL_Log undef, 5, 'No Mac Found!';
}
};
if ($@) {
return undef;
}
return undef if (defined($mac) && ($mac eq '00:00:00:00:00:00')); # Unter Windows wird im Fehlerfall diese Adresse zurückgegeben.
return $mac;
}
########################################################################################
#
# MEDIAPORTAL_Wakeup
#
########################################################################################
sub MEDIAPORTAL_Wakeup($;$$) {
my ($hwaddr, $ipaddr, $port) = @_;
$ipaddr = '255.255.255.255' if (!defined($ipaddr));
$port = getservbyname('discard', 'udp') if (!defined($port));
# Zur Sicherheit zweimal senden...
return MEDIAPORTAL_DoWakeup($hwaddr, $ipaddr, $port) || MEDIAPORTAL_DoWakeup($hwaddr, $ipaddr, $port);
}
########################################################################################
#
# MEDIAPORTAL_DoWakeup
#
########################################################################################
sub MEDIAPORTAL_DoWakeup($;$$) {
my ($hwaddr, $ipaddr, $port) = @_;
$ipaddr = '255.255.255.255' if (!defined($ipaddr));
$port = getservbyname('discard', 'udp') if (!defined($port));
# Validate hardware address (ethernet address)
my $hwaddr_re = join(':', ('[0-9A-Fa-f]{1,2}') x 6);
if ($hwaddr !~ m/^$hwaddr_re$/) {
warn "Invalid hardware address: $hwaddr\n";
return undef;
}
# Generate magic sequence
my $pkt = '';
foreach (split /:/, $hwaddr) {
$pkt .= chr(hex($_));
}
$pkt = chr(0xFF) x 6 . $pkt x 16;
# Allocate socket and send packet
my $raddr = gethostbyname($ipaddr);
my $them = pack_sockaddr_in($port, $raddr);
my $proto = getprotobyname('udp');
socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt : $!";
send(S, $pkt, 0, $them) or die "send : $!";
close S;
return 1;
}
########################################################################################
#
# MEDIAPORTAL_GetTimeSeconds
#
########################################################################################
sub MEDIAPORTAL_GetTimeSeconds($) {
my ($timeStr) = @_;
return MEDIAPORTAL_Max(int($1)*3600 + int($2)*60 + int($3), 1) if ($timeStr =~ m/(\d+):(\d+):(\d+)/);
return 0;
}
########################################################################################
#
# MEDIAPORTAL_ConvertSecondsToTime
#
########################################################################################
sub MEDIAPORTAL_ConvertSecondsToTime($) {
my ($seconds) = @_;
return sprintf('%01d:%02d:%02d', $seconds / 3600, ($seconds%3600) / 60, $seconds%60) if ($seconds > 0);
return '0:00:00';
}
########################################################################################
#
# MEDIAPORTAL_Max
#
########################################################################################
sub MEDIAPORTAL_Max($$) {
$_[$_[0] < $_[1]]
}
########################################################################################
#
# MEDIAPORTAL_isInList
#
########################################################################################
sub MEDIAPORTAL_isInList($@) {
my($search, @list) = @_;
return 1 if MEDIAPORTAL_posInList($search, @list) >= 0;
return 0;
}
########################################################################################
#
# MEDIAPORTAL_posInList
#
########################################################################################
sub MEDIAPORTAL_posInList($@) {
my($search, @list) = @_;
for (my $i = 0; $i <= $#list; $i++) {
return $i if ($list[$i] && $search eq $list[$i]);
}
return -1;
}
########################################################################################
#
# MEDIAPORTAL_Dumper - Returns the 'Dumpered' Output of the given Datastructure-Reference
#
########################################################################################
sub MEDIAPORTAL_Dumper($) {
my ($varRef) = @_;
$Data::Dumper::Indent = 0;
my $text = Dumper($varRef);
$Data::Dumper::Indent = 2;
return $text;
}
########################################################################################
#
# MEDIAPORTAL_Log - Log to the normal Log-command with the prefix 'MEDIAPORTAL'
#
########################################################################################
sub MEDIAPORTAL_Log($$$) {
my ($devicename, $level, $text) = @_;
Log3 $devicename, $level, 'MEDIAPORTAL: '.$text;
}
1;
=pod
=item summary Connects to a running MediaPortal instance via the WifiRemote plugin.
=item summary_DE Verbindet sich über das Wifiremote-Plugin mit einer Mediaportal-Instanz.
=begin html
MEDIAPORTAL
Connects to a running MediaPortal instance via the WifiRemote plugin
Example
define wohnzimmer_Mediaportal MEDIAPORTAL 192.168.0.47:8017
Define
define <name> MEDIAPORTAL host[:port]
Define a Mediaportal interface to communicate with a Wifiremote-Plugin of a Mediaportal-System.
host[:port]
The name and port of the Mediaportal-Wifiremote-Plugin. If Port is not given, the default of 8017
will be used.
Set
- Common Tasks
-
connect
Connects to Mediaportal immediately without waiting for the normal Fhem-Timeout for reconnect (30s).
-
powermode <mode>
One of (logoff, suspend, hibernate, reboot, shutdown, exit). Sets the powermode, e.g. shutdown, for shutdown the computersystem of the Mediaportal-System.
-
reconnect
Re-Connects to Mediaportal immediately.
- Control-Commands
-
command <command>
One of (stop, record, pause, play, rewind, forward, replay, skip, back, info, menu, up, down, left, right, ok, volup, voldown, volmute, chup, chdown, dvdmenu, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, clear, enter, teletext, red, blue, yellow, green, home, basichome, nowplaying, tvguide, tvrecs, dvd, playlists, first, last, fullscreen, subtitles, audiotrack, screenshot). Sends the given command to the player.
-
key <keyvalue>
Sends the given key to the player.
-
sleep
Sends the hinernate-signal to Mediaportal. This command is a shortcut for "powermode hibernate"
-
wakeup
Wakes the Mediaportal-System up (WakeUp-On-LAN).
- Play-Commands
Get
- Common Tasks
-
status
Call for the answer of a status
-Message. e.g. Asynchronously retrieves the information of "Title" and "PlayStatus".
-
nowplaying
Call for the answer of a nowplaying
-Message. e.g. Asynchronously retrieves the information of "Duration", "Position" and "File"".
Attributes
- Common
disable <value>
One of (0, 1). With this attribute you can disable the module.
generateNowPlayingUpdateEvents <value>
One of (0, 1). With this value you can disable (or enable) the generation of NowPlayingUpdate
-Events. If set, Fhem generates an event per second with the updated time-values for the current playing. Defaults to "0".
HeartbeatInterval <interval>
In seconds. Defines the heartbeat interval in seconds which is used for testing the correct work of the connection to Mediaportal. A value of 0 deactivate the heartbeat-check. Defaults to "15".
macaddress <address>
Sets the MAC-Address for the Player. This is needed for WakeUp-Function. e.g. "90:E6:BA:C2:96:15"
- Authentication
authmethod <value>
One of (none, userpassword, passcode, both). With this value you can set the authentication-mode.
password <value>
With this value you can set the password for authentication.
username <value>
With this value you can set the username for authentication.
=end html
=begin html_DE
MEDIAPORTAL
Verbindet sich über das Wifiremote-Plugin mit einer laufenden Mediaportal-Instanz.
Beispiel
define wohnzimmer_Mediaportal MEDIAPORTAL 192.168.0.47:8017
Define
define <name> MEDIAPORTAL host[:port]
Definiert ein Mediaportal Interface für die Kommunikation mit einem Wifiremote-Plugin einer Mediaportal Installation.
host[:port]
Der Hostname und der Port eines laufenden Mediaportal-Wifiremote-Plugins. Wenn der Port nicht angegeben wurde, wird 8017
als Standard verwendet.
Set
- Grundsätzliches
-
connect
Erzwingt eine sofortige Verbindung zu Mediaportal. Normalerweise würde die normale Verbindungswiederholung von Fhem (30s) abgewartet werden.
-
powermode <mode>
Eins aus (logoff, suspend, hibernate, reboot, shutdown, exit). Setzt den powermode, z.B. shutdown, zum Herunterfahren des Computers des Mediaportal-Systems.
-
reconnect
Erzwingt eine sofortige Trennung und Neuverbindung zu Mediaportal.
- Control-Befehle
-
command <command>
Eins aus (stop, record, pause, play, rewind, forward, replay, skip, back, info, menu, up, down, left, right, ok, volup, voldown, volmute, chup, chdown, dvdmenu, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, clear, enter, teletext, red, blue, yellow, green, home, basichome, nowplaying, tvguide, tvrecs, dvd, playlists, first, last, fullscreen, subtitles, audiotrack, screenshot). Sendet das entsprechende Kommando an den Player.
-
key <keyvalue>
Sendet die entsprechende Taste an den Player.
-
sleep
Startet den Hibernate-Modus. Dieser Befehl ist ein Shortcut für "powermode hibernate"
-
wakeup
Weckt den Mediaportal-Rechner auf (WakeUp-On-LAN).
- Abspielbefehle
Get
- Grundsätzliches
-
status
Sendet eine Aufforderung für das Senden einer status
-Nachricht. Liefert dann asynchron die Informationen "Title" und "PlayStatus".
-
nowplaying
Sendet eine Aufforderung für das Senden einer nowplaying
-Nachricht. Liefert dann asynchron die Informationen "Duration", "Position" und "File"".
Attribute
- Grundsätzliches
disable <value>
Eins aus (0, 1). Mit diesem Attribut kann das Modul deaktiviert werden.
generateNowPlayingUpdateEvents <value>
Eins aus (0, 1). Mit diesem Attribut kann die Erzeugung eines NowPlayingUpdate
-Events an- oder abgeschaltet werden. Wenn auf "1" gesetzt, generiert Fhem ein Event pro Sekunde mit den angepassten Zeitangaben. Standard ist "0".
HeartbeatInterval <intervall>
In Sekunden. Legt das Intervall für die Prüfung der Verbindung zu Mediaportal fest. Mit "0" kann die Prüfung deaktiviert werden. Wenn kein Wert angeggeben wird, wird "15" verwendet.
macaddress <address>
Gibt die Mac-Adresse des Mediaportal-Rechners an. Das wird für die WakeUp-Funktionalität benötigt. z.B. "90:E6:BA:C2:96:15"
- Authentifizierung
authmethod <value>
Eins aus (none, userpassword, passcode, both). Hiermit wird der Authentifizierungsmodus festgelegt.
password <value>
Hiermit wird das Passwort für die Authentifzierung festgelegt.
username <value>
Hiermit wird der Benutzername für die Authentifizerung festgelegt.
=end html_DE
=cut