Control Emotiva XMC-1 audio processor

Use this forum to discuss possible implementation of a new feature before opening a ticket.
A developer shall edit the topic title with "[xxx]" where xxx is the id of the accompanying tracker id.
Duplicate posts about the same id. +1 posts are not allowed.

Moderators: leecollings, remb0

Post Reply
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Control Emotiva XMC-1 audio processor

Post by RogerSch »

I have a audio surround processor from Emotiva the XMC-1: https://emotiva.com/products/pres-and-pros/xmc-1
Image

This surround processor can also be controlled via the Ethernet port. For this the vendor has created a document which describes the "Emotiva Network Remote Control protocol". Here is this document.
XMC-1_network_interface_description.docx
(49.24 KiB) Downloaded 271 times
Now I want to control some basic functions via Domoticz. My big question is; can anybody give me some guidance what the best / easiest approach is to enhance Domoticz with functionality to control the XMC-1? Are there already solutions out there which make use of a comparable UDP protocol implementation which could be used as a basis?

Thanks!
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

@ RogerSch: lucky you!
Here the code I have developed in Python. Beware that this code is based on previous firmware version (3.x). You may have to adapt if your unit runs v4. I have developed the very basic functions, based on that it would not be difficult to add some other functions (like volume up/down for instance). Python has been chosen because it implements the socket lib which is fairly easy to use.

This code sends the power On/Off command to XMC-1 using iTach IP2IR because I don't want to let the unit in video standby mode due to power drain (35W). So in this specific case, I use the IR in plug at the backside of the unit.

Code: Select all

#!/usr/bin/env python
import socket
import sys

power = sys.argv[1]

TCP_IPADDRESS = "192.168.21.239"
TCP_PORT = 4998
BUFFER_SIZE = 1000
if power == "OFF":
    MESSAGE = 'sendir,1:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,1517,341,85,21,3655\r'
elif power == "ON":
    MESSAGE = 'sendir,1:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,1517,341,85,21,3655\r'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IPADDRESS, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
if not 'completeir' in data:
    print 'Status', 'Erreur de transmission avec XMC-1'
    
print "received data:", data

This code sends to XMC-1 (and iTach but this is another story) the code to select the desired input

Code: Select all

#!/usr/bin/env python
# -*- coding: latin-1 -*-
import socket
import sys
import string
from time import sleep
import errno
import fcntl, os
#import domoticz

# Preamp codes
#iTACH IP2IR module
CD='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,32,32,64,64,32,32,64,64,32,3225\r'
TUNER='sendir,1:2,1,36023,1,1,32,32,64,32,32,32,32,64,32,32,32,32,64,32,32,64,64,64,32,32,32,3600\r'
PHONO='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,32,32,64,64,64,64,32,32,32,3235\r'
VIDEO='sendir,1:2,1,36023,1,1,32,32,64,32,32,32,32,64,32,32,32,32,32,32,32,32,64,64,64,64,32,3235\r'
AUX='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,64,64,32,32,32,32,64,64,32,3235\r'
TAPE='sendir,1:2,1,36023,1,1,32,32,64,32,32,32,32,64,32,32,32,32,64,64,32,32,32,32,64,32,32,3267\r'
PHASEIN='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,32,32,32,32,64,32,32,32,32,32,32,3267\r'
PHASEOUT='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,32,32,32,32,64,64,32,32,64,3267\r'
MUTE='sendir,1:2,1,36023,1,1,32,32,32,32,64,32,32,64,32,32,32,32,64,32,32,64,32,32,64,64,32,3235\r'
VOLUME_PLUS='sendir,1:2,1,36023,1,1,32,32,64,32,32,32,32,64,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,3235\r'
VOLUME_MOINS='sendir,1:2,2,36023,1,1,32,32,64,32,32,32,32,64,32,32,32,32,32,32,32,32,32,32,32,32,64,32,32,3267\r'

XMC_POWERON='sendir,1:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,1517,341,85,21,3655\r'
XMC_STANDBY='sendir,1:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,1517,341,85,21,3655\r'

# end of iTach

XMC_COMMAND='<?xml version="1.0" encoding="utf-8"?><emotivaControl><commandName value="commandValue" ack="yes" /></emotivaControl>'
XMC_PING='<?xml version="1.0" encoding="utf-8"?><emotivaPing />'

SLEEPTIME=0.4
audio = sys.argv[1]

IP2IR_IPADDRESS = "192.168.21.239"
IP2IR_PORT = 4998
XMC_IPADDRESS = "192.168.21.229"
XMC_TRANSACTION_PORT_IN = 7000
XMC_TRANSACTION_PORT_RESPONSE = 7001
XMC_CONTROL_PORT = 7002

BUFFER_SIZE = 1000

#row 0 is command
#row 1 is IP address
#row 2 is port
#row 3 is protocol
    
if audio == 'Plex':
    #Set preamp input to Vidéo and XMC input to Input 1
    MESSAGE=[[XMC_POWERON,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"],[XMC_COMMAND,XMC_IPADDRESS,XMC_CONTROL_PORT,"UDP"],[VIDEO,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]
    MESSAGE[1][0]=string.replace(MESSAGE[1][0],'commandName','source_1')
    MESSAGE[1][0]=string.replace(MESSAGE[1][0],'commandValue','0')
elif audio == 'DVD':
    #Set preamp input to Vidéo and XMC input to Input 2
    MESSAGE=[[XMC_POWERON,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"],[XMC_COMMAND,XMC_IPADDRESS,XMC_CONTROL_PORT,"UDP"],[VIDEO,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]
    MESSAGE[1][0]=string.replace(MESSAGE[1][0],'commandName','source_2')
    MESSAGE[1][0]=string.replace(MESSAGE[1][0],'commandValue','0')
elif audio == 'jRiver':
    #Set preamp input to Audio
    MESSAGE=[[AUX,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]
elif audio == 'CD':
    #Set preamp input to CD
    MESSAGE=[[CD,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]
elif audio == 'Tourne disque':
    #Set preamp input to Phono
    MESSAGE=[[PHONO,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]
elif audio == 'XMC_STANDBY':
    MESSAGE=[[XMC_STANDBY,IP2IR_IPADDRESS,IP2IR_PORT,"TCP"]]

sTCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sUDPreceive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sUDPreceive.bind(('',XMC_TRANSACTION_PORT_RESPONSE))
fcntl.fcntl(sUDPreceive, fcntl.F_SETFL, os.O_NONBLOCK)
#for row in MESSAGE:
#    #for e in row:
#        #print e
#    print row
IPADDRESS_PREVIOUS=""
loop=0
for row in MESSAGE:
    if row[3] == "UDP": # it is XMC by design
        # send a ping and check if unit is On. If not wait until it is ready (PowerOn has been sent before)
        while True:
            # send a ping until a response is given
            sUDP.sendto(XMC_PING, (XMC_IPADDRESS, XMC_TRANSACTION_PORT_IN))
            #print ('ping sent: ', MESSAGE[0][0])
            # wait some time to let the unit answer
            sleep (0.01)
            try:
                data = sUDPreceive.recvfrom(500)
            except socket.error, e:
                err = e.args[0]
                if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                    sleep(SLEEPTIME)
                    #print 'No data available'
                    loop+=1
                    if loop*SLEEPTIME >= 70:
                        #print('timeout')
                        exit()
                    continue
                else:
                    # a "real" error occurred
                    print e
                    sys.exit(1)
                #TBD implement a timeout of 20 sec in case there is a problem with the unit
            else:
                # unit is ready send the command now
                sUDP.sendto(row[0], (row[1], row[2]))
                # TBD : check if OK
                break
    else: # TCP protocol
        if IPADDRESS_PREVIOUS != row[1]:
            if IPADDRESS_PREVIOUS != "": s.close()
            sTCP.connect((row[1], int(row[2])))
            IPADDRESS_PREVIOUS=row[1]
        #print ("TCP", row[0])
        result = sTCP.send(row[0])
        #print (result)
        data = sTCP.recv(BUFFER_SIZE)
        #print "received data:", data

sUDP.close
sUDPreceive.close
sTCP.close
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

@Number8

I've been indeed lucky. :D This will give me a good starting point.

I used your python script as a basis and removed everything which I don't need for me very first test program. Just Volume Up and Volume Down function with no error checking etc. Assumption is also that the XMC-1 is powered on.
Here is my code (which is not optimized). In case you see a major flaw then please let me know.

Code: Select all

#!/usr/bin/env python
# -*- coding: latin-1 -*-
import socket
import sys
import string
#import domoticz

XMC_COMMAND='<?xml version="1.0" encoding="utf-8"?><emotivaControl><commandName value="commandValue" ack="no" /></emotivaControl>'

DoThis = sys.argv[1]

XMC_IPADDRESS = "192.168.1.113"
# XMC_TRANSACTION_PORT_IN = 7000
# XMC_TRANSACTION_PORT_RESPONSE = 7001
XMC_CONTROL_PORT = 7002


#row 0 is command
#row 1 is IP address
#row 2 is port
MESSAGE=[XMC_COMMAND,XMC_IPADDRESS,XMC_CONTROL_PORT]
    
if DoThis == 'VolUp':
    #Increase volume by 1 dB
    MESSAGE[0]=string.replace(MESSAGE[0],'commandName','volume')
    MESSAGE[0]=string.replace(MESSAGE[0],'commandValue','1')
	sUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	sUDP.sendto(MESSAGE[0], (MESSAGE[1], MESSAGE[2]))
	sUDP.close
elif DoThis == 'VolDown':
	#Decrease volume by 1 dB
	MESSAGE[0]=string.replace(MESSAGE[0],'commandName','volume')
    MESSAGE[0]=string.replace(MESSAGE[0],'commandValue','-1')
	sUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	sUDP.sendto(MESSAGE[0], (MESSAGE[1], MESSAGE[2]))
	sUDP.close

Top
No I need to figure where to place the python script on my Synology NAS. I've have installed the Python3 package of Synology.

Thanks a lot
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

Seems to me that you could give a shot.
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

Thanks @Number8.

After correcting some editorial failures like replacing TAB's with white spaces, I can run the Python script successfully from my PC. :D
So a first small step in controlling the XMC-1 from a Python has succeeded.

Now I need to figure out how to link a Python correctly to a virtual switch in Domoticz running on my Synology NAS. My first attempt did succeed. But I'm confident with other examples on the Domoticz forum how to solve this.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

Glad to read that. As far as Vol up/down in Domoticz is concerned, the only dummy device I see is the switch button, of type selector or maybe better dimmer. What are your thoughts?
Debian buster on NUC and three RPi with buster.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

If the selector switch is used it could have several buttons like: Mute and some fixed levels, with a slider switch beside for more control over the volume level.
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

Mmm somehow I got stuck. The following python script works. I can execute it on windows PC and even from a Terminal session logged onto my Synology NAS.

Terminal command which works:

Code: Select all

/volume1/@appstore/DomoticzScripts$ python ControlXMC1.py volume 1
I copied this into to the "Action On" in a virtual switch:

Code: Select all

script://volume1/@appstore/DomoticzScripts$ python ControlXMC1.py volume 1
It doesn't function when I press the Virtual switch.
What am I doing wrong?

Code: Select all

#!/usr/bin/env python
# -*- coding: latin-1 -*-
#
# Simple script to send commands to the Emotiva XMC-1 Surround Processor
# It is based upon XMC-1_network_interface_description.pdf V1.0
# First parameter is the command as defined in the PDF
# Second parameter is the Value to be applied. If no second parameter is present, Value is set to 0
# The fixed IP address of the XMC-1 needs to be defined below
#
# Author: R. Schuncken
# Date: 18 December 2016
# Version 1.0
#
import socket
import sys
import string
#import domoticz

XMC_COMMAND='<?xml version="1.0" encoding="utf-8"?><emotivaControl><commandName value="commandValue" ack="no" /></emotivaControl>'
XMC_IPADDRESS = "192.168.1.113"
# XMC_TRANSACTION_PORT_IN = 7000
# XMC_TRANSACTION_PORT_RESPONSE = 7001
XMC_CONTROL_PORT = 7002
MESSAGE=[XMC_COMMAND,XMC_IPADDRESS,XMC_CONTROL_PORT]

NumArgs = len(sys.argv)
ChangeValue = '0'

if (NumArgs > 1):
    if (NumArgs > 2):
        ChangeValue = sys.argv[2]
    MESSAGE[0]=string.replace(MESSAGE[0],'commandName',sys.argv[1])
    MESSAGE[0]=string.replace(MESSAGE[0],'commandValue',ChangeValue)
    sUDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sUDP.sendto(MESSAGE[0], (MESSAGE[1], MESSAGE[2]))
    sUDP.close
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

Did you check the execution bit? And it has to be root
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

Execution bit set. Root to be verified but that should not be a problem as I can execute the script from a Telnet session.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

that should not be a problem as I can execute the script from a Telnet session
Not too sure, I think Domoticz needs the script to be root to be executed by a button. Maybe some other fellows can confirm?
Debian buster on NUC and three RPi with buster.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

script://volume1/@appstore/DomoticzScripts$ python ControlXMC1.py volume 1
Oops beware you need script:/// (triple)
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

I tried that also. No luck...
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

Number8 wrote:
that should not be a problem as I can execute the script from a Telnet session
Not too sure, I think Domoticz needs the script to be root to be executed by a button. Maybe some other fellows can confirm?
Ownership is currently admin. Can't change it to root with chmod as I get an error message.
Question why is that needed if the file rights are 777.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

script://volume1/@appstore/DomoticzScripts$ python ControlXMC1.py volume 1
This cannot work. You have to call the python exe and make sure it resolves. Look at where it is installed and use an absolute path
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

I finally got it to work but only after defining a LUA script for the switches and in the LUA script executing the python script.

Now I can switch on and off Zone 2 and control volume of Zone 1 and Zone 2... Exactly what I want.

@Number8 thanks for your help.

In case anybody is interested in the final python code and LUA script I'll upload them here. Please let me know.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

This is what I did here viewtopic.php?f=6&t=14912
This code is just a skeleton to test the launch of a Python script from LUA.
What kind of button did you use for volume up/down?
Debian buster on NUC and three RPi with buster.
RogerSch
Posts: 51
Joined: Saturday 04 April 2015 10:42
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by RogerSch »

Number8 wrote:What kind of button did you use for volume up/down?
For the time being just two "Push On" buttons. I couldn't find an existing button (one!) which suits volume up and down well.
I would say there is some improvement possible in controling A/V devices and also on the graphical design of the Domoticz app. But adapting that is a bit too complex for me.
Number8
Posts: 374
Joined: Friday 23 May 2014 7:55
Target OS: Linux
Domoticz version: 2022.1
Location: Saint Pierre de Jards
Contact:

Re: Control Emotiva XMC-1 audio processor

Post by Number8 »

I would say there is some improvement possible in controling A/V devices
Agree
But adapting that is a bit too complex for me
Same for me ;)

So far I use a selector switch with 8 predefined sound levels, I use an On/Off button for the Mute function, and I will use a dimmer switch in order to set any levels between 0/100. When the user set a predefined sound level, the value of the "dimmer" switch is updated accordingly, however, the slider is not, which seems to be a design flaw at this stage.
Debian buster on NUC and three RPi with buster.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest