Ankündigung

Einklappen
Keine Ankündigung bisher.

- √ - Plugin fuer Yamaha Reciever

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    [wiregate] - √ - Plugin fuer Yamaha Reciever

    Hallo zusammen,

    nach vielen erfolglosen Versuchen wende ich mich nun hilfesuchend an Euch.

    Das Plugin soll meinen Yamaha RX-V773 via TCP ansteuern. Ich habe mich am Sqeezebox Plugin orientiert, nur leider klappt es nicht.

    Derzeit scheitere ich schon bei der GA Anmeldung. Solange "defined $msg{'value'}" mit dabei steht kommt das Script an dieser Stelle nicht weiter.

    Nehme ich den "defined" raus, komme ich weiter und über die erste IF Abfrage. Allerdings bekomme ich dann keinen Wert mehr aus der $msg{'value'} für die weitere Verarbeitung. Außerdem reagiert das Plugin z.B. auch auf 1/1/9, obwohl diese nicht angemeldet wird.

    Vielleicht sieht hier jemand den Fehler oder hat den entscheidenden Tipp für mich.

    Besten dank und allen ein schönes Wochenende!
    Basti

    Code:
    # YAMAHA RX-V773 Steuerung über Wiregate
    use IO::Socket;
    ### Definitionen
    ################################################################################################################################
    my %function=(
    ## YAMAHA Receiver
    # MAIN ZONE
    #  GA  Command 0  Command 1   Description
    #-------------------------------------------------------------------------------------------------------------------------------
    "MAINPWR"=> "1/1/1",  #@MAIN:PWR=Standby @MAIN:PWR=On  Main Power On/Off
    "MAINVOL"=> "1/1/2",  #@MAIN:VOL=DOWN 2dB @MAIN:VOL=UP 2 dB Main Volume UP/DOWN
    "MAINMUTE"=> "1/1/3", #@MAIN:MUTE=Off  @MAIN:MUTE=On  Main Volume MUTE
    "MAINSRC"=> "1/1/4", #@MAIN:SRC=xxx  @MAIN:SRC=xxx  Main Source
    "MAINSLEEP"=> "1/1/5", #@MAIN:SLEEP=Off @MAIN:SLEEP=30  Main Power Sleep 30 Min
    # ZONE 2
    #  GA  Command 0  Command 1   Description
    #-------------------------------------------------------------------------------------------------------------------------------
    "ZONE2PWR"=> "1/1/20",  #@ZONE2:PWR=Standby @ZONE2:PWR=On  ZONE2 Power On/Off
    "ZONE2VOL"=> "1/1/21",  #@ZONE2:VOL=DOWN 2dB @ZONE2:VOL=UP 2 dB ZONE2 Volume UP/DOWN
    "ZONE2MUTE"=> "1/1/22",  #@ZONE2:MUTE=Off @ZONE2:MUTE=On  ZONE2 Volume MUTE
    "ZONE2SRC"=> "1/1/23",  #@ZONE2:SRC=xxx  @ZONE2:SRC=xxx  ZONE2 Source
    "ZONE2SLEEP"=> "1/1/24" #@ZONE2:SLEEP=Off @ZONE2:SLEEP=30  ZONE2 Power Sleep 30 Min
    );
    #################################################################################################################################
    # Verbindungseinstellungen
    my $send_ip = '192.168.0.50'; # SendeIP
    my $send_port = '50000'; # Sendeport
    ### Ende Definitionen
     
    # Eigenen Aufruf-Zyklus setzen
    $plugin_info{$plugname.'_cycle'} = 0;
    # Anmeldung an den Gruppenadressen
    while (my($key,$ga) = each %function)
    {
    $plugin_subscribe{$function{$key}}{$plugname} = 1;
    }
    #################################################################################################################################
    ### Verarbeitung
    # Main Power ON/OFF
    if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINPWR} && defined $msg{'value'}) {
        if ($msg{'value'} eq "0") {
     my $command="@MAIN:PWR=Standby";
     my $return_val = sendCommand($command);
        }
        if ($msg{'value'} eq "1") {
     my $command="@MAIN:PWR=On";
     my $return_val = sendCommand($command);
        }
    }
    #################################################################################################################################
    # Log
    return 0;
    sub sendCommand {
    my $cmd = $_[0];
    my $sock = new IO::Socket::INET (
    PeerAddr => $send_ip,
    PeerPort => $send_port,
    Proto => 'tcp',
    );
    die "Error: $!\n" unless $sock;
    print $sock ($cmd."\n\r") ;
    plugin_log($plugname, $cmd);
    close($sock);
    }

    #2
    Erweitere doch einfach mit ein paar Log-Einträgen um das zu debuggen.
    Ich hab da zwei Vermutungen:

    1. Sind die Adressen in der eibga.conf im Wiregate eingetragen bzw. übers Webmin eingetragen?

    2. Evtl. macht einfach der Befehl "@MAIN:PWR=On" das Problem da @MAIN vom Plugin als Array interpretiert werden will?
    Umgezogen? Ja! ... Fertig? Nein!
    Baustelle 2.0 !

    Kommentar


      #3
      Die GAs habe ich jetzt mal eingetragen.

      Das mit dem Array klingt logisch. Wie muss das geschreiben werden das es als reiner Text angesehen wird? Leider benötigt das der Receiver genau in diesem Format.

      => Habe nun das ganze so geschreiben: "@"."MAIN:PWR=On"
      Mittlerweile geht er auch in die Sub Routine und ich sehe bereits TCP Pakete. Nur sind in den Paketen keine Nutzdaten. Was mache ich hier falsch?

      => Zu sicherheit nun nochmal anderst: "%40MAIN%3APWR%3DStandby"

      Mir ist aufgefallen das ich selbst bei print $sock ("HELLOWORLD \n") ; keine Lesbaren Infos in dem TCP paket habe.

      Kommentar


        #4
        kurz zur Erkläring...

        Wenn du die Adressen nicht eingetragen hast, ist ($msg{'value'} = 00 oder 01. Desshalb funktioniert die if Auswertung nicht.

        Also entweder im Wiregate eintragen dann gehen 0 und 1 oder die Abfrage auf 00 und 01 ändern. -> weil die "Rohdaten" HEX sind

        Das defined $msg{'value'} kannst du dir eigentlich spaaren. Denn ohne Wert würde die angemeldete GA das Plugin garnich aufrufen.

        Noch zum socket...

        Wiso so kompliziert? Es gibt sehr viele Plugins die mit IO::Socket::INET arbeiten. Versuche es mal so...

        Oben im Plugin nach der Definition der Variablen die socket initialisierung:

        Code:
        if (!$socket[$socknum]) { # socket erstellen
            if ($denon_ip) {
                $socket[$socknum] = IO::Socket::INET->new(PeerAddr => $denon_ip, Timeout => 120, Blocking => 0)
                     or return ("open of $denon_ip  failed: $!");
            } else {
                $socket[$socknum] = IO::Socket::INET->new(LocalPort => $send_port,
                                          Proto => "tcp",
                                          LocalAddr => "localhost",
                                          PeerPort  => $send_port,
                                          PeerAddr  => $send_ip,
                                          ReuseAddr => 1
                                           )
                         or return ("open of $recv_ip : $recv_port failed: $!");
            }
        
            $socksel->add($socket[$socknum]); # add socket to select
        
            $plugin_socket_subscribe{$socket[$socknum]} = $plugname; # subscribe plugin
            return "opened Socket $socknum";
        }
        Dazu brauchst du bei den Variablendefinitionen noch folgendes:

        my $socknum = 218;

        Und unten wo du auf den socket sendest an Stelle von print und der ganzen Socket geschichte nur noch folgendes:

        Code:
        sub sendCommand {
        my $cmd = $_[0];
        syswrite($socket[$socknum],$cmd."\r");
        }
        Hoffe das hilft
        Gruss Patrik alias swiss

        Kommentar


          #5
          Hallo Patrick,

          ich würde von Sockets Abstand halten: Memleaks!
          So sehr ich den socat auch mag.

          Beobachte das mal in der Plugin-Übersicht. Die einfache Sub ist doch genauso easy ... eigentlich noch viel einfacher. Alles was bei Plugins mit Sockets zu tun hat treibt den Speicherverbrauch in die Höhe.

          Grüße
          Umgezogen? Ja! ... Fertig? Nein!
          Baustelle 2.0 !

          Kommentar


            #6
            In der sub wird genauso ein Socket geöffnet... Der Vorteil der oberenVariante es, dass er später auch Rückmeldungen empfangen und auswerten könnte...

            Aber jedem wie ihm beliebt

            -> Was kann man gegen die Memleaks machen und wie wirken sie sich auf das Plugin aus?
            Gruss Patrik alias swiss

            Kommentar


              #7
              Danke für die Info bzgl. "defined" jetzt ist es mir klar wieso.

              Mit dem socat hatte ich es auch schon versucht. Hatte aber noch weniger geklappt Ich werde es mir nochmals ansehen.

              Mich wundert es, das es mit der Sub nicht geht, da dies bis auf die Befehle identisch mit dem Squeezplugin ist. Vielleicht baue ich mir diesen mal ein und schaue was am Wireshark zu sehen ist.

              Besten Danke schonmal!

              Kommentar


                #8
                Zitat von swiss Beitrag anzeigen
                -> Was kann man gegen die Memleaks machen und wie wirken sie sich auf das Plugin aus?
                Garnichts .
                Auf das Plugin hat das keine Auswirkung, nur der wiregated started öfter neu ... wenn man es verhindern kann ...
                Das Problem bei der Socketlösung ist dass der Speicher schneller "verbraucht" wird, dies sind zumindest meine Beobachtungen.
                Rückmeldungen kann man sich auch mit der Sub geben lassen:

                Code:
                my $answer = <$sock>
                Grüße
                Umgezogen? Ja! ... Fertig? Nein!
                Baustelle 2.0 !

                Kommentar


                  #9
                  Ok. Danke für die Info Dann könnte dass der Grund sein, wiso mein WG öfters (ca. alle 7 tage) mal neu gestartet hat? Das einzige Plugin mit Socket dass ich am laufen hatte, war für den Denon aber das brauche ich nun nicht mehr, da ich das Surroundsystem jetzt über RTI an KNX angebunden habe Seit da scheint das WG durchzulaufen
                  Gruss Patrik alias swiss

                  Kommentar


                    #10
                    Das alte Squeeze Plugin brauchte keine 24 Stunden für den wiregated.

                    Mein altes eBus-Plugin (Socketbasiert) hat etwas länger gebraucht aber < 48 Stunden.
                    Umgezogen? Ja! ... Fertig? Nein!
                    Baustelle 2.0 !

                    Kommentar


                      #11
                      Was kann man tun um nicht sockets zu benutzten? Ich verstehe den Referenz zu "die einfache Sub" nicht.

                      /Per

                      Kommentar


                        #12
                        Wenn man Sockets braucht, dann braucht man sie. Die müssen nur nicht ständig offen sein wenn es das nicht braucht so wie es das Beispiel von Patrick macht.

                        Vielleicht ist es ja auch nur ein WireGate Phaenomen, ich konnte jedenfalls einen direkten Zusammenhang zwischen Speicherverbruach und den Sockets beimir feststellen. Will aber niemandem was ein- oder ausreden.
                        Letztlich ist es dann auch egal ob der wiregated nach 12,24 oder 1638 Stunden neu startet.

                        Grüße
                        Umgezogen? Ja! ... Fertig? Nein!
                        Baustelle 2.0 !

                        Kommentar


                          #13
                          Ich habe die Steuerung meines RX-V1067 mit YNC gelöst. Ich habe zuerst mit YNCA (wie du) probiert, aber es funktionert nicht so gut.

                          YNC scheint zuerst komplizierter, und Yamaha versucht ganz klar nicht in der Dokumentation es einfach zu gestalten. Aber die Kommunikation funktionert besser.

                          Ein paar Schnipsel von meinem unschönen Plug-in:
                          Code:
                          use LWP::UserAgent;
                          use XML::Simple;
                          use LWP::Sim
                          Code:
                          my $sendarray->{'cmd'} = 'PUT';
                          $sendarray->{'Zone_2'}->{'Power_Control'}->{'Power'} = ['On'];
                          $sendXML = '<?xml version="1.0" encoding="utf-8"?>' .XMLout($sendarray,rootname => 'YAMAHA_AV', KeyAttr => [ ]);
                          my $userAgent = LWP::UserAgent->new(agent => 'perl post');
                          my $response = $userAgent->post('http://'.$send_ip.'/YamahaRemoteControl/ctrl', Content_Type => 'text/xml',Content => $sendXML);
                          Ich baue mit XMLout die xml-Befehle zusammen, aber jetzt finde ich das unnötig - einfacher ist eher, es als Text-Konstanten in der Code einzufügen.

                          Ein beispiel von einem xml-Befehl:
                          Code:
                          <?xml version="1.0" encoding="utf-8"?><YAMAHA_AV cmd="PUT"><Main_Zone><Volume><Lvl><Val>Down 5 dB</Val><Exp></Exp><Unit></Unit></Lvl></Volume></Main_Zone></YAMAHA_AV>
                          Es gibt von Yamaha eine schlimme xls-File mit allen Befehlen

                          http://www.avhifiresources.co.uk/con...ion%20Tree.xls

                          Um den Status vom Receiver zu bekommen macht man so:

                          Code:
                          my $sendXML =
                          '<?xml version="1.0" encoding="utf-8"?>
                          <YAMAHA_AV cmd="GET">
                          <Zone_2>
                          <Basic_Status>GetParam</Basic_Status>
                          </Zone_2>
                          </YAMAHA_AV>';
                          my $userAgent = LWP::UserAgent->new(agent => 'perl post');
                          my $response = $userAgent->post('http://'.$send_ip.'/YamahaRemoteControl/ctrl', Content_Type => 'text/xml',Content => $sendXML);
                          /Per

                          Kommentar


                            #14
                            Hallo zusammen,

                            nun hats endlich geklappt.

                            Zwei Probleme: Natürlich kann man bei TCP nichts mitsniffen, wenn auf der Snifferseite niemand antwortet, denn es kommt ja nie der Handshake zustande. Hab es via Port Mirroring dann aber doch Mitschneiden können.

                            Benötigt wird ein carriage return und line feed zum Abschluss des Commands. Nur war das wohl nicht in der richtigen Reihenfolge.

                            Hier nun nochmal der funktionieren Code für einen Yamaha Receiver.

                            Code:
                            # YAMAHA RX-V773 Steuerung über Wiregate
                            # V0.1 08.02.2013
                            # V1.0 10.02.2013 First Final
                            ### Definitionen
                            ##################################################################################################################
                            my %function=(
                            ## YAMAHA Receiver
                            # MAIN ZONE
                            #  GA  Command 0  Command 1  Description
                            #-----------------------------------------------------------------------------------------------------------------
                            "MAINPWR"=> "1/1/1",  #@MAIN:PWR=Standby @MAIN:PWR=On  Main Power On/Off
                            "MAINVOL"=> "1/1/2",  #@MAIN:VOL=DOWN 2dB @MAIN:VOL=UP 2 dB Main Volume UP/DOWN
                            "MAINMUTE"=> "1/1/3", #@MAIN:MUTE=Off  @MAIN:MUTE=On  Main Volume MUTE
                            "MAINSRC"=> "1/1/4", #@MAIN:SRC=xxx  @MAIN:SRC=xxx  Main Source
                            "MAINSLEEP"=> "1/1/5", #@MAIN:SLEEP=Off @MAIN:SLEEP=30  Main Power Sleep 30 Min
                            # ZONE 2
                            #  GA  Command 0  Command 1  Description
                            #-----------------------------------------------------------------------------------------------------------------
                            "ZONE2PWR"=> "1/1/20",  #@ZONE2:PWR=Standby @ZONE2:PWR=On  ZONE2 Power On/Off
                            "ZONE2VOL"=> "1/1/21",  #@ZONE2:VOL=DOWN 2dB @ZONE2:VOL=UP 2 dB ZONE2 Volume UP/DOWN
                            "ZONE2MUTE"=> "1/1/22",  #@ZONE2:MUTE=Off @ZONE2:MUTE=On  ZONE2 Volume MUTE
                            "ZONE2SRC"=> "1/1/23",  #@ZONE2:SRC=xxx  @ZONE2:SRC=xxx  ZONE2 Source
                            "ZONE2SLEEP"=> "1/1/24" #@ZONE2:SLEEP=Off @ZONE2:SLEEP=30  ZONE2 Power Sleep 30 Min
                            );
                            ##################################################################################################################
                            # Verbindungseinstellungen
                            my $send_ip = '192.168.0.46'; # SendeIP
                            my $send_port = '50000'; # Sendeport
                            ### Ende Definitionen
                             
                            # Eigenen Aufruf-Zyklus setzen
                            $plugin_info{$plugname.'_cycle'} = 0;
                            # Anmeldung an den Gruppenadressen
                            while (my($key,$ga) = each %function)
                            {
                              $plugin_subscribe{$function{$key}}{$plugname} = 1;
                            }
                            ##################################################################################################################
                            ### Verarbeitung
                            # Main Power ON/OFF
                            if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINPWR} && defined $msg{'value'}) {
                                if ($msg{'value'} eq "0") {
                             my $command = "MAIN:PWR=Standby";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq "1") {
                             my $command = "MAIN:PWR=On";
                             my $return_val = sendCommand($command);
                                }
                                return 0;
                            }
                            # Main VOL UP/DOWN
                            if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINVOL} && defined $msg{'value'}) {
                                if ($msg{'value'} eq "0") {
                             my $command = "MAIN:VOL=Down 2 dB";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq "1") {
                             my $command = "MAIN:VOL=Up 2 dB";  
                             my $return_val = sendCommand($command);
                                }
                                return 0;
                            }
                            # Main VOL MUTE
                            if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINMUTE} && defined $msg{'value'}) {
                                if ($msg{'value'} eq "0") {
                             my $command = "MAIN:MUTE=Off";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq "1") {
                             my $command = "MAIN:MUTE=On";
                             my $return_val = sendCommand($command);
                                }
                                return 0;
                            }
                            # Main Source
                            if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINSRC} && defined $msg{'value'}) {
                                if ($msg{'value'} eq 1) {
                             my $command = "MAIN:INP=TUNER";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq 2) {
                             my $command = "MAIN:INP=NET RADIO";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq 3) {
                             my $command = "MAIN:INP=PC";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq 4) {
                             my $command = "MAIN:INP=AV1";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq 5) {
                             my $command = "MAIN:INP=HDMI1";
                             my $return_val = sendCommand($command);
                                }
                                return 0;
                            }
                            # Main Sleep
                            if ($msg{'apci'} eq "A_GroupValue_Write" && $msg{'dst'} eq $function{MAINSLEEP} && defined $msg{'value'}) {
                                if ($msg{'value'} eq 0) {
                             my $command = "MAIN:SLEEP=Off";
                             my $return_val = sendCommand($command);
                                }
                                if ($msg{'value'} eq 1) {
                             my $command = "MAIN:SLEEP=30 min";
                             my $return_val = sendCommand($command);
                                }
                                return 0;
                            }
                            ##################################################################################################################
                            sub sendCommand {
                            use IO::Socket;
                            my $cmd = $_[0];
                            my $sock = new IO::Socket::INET (
                            PeerAddr => $send_ip,
                            PeerPort => $send_port,
                            Proto => 'tcp',
                            );
                            die "Error: $!\n" unless $sock;
                            print $sock ("@".$cmd."\r"."\n") ;
                            plugin_log($plugname, $cmd);
                            close($sock);
                            }
                            Danke an alle Helfer!
                            Angehängte Dateien

                            Kommentar


                              #15
                              Zitat von xachsewag Beitrag anzeigen
                              Zwei Probleme: Natürlich kann man bei TCP nichts mitsniffen, wenn auf der Snifferseite niemand antwortet, denn es kommt ja nie der Handshake zustande. Hab es via Port Mirroring dann aber doch Mitschneiden können.
                              Hmm, ich grinse jetzt nur und denke kurz an die Gebetsmühle [Tagtraum: Ein nicht managebarer Switch ohne Port-Mirroring ist ein nutzloses Stück Elektroschrott - oder nur für Lisa&Otto was Wert]

                              Hier nun nochmal der funktionieren Code für einen Yamaha Receiver.
                              Wer schaffts ins SVN? (Alte Stände hab ich keine entdeckt aber Vorgänger, ähnliche? Selbst wenn könnte ich es nicht alleine beurteilen..)
                              Sollte alles hier:
                              SourceForge.net Repository - [openautomation] Index of /wiregate/plugin/generic
                              landen sonst geht sowas IMHO unter, was immer Schade ist..
                              Hab die Tage erst drei Kreuze gemacht das das meiste irgendwo im SVN liegt, weil wer erinnert sich schon, was er mal so nebenbei vor 2-3J konstruiert hat?!

                              Makki
                              EIB/KNX & WireGate & HS3, Russound,mpd,vdr,DM8000, DALI, DMX
                              -> Bitte KEINE PNs!

                              Kommentar

                              Lädt...
                              X