So, I devised a way to both send commands to the VSX-1021-K and for all response messages from the receiver to be put immediately into an Indigo variable using a persistent telnet connection to the receiver in the background. Be forewarned, this is a somewhat advanced setup, so if you'd like to replicate this with the VSX-1021-K or other networked Pioneer receiver, be prepared to do quite a bit of command-line work on the Mac with Indigo running on it.
Setup requirements:
- Pioneer VSX-1021-K (or similar networkable Pioneer receiver. The command set is similar for all of them).
- Wired network connection to the receiver (a Wi-Fi connection may work with the optional wireless adapter, but I haven't tested this).
- Static IP address assigned to the receiver.
- Indigo 4 Pro (or later).
- The Mac running Indigo Pro will need to be on all the time.
This is a 2 stage process. First, we need to create a shell script that will act as a receiver response proxy, sending all command responses from the receiver to a variable in Indigo. Second, we need to create a LaunchAgent definition for this shell script so whenever you restart the computer (or log out then back in), the connection to the receiver is re-estabilshed.
Stage 1
- Open the Indigo Pro client and create 2 variables. First, a variable named "ReceiverCommand" and second, a variable named "ReceiverCommandResponse".
- Open the Terminal application (/Applications/Utilities) on the Mac with Indigo server running on it. Be sure you're logged into the computer as the same user from which IndigoServer runs, otherwise none of this will work. In most cases, you will be logged into the computer as that user.
- Use the "vi" or "nano" command-line text editor to create the shell script. I prefer vi, but nano is simpler to use if you're new to command-line work. (The "^" character in the nano command list at the bottom of the main nano screen represents pressing the "control" key while pressing the letter immediately after the "^" character). Begin creating the shell script with the "vi" tool by typing
or by typing the following for use with the "nano" toolCode: Select all
vi "/Library/Application Support/Perceptive Automation/Indigo 4/Scripts/Background Tasks/receiver_connect.sh"
From here on, I'll assume that you know how to insert text and save it once you're done with whichever editor you're using. Note that if you're doing this with Indigo 5, you'll need to change the "Indigo 4" path above to "Indigo 5" and be sure the "Scripts" and "Background Tasks" folders exist in the Indigo 5 folder.Code: Select all
nano "/Library/Application Support/Perceptive Automation/Indigo 4/Scripts/Background Tasks/receiver_connect.sh"
- Insert the following code into this new receiver_connect.sh file.
Replace the 192.168.1.190 IP address above with your receiver's actual IP address then save the file. This simple shell script uses the "nc" (netcat) tool to continuously listen for commands sent on TCP/IP port 65023 (this is a random number I picked) then re-send those commands to the telnet application, which is connected to the receiver. The telnet application sends those commands to the receiver which then produces a textual command response. The telnet application outputs those responses to the built-in shell "while" loop in the above script. The "while" loop reads one line of text from telnet at a time and uses the "osascript" tool to execute AppleScript telling IndigoServer to update the "ReceiverCommandResponse" variable with the receiver's response message.Code: Select all
#!/bin/bash nc -k -l 65023 | telnet 192.168.1.190 | while read line do /usr/bin/osascript -e "tell application \"IndigoServer\"" -e "set value of variable \"ReceiverCommandResponse\" to \"$line\"" -e "end tell" done
- Run the following command to make the shell script executable by the current user and group (being sure to replace "Indigo 4" with "Indigo 5" if you're using that version).
Code: Select all
chmod ug+x "/Library/Application Support/Perceptive Automation/Indigo 4/Scripts/Background Tasks/receiver_connect.sh"
- Open the Terminal application (if it's not already open). Again, you must be logged into the computer as the user under which IndigoServer is running.
- Create a new LaunchAgent file so that when you log out then back in or restart the computer, the connection to the receiver is re-established. The following command is for the "vi" tool, but just replace "vi" with "nano" if you prefer that text editor.
Code: Select all
vi ~/Library/LaunchAgents/com.nathansheldon.receiver_connect.plist
- Insert the following code into that file. Be sure to change "Indigo 4" to "Indigo 5" if you're using Indigo 5.
Save the file. This XML code instructs the launchd process that always runs on Mac OS X to run the shell script you just created every time you log into the current user account.Code: Select all
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Disabled</key> <false/> <key>KeepAlive</key> <true/> <key>WorkingDirectory</key> <string>/Library/Application Support/Perceptive Automation/Indigo 4/Scripts/Background Tasks</string> <key>Program</key> <string>/Library/Application Support/Perceptive Automation/Indigo 4/Scripts/Background Tasks/receiver_connect.sh</string> <key>Label</key> <string>com.nathansheldon.receiver_connect</string> </dict> </plist>
- Open the Indigo Pro client (if it isn't already open).
- Create a new trigger with the following parameters.
Trigger tab
Name: <whatever you like, I use "Send Receiver Command">
Type: "Variable Changed"
Variable: "ReceiverCommand", "changes" radio button selected.
Condition tab
Upon trigger do actions: "If script returns true:" selected with the following code in the field below that button.Actions tabCode: Select all
if value of variable "ReceiverCommand" is not "" then return true else return false end if
Type: "Execute AppleScript"
Embedded: radio button selected, with the following code inserted in the text area below it.This trigger activates whenever the "ReceiverCommand" variable changes (unless that variable contains nothing) then sends the content of the "ReceiverCommand" variable to the receiver using the "nc" (netcat) tool. It then clears the content of the "ReceiverCommand" variable.Code: Select all
set theCommand to value of variable "ReceiverCommand" -- Send the command to the receiver via netcat (nc). do shell script "echo \"" & theCommand & "\" | nc localhost 65023" -- Reset the ReceiverCommand variable to blank. set value of variable "ReceiverCommand" to ""
3. Logout then Login or Restart the Computer
This is the easiest way to start the background connection to the receiver (though you could also just run the launchctl command with the appropriate parameters, but this is easier).
4. Setting up a Trigger in Indigo to Handle Command Responses
This is where a lot of customization for your specific setup comes in. For my setup, I created the following trigger.
Trigger tab
Name: <whatever you like. I used "Receiver Command Response">
Type: "Variable Changed"
Variable: "ReceiverCommandResponse", "changes" radio button selected.
Condition tab
Upon trigger do actions: "If script returns true:" selected with the following code in the field below that button.
Code: Select all
if value of variable "ReceiverCommandResponse" is not "" then
return true
else
return false
end if
Type: "Execute AppleScript"
Embedded: radio button selected, with the following code inserted in the text area below it.
Code: Select all
-- Custom actions based on responses.
if value of variable "ReceiverCommandResponse" is "BridgeCo AG Telnet server" then
-- Receiver Connection Initiated
-- To work around a bug that causes an E04 (unknown command) error response on the first command when the receiver_connect.sh daemon first connects to the receiver, send a ?P power status request to clear the error.
set value of variable "ReceiverCommand" to "?P"
else if value of variable "ReceiverCommandResponse" is "PWR0" then
-- Power On
set value of variable "isReceiverPowerOn" to "true"
set value of variable "ReceiverCommand" to "?V"
delay 0.1
set value of variable "ReceiverCommand" to "?M"
else if value of variable "ReceiverCommandResponse" is "PWR1" then
-- Power Off
else if value of variable "ReceiverCommandResponse" is "MUT0" then
-- Mute On
else if value of variable "ReceiverCommandResponse" is "MUT1" then
-- Mute Off
else if value of variable "ReceiverCommandResponse" starts with "FN" then
-- Input Change
set i to value of variable "ReceiverCommandResponse"
set i to (characters 3 through 4 of i) as text
if i is "01" then
-- CD
else if i is "02" then
-- TUNER
-- Request the current band/frequency
set value of variable "ReceiverCommand" to "?FR"
delay 0.1
set value of variable "ReceiverCommand" to "?PR"
else if i is "03" then
-- CD-R/TAPE
else if i is "04" then
-- DVD
else if i is "05" then
-- TV/SAT
else if i is "10" then
-- VIDEO 1
else if i is "14" then
-- VIDEO 2
else if i is "15" then
-- DVR/BDR
else if i is "17" then
-- iPod/USB
else if i is "19" then
-- HDMI 1
else if i is "25" then
-- BD
else if i is "26" then
-- Home Media Gallery
else if i is "27" then
-- SIRIUS
end if
-- Now request the input name of the current input.
set value of variable "ReceiverCommand" to "?RGB" & i
else if value of variable "ReceiverCommandResponse" starts with "RGB" then
-- Input Name Request
set t to value of variable "ReceiverCommandResponse"
set l to (count of characters in t)
set n to (characters 7 through l of t) as text
set v to (characters 4 through 5 of t) as text
-- n is the input name.
-- v is the input number.
else if value of variable "ReceiverCommandResponse" starts with "VOL" then
-- Volume Level
set receiverVolume to value of variable "ReceiverCommandResponse"
set receiverVolume to (characters 4 through 6 of receiverVolume) as text
set receiverVolume to (receiverVolume) as number
-- Convert volume to dB.
if receiverVolume > 0 then
set receiverVolumeDB to -80.5 + 0.5 * receiverVolume
else
set receiverVolumeDB to "-∞"
end if
-- receiverVolume is the numerical volume
-- receiverVolumeDB is the associated decibel volume trip or amplification level (-infinity to +12 dB).
else if value of variable "ReceiverCommandResponse" starts with "FL" then
-- Fluoro-Luminescent Display Content Request
set theString to value of variable "ReceiverCommandResponse"
set theString to (characters 5 through 32 of theString) as text
set theResult to ""
set i to 1
repeat until i > 28
set x to character i of theString
set i to i + 1
set y to character i of theString
if x is "A" then
set x to 10
else if x is "B" then
set x to 11
else if x is "C" then
set x to 12
else if x is "D" then
set x to 13
else if x is "E" then
set x to 14
else if x is "F" then
set x to 15
end if
set x to x * 16
if y is "A" then
set y to 10
else if y is "B" then
set y to 11
else if y is "C" then
set y to 12
else if y is "D" then
set y to 13
else if y is "E" then
set y to 14
else if y is "F" then
set y to 15
end if
set theNum to x + y
-- Special character handling.
if theNum is 1 then
set theChar to "rp/sh "
else if theNum is 2 then
set theChar to "rp "
else if theNum is 3 then
set theChar to "sh "
else if theNum is 4 then
set theChar to "◊ "
else if theNum is 5 then
set theChar to "[)"
else if theNum is 6 then
set theChar to "(]"
else if theNum is 7 then
set theChar to "I"
else if theNum is 8 then
set theChar to "II"
else if theNum is 9 then
set theChar to "<"
else if theNum is 10 then
set theChar to ">"
else if theNum is 11 then
set theChar to "\\^^/"
else if theNum is 12 then
set theChar to "."
else if theNum is 13 then
set theChar to ".0"
else if theNum is 14 then
set theChar to ".5"
else if theNum is 15 then
set theChar to "Ω"
else if theNum is 16 then
set theChar to "0"
else if theNum is 17 then
set theChar to "1"
else if theNum is 18 then
set theChar to "2"
else if theNum is 19 then
set theChar to "3"
else if theNum is 20 then
set theChar to "4"
else if theNum is 21 then
set theChar to "5"
else if theNum is 22 then
set theChar to "6"
else if theNum is 23 then
set theChar to "7"
else if theNum is 24 then
set theChar to "8"
else if theNum is 25 then
set theChar to "9"
else if theNum is 26 then
set theChar to "A"
else if theNum is 27 then
set theChar to "B"
else if theNum is 28 then
set theChar to "C"
else if theNum is 29 then
set theChar to "F"
else if theNum is 30 then
set theChar to "M"
else if theNum is 31 then
set theChar to "¯"
else
set theChar to ASCII character theNum
end if
set theResult to theResult & theChar
set i to i + 1
end repeat
-- theResult is the ASCII equivalent of what's displayed on the receiver display.
else if value of variable "ReceiverCommandResponse" starts with "MC" then
-- MCACC Memory Change
set m to value of variable "ReceiverCommandResponse"
set m to character 3 of m
if m is "1" then
-- MCACC Memory 1 selected
else if m is "2" then
-- MCACC Memory 2 selected
else if m is "3" then
-- MCACC Memory 3 selected
else if m is "4" then
-- MCACC Memory 4 selected
else if m is "5" then
-- MCACC Memory 5 selected
else if m is "6" then
-- MCACC Memory 6 selected
end if
else if value of variable "ReceiverCommandResponse" starts with "IS" then
-- Phase Control Update
set p to value of variable "ReceiverCommandResponse"
set p to character 3 of p
-- p = 0: Phase Control Off
-- p = 1: Phase Control On
-- p = 2: Full Band Phase Control On
else if value of variable "ReceiverCommandResponse" starts with "VSB" then
-- Virtual Sound Back Update
set sb to value of variable "ReceiverCommandResponse"
set sb to character 4 of sb
-- sb = 0: Off
-- sb = 1: On
else if value of variable "ReceiverCommandResponse" starts with "VHT" then
-- Virtual Height Update
set h to value of variable "ReceiverCommandResponse"
-- h = 0: Off
-- h = 1: On
else if value of variable "ReceiverCommandResponse" starts with "CLV" then
-- Speaker Channel Volume Level Update
set c to value of variable "ReceiverCommandResponse"
set l to (characters 7 through 8 of c) as text
set l to (l) as number
set c to (characters 4 through 6 of c) as text
-- c = L__: Front Left
-- c = R__: Front Right
-- c = C__: Center
-- c = SL_: Surround Left
-- c = SR_: Surround Right
-- c = SBL: Surround Back Left
-- c = SBR: Surround Back Right
-- c = SW_: Subwoofer
-- c = LH_: Front Left Height
-- c = RH_: Front Right Height
-- c = LW_: Front Left Wide
-- c = RW_: Front Right Wide
-- l = 26 - 74: channel volume from -12 dB to +12 dB (in 0.5 dB increments)
else if value of variable "ReceiverCommandResponse" starts with "SPK" then
-- Speaker Status Update
set s to value of variable "ReceiverCommandResponse"
set s to character 4 of s
-- s = 0: Speakers Off
-- s = 1: Speakers A On
-- s = 2: Speakers B On
-- s = 3: Speakers A+B On
else if value of variable "ReceiverCommandResponse" starts with "HA" then
-- HDMI Audio Select Update
set h to value of variable "ReceiverCommandResponse"
set h to character 3 of h
-- h = 0: Amp
-- h = 1: Through
else if value of variable "ReceiverCommandResponse" starts with "PQ" then
-- PQLS Status Update
set p to value of variable "ReceiverCommandResponse"
set p to character 3 of p
-- p = 0: Off
-- p = 1: Auto
else if value of variable "ReceiverCommandResponse" starts with "PKL" then
-- Panel Key Lock Status Update
set p to value of variable "ReceiverCommandResponse"
set p to character 4 of p
-- p = 0: Panel Key and Volume Lock Off
-- p = 1: Panel Key Lock On
-- p = 2: Panel Key and Volume Lock On
else if value of variable "ReceiverCommandResponse" starts with "RML" then
-- Remote Lock Status Update
set r to value of variable "ReceiverCOmmandResponse"
set r to character 4 of r
-- r = 0: Off
-- r = 1: On
else if value of variable "ReceiverCommandResponse" is "APR0" then
-- Zone 2 Power On
else if value of variable "ReceiverCommandResponse" is "APR1" then
-- Zone 2 Power Off
else if value of variable "ReceiverCommandResponse" starts with "Z2F" then
-- Zone 2 Input Select Update
set z to value of variable "ReceiverCommandResponse"
set z to (characters 4 through 5 of z) as text
-- See "Input Change" definitions for the "FN*" response above
else if value of variable "ReceiverCommandResponse" starts with "FR" then
-- Tuner Frequence Change
set f to value of variable "ReceiverCommandResponse"
set b to character 3 of f
set f to (characters 4 through 8 of f) as text
if b is "F" then
set tmp to (characters 1 through 3 of f) as text
set tmp to tmp & "."
set tmp to tmp & (characters 4 through 5 of f) as text
set f to (tmp) as number
else
set f to (f) as number
end if
-- b = A: AM
-- b = F: FM
-- f = frequency (either in kHz for AM or MHz for FM).
else if value of variable "ReceiverCommandResponse" starts with "PR" then
-- Tuner Preset Change
set p to value of variable "ReceiverCommandResponse"
set n to (characters 4 through 5 of p) as text
set n to (n) as number
set p to character 3 of p
-- p = A - G: Preset Class A through G
-- n = 0 - 9: Preset Number (within class) 0 through 9
-- Request the band and frequency of this preset.
set value of variable "ReceiverCommand" to "?FR"
else if value of variable "ReceiverCommandResponse" starts with "SIR" then
-- Sirius Satellite Radio Channel Change
set s to value of variable "ReceiverCommandResponse"
set s to (characters 4 through 7 of s) as text
set s to (s) as number
-- s: Sirius channel number
end if