Page 1 of 1

Pioneer Ethernet Plugin Help

Posted: Mon May 26, 2014 1:57 am
by rebelmaveric19
Alright i have been a long time lurker on these forums and found all of my answers without posting for years but I am stumped on this one.......I do not know alot about python, just what I have picked up from decyphoring code from other peoples plugins. What I am trying to do is use VoxCommando and this Pioneer Ethernet Plugin to control my VSX-1021k. I have gotten everything to work correctly except for setting my volume to a certain level. I have made a command that I can say to VoxCommando "Set receiver volume {1}" and it passes that payload to Eventghost, where I get lost is no matter what I do the Pioneer plugin dosent like the payload. I can set the action like "Pioneer AV Ethernet: Set Master Volume: 150" and it works great but using "Pioneer AV Ethernet: Set Master Volume: {eg.event.payload[0]}" nets me a "unknown" from the receiver. I have also set up a flash OSD to see if the payload is being corectly sent from VoxCommando and it is. Also tried setting and using a variable in place of {eg.event.payload[0]} and also hit a brick wall. Will someone with more python experience please be so kind as to tell me why this won't work. Thanks for your time!

Here is the code for the Pioneer Plugin:

Code: Select all

###
### Pioneer Ethernet
### ================

### Public Domain
###
###
### Revision history:
### -----------------
### 0.1 - initial
### 0.2 - Added: variable commands (Volume)
###              parsing of received hex additional data
###              standby and resume states working
###              comments into code
###              socket is now managed into the listener
###              debug support
### 0.3 - Modified: responses from power commands
###       Added: control of excepctions if receiver is disconnected
###              messages indicating connection status 
###

help = """\
Plugin to control Pioneer Receivers via Ethernet.
Note that not all commands work with every model."""

eg.RegisterPlugin(
    name = "Pioneer AV Ethernet",
    author = "sergiensergien (based on Onkyo development by prostetnic, Bartman, Fiasco, FoLLgoTT)",
    version = "0.3." + "$LastChangedRevision: 1246 $".split()[1],
    kind = "external",
    guid = "{50e42894-579e-4ae2-9d9e-3b67c2c338cf}",
    description= "Control Pioneer A/V Receivers via Ethernet",
    help = help,
    canMultiLoad = True,
    createMacrosOnAdd = True,
    icon = (
        "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAA"
        "AAd0SU1FB9YDBAsPCqtpoiUAAAAWdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCAyLjZsqHS1"
        "AAADe0lEQVQ4T02TXVCUZRSAPyZsxpnqoovum+miq+6qFUJYQP7cogS2VpGFAAlKpyAC"
        "EVh+4k80WGADQWlxZRfZACH5ECVY5TdHiEbAIQVkHRzUCZK/ZWGXp10SxjPzXrzvvM9z"
        "zpw5xwUQXg7ndX1jw3VkYmrzycK/gusrgrB3z17hvXfffv2tN99YcXHEi///g07Bznkw"
        "+9i1yvAbqvJKolRJhJ2KQp4ZQWTWd5wsV9Ni6sWybn3tZWYXvjt531V1tgJF8lcEZbij"
        "MLgRbTpAVHcgyk5/QnSefHrmc7QdV1hbX9+VbAvuTk67ZpfVIDsWgu/ZfURfD+TElVBy"
        "m4+TooshvDaAL697EPOHLzK1L9prbayuWbYlwsLzFZfCql+Qx8XhqfoAZUsIhsEGLGsW"
        "Nm12FlZtTM0/w2DSEmn0dEgclRSFcFG8wcamTRAqtO0kpRficdQLpV5Gr7mf3qFHzC1u"
        "YF61MvrIztD0OsP3F6m/ZUDZ7klosxfxJZn0j04hpJ+uIvZ4EpJvJKhvFWOzW1lc2qT/"
        "zznuzdnoGnlG+8BDWnvMDE7M8q1eQcygN6GFkWj0nQgp+WUcilTyUaIHzRPtWKx2rLYt"
        "5hfXHBnMNIjDtHbfY3RmmcdLdkrEfKIHDyDLPYS6vhnhh9wSgiPCcYvbT+3gNQbGluib"
        "WOTG8EOaTGOY/nrKwPgynXdm+H3gCZkNeQ6BP0GnZGgMRoTUnDMcSfgaiUJKWuPP6MRx"
        "LhjvUN3Qh671NnVNQ1y9Oe2YgUmaeqY4WnMEpSgl5ORhzhmaEFRFpSTnOpool+GXFoa6"
        "sQNNXReVupucv9zHeWM3Gl0HNY0mci7VEtF2EJ+8fSTkpSP23EaYmpl1ySgowk8ehiTc"
        "i6iiExRcNKC+0IlG20m5XqRCK5J9qYxoMZSgail+scEUn6vn+bJFImxtbQkl5dWoCkvx"
        "Cg3k/Uh3grKCSahJJln3E8n1BSQ2JhArHuSTUgneET6kFWno6h3GyW5P4sqqRUhMLSCn"
        "uJQA+cdIFYF8GC3F/Xs3vDM8kaZ4sP+YD/4RX5B+Wk1l3SXnkG2zu7uwZrHuqa1rILuw"
        "hNSsfOSxsQQoPkN2WI4iPp7EzBx+dPRLb7zK0orl1Z2FEmwvTM4HZ0kzZvM7hqZfMbaJ"
        "jEw8YHh8kvrGFmr1euaf/iPZAW12uzD2t1n4DwtSpLoLWTYZAAAAAElFTkSuQmCC"
    ),
)


import socket
import asynchat
import asyncore
import re
import binascii
import itertools
import operator
import time
import eg

cmdList = (
    ('Power / Sleep', None, None, None, None),
        ('Power.Off',               'Power Off',                       'PF',     None, 'PWR1'  ),
        ('Power.On',                'Power On',                        'PO',     None, 'PWR0'  ),       
    ('Master Volume', None, None, None, None),
        ('Volume.Up',               'Master Volume Up',                'VU',     None, None    ),
        ('Volume.Down',             'Master Volume Down',              'VD',     None, None    ),
        ('Volume.Set',              'Set Master Volume (000-200)',       'VL',     '000-200', None  ),
        ('Mute.On',                 'Mute On',                         'MF',     None, 'MUT0'  ),
        ('Mute.Off',                'Mute Off',                        'MO',     None, 'MUT1'  ),
    ('Input Select Command', None, None, None, None),
        ('Input.DVD',               'DVD',                             '04FN',   None, 'FN04'  ),
        ('Input.BD',                'BD',                              '25FN',   None, 'FN25'  ),
        ('Input.TV/SAT',            'TV / SAT',                        '05FN',   None, 'FN05'  ),
        ('Input.DVR/BRD',           'DVR / BRD',                       '15FN',   None, 'FN15'  ),
        ('Input.Video',             'Video',                           '10FN',   None, 'FN10'  ),
        ('Input.HDMI1',             'HDMI 1',                          '19FN',   None, 'FN19'  ),
        ('Input.HDMI2',             'HDMI 2',                          '20FN',   None, 'FN20'  ),
        ('Input.HDMI3',             'HDMI 3',                          '21FN',   None, 'FN21'  ),
        ('Input.HDMI4',             'HDMI 4',                          '22FN',   None, 'FN22'  ),
        ('Input.HDMIFront',         'HDMI Front',                      '23FN',   None, 'FN23'  ),
        ('Input.iRadio',            'Internet Radio',                  '26FN',   None, 'FN26'  ),
        ('Input.IPOD/USB',          'iPOD / USB',                      '17FN',   None, 'FN17'  ),
        ('Input.XMRadio',           'XM Radio',                        '18FN',   None, 'FN18'  ),
        ('Input.CD',                'CD',                              '01FN',   None, 'FN01'  ),
        ('Input.CDR/Tape',          'CD-R / Tape',                     '03FN',   None, 'FN03'  ),
        ('Input.Tuner',             'Tuner',                           '02FN',   None, 'FN02'  ),
        ('Input.Adapter',           'Adapter',                         '33FN',   None, 'FN33'  ),
        ('Input.Sirius',            'Sirius',                          '27FN',   None, 'FN27'  ),
        ('Input.HDMI.Cycle',        'HDMI Input (Cycle)',              '31FN',   None, None    ),
        ('Input.Up',                'Next Input',                      'FU',     None, None    ),
        ('Input.Down',              'Previous Input',                  'FD',     None, None    ),
    ('Stereo Front Stage Mode', None, None, None, None),
        ('Stereo.Cycle',            'Stereo Mode(Cycle)',              '0001SR', None, None    ),
        ('Stereo.Stereo',           'Stereo',                          '0009SR', None, 'LM0001'),
        ('Stereo.FrontStageWide',   'Front Stage Wide',                '0004SR', None, 'LM0003'),
        ('Stereo.FrontStageNarrow', 'Front Stage Narrow',              '0003SR', None, 'LM0002'),
    ('Stream Direct Mode', None, None, None, None),
        ('Stream.Cycle',            'Stream Direct Mode (Cycle)',      '0005SR', None, None    ),
        ('Stream.Direct',           '2 Channel',                       '0007SR', None, 'LM0601'),
        ('Stream.PureDirect',       '2 Channel',                       '0008SR', None, 'LM0701'),
        ('Stream.ALC',              '2 Channel',                       '0151SR', None, 'LM0501'),
        ('Stream.Auto Surround',    '2 Channel',                       '0006SR', None, 'LM0401'),
    ('Surround Mode', None, None, None, None),
        ('Surround.Cycle',          'Dolby Surround Mode (Cycle)',     '0010SR', None, None),
        ('Surround.ProLogic',       'Dolby ProLogic',                  '0012SR', None, 'LM0107'),
        ('Surround.PLIIxMovie',     'Dolby ProLogic IIx Movie',        '0013SR', None, 'LM0102'),
        ('Surround.PLIIxMusic',     'Dolby ProLogic IIx Music',        '0014SR', None, 'LM0104'),
        ('Surround.PLIIxGame',      'Dolby ProLogic IIx Game',         '0015SR', None, 'LM0106'),
        ('Surround.Neo6Cinema',     'Neo:6 Cinema',                    '0016SR', None, 'LM0108'),
        ('Surround.Neo6Music',      'Neo:6 Music',                     '0017SR', None, 'LM0109'),
        ('Surround.PLIIz',          'Dolby ProLogic IIz Height (*)',   None    , None, None    ),
        ('Surround.WideSrndMovie',  'Wide Surround Movie (*)',         None    , None, None    ),
        ('Surround.WideSrndMusic',  'Wide Surround Music (*)',         None    , None, None    ),
        ('Surround.NeuralSrnd',     'Neural Surround (*)',             None    , None, None    ),
        ('Surround.DolbyDigitalEX', 'Dolby Digital EX (*)',            None    , None, None    ),
        ('Surround.DTS.ES',         'DTS ES (*)',                      None    , None, None    ),
        ('Surround.DTS.Neo6',       'DTS Neo:6 (*)',                   None    , None, None    ),
        ('Surround.NeuralSrnd',     'Neural Surround (*)',             None    , None, None    ),
    ('Advanced Surround', None, None, None, None),
        ('Advanced.Cycle',          'Wide Surround Movie',             '0100SR', None, None    ),
        ('Advanced.Action',         'Adv. Surround: Action',           '0101SR', None, 'LM0201'),
        ('Advanced.Sci-Fi',         'Adv. Surround: Sci-Fi',           '0102SR', None, 'LM0203'),
        ('Advanced.Drama',          'Adv. Surround: Drama',            '0103SR', None, 'LM0202'),
        ('Advanced.Show',           'Adv. Surround: Show',             '0104SR', None, 'LM0202'),
        ('Advanced.MonoFilm',       'Adv. Surround: Mono Film',        '0105SR', None, 'LM0205'),
        ('Advanced.Expanded',       'Adv. Surround: Expanded',         '0106SR', None, 'LM0204'),
        ('Advanced.Classical',      'Adv. Surround: Classical',        '0107SR', None, 'LM0206'),
        ('Advanced.Unplugged',      'Adv. Surround: Unplugged',        '0109SR', None, 'LM020a'),
        ('Advanced.Pop/Rock',       'Adv. Surround: Pop/Rock',         '0110SR', None, 'LM020c'),
        ('Advanced.ExpStereo',      'Adv. Surround: Exp. Stereo',      '0111SR', None, 'LM020b'),
        ('Advanced.TVSurround',     'Adv. Surround: TV Surround',      '0112SR', None, 'LM020d'),
        ('Advanced.AdvancedGame',   'Adv. Surround: Advanced Game',    '0116SR', None, 'LM0207'),
        ('Advanced.Sports',         'Adv. Surround: Sports',           '0118SR', None, 'LM0208'),
        ('Advanced.PhonesSrnd',     'Adv. Surround: Phones Srnd. (*)', None,     None, None    ),
    ('State Queries', None, None, None, None),
        ('Power.State',             'Returns Power State',             '?P',     None, 'PWR'   ),
        ('Volume.State',            'Returns Master Volume level',     '?V',     None, 'VOL'   ),
        ('Mute.State',              'Returns Mute State',              '?M',     None, 'MUT'   ),
        ('Input.State',             'Returns Current Input',           '?F',     None, None    ),
        ('Mode.State',              'Returns Listening Mode',          '?S',     None, None    ),
        ('Listening.Info',          'Returns Listening Info',          '?L',     None, None    ),
    (None, None, None, None, None),       
)

class PioneerEventer(asynchat.async_chat):
    """Pioneer engine class. Implements command line user interface."""
        
    ### Initializing all the variables and open the tcp connection..
    ###
    def __init__(self, host, port, plugin): 
        asynchat.async_chat.__init__(self)   
        self.set_terminator("\x0d\x0a")
        self.reading_headers = False
        self.data = ""
        self.host = host
        self.port = port
        self.plugin = plugin
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.socket.connect((self.host, self.port))
            connected = True
        except socket.error, exc:
            print 'PIONEER: Connect fail:', (self.host, self.port)
            connected = False
        if connected == True:
            asynchat.async_chat.__init__(self, sock=self.socket)   
            self.plugin.TriggerEvent("connected")
        eg.RestartAsyncore()
        
    ### This will be run if the connections is succesful
    ###
    def handle_connect(self):
        # connection succeeded
        connected = True
        print "PIONEER: Listening to device started"
        
    ### This will be run if the tcp connection is disconnected
    ### or if we want to close it ourselves.
    ###
    def handle_close(self):
        print "PIONEER: Listener Close"
        # self.handler.reader = None
        connected = False
        self.plugin.TriggerEvent("disconnected")
        self.close()
        
    ### This will be run if there is a problem opening the connection
    ###
    def handle_expt(self):
        # connection failed
        # if eg.debugLevel:
        eg.PrintTraceback()
        connected = False
        print "PIONEER: Listener Failed"
        self.plugin.TriggerEvent("disconnected")
        self.close()

    ### This gets run whenever asynchat detects there is data waiting
    ### for us to be read at the socket, to put it in our buffer
    ###
    def collect_incoming_data(self, data):
        # received a chunk of incoming data
        self.data = self.data + data
        if eg.debugLevel:
            print "PIONEER (Debug): Eventer Collecting"

    ### This gets run whenever asynchat detects there is data waiting
    ### for us to be examined, so this is where it's all at..
    ###
    def found_terminator(self):
        # got a response line
        data = self.data
        self.data = ""
        if eg.debugLevel:
            print "PIONEER (Debug): Received " + str(data)
        
        ### The PIONEER device sends a keep-alive consisting only in the terminator
        ### So if "data" is not empty, we want to process it.
        if len(data):
            ### First we search through our known fixed responses for a match 
            response = operator.itemgetter(4)
            try:
                datum = map(response, cmdList).index(str(data))
                self.plugin.TriggerEvent("Received." + cmdList[datum][0], None)
            except ValueError:
                ### If not fixed match, it can be a long info message ...
                if len(data) > 6:
                    print "PIONEER: Says " + data[:4] + " : " + binascii.unhexlify(data[4:])
                ### Or, perhaps, it's a big hole in our knowledge of Pioneer devices ...
                else:
                    self.plugin.TriggerEvent("Received.Unknown", str(data))
        else:
            if eg.debugLevel:
                print "PIONEER (Debug): Keep alive"

### Sends data to our device when called (with no additional argument)
###
class CmdAction(eg.ActionClass):
    """Base class for all argumentless actions"""

    def __call__(self):
        if self.plugin.eventer == 0:
            self.plugin.InitConnection()    
        if self.plugin.eventer.connected == True:
            datum = self.plugin.eventer.socket.send(str(self.cmd) + '\x0d')
            if eg.debugLevel:
                print "PIONEER (Debug): Send (" + repr(datum) + ") : " + str(self.cmd)
        else:
            self.plugin.TriggerEvent("disconnected")

### Sends data to our device when called (with additional argument)
###
class ValueAction(eg.ActionWithStringParameter):
    """Base class for all actions with adjustable argument"""

    def __call__(self, data):
        if self.plugin.eventer == 0:
            self.plugin.InitConnection()    
        if self.plugin.eventer.connected == True:
            datum = self.plugin.eventer.socket.send(str(data) + str(self.cmd) + '\x0d')
            if eg.debugLevel:
                print "PIONEER (Debug): Send (" + repr(datum) + ") : " + str(self.cmd) + " = " + data
        else:
            self.plugin.TriggerEvent("disconnected")


### Sends RAW data to our device when called (with no additional argument)
###
class Raw(eg.ActionWithStringParameter):
    name = 'Send Raw command'

    def __call__(self, data):
        if self.plugin.eventer == 0:
            self.plugin.InitConnection()    
        if self.plugin.eventer.connected == True:
            datum = self.plugin.eventer.socket.send(str(data) + '\x0d')
            if eg.debugLevel:
                print "PIONEER (Debug): RAW Send (" + repr(datum) + ") : " + str(data)
        else:
            self.plugin.TriggerEvent("disconnected")

### The EventGhost classes and functions are over here..
###
###
class PioneerEthernet(eg.PluginClass):

    ### Initialization of the plugin.
    ### We load all the commands from the command table.
    ###
    def __init__(self):
        self.serial = None
        group = self

        for cmd_name, cmd_text, cmd_cmd, cmd_rangespec, cmd_answer in cmdList:
            if cmd_text is None:
                # New subgroup, or back up
                if cmd_name is None:
                    group = self
                else:
                    group = self.AddGroup(cmd_name)
            elif cmd_rangespec is not None:
                # Command with argument
                actionName, paramDescr = cmd_text.split("(")
                actionName = actionName.strip()
                paramDescr = paramDescr[:-1]
                minValue, maxValue = cmd_rangespec.split("-")

                class Action(ValueAction):
                    name = actionName
                    cmd = cmd_cmd
                    parameterDescription = "Value: (%s)" % paramDescr
                Action.__name__ = cmd_name
                group.AddAction(Action)
            else:
                # Argumentless command
                class Action(CmdAction):
                    name = cmd_text
                    cmd = cmd_cmd
                Action.__name__ = cmd_name
                group.AddAction(Action)

        group.AddAction(Raw)

    def __start__(self, host, port):
        self.host = host
        self.port = port
        self.InitConnection()

    def __stop__(self):
        if self.eventer:
            self.eventer.close()
        self.eventer = None
        return

    ### Listener Initialization. It is called when the plugin starts and
    ### when the system cames back from a suspended state.
    ###
    def InitConnection(self):
        try:
            self.eventer = PioneerEventer(self.host, self.port, self)            
        except socket.error, exc:
            self.eventer = 0
            raise self.Exception(exc[1])

        #Send useful Queries to start macros if needed
        if self.eventer.connected != 0:
            datum = self.eventer.socket.send('?M\x0d')
            datum = self.eventer.socket.send('?F\x0d')
            datum = self.eventer.socket.send('?L\x0d')
            datum = self.eventer.socket.send('?S\x0d')
    
    ### When we suspend the systems we close down the connection
    ### to the device.
    ###
    def OnComputerSuspend(self, suspendType):
        if self.eventer:
            self.eventer.handle_close()
            print "PIONEER: Disconnected from the PIONEER device!"
        self.eventer = None

	### When we resume from a suspended state we have to wait for the
	### interfaces to came back in line and restablish the connections ...
	### the waiting time can be up to 20 secs in wireless enviroment.
	###
    def OnComputerResume(self, suspendType):
        print "PIONEER: Resuming connection to PIONEER device"
        time.sleep(20)
        self.InitConnection()

    ### Plugin configuration.
    ### Change "host" with the IP of the PIONEER device.
    ###
    def Configure(self, host="192.168.2.100", port=8102):
        panel = eg.ConfigPanel()
        hostCtrl = panel.TextCtrl(host)
        portCtrl = panel.SpinIntCtrl(port, max=65535)

        panel.AddLine("Host:", hostCtrl)
        panel.AddLine("Port:", portCtrl)

        while panel.Affirmed():
            panel.SetResult(
                hostCtrl.GetValue(),
                portCtrl.GetValue()
            )

Re: Pioneer Ethernet Plugin Help

Posted: Mon May 26, 2014 6:31 pm
by Sem;colon
Well, I can't help you with this plugin, but you may want to take a look at that one:viewtopic.php?f=10&t=3836

Re: Pioneer Ethernet Plugin Help

Posted: Mon May 26, 2014 10:35 pm
by rebelmaveric19
Hey SemiColon, I tried your plugin too by sending {eg.event.payload[0]}VL and can't get it to work either but can get it to work by sending 150VL. I even did a "print eg.event.payload[0]" and the payload is getting sent over from VoxCommando just fine. I am stumped. Can you help me with your plugin?

Re: Pioneer Ethernet Plugin Help

Posted: Tue May 27, 2014 1:22 pm
by kkl
Just a guess, but I suspect that eg.event.payload[0] is a numeric value and it needs to be a string.

Re: Pioneer Ethernet Plugin Help

Posted: Tue May 27, 2014 6:57 pm
by Sem;colon
copy this in your configuration/macro where the volume set should be triggered:

Code: Select all

<?xml version="1.0" encoding="UTF-8" ?>
<EventGhost Version="1640">
    <Action>
        EventGhost.PythonCommand(u"eg.plugins.Pioneer_AV_NET.SendCommand(unicode(eg.event.payload[0])+u'VL', u'idOfYourHifi')")
    </Action>
</EventGhost>
replace idOfYourHifi with the alias name you specified in the "Add Host" function.

This should work.

Re: Pioneer Ethernet Plugin Help

Posted: Wed May 28, 2014 7:34 pm
by rebelmaveric19
Thank you very much SemiColon, I did not use your exact action as I deciphered it and made it work with the "other" plugin. You gave me the right syntax to perform an event. The reason I use the "other" plugin is because it automatically creates events when something on the receiver is changed (power on/off, volume changes, etc) and use them to trigger macros in my event tree. Unless I am missing something in your plugin I couldnt get events to populate in the log automatically unless called upon. It would have taken me much longer to figure this out if you hadn't posted that. Really.......thank you. May I ask one more favor, where would I have read something to show me this if I googled it (what phrase should I google to get me there.....)

Code: Select all

<?xml version="1.0" encoding="UTF-8" ?>
<EventGhost Version="1640">
    <Macro Name="Set Master Volume {1}" Expanded="True">
        <Event Name="Broadcast.SetReceiverVol" />
        <Action Name="eg.plugins.PioneerEthernet.Raw(unicode(eg.event.payload[0])+u'VL')">
            EventGhost.PythonCommand(u"eg.plugins.PioneerEthernet.Raw (unicode(eg.event.payload[0])+u'VL')")
        </Action>
    </Macro>
</EventGhost>

Re: Pioneer Ethernet Plugin Help

Posted: Thu May 29, 2014 9:28 am
by Sem;colon
rebelmaveric19 wrote:Thank you very much SemiColon
You're welcome!
rebelmaveric19 wrote:The reason I use the "other" plugin is because it automatically creates events when something on the receiver is changed (power on/off, volume changes, etc) and use them to trigger macros in my event tree. Unless I am missing something in your plugin I couldnt get events to populate in the log automatically unless called upon.
Well, I guess you missed something, my plugin does that as well.
But sure, if the other plugin works for you, why changing it ;-)
rebelmaveric19 wrote:May I ask one more favor, where would I have read something to show me this if I googled it (what phrase should I google to get me there.....)
hmm, I don't know, it's just python... :D