Dieses Plugin dient dazu ein XBMC MediaCenter über den KNX-Bus fernzusteuern (ausgelegt für den Denro One, funktioniert aber auch mit allen anderen Tastern).
Gedacht ist es für folgendes Szenario:
Szenario
In einem Raum (Küche, Bad, usw.) steht ein Fernseher mit aktiven Lautsprechern und ein MediaCenter-PC mit XBMC dient als Zuspieler. Dies Plugin macht zusammen mit einem 2 bis 4-fach Tastsensor (eventuell mit Infodisplay) eine Fernsteuerung bzw. ein Radio, ähnlich wie die klassischen Unterputz-Radios. Radio deshalb, weil zur Bedienung nicht der Fernseher benötigt wird, die Bedienung mit KNX-Tastern erfolgt und standardmäßig Streams von Radiostationen ausgewählt und abgespielt werden. Die Bedienung ist auf die wichtigsten Grundfunktion beschränkt (vergleichbar mit den einfachen Unterputzradios).
Funktionsweise
Ein- und Ausgeschaltet wir das MediaCenter über eine schaltbare Steckdose oder das Power On/Off WOL-Plugin. Das Ein-/Ausschalten könnte z.B. zusammen mit dem Licht oder durch einen Präsenzmelder erfolgen, auch ein Ein-/Ausschalten über die GA für "Play" ist natürlich möglich.
Beim Einschalten wird eine Playlist mit Radiostreams (Beispiel im Anhang) automatisch abgespielt (Einstellbar im XBMC unter System -> Einstellungen -> Skin -> Allgemein, die Funktion ist abhängig vom verwendeten Skin).
Mit Vor- und Zurücktasten kann in der Playlist gesprungen und damit eine Radiostation ausgewählt werden. Die Standardfunktion wie Play/Pause und Mute/Lautstärke sind natürlich auch vorhanden.
Das Plugin reagiert unterschiedlich, je nach aktueller Situation:
Der Denro One hat einen Nachteil, dass trotz des schönen Displays keine über den KNX-Bus übertragenen freien Texte anzeigen werden können. Sollte ein Infodisplay oder z.B. der Gira Tastsensor 3 Plus im Einsatz sein, dann kann der Name des aktuellen Streams ebenfalls angezeigt werden.
Konfiguration
Als Voraussetzung wird mindestens XBMC "Dharma" 10.0 benötigt (erst dieses bietet die verwendete JSON-RPC-Schnittstelle).
Hier ist der Quellcode des Plugins:
Gedacht ist es für folgendes Szenario:
Szenario
In einem Raum (Küche, Bad, usw.) steht ein Fernseher mit aktiven Lautsprechern und ein MediaCenter-PC mit XBMC dient als Zuspieler. Dies Plugin macht zusammen mit einem 2 bis 4-fach Tastsensor (eventuell mit Infodisplay) eine Fernsteuerung bzw. ein Radio, ähnlich wie die klassischen Unterputz-Radios. Radio deshalb, weil zur Bedienung nicht der Fernseher benötigt wird, die Bedienung mit KNX-Tastern erfolgt und standardmäßig Streams von Radiostationen ausgewählt und abgespielt werden. Die Bedienung ist auf die wichtigsten Grundfunktion beschränkt (vergleichbar mit den einfachen Unterputzradios).
Funktionsweise
Ein- und Ausgeschaltet wir das MediaCenter über eine schaltbare Steckdose oder das Power On/Off WOL-Plugin. Das Ein-/Ausschalten könnte z.B. zusammen mit dem Licht oder durch einen Präsenzmelder erfolgen, auch ein Ein-/Ausschalten über die GA für "Play" ist natürlich möglich.
Beim Einschalten wird eine Playlist mit Radiostreams (Beispiel im Anhang) automatisch abgespielt (Einstellbar im XBMC unter System -> Einstellungen -> Skin -> Allgemein, die Funktion ist abhängig vom verwendeten Skin).
Mit Vor- und Zurücktasten kann in der Playlist gesprungen und damit eine Radiostation ausgewählt werden. Die Standardfunktion wie Play/Pause und Mute/Lautstärke sind natürlich auch vorhanden.
Das Plugin reagiert unterschiedlich, je nach aktueller Situation:
- Wenn z.B. ein Video geschaut wird, dann fungiert das Plugin als Fernbedienung, d.h. die Wiedergabe kann z.B. pausiert und die Lautstärke geändert werden.
- Läuft gerade keine Musik oder ein Film, dann wird bei einem Druck auf Play eine Standardplaylist mit Streams zu den Radiostationen geladen und das Abspielen gestartet, d.h. das Plugin arbeitet wie oben beschrieben als "Radio".
Der Denro One hat einen Nachteil, dass trotz des schönen Displays keine über den KNX-Bus übertragenen freien Texte anzeigen werden können. Sollte ein Infodisplay oder z.B. der Gira Tastsensor 3 Plus im Einsatz sein, dann kann der Name des aktuellen Streams ebenfalls angezeigt werden.
Konfiguration
Als Voraussetzung wird mindestens XBMC "Dharma" 10.0 benötigt (erst dieses bietet die verwendete JSON-RPC-Schnittstelle).
- Im XBMC muss der Webserver aktiviert sein (System -> Einstellungen -> Netzwerk)
- Anschließend wird bei XBMC eine Standard-Playlist benötigt, diese kann in XBMC erzeugt oder als Vorlage die angehängte in das Benutzerverzeichnis kopiert werden (bei Linux mit XBMC Live ist es "/home/xbmc/.xbmc/userdata/playlists/music/")
- Als nächstes das Plugin im Wiregate Gateway erzeugen und die Gruppenadressen (GA) im Definitionsbereich anpassen. Wenn eine GA nicht verwendet wird, diese einfach leer lassen.
Die Funktion der einzelnen GAs kann den Kommentaren entnommen werden. - Dann muss XBMC noch ein- und ausgeschaltet werden, dies geschieht z. B. über das Power On/Off-Plugin oder einer schaltbaren Steckdose.
- Jetzt noch die GAs den Tasten eines Tastsensors zuordnen bzw. in meinem Fall der Audio-GAs des Denro One und schon sollte es funktionieren
Hier ist der Quellcode des Plugins:
Code:
# Plugin um ein XBMC-MediaCenter als "Radio" zu verwenden
#
### Definitionen
# Gruppenadressen zur Steuerung mit dem Denro One
# Nicht benötigte Gruppenadressen leer lassen
my $volume_ga = "8/1/0"; # Obj. 211 Audio-Lautstärke
my $volume_status_ga = "8/1/1"; # Obj. 212 Status der Audio-Lautstärke
my $mute_ga = "8/1/2"; # Obj. 213 Audio-Stumm
my $back_ga = "8/1/3"; # Obj. 214 Audio-Zurück, bzw. Vor-/Zurückspringen (1/0) wenn $next_ga = ""
my $play_ga = "8/1/4"; # Obj. 215 Audio-Abspielen
my $play_status_ga = "8/1/5"; # Obj. 216 Status der Audio-Wiedergabe
my $next_ga = ""; # Obj. 217 Audio-Vor, bzw. wenn "" dann ist $back_ga Vor-/Zurückspringen (beim Denro One nicht verwendet)
# Weitere Gruppenadressen
my $stop_ga = ""; # Wiedergabe beenden
my $title_status_ga = ""; # Aktuell abgespielter Titel
my $rewind_ga = ""; # Zurückspulen, bzw. Vor-/Zurückspulen (1/0) wenn $fast_forward_ga = ""
my $fast_forward_ga = ""; # Vorspulen, bzw. wenn "" dann ist $rewind_ga Vor-/Zurückspulen
# XBMC Einstellungen
my $xbmc_ip = "192.168.0.24"; # IP-Adresse vom MediaCenter mit XBMC
my $xbmc_port = "8080"; # Port des XBMC-Webservers
my $user = "xbmc"; # Benutzername für Login
my $password = "xbmc"; # Passwort des Benutzers
my $default_volume = "50"; # Lautstärke beim Einschalten von 0 bis 100 und "" für keine Default-Lautstärke
my $path_to_playlist = "/home/xbmc/.xbmc/userdata/playlists/music/Radio.m3u"; # Pfad zur Radio-Playlist auf dem XBMC
### Ende Definitionen
# Eigenen Aufruf-Zyklus auf 15 Sekunden setzen
# der Aufrufzyklus ist unabhängig von der Taktzeit und muss kürzer sein!
$plugin_info{$plugname.'_cycle'} = 15;
# Plugin an Gruppenadressen "anmelden"
if ( $volume_ga ) { $plugin_subscribe{$volume_ga}{$plugname} = 1; }
if ( $mute_ga ) { $plugin_subscribe{$mute_ga}{$plugname} = 1; }
if ( $back_ga ) { $plugin_subscribe{$back_ga}{$plugname} = 1; }
if ( $play_ga ) { $plugin_subscribe{$play_ga}{$plugname} = 1; }
if ( $next_ga ) { $plugin_subscribe{$next_ga}{$plugname} = 1; }
if ( $stop_ga ) { $plugin_subscribe{$stop_ga}{$plugname} = 1; }
# Weitere globale Variablen
my $playlist_id; # ID der aktuellen Playlist
my $current_volume; # Aktuelle Lautstärke
my $current_title; # Aktuell abgespielter Titel
my $current_play_status; # Status des Player (Wiedergabe/Pause)
my $current_volume; # Aktuelle Laustärke
if (%msg) {
if ($msg{'apci'} eq "A_GroupValue_Write") {
if ($msg{'dst'} eq $volume_ga) {
#Wert vom Bus
if (defined $msg{'value'}) {
$current_volume = volume($msg{'value'});
knx_write($volume_status_ga,$current_volume,5);
}
} elsif ($msg{'dst'} eq $mute_ga) {
if (defined $msg{'value'}) {
#$current_volume = volume_status();
#if ( $msg{'value'} == "1" && $current_volume > 0) {
# mute();
#} elsif ($msg{'value'} == "0" && $current_volume == 0) {
# mute();
#}
$current_volume = volume(0);
knx_write($volume_status_ga,$current_volume,5);
}
} elsif ($msg{'dst'} eq $back_ga) {
if (defined $msg{'value'}) {
if ( !$next_ga ) {
if ( $msg{'value'} == "1" ) {
skip_next();
} else {
skip_back();
}
} else {
if ( $msg{'value'} == "1" ) {
skip_back();
}
}
}
} elsif ($msg{'dst'} eq $rewind_ga) {
if (defined $msg{'value'}) {
if ( !$fast_forward_ga ) {
if ( $msg{'value'} == "1" ) {
fast_forward();
} else {
rewind();
}
} else {
if ( $msg{'value'} == "1" ) {
rewind();
}
}
}
} elsif ($msg{'dst'} eq $fast_forward_ga) {
if (defined $msg{'value'}) {
if ( $msg{'value'} == "1" ) {
fast_forward();
}
}
} elsif ($msg{'dst'} eq $play_ga) {
my $play_status = play_status();
if ( $msg{'value'} == "1" && $play_status == "0") {
$current_play_status = play();
} elsif ($msg{'value'} == "0" && $play_status == "1") {
$current_play_status = pause();
}
knx_write($play_status_ga,$current_play_status,1);
} elsif ($msg{'dst'} eq $next_ga) {
if (defined $msg{'value'}) {
if ( $msg{'value'} == "1" ) {
skip_next();
}
}
}
}
}
# Um die Busbelastung zu minimieren, wird der Status nur aktualisiert,
# wenn das MediaCenter auf einen Ping antwortet
my $ping_result = ping_test( $xbmc_ip );
if ( $ping_result == 1 ) {
# Status aktualisieren
if ( $volume_status_ga ) {
$current_volume = volume_status();
knx_write($volume_status_ga,int($current_volume),5);
}
if ( $play_status_ga ) {
$current_play_status = play_status();
knx_write($play_status_ga,$current_play_status,1);
}
if ( $title_status_ga ) {
$current_title = current_title();
knx_write($title_status_ga,$current_title,16);
}
}
return;
sub volume {
my ($volume) = @_;
if ( $volume eq "" ) { $volume == 0; }
my $method = "XBMC.SetVolume";
my $result = json_request($method, int($volume));
$result =~ m#.*"result"\s:\s(\d*).*#s;
return $1;
}
sub volume_status {
my $method = "XBMC.GetVolume";
my $result = json_request($method);
#print $result."\n";
$result =~ m#.*"result"\s:\s(\d*).*#s;
return $1;
}
sub mute {
my $method = "XBMC.ToggleMute";
my $result = json_request($method);
#print $result."\n";
$result =~ m#.*"result"\s:\s(\d*).*#s;
return $1;
}
sub skip_back {
my $player = active_player();
if ( !$player ) { return 0; } # Wenn nichts aktiv die Funktion verlassen
my $method = $player."Player.SkipPrevious";
my $result = json_request($method);
$result =~ m#.*"result"\s:\s"(\w*)".*#s;
return $1;
}
sub play {
my $player = active_player();
if ( $player eq "" ) {
$player = "Audio";
radio_playlist_create(); # Neue Radio-Playlist erzeugen
volume( $default_volume ); # Default-Lautstärke setzen
play_list( $player ); # Ersten Eintrag der Playlist abspielen
return 1;
}
my $playStatus = play_status( $player );
if ( $playStatus == "1" ) {
return 1;
} else {
my $method = $player."Player.PlayPause";
my $result = json_request($method);
#print $result."\n";
$result =~ m#.*"paused"\s:\s(\w*).*"playing"\s:\s(\w*).*#s;
my $pause = $1;
my $playing = $2;
#print "Playing: $playing Pause: $pause\n";
if ( $playing eq "true" && $pause eq "false" ) {
return 1;
} else {
return 0;
}
}
return 0;
}
sub pause {
my $player = active_player();
if ( !$player ) { return 0; };
my $playStatus = play_status( $player );
if ( $playStatus == 0 ) {
return 0;
} else {
my $method = $player."Player.PlayPause";
my $result = json_request($method);
#print $result."\n";
$result =~ m#.*"paused"\s:\s(\w*).*"playing"\s:\s(\w*).*#s;
my $pause = $1;
my $playing = $2;
#print "Playing: $playing Pause: $pause\n";
if ( $playing eq "true" && $pause eq "false" ) {
return 1;
} else {
return 0;
}
}
return 0;
}
sub play_list {
(my $player) = @_;
if ( !$player ) {
$player = active_player();
if ( !$player ) {
return 0; # Wenn nichts aktiv die Funktion verlassen
}
}
my $method = $player."Playlist.Play";
my $playing_id = get_playing_id($player);
if ( $playing_id eq "" ) { $playing_id = 0; }
my $result = json_request($method, $playing_id);
#print "\n$result\n";
}
sub skip_next {
my $player = active_player();
if ( !$player ) { return 0; } # Wenn nichts aktiv die Funktion verlassen
my $method = $player."Player.SkipNext";
my $result = json_request($method);
$result =~ m#.*"result"\s:\s"(\w*)".*#s;
return $1;
}
sub stop {
my $player = active_player();
if ( !$player ) { return 0; } # Wenn nichts aktiv die Funktion verlassen
my $method = $player."Player.Stop";
my $result = json_request($method);
$result =~ m#.*"result"\s:\s"(\w*)".*#s;
return $1;
}
sub play_status {
(my $player) = @_;
if ( !$player ) {
$player = active_player();
if ( $player eq "" ) {
return 0; # Wenn nichts aktiv die Funktion verlassen
}
}
my $method = $player."Player.State";
my $result = json_request($method);
#print $result."\n";
$result =~ m#.*"partymode"\s:\s(\w*),.*"paused"\s:\s(\w*),.*"playing"\s:\s(\w*).*#s;
my $partymode = $1;
my $pause = $2;
my $playing = $3;
if ( $playing eq "true" && $pause eq "false" ) {
return 1;
} else {
return 0;
}
}
sub current_title {
(my $player) = @_;
if ( !$player ) {
$player = active_player();
if ( !$player ) {
return 0; # Wenn nichts aktiv die Funktion verlassen
}
}
my $method = $player."Playlist.GetItems";
my $result = json_request($method);
my @labels;
print "\Result: $result\n";
while ($result =~ s#"label"\s:\s"(.*?)"##s) {
push(@labels, $1);
}
#print "\nAlle Label: @labels\n";
my $current_id = get_playing_id($player);
$labels[$current_id]=substr($labels[$current_id],0,14); # String auf 14 Byte kürzen (DPT 16)
#print "\nAktueller Titel: $labels[$current_id]\n";
return "$labels[$current_id]";
}
sub rewind {
my $player = active_player();
if ( !$player ) { return 0; } # Wenn nichts aktiv die Funktion verlassen
my $method = $player."Player.Rewind";
my $result = json_request($method);
$result =~ m#.*"result"\s:\s"(\w*)".*#s;
return $1;
}
sub fast_forward {
my $player = active_player();
if ( !$player ) { return 0; } # Wenn nichts aktiv die Funktion verlassen
my $method = $player."Player.Forward";
my $result = json_request($method);
$result =~ m#.*"result"\s:\s"(\w*)".*#s;
return $1;
}
sub json_request {
my ($method, $param) = @_;
my $command = "curl -s -S -m 3 -X POST -d '".'{"jsonrpc": "2.0", "method": "'.$method.'"';
if ( $param ne "" ) {
$command = $command.', "params": '.$param;
}
my $command = $command.', "id": 1}'."'"." http://$xbmc_ip:$xbmc_port/jsonrpc";
#print "Command: ".$command."\n";
my $result = `$command`;
return $result;
}
sub radio_playlist_create {
# Eine vorhandene Playlist leeren
my $method = "AudioPlaylist.Clear";
my $result = json_request($method);
# Playlist neu füllen mit den Inhalten der angegebenen Playlist
$method = "AudioPlaylist.Add";
my $params = '{ "playlist-file" : "'.$path_to_playlist.'"}';
$result = json_request($method, $params);
}
sub active_player {
my $method = "Player.GetActivePlayers";
my $result = json_request($method);
print $result."\n";
$result =~ m#.*"audio"\s:\s(\w*),.*"picture"\s:\s(\w*),.*"video"\s:\s(\w*).*#s;
if ( $1 eq "true" ) {
# Audio aktiv
return "Audio";
} elsif ( $2 eq "true") {
# Picture aktiv
return "Picture";
} elsif ( $3 eq "true") {
# Video aktiv
return "Video";
} else {
# Nichts ist aktiv
return;
}
}
sub get_playing_id {
(my $player) = @_;
if ( !$player ) {
$player = active_player();
if ( !$player ) {
return 0; # Wenn nichts aktiv die Funktion verlassen
}
}
my $method = $player."Playlist.GetItems";
# my $params = '{ "fields": ["title","artist"] }';
my $result = json_request($method);
$result =~ m#.*"current"\s:\s(\d+),.*"end"\s:\s(.*),.*"start"\s:\s(\d+),.*"total"\s:\s(\d+).*#s;
#print $result."Current ID: $1 Letzte ID: $2 Start ID: $3 Anzahl: $4\n";
return $1;
}
sub ping_test {
(my $ip_adr) = @_;
my $command = "ping -c 2 -w 5 ".$ip_adr;
my $status = `$command`;
if($status =~ /bytes from/) { return 1; }
elsif($status =~ /0 received/) { return 0; }
return "Ein Fehler ist beim Testen der IP $ip_adr aufgetreten";
}



, vielleicht noch als Ergänzung warum ich XBMC und einen MediaCenter-PC nutze bzw. vorgesehen habe und keinen MediaPlayer wie z. B. einen WD Live.
Es ist sehr flexibel hat eine schicke Oberfläche, ist durch Plugins erweiterbar und wenn die PVR Funktionalität stabil läuft für mich optimal. Fehlt nur noch ein Plugin zur Steuerung der KNX Komponenten... 

geht zwar, sieht aber k* aus und ist k* zu lahm. Browser ist nach wie vor ein Drama auf der Dream, aufm XBMC macht man den halt mit der Cometvisu auf 

Kommentar