Hallo,
inspiriert durch das Script von Makki habe ich eine überarbeitet Version für meinen AVR-X1100W geschrieben..
An dieser Stelle vielen Dank Makki für dein Plugin und einige Tipps.
Das Script benötigt kein Wiregate internes Socket.
Das Plugin unterstützt momentan:
- Power ON/OFF/MUTE für Hauptzone und Zone 2 mit Rückmeldung
- Lautstärke mit Rückmeldung
- Wahl der Quelle für die Hauptzone
Das Telnet interface läuft bei mir, bis jetzt, sehr stabil.
Das besondere an der Telnetschnittstelle ist, das nur carriage return <CR> als Befehlsabschluss akzeptiert wird, ein line feed <LF> stört die Telnetverbindung.
Sobald man gezielt einen Status abfragt, bekommt man viel zu viele Antworten, auch solche die nichts mit der Anfrage zu tun haben.
Manchmal mehr als 10 Antworten.
Auch hier wird jede Zeile mit einem <CR> abgeschlossen.
Die Abfrage des Status und setzten der Lautstärke ist sehr speziell, der Kommawert wird durch eine dreistellige Zahl dargestellt.
z.B.
40,0 - 40,5 - 41
wird per Telnet so übertragen:
40 - 405 - 41
Auswahl_175.png
Als Basis für die Befehle habe ich im I-Net ein Dokument mit dem Titel "Denon_Maranze__AV_SR_NR_PROTOCOL_V02" gefunden.
Hier kann noch sehr viel ausgebaut werden.
inspiriert durch das Script von Makki habe ich eine überarbeitet Version für meinen AVR-X1100W geschrieben..
An dieser Stelle vielen Dank Makki für dein Plugin und einige Tipps.
Das Script benötigt kein Wiregate internes Socket.
Das Plugin unterstützt momentan:
- Power ON/OFF/MUTE für Hauptzone und Zone 2 mit Rückmeldung
- Lautstärke mit Rückmeldung
- Wahl der Quelle für die Hauptzone
Das Telnet interface läuft bei mir, bis jetzt, sehr stabil.
Das besondere an der Telnetschnittstelle ist, das nur carriage return <CR> als Befehlsabschluss akzeptiert wird, ein line feed <LF> stört die Telnetverbindung.
Sobald man gezielt einen Status abfragt, bekommt man viel zu viele Antworten, auch solche die nichts mit der Anfrage zu tun haben.
Manchmal mehr als 10 Antworten.
Auch hier wird jede Zeile mit einem <CR> abgeschlossen.
Die Abfrage des Status und setzten der Lautstärke ist sehr speziell, der Kommawert wird durch eine dreistellige Zahl dargestellt.
z.B.
40,0 - 40,5 - 41
wird per Telnet so übertragen:
40 - 405 - 41
Code:
# Plugin Denon-AVR # Kommunikation via TCP über socket # Version: 0.1 2011-01-31 # Denon-AVR Plugin von Makki überarbeitet von LSD # Version lsd_0.1 2015.06.10 #Deaktivieren #$plugin_info{$plugname.'_cycle'} = 0; #return "deactivated"; # COMPILE_PLUGIN my $debug = 1; my $pwm = '15/3/0'; # Power Main 1bit my $pwz = '15/3/1'; # Power Zone2 1bit my $vlm = '15/3/2'; # Lautstärke Main 0-100 dpt: 5.010 my $vlz = '15/3/3'; # Lautstärke Zone2 0-100 dpt: 5.010 my $vlmt = '15/3/4'; # Lautstärke Main up 1bit dpt: 1.017 my $vlzt = '15/3/5'; # Lautstärke Zone 2 down 1bit dpt: 1.017 my $vlms = '15/3/6'; # Status Lautstärke Main 0-100 dpt: 5.010 my $vlzs = '15/3/7'; # Status Lautstärke Zone2 0-100 dpt: 5.010 my $select = '15/3/8'; # FAVORITE 1 (ZMFAVORITE1<CR>) dpt:5.010 my $icm = '15/3/9' ; # Imputwähler Main dpt: 5.010 my $icz = '15/3/10' ; # Imputwähler Zone 2 dpt: 5.010 my $mum = '15/3/11' ; # Mute Main my $muz = '15/3/12' ; # Mute Zone 2 my $denon_ip = "192.168.255.213:23"; my $socknum = 1; $plugin_info{$plugname.'_cycle'} = 10; # Plugin an Gruppenadresse "anmelden" $plugin_subscribe{$pwm}{$plugname} = 1; #Plugin ausführen, sobald ein GA angesprochen wird $plugin_subscribe{$pwz}{$plugname} = 1; $plugin_subscribe{$vlm}{$plugname} = 1; $plugin_subscribe{$vlz}{$plugname} = 1; $plugin_subscribe{$vlmt}{$plugname} = 1; $plugin_subscribe{$vlzt}{$plugname} = 1; $plugin_subscribe{$mum}{$plugname} = 1; $plugin_subscribe{$muz}{$plugname} = 1; $plugin_subscribe{$select}{$plugname} = 1; # ## ### Script Start Grund des Scriptes my $event=undef; if (!$plugin_initflag) { $event='restart'; # Restart des daemons / Reboot } elsif ($plugin_info{$plugname.'_lastsaved'} > $plugin_info{$plugname.'_last'}) { $event='modified'; # Plugin modifiziert } elsif (%msg) { $event='bus'; # Bus } elsif ($fh) { $event='socket'; # Netzwerktraffic } else { $event='cycle'; # Zyklus } if ($debug == 1){ plugin_log($plugname, "1 Startgrund - Event: ".$event) } ### ## # ### Loop schleifen Erkennung if ($plugin_cache{$plugname.'_LOOP'} == 1) { if ($debug > 0){ plugin_log($plugname, "1 Loop - Loop erkannt Script beenden"); } $plugin_cache{$plugname.'_LOOP'} = 0; return "Loop"; } if (!$socket[$socknum]) { # socket erstellen if ($debug == 1){ plugin_log($plugname, "2 socket - Socket:$socknum zur IP $denon_ip wird aufgebaut "); } $socket[$socknum] = new IO::Socket::INET ( PeerHost => $denon_ip, PeerPort => '23', Proto => 'tcp', Timeout => 1, ReadTimeout => 0.5, WriteTimeout => 0.5, Blocking => 0 ) or return ("open of $denon_ip failed: $!"); #$socksel->add($socket[$socknum]); # add socket to select #$plugin_socket_subscribe{$socket[$socknum]} = $plugname; # subscribe plugin return "opened Socket $socknum"; }else{ if ($debug == 1){ plugin_log($plugname, "2a socket - Socket:$socknum zur IP $denon_ip besteht "); plugin_log($plugname, "2b socket - Inhalt fh: $fh "); } } ### Zyklscher oder Initial Aufruf if ($event eq 'cycle' or $event eq 'modified' or $event eq 'restart') { if ($debug == 1){ plugin_log($plugname, "1 Cycle - Zuekilisch oder Initial Start"); } my $vals; my $read; my @split; my $runden=0; #Power On Off bei Hauptzone und Zone 2 syswrite($socket[$socknum], "PW?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; while($runden <= $vals) { if ($debug == 1 or $debug == 2){ plugin_log($plugname, "2a Cycel - Split PW? ".$runden." : ".$split[$runden]); } if ($split[$runden] eq "ZMOFF" or $split[$runden] eq "PWSTANDBY") { if ($plugin_cache{$plugname.'_ZM'} == 0) { if ($debug == 2){ plugin_log($plugname, '2b Cycle - ZMOFF erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_ZM'} = 0; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($pwm ,0,1); if ($debug == 1 or $debug == 2){ plugin_log($plugname, "2b Cycle - ZMOFF erkannt"); } } } elsif ($split[$runden] eq "ZMON") { if ($plugin_cache{$plugname.'_ZM'} == 1) { if ($debug == 2){ plugin_log($plugname, '2b Cycle - ZMON erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_ZM'} = 1; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($pwm ,1,1); if ($debug == 2){ plugin_log($plugname, "2b Cycle - ZMON erkannt"); } } } elsif ($split[$runden] eq "Z2OFF") { if ($plugin_cache{$plugname.'_Z2'} == 0) { if ($debug == 2){ plugin_log($plugname, '2b Cycle - Z2OFF erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_Z2'} = 0; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($pwz ,0,1); if ($debug == 1 or $debug == 2){ plugin_log($plugname, "2b Cycle - Z2OFF erkannt"); } } } elsif ($split[$runden] eq "Z2ON") { if ($plugin_cache{$plugname.'_Z2'} == 1) { if ($debug == 2){ plugin_log($plugname, '$split[$runden]2b Cycle - Z2ON erkannt - keine Aenderung'); } } else {$split[$runden] = $plugin_cache{$plugname.'_Z2'} = 1; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($pwz ,1,1); if ($debug == 1 or $debug == 2){ plugin_log($plugname, "2b Cycle - Z2ON erkannt"); } } } $runden++; } #Lautstärke ermillung bei Hauptzone $runden=0; syswrite($socket[$socknum], "MV?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; while($runden <= $vals) { if ($debug == 3){ plugin_log($plugname, "2a Cycel - Split MV? ".$runden." : ".$split[$runden]); } #Prüfen ob Antwort auf MV<Zahl> besteht (z.B. MVxx oder MVxxx) if ($split[$runden] =~ /^MV\d/) { #erste zwei Zeichen entfernen $split[$runden] =~ s/^..//; #Prüfen ob zwei oder dreistellig -> xxy wird nach xx.y gewandelt if ($split[$runden] =~ /\d\d\d/) { $split[$runden] = $split[$runden]/10; } if ($debug == 3){ plugin_log($plugname, "2b Cycel - Erkannte MV Lautstärke $split[$runden]"); } # Wert von 0 - 100 nach 0 - 255 umrechnrn #$split[$runden] = sprintf("%.0f",($split[$runden]*2.55)); #$split[$runden] = $split[$runden]*10; if ($debug == 3){ plugin_log($plugname, "2c Cycel - Umwandlung MV % nach Binaer: $split[$runden]"); } knx_write($vlms ,$split[$runden],5.010); if ($debug == 1 or $debug == 3){ plugin_log($plugname, "2d Cycle - MV erkannt $split[$runden] geschrieben "); } } $runden++; } #Lautstärke ermillung bei Zone 2 $runden=0; syswrite($socket[$socknum], "Z2?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; while($runden <= $vals) { if ($debug == 4){ plugin_log($plugname, "2a Cycel - Split Z2? ".$runden." : ".$split[$runden]); } #Prüfen ob Antwort auf Z2<Zahl> besteht (z.B. MVxx oder MVxxx) if ($split[$runden] =~ /^Z2\d/) { #erste zwei Zeichen entfernen $split[$runden] =~ s/^..//; #Prüfen ob zwei oder dreistellig -> xxy wird nach xx.y gewandelt if ($split[$runden] =~ /\d\d\d/) { $split[$runden] = $split[$runden]/10; } if ($debug == 4){ plugin_log($plugname, "2b Cycel - Erkannte Z2 Lautstärke $split[$runden]"); } # Wert von 0 - 100 nach 0 - 255 umrechnrn #$split[$runden] = sprintf("%.0f",($split[$runden]*2.55)); if ($debug == 4){ plugin_log($plugname, "2c Cycel - Umwandlung Z2 % nach Binaer: $split[$runden]"); } knx_write($vlzs ,$split[$runden],5.010); if ($debug == 1 or $debug == 4){ plugin_log($plugname, "2d Cycle - Z2 erkannt $split[$runden] geschrieben "); } } $runden++; } #Source Ermittlung Main und Zone 2 syswrite($socket[$socknum], "SI?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; $runden=0; while($runden <= $vals) { if ($debug == 5){ plugin_log($plugname, "2a Cycel - Split SI? ".$runden." : ".$split[$runden]); } if ($split[$runden] =~ /^SI\w/) { #erste zwei Zeichen entfernen $split[$runden] =~ s/^..//; if ($debug == 5){ plugin_log($plugname, "2b Cycel - SI: $split[$runden]"); } } $runden++; } #Mute Main syswrite($socket[$socknum], "MU?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; $runden=0; while($runden <= $vals) { if ($debug == 6){ plugin_log($plugname, "2a Cycel - Split MU? ".$runden." : ".$split[$runden]); } if ($split[$runden] eq "MUOFF") { if ($plugin_cache{$plugname.'_MMUTE'} == 0) { if ($debug == 6){ plugin_log($plugname, '2b Cycle - MMUTE off erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_MMUTE'} = 0; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($mum ,0,1); if ($debug == 1 or $debug == 6){ plugin_log($plugname, "2b Cycle - Main Mute off"); } } } elsif ($split[$runden] eq "MUON") { if ($plugin_cache{$plugname.'_MMUTE'} == 1) { if ($debug == 6){ plugin_log($plugname, '2b Cycle - Main MUTE on erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_MMUTE'} = 1; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($mum ,1,1); if ($debug == 1 or $debug == 6){ plugin_log($plugname, "2b Cycle - Main Mute on"); } } } $runden++; } #Mute Zone2 syswrite($socket[$socknum], "Z2MU?"."\r"); $vals=sysread($socket[$socknum],$read,10240); @split=split("\r",$read); $vals=@split; $vals--; $runden=0; while($runden <= $vals) { if ($debug == 6){ plugin_log($plugname, "2a Cycel - Split Z2MU? ".$runden." : ".$split[$runden]); } if ($split[$runden] eq "Z2MUOFF") { if ($plugin_cache{$plugname.'_ZMUTE'} == 0) { if ($debug == 6){ plugin_log($plugname, '2b Cycle - Zone2 MUTE off erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_ZMUTE'} = 0; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($muz ,0,1); if ($debug == 1 or $debug == 6){ plugin_log($plugname, "2b Cycle - Zone2 Mute off"); } } } elsif ($split[$runden] eq "Z2MUON") { if ($plugin_cache{$plugname.'_ZMUTE'} == 1) { if ($debug == 6){ plugin_log($plugname, '2b Cycle - Zone2 MUTE on erkannt - keine Aenderung'); } } else { $plugin_cache{$plugname.'_MMUTE'} = 1; $plugin_cache{$plugname.'_LOOP'} = 1; knx_write($muz ,1,1); if ($debug == 1 or $debug == 6){ plugin_log($plugname, "2b Cycle - Zone2 Mute on"); } } } $runden++; } return "3 Cycle - Anzahl der Befehle: $runden"; } ### Aktion ausführen nach einer Modifizirung Variabeln initalisieren if ($event eq 'modified' or $event eq 'restart') { if ($debug == 1){ plugin_log($plugname, "3 - Initalisirung gestartet"); } } ### Power Main angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $pwm ) { if ($debug == 1){ plugin_log($plugname, "3 PM - Power Main on/off" ); } #my @vals = qw/PWSTANDBY PWON/; #1bit on/off my @vals = qw/ZMOFF ZMON/; #1bit on/off syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 PM - erkannt $vals[$msg{'data'}]"; } ### Power Zone2 angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $pwz ) { if ($debug == 1){ plugin_log($plugname, "3 ZM - Power Zone2 on/off" ); } my @vals = qw/Z2OFF Z2ON/; #1bit on/off syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 ZM - erkannt $vals[$msg{'data'}]"; } ### Lautstaerke Master dynamische 0-255 angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $vlm ) { if ($debug == 1){ plugin_log($plugname, "3 - Lautstaerke Master dynamisch" ); } #$msg{'data'}=hex($msg{'data'}); #$msg{'data'}=100/255*$msg{'data'}; #$msg{'data'}=sprintf "%.1f", $msg{'data'}; syswrite($socket[$socknum], sprintf("MV%02d\r",$msg{'data'})); return "4 - erkannt MV: $msg{'data'}]"; } ### Lautstaerke Zone2 dynamische 0-255 angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $vlz ) { if ($debug == 1){ plugin_log($plugname, "3 - Lautstaerke Zone2 dynamisch" ); } #$msg{'data'}=sprintf "%.1f", 100/255*hex($msg{'data'}); syswrite($socket[$socknum], sprintf("Z2%02d\r",$msg{'data'})); return "4 - erkannt Z2: $msg{'data'}]"; } ### Lautstaerke Master Up/Down angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $vlmt ) { if ($debug == 1){ plugin_log($plugname, "3 - Lautstaerke Master up/down" ); } my @vals = qw/MVDOWN MVUP/; #1bit on/off syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 - erkannt $vals[$msg{'data'}]"; } ### Lautstaerke Zone2 Up/Down angesprochen wurde if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $vlzt ) { if ($debug == 1){ plugin_log($plugname, "3 - Lautstaerke Zone2 up/down" ); } my @vals = qw/Z2DOWN Z2UP/; #1 on/off syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 - erkannt $vals[$msg{'data'}]"; } ### MUTE Main on/off if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $mum ) { if ($debug == 1){ plugin_log($plugname, "3 - Mute Main" ); } my @vals = qw/MUOFF MUON/; syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 - erkannt $vals[$msg{'data'}]"; } ### MUTE Zone2 on/off if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $muz ) { if ($debug == 1){ plugin_log($plugname, "3 - Mute Zone2" ); } my @vals = qw/Z2MUOFF Z2MUON/; syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); return "4 - erkannt $vals[$msg{'data'}]"; } ### Quelle waehlen if ($msg{'apci'} eq "A_GroupValue_Write" and $msg{'dst'} eq $select ) { if ($debug == 1){ plugin_log($plugname, "3 - Quelle waehlen" ); } #my @vals = qw/SISAT\/CBL SIMPLAY/; #1 on/off my @vals = qw /SISAT\/CBL SIMPLAY SIIRP SIIRADIO SIPHONO SICD SITUNER SIDVD SIBD SITV SIDVR SIGAME SIV.AUX SIDOCK SIIPOD SINET\/USB SINAPSTER SILASTFM SIFLICKR SIFAVORITES SSIERVER SIUSB\/IPOD/; syswrite($socket[$socknum], $vals[$msg{'data'}]."\r"); select(undef, undef, undef, 2.5); #kleine Pause syswrite($socket[$socknum], "PSMULTEQ:AUDYSSEY"."\r"); return "4 - erkannt $vals[$msg{'data'}]"; } return "ende";
Als Basis für die Befehle habe ich im I-Net ein Dokument mit dem Titel "Denon_Maranze__AV_SR_NR_PROTOCOL_V02" gefunden.
Hier kann noch sehr viel ausgebaut werden.
Kommentar