Lately I was thinking about how to simplify my audio setup.
I have a Rotel PreAmp and Amp, which needed to be powered up manually if I wanted to listen to some music or radio. I have connected a Sonos Connect and a Raspberry Pi with a HifiBerry Digi+ module to it.
I would like an implementation like the standalone Sonos speakers. You just open the App, select your music and start listening without any need to go to the speaker and turn it on or set the input source.
Luckily my PreAmp has a serial RS232 connection. So I can use my Raspberry Pi which is already located next to the PreAmp to control it over this Interface.
I just used a USB to RS232 (male) cable to connect them both. Before I was able to connect it to the PreAmp the nuts of the connector had to be removed (use a small plier if you can’t unscrew them). You can also use an additional DB9 cable with thumb screws on both sides.
After connecting the Pi and the PreAmp you the Adapter is accesable at the path “/dev/ttyUSB0”. As I am writing my script in python, you need (besides the basic python package) also “python-serial”.
sudo apt-get install python python-serial
First you should check the the protocol specifications of your audio amplifier. This can usually be found on the website of the manufacturer.
In case of my PreAmp there are the following relevant commands:
power_off (powers the PreAmp off)
opt1 (select Optical 1 input)
coax2 (select Coaxial 2 input)
Every command needs a terminating character. In case of Rotel it is “!”.
My script has an infinite “while-loop” and checks the power status of the amp as well as the playing status of the Sonos and of the Raspberry Pi.
The Raspberry Pi runs an image of max2play which starts squeezelite and a jivelite client. I use it as a remote player for my Roon Server. It will get music streams (similar to the Sonos System) hosted on a network attached Storage. But in contrast to Sonos it can also play Hi-Def audio files (24 Bit, 192 kHz). It also has the Raspberry Pi touchscreen attached.
There was no easy way to find out if the Raspberry Pi is currently playing audio (maybe someone has a better idea?). I figured out, that the max2play image had a screensaver for jivelite “Blank Screen”. This will power off the touchdisplay and this can be figured out by entering:
If it returns “1” your display is powered off. If it returns “0” it is currently active.
The playing status of Sonos will be displayed on a debug website of the sonos products.
I created a list called “playing” and put the power-off command in there first. If an audio player is active it will be appended to the list and be removed when it stops playing.
The last element in this list is the current active setting for the PreAmp.
#!/usr/bin/env python import time import serial import sys import urllib # Set Variables here squeezepi_input = 'coax2' sonos_input = 'opt1' amp_poweroff_cmd = 'power_off' sonosip = '10.0.1.34' rs232port = '/dev/ttyUSB0' rs232baudrate = 115200 debug = False ## Initializing some needed Variables playing = [amp_poweroff_cmd] lastplaying =  running = True ## Initializing RS232 Connection to Amp... ser = serial.Serial( port=rs232port, baudrate=rs232baudrate, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS ) ## Loop to check devices status... while running == True: if debug: print '#############################################' input = '' #reset last string playerswitch = '' #reset last string ## Check if squeezepi is currently turned on (via active display backlight)... squeezepi = not bool(int(open('/sys/class/backlight/rpi_backlight/bl_power', 'r').read())) if squeezepi and 'squeezepi' not in playing: playing.append('squeezepi') if not squeezepi and 'squeezepi' in playing: playing.remove('squeezepi') ## Check if Sonos is currently playing... try: sonosamp = urllib.urlopen('http://' + sonosip + ':1400/status/perf').read() except: sonosamp = "Not available" for sonosampstate in sonosamp.split("\n"): if "currently" in sonosampstate: sonosamp = sonosampstate.strip() if 'PLAYING' in sonosamp: if 'sonos' not in playing: playing.append('sonos') else: if 'sonos' in playing: playing.remove('sonos') ## Getting amp information through RS232 ampstatus = '' ser.isOpen() ser.write('get_display!') time.sleep(1) while ser.inWaiting() > 0: ampstatus += ser.read(1) ## Based on the "VOL" in the display, you know the device is powered on... if 'VOL' in ampstatus: amppower = True if squeezepi_input.upper() in ampstatus: current_input = squeezepi_input elif sonos_input.upper() in ampstatus: current_input = sonos_input else: current_input = '' amppower = False ## Print current settings for debug purposes. if debug: print 'Amp-Power: ' + str(amppower) print 'squeezepi: ' + str(squeezepi) print 'sonos: ' + str('sonos' in playing) if playerswitch: print 'switch: ' + str(playerswitch != '') if len(playing) > 1: print 'Selected Player: ' + str(playing[-1]) if current_input != '': print 'Current input: ' + str(current_input) if len(playing) > 1: print 'Active Players: ' + str(playing[1:3]) if lastplaying != playing: playerswitch = True lastplaying = playing[:] # This if-condition is called if the state of one device has been changed or if the gained info from the devices mismatch. if playerswitch: if len(playing) > 1: if current_input != eval(str(playing[-1]) + '_input'): input = eval(str(playing[-1]) + '_input') print 'Changing to input: ' + eval(str(playing[-1]) + '_input') else: if amppower: input = amp_poweroff_cmd if input != '': ser.write(input + '!') if debug: print '*** Sending RS232 Command! *** (' + input + ')' out = '' time.sleep(2) while ser.inWaiting() > 0: out += ser.read(1) ser.close() exit()