Ankündigung

Einklappen
Keine Ankündigung bisher.

AV-Receiver Pioneer einbinden

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    #31
    Hallo,
    hier kann ich auch mal was einbringen. Ich habe mir auch ein Pioneer AVR Plugin "gebastelt", speziell für den VSX921 via telnet.
    Das funktioniert soweit inkl. der "Übersetzung" des Display. Das Plugin basiert auf dem Denon-Plugin.

    Vielleicht kannst Du was verwenden.

    Hier mal die Infos:
    conf
    Code:
    [Pioneer]
        [[Power]]
            type = bool
            visu_acl = rw
            pioneer_send = power
            enforce_updates = on
        [[Mute]]
            type = bool
            visu_acl = rw
            pioneer_send = mute
            enforce_updates = on
        [[Volume]]
            type = num
            visu_acl = rw
            pioneer_send = volume
            pioneer_listen = volume
            enforce_updates = on
        [[VolumeUp]]
            type = bool
            visu_acl = rw
            pioneer_send = volume+
            enforce_updates = on
        [[VolumeDown]]
            type = bool
            visu_acl = rw
            pioneer_send = volume-
            enforce_updates = on
        [[Source]]
            type = str
            visu_acl = rw
            pioneer_send = source
            pioneer_listen = source
            enforce_updates = on
        [[Source_Text]]
            type = str
            visu_acl = rw
            enforce_updates = on
        [[SourceCyclic]]
            type = str
            visu_acl = rw
            pioneer_send = sourcecyclic
            enforce_updates = on        
        [[NowPlaying]]
            type = str
            visu_acl = rw
            pioneer_listen = title
            enforce_updates = on
        [[Station]]
            type = str
            visu_acl = rw
            pioneer_listen = station
            enforce_updates = on      
        [[HMG_Play]]
            type = num
            visu_acl = rw
            pioneer_send = hmg_play
        [[HMG_Previous]]
            type = num
            visu_acl = rw
            pioneer_send = hmg_pre
        [[HMG_Next]]
            type = num
            visu_acl = rw
            pioneer_send = hmg_next
        [[Bass]]
            type = num
            visu_acl = rw
            pioneer_listen = bass
            enforce_updates = yes
        [[BassUp]]
            type = num
            visu_acl = rw
            pioneer_send = bass+
            enforce_updates = on
        [[BassDown]]
            type = num
            visu_acl = rw
            pioneer_send = bass
            enforce_updates = on
        [[Treble]]
            type = num
            visu_acl = rw
            pioneer_listen = treble
            enforce_updates = yes
        [[TrebleUp]]
            type = num
            visu_acl = rw
            pioneer_send = treble+
            enforce_updates = on
        [[TrebleDown]]
            type = num
            visu_acl = rw
            pioneer_send = treble-
            enforce_updates = on
        [[FLDisplay]]
            type = str
            visu_acl = rw
            pioneer_listen = fldisplay
            enforce_updates = yes
        [[ListeningModeSet]]
            type = str
            visu_acl = rw
            pioneer_send = listeningmodeset
            pioneer_listen = listeningmodeset
            enforce_updates = yes
        [[ListeningModeSet_Text]]
            type = str
            visu_acl = rw      
            enforce_updates = yes
        [[ListeningMode]]
            type = str
            visu_acl = rw
            pioneer_listen = listeningmode
            enforce_updates = yes
        [[ListeningMode_Text]]
            type = str
            visu_acl = rw      
            enforce_updates = yes
        [[iRadioFav]]
            type = str
            visu_acl = rw
            pioneer_send = iRadioF
            enforce_updates = yes
        [[RadioFav]]
            type = str
            visu_acl = rw
            pioneer_send = RadioF
            enforce_updates = yes
        [[RadioFavCyclic]]
            type = bool
            visu_acl = rw
            pioneer_send = RadioFcyclic
            enforce_updates = yes        
    
    
    #    [[ZonePower]]
    #        type = bool
    #        visu_acl = rw
    #        pioneer_send = zonepower
    #        enforce_updates = on
    #    [[ZoneMute]]
    #        type = bool
    #        visu_acl = rw
    #        pioneer_send = zonemute
    #        enforce_updates = on
    #    [[ZoneVolume]]
    #        type = num
    #        visu_acl = rw
    #        pioneer_send = zonevolume
    #        enforce_updates = on
    #    [[ZoneVolumeUp]]
    #        type = bool
    #        visu_acl = rw
    #        pioneer_send = zonevolume+
    #        enforce_updates = on
    #    [[ZoneVolumeDown]]
    #        type = bool
    #        visu_acl = rw
    #        pioneer_send = zonevolume-
    #        enforce_updates = on
    #    [[ZoneSource]]
    #        type = str
    #        visu_acl = rw
    #        pioneer_send = zonesource
    #        enforce_updates = on
    #    [[ZoneNowPlaying]]
    #        type = str
    #        visu_acl = rw
    #        pioneer_listen = zonetitle
    #    [[ZoneStation]]
    #        type = str
    #        visu_acl = rw
    #        pioneer_listen = zonestation
    #    [[ZoneNext]]
    #        type = num
    #        visu_acl = rw
    #        pioneer_listen = zonenext
    #    enforce_updates = on
    #    [[ZonePrevious]]
    #        type = num
    #        visu_acl = rw
    #        pioneer_listen = zoneprevious
    #    enforce_updates = on
    und das Plugin selbst
    Code:
      
        import logging
        import threading
        from subprocess import call
        from time import sleep
    
        import lib.connection
    
        logger = logging.getLogger('Pioneer')
    
    
        class Pioneer(lib.connection.Client):
    
            def _wait(time_lapse):
                time_start = time.time()
                time_end = (time_start + time_lapse)
    
                while time_end > time.time():
                    pass
    
            def sendTimerExpired():
                #send last command again
                self._send(self,self._lastCommand);
    
            # Initialize connection to receiver
            def __init__(self, smarthome, host, port=23, cycle=15):
                logger.info("Pioneer: connecting to {0}:{1}".format(host, port))
                lib.connection.Client.__init__(self, host, port, monitor=True)
                self.terminator = b'\r'
                self._host = host
                self._sh = smarthome
                self._items = {}
                self._sources = {}
                self._cmd_lock = threading.Lock()
                self._status_objects = ['?V', '?F', '?M', '?S', '?BA', '?TR', '?FL' , '?GAH', '?L']
                self._status_objects_count = len(self._status_objects)
                self._status_objects_pointer = 0
                self._status_cycle_counter = 0
                self._lastCommand = ''
                self._sendTimeout = threading.Timer(3,self.sendTimerExpired)
    
                # After power on poll status objects (Scheduler)
                self._sh.scheduler.add('pioneer-status-update', self._update_status, cycle=2)
                self._sh.scheduler.change('pioneer-status-update', active=False)
    
                # Sadly the Pioneer does not send an event on now playing change
                self._sh.scheduler.add('pioneer-nowplaying-update', self._update_now_playing, cycle=cycle)
                self._sh.scheduler.change('pioneer-nowplaying-update', active=False)
    
            # On connect poll states
            def handle_connect(self):
                self._send('?P')
                logger.debug("Connection handled")
    
            # Parse received input from Pioneer and set items
            def found_terminator(self, data):
                data = data.decode()
                self._sendTimeout.cancel()
                logger.debug("Pioneer: Response: {0} from {1}".format(data, self._host))
                # AVR switched on
                if 'PWR0' in data:
                    logger.info("Pioneer: {0} powered on".format(self._host))
                    self._items['power'](True, 'Pioneer', self._host)
                    sleep(1.5)
                    self._sh.scheduler.change('pioneer-status-update', active=True)
    
                # AVR entered standby
                elif 'PWR1' in data:
                    logger.info("Pioneer: {0} powered off".format(self._host))
                    self._items['power'](False, 'Pioneer', self._host)
                    self._sh.scheduler.change('pioneer-status-update', active=False)
    
                # AVR entered zone2 on
                #elif data == 'APR0':
                #    logger.info("Pioneer: {0} zone powered on".format(self._host))
                #    self._items['zonepower'](True, 'Pioneer', self._host)
                #    self._sh.scheduler.change('status-update', active=False)
    
                # AVR entered zone2 standby
                #elif data == 'APR1':
                #    logger.info("Pioneer: {0} zone powered off".format(self._host))
                #    self._items['zonepower'](False, 'Pioneer', self._host)
                #    self._sh.scheduler.change('status-update', active=False)
    
                # AVR Zone2 is muted
                #elif data == 'Z2MUT0':
                #    logger.info("Pioneer: {0} zone muted".format(self._host))
                #    self._items['zonemute'](True, 'Pioneer', self._host)
    
                # AVR Zone2 is unmuted
                #elif data == 'Z2MUT1':
                #    logger.info("Pioneer: {0} zone unmuted".format(self._host))
                #    self._items['zonemute'](False, 'Pioneer', self._host)
    
                # AVR is muted
                elif 'MUT0' in data:
                    logger.info("Pioneer: {0} muted".format(self._host))
                    self._items['mute'](True, 'Pioneer', self._host)
    
                # AVR is unmuted
                elif 'MUT1' in data:
                    logger.info("Pioneer: {0} unmuted".format(self._host))
                    self._items['mute'](False, 'Pioneer', self._host)
    
                # Master volume
                elif 'VOL' in data:
                    try:
                        vol = data[4:]
                        #vol = int(vol)
                        logger.debug("Volume Data: "+str(vol))
                        if vol.isdigit():
                            logger.info("Pioneer: {0} is at volume {1}".format(self._host, vol))
                            self._items['volume'](vol, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: Unknown volume info received")
                    except:
                        logger.debug("Pioneer: No volume info received")
    
                # Zone volume
                #elif 'ZV' in data:
                #    try:
                #        vol = data[4:][:3]
                #        if vol.isdigit():
                #            logger.info("Pioneer: {0} is at zonevolume {1}".format(self._host, vol))
                #            self._items['zonevolume'](vol, 'Pioneer', self._host)
                #        else:
                #            logger.debug("Pioneer: Unknown zonevolume info received-{0}".format(vol))
                #    except:
                #        logger.debug("Pioneer: Unknown zonevolume info received")
    
                # TREBLE setting
                elif 'TR' in data:
                    try:
                        treble = data[3:]
                        logger.debug("Treble Data: "+str(treble))
                        if treble.isdigit():
                            logger.info("Pioneer: {0} treble setting is {1}".format(self._host, treble))
                            self._items['treble'](treble, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: Unknown Treble info received")
                    except:
                        logger.debug("Pioneer: No Treble info received")
    
                # BASS setting
                elif 'BA' in data:
                    try:
                        bass = data[3:]
                        logger.debug("Bass Data: "+str(bass))
                        if bass.isdigit():
                            logger.info("Pioneer: {0} bass setting is {1}".format(self._host, bass))
                            self._items['bass'](bass, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: Unknown Bass info received")
                    except:
                        logger.debug("Pioneer: No Bass info received")      
    
                #FL display information
                elif 'FL' in data:
                    try:
                        content = data[5:][:28]
                        logger.info("Pioneer: {} FL Display Data {}".format(self._host, content))
                        content = "".join(list(map(lambda i: chr(int(content[2 * i : ][ : 2], 0x10)), range(14)))).strip()
                        logger.info("Pioneer: {} FL Display Output {}".format(self._host, content))
                        self._items['fldisplay'](content, 'Pioneer', self._host)
                    except:
                        logger.debug("Pioneer: No FL display line info received")
    
                # Information on title and artist now playing
                elif 'GEH0' in data:
                    try:
                        line = data[5:][:1]
                        if line.isdigit():
                            line = int(line)
                            if line == 1:
                                content = data[10:-1]
                            elif line == 4:
                                content = data[10:-1]
                            else:
                                content = data[10:-1]
                            if content:
                                # Now playing
                                if line == 1:
                                    logger.info("Pioneer: {} Now playing {}".format(self._host, content))
                                    self._items['title'](content, 'Pioneer', self._host)
                                # Internet radio Station name
                                elif line == 4:
                                    logger.info("Pioneer: {} Internet radio station {}".format(self._host, content))
                                    self._items['station'](content, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: Unknown HMG line info received")
                    except:
                        logger.debug("Pioneer: No HMG line info received")
    
                # Input source information
                elif 'FN' in data:
                    try:
                        source = data[3:][:2]
                        logger.debug("Source Data: "+str(source))
                        if source.isdigit():
                            logger.info("Pioneer: {0} is at Input {1}".format(self._host, source))
                            self._items['source'](source, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: unknown source info received: "+str(source))
                    except:
                        logger.debug("Pioneer: No source info received: "+str(source))
    
                # Input zone source information
                #elif 'Z2F' in data:
                #    source = data[4:]
                #    logger.info("Pioneer: {0} zone source is {1}".format(self._host, source))
                #    self._items['zonesource'](zonesource, 'Pioneer', self._host)
    
                # Listening Mode Set
                elif 'SR' in data:
                    try:
                        mode = data[3:][:4]
                        logger.debug("Listening Mode Set Data: "+str(mode))
                        if mode.isdigit():
                            logger.info("Pioneer: Master {0} is at listening mode set {1}".format(self._host, mode))
                            self._items['listeningmodeset'](mode, 'Pioneer', self._host)
                        else:
                            logger.debug("Pioneer: Unknown listening mode set info received")
                    except:
                        logger.debug("Pioneer: No listening mode set info received: "+str(mode))
    
                # Listening Mode
                elif 'LM' in data:
                    try:
                        mode = data[3:][:4]
                        logger.debug("Listening Mode Data: "+str(mode))
                        logger.info("Pioneer: Master {0} is at listening mode {1}".format(self._host, mode))
                        self._items['listeningmode'](mode, 'Pioneer', self._host)
                    except:
                        logger.debug("Pioneer: No listening mode info received: "+str(mode))
    
            # Set plugin to alive
            def run(self):
                self.alive = True
    
            # Close connection to receiver and set alive to false
            def stop(self):
                self.alive = False
                self.close()
    
            # Parse items and bind commands to plugin
            def parse_item(self, item):
                if 'pioneer_send' in item.conf:
                    cmd = item.conf['pioneer_send']
                    if (cmd is None):
                        return None
                    else:
                        self._items[cmd] = item
                    return self.update_item
                elif 'pioneer_listen' in item.conf:
                    info = item.conf['pioneer_listen']
                    if (info is None):
                        return None
                    else:
                        self._items[info] = item
                        logger.debug("Pioneer: Listening to {} info".format(info))
                    return self.update_item
                else:
                    return None
    
            # TODO: Logic not yet used
            def parse_logic(self, logic):
                pass
    
            # Receive commands, process them and forward them to receiver
            def update_item(self, item, caller=None, source=None, dest=None):
                if caller != 'Pioneer':
                    if 'pioneer_send' in item.conf:
                        command = item.conf['pioneer_send']
                        value = item()
                        logger.info("Pioneer: {0} set {1} to {2} for {3}".format(caller, command, value, item.id()))
                        if(command == 'power') and (isinstance(value, bool)):
                            self._send('PO' if value else 'PF')
                        #if(command == 'zonepower') and (isinstance(value, bool)):
                        #    self._send('APO' if value else 'APF')
                        elif(command == 'mute') and (isinstance(value, bool)):
                            self._send('MO' if value else 'MF')
                        #elif(command == 'zonemute') and (isinstance(value, bool)):
                        #    self._send('Z2MO' if value else 'Z2MF')
                        elif(command == 'volume') and (isinstance(value, int)):
                            self._send('{0:0>3d}VL'.format(value))
                        #elif(command == 'zonevolume') and (isinstance(value, int)):
                        #    self._send('{0:0>2d}ZV'.format(value))
                        elif(command == 'hmg_next'):
                            self._send('13NW')
                        elif(command == 'volume+'):
                            self._send('VU')
                        elif(command == 'volume-'):
                            self._send('VD')
                        #elif(command == 'zonevolume+'):
                        #    self._send('ZU')
                        #elif(command == 'zonevolume-'):
                        #    self._send('ZD')
                        elif(command == 'hmg_pre'):
                            self._send('12NW')
                        elif(command == 'hmg_play'):
                            self._send('10NW')
                        elif(command == 'source'):
                            self._send('{}FN'.format(value))
                        #elif(command == 'zonesource'):
                        #    self._send('{}ZS'.format(value))
                        elif(command == 'sourcecyclic'):
                            self._send('FU')
                            self._send('?F')
                        elif(command == 'bass+'):
                            self._send('BI')
                        elif(command == 'bass-'):
                            self._send('BD')
                        elif(command == 'treble+'):
                            self._send('TI')
                        elif(command == 'treble-'):
                            self._send('TD')
                        elif(command == 'listeningmodeset'):
                            #value="{0:04d}".format(value)
                            self._send('{0}SR'.format(value))
                        elif(command == 'iRadioF'):
                            self._send('{}NW'.format(value))
                            self._send('30NW')
                        elif(command == 'RadioF'):
                            self._send('{}PR'.format(value))
                        elif(command == 'RadioFcyclic'):
                            self._send('TPI')
                        else:
                            logger.warning("Pioneer: Command {0} or value {1} invalid".format(command, value))
    
            # Poll for status updates
            def _update_status(self):
                self._send(self._status_objects[self._status_objects_pointer])
                self._status_objects_pointer += 1
                if self._status_objects_pointer >= self._status_objects_count:
                    self._status_objects_pointer = 0
                    self._status_cycle_counter += 1
                if self._status_cycle_counter == 2:
                    self._sh.scheduler.change('pioneer-status-update', active=False)
                    self._status_cycle_counter = 0
    
            # Poll for now playing updates
            def _update_now_playing(self):
                self._send('?GAH')
    
            # Send commands to receiver if connected
            def _send(self, cmd):
                if not self.connected:
                    try:                
                        logger.debug("Pioneer: No mode info received: {0}".format(mode))()
    
                    except:
                        logger.debug("Pioneer: (Re)connect failed in send")
                        logger.warning("Pioneer: No connection, can not send command: {0}".format(cmd))
                        self._cmd_lock.acquire()
                        self.send(bytes(cmd + '\r', 'utf-8'))
                        self._lastCommand = cmd
                        self._sendTimeout.start()
                        self._cmd_lock.release()                  
                        return
                else:
                    try:
                        self._cmd_lock.acquire()
                        logger.debug("Pioneer: Sende Anfrage {0}".format(cmd))
                        self.send(bytes(cmd + '\r', 'utf-8'))
                        self._cmd_lock.release()
                    except:
                        return
        #!/usr/bin/env python
    Hilft es?

    Viele Grüße

    Kommentar


      #32
      Danke Sisamiwe Das hatte ich soweit die letzte Zeit auch im Einsatz. Mich hat es dann genervt, dass nie klar war, ob nun das Update angekommen ist oder nicht. Man weiß auch nicht, ob die Verbindung da ist oder nicht (zB Steckdose aus), etc. Daher habe ich auf der Basis mal ein ziemlich komplexes Ding dazu gebastelt, mit Retries, Abfragen, etc. Ist aber deutlich zu wenig flexibel für andere Geräte..
      Daher wollte ich das jetzt mal komplett neu aufbauen, auch gleich als SmartPlugin umsetzen und MultiInstance, da ich zB 2 Pioneers daheim hab.

      Die Sache mit der Titel-Anzeige kann ich aber bestimmt brauchen. Ich nutz das zwar nicht, sollte aber jedenfalls ins Plugin.

      Kommentar


        #33
        Onkelandy

        Ich werde dein Update, wenn du es soweit funktionsfähig hast, mal einbinden und dir berichten. Danke für die tolle Arbeit.
        Ich habe gerade egsehen, das mein Receiver kein RS232 hat. Muss ich mit dem Netzwerk-Protokoll leben.

        Gruss,

        Stefan
        Zuletzt geändert von pfischi; 05.01.2017, 10:37.
        Sonos

        Kommentar


          #34
          Sisamiwe Könntest du die Codezeile noch ein wenig erläutern? Bei mir kommt leider nur Kauderwelsch mit Sonderzeichen raus. Tippe mal auf ein Problem mit dem Zeichensatz, aber ich weiß nicht wirklich, wie ich es beheben kann.
          content = "".join(list(map(lambda i: chr(int(content[2 * i : ][ : 2], 0x10)), range(14)))).strip()

          Eine Antwort ist zB: U�Bå5DU$Tò Angezeigt wird Ext. Stereo

          Kommentar


            #35
            Das ist die Umrechnung der Displayausgabe im Tuner bzw. Normalbrieb.
            Der AVR gibt es als aneinandergebundene HEX-Werte beginnend mit FL aus, wie bspw. FL022020204D555445204F4E20202020.
            Nun muss die Zahlenkombination nach FL immer in 2er Pärchen getrennt, von HEX nach BIN umgewandelt und dann in ein Zeichen umgewandelt werden um danach wieder zum Test zusammengefügt zu werden.

            HEX --> BIN--> Zeichen
            02 --> 00000010 --> "Space"
            20 --> 32 --> "Space"
            4D --> 77 --> M
            FL022020204D555445204F4E20202020 --> MUTE ON

            Schau mal im Anhang auf Seite 26.

            Die CODE Zeile macht all die Umwandelungen und gibt den Test aus. Diese habe ich zusammen mit einem Python-Genie entwickelt.

            Hilft das?


            Angehängte Dateien

            Kommentar


              #36
              Danke für die Info! Ich hatte mir den Anhang schon mal durchgelesen, ist aber doch eher Bahnhof für mich.
              Interessanterweise bekomme ich bei mir ein korrektes Ergebnis, wenn ich den Content von 2 bis 28 Zeichen limitiere. Also die Spaces zu beginn überspringen ist nicht..
              Also so funzt es: content = data[2:][:28]

              Das müsste doch bei dir gleich sein? In deinem Code steht nämlich, dass erst ab dem 5. Character geguckt wird.

              Um die Leerzeichen wegzubringen brauche ich ein re.sub(r'^[^A-Z0-9]*', '', content), da strip() oder lstrip() irgendwie nicht greift, warum auch immer.

              Kommentar


                #37
                Der Vollständigkeit halber soll hier noch auf das AV Device Plugin verwiesen werden, das derzeit Denon und Pioneer Geräte unterstützt..
                https://knx-user-forum.de/forum/supp...enon-etc/page5

                Auch die Pioneer-Funktionalität ist inzwischen optimiert worden..

                Kommentar

                Lädt...
                X