I made this a while back ago, so some of the details maybe are not as clear as they could be. Feel free to reach out and leave a comment if you have any questions.
This project has been running for several months now at a small TV studio without any reported issues. If you are hesitant about homebrewing a solution, I did receive an email from someone who also suggested a MIDI relay box http://www.midisolutions.com/prodr8.htm. I personally have no experience or feedback about this product, but I figured it may help someone else out while looking for different solutions.
Video is posted at the bottom of the page, to see it in action!
I used a Raspberry Pi (1) Model B+ for this project, although a newer model would also work. The TV studio used channels 1-10 on the Behringer mixer as microphone inputs. They wanted the on-air sign to automatically turn on if any of these mics were live. Seeing that the Behringer can be controlled over the network, I found the lowest cost solution would be to use a Raspberry Pi with some python code to poll the status of the microphone channels and in turn, trigger a GPIO to turn on and off the on-air sign.
Here's a picture of the Pi with only an LED and series resistor connected to GPIO 18 for testing purposes
Interacting with the Behringer Mixer
I searched around a bit and found that I can control the mixer as well as get status of all of its settings remotely over the network. It uses the X32 protocol (link at the bottom) over UDP port 10023. I was unable to find a way to get status of all of the channels (levels and mute status) with a single command so instead I ended up polling each channel that we wanted to monitor individually using the command /node , s
For channel 1, I would send,
/node ,s ch/01/mix
and it would return a string
X->, 52 B: node~~~~,s~~/ch/01/mix ON +3.9 OFF +0 OFF -oo~~~~
The highlighted parts are what we are interested in (Channel/Mute status = ON, Channel is on, it is NOT muted)(Fader Level = +3.9)
Raspberry Pi Python Code
I used python to write a script to poll the Behringer mixer that is on the same network. The code could be improved upon many ways, one being that it currently does not re-open the UDP socket if a failure occurs. I'm sure other parts can certainly be cleaned up a bit too, but it's been working fine for a few months now at the site, so I'm satisfied with it.
The code first opens up a UDP socket on the IP address and port specified (10.10.10.25, 10023) and then continues to poll each channel we wanted to monitor (1-10) using the command "/node ,s" for its status. The Behringer mixer returns mute status (with an ON or OFF), ON being that the channel is on and signal is allowed to pass, along with the actual level the fader is set too (or infinity = ‐oo) which then the code looks for a lower case "o" = decimal 111. If a channel returns ON and the fader is not all the way down, it then adds a 1 to the channel list. The code then finally checks if any channels in the list are set to 1, if any channel in the list is set to 1, it will trigger the GPIO 18 to on, otherwise if all of the channels are set to 0, it will trigger GPIO 18 to off.
Because it is constantly polling each channel few times a second, the response time to trigger the on-air sign on or off is very fast (maybe 1/2 a second).
Create the onair.py file
Copy and paste the code below (
y to save)
Polls a Behringer mixer over UDP port 10023 (channels 1-10), if any are Not muted and the fader is up, it will trigger GPIO 18 to True
import socket #for sockets
import sys #for exit
import RPi.GPIO as GPIO
# create dgram udp socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print '[-] ERR: Failed to create socket'
led = 18
host = '10.10.10.25';
port = 10023;
onair = 0;
channel_status = ;
state = 0;
count = 0;
for x in range(1,11):
if count > 5:
state = 0
count = 0
channel = str(x).zfill(2)
s.sendto("/node"+'\x00\x00\x00'+",s"+'\x00\x00'+"ch/" + channel + "/mix"+'\x00\x00\x00', (host, port))
d = s.recvfrom(1024)
if len(d) == 0:
print '[-] ERR: No data received'
reply = d
addr = d
except socket.timeout, e:
err = e.args
if err == 'timed out':
print '[-] ERR: Recv timed out, retry later'
count += 1
except socket.error, e:
err = e.arg
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
print '[-] ERR: No data available'
print '[-] ERR: Error Code : ' + str(e) + ' Message ' + e
count += 1
volume_ack = reply.split(' ',2)
data = bytearray(volume_ack)
volume = int(data)
if volume_ack == 'ON' and volume != 111:
if 1 in channel_status and state == 0:
print 'On Air'
state = 1
elif 1 in channel_status:
state = 1
print 'Off Air'
state = 0
channel_status = ;
Make the script executable
chmod +x onair.py
Manually run the script (accessing the GPIO requires sudo)
Starting the Code At Boot
The python code above needs to start whenever the Raspberry Pi boots up. Using nano, I simply added a line to /etc/rc.local for this.
sudo nano /etc/rc.local
add the following line to the end ofthe file BUT above the last line exit 0
(sleep 15;python onair.py)&
Wiring in the On-Air Sign
We just built a simple circuit, connecting the base of a transistor to a GPIO pin on the Raspberry Pi, this then controls a relay to switch the 12VDC on-air sign on and off. Here is a picture of the board we made that connected to GPIO 18 on the Raspberry Pi.
Video of the Pi Controller in Action
Here's a short video we made demonstrating the Pi controller in action