A Ruby implementation of eISCP (ethernet Integra Serial Control Protocol) for controlling Onkyo receivers.
I'm still sort of updating this code. Please feel free to reach out if there's something you need that it doesn't do, I may be willing to help.
The python version linked below sees much more activity.
-
Automatically discover receivers in the broadcast domain
-
Send commands to receivers and parse returned messages
-
Open a TCP socket to receive solicited and non-solicited status updates.
-
Mock reciever (currently only responds to discovery)
-
Human-readable commands
**Inspired by https://github.com/miracle2k/onkyo-eiscp
**Protocol information from http://michael.elsdoerfer.name/onkyo/ISCP-V1.21_2011.xls
-
Command validation
-
Parsing of all human readable commands (run the tests to see some commands that aren't parsable in human readable form yet.
-
Reasonable variants for human-readable commands (ex.
main-volume
orvolume
as opposed tomaster-volume
) -
Model compatability checking
-
Logging
-
Exhaustive testing and documentation
-
Install the library
gem install onkyo_eiscp_ruby
-
Require the library
require 'eiscp'
-
You might want to
include EISCP
if you know you won't pollute your namespace with Constants underEISCP
(Dictionary
,Message
,Parser
,Receiver
,VERSION
) -
You can do most everything through the
Receiver
andMessage
objects. If you want to accept user input you will probably want to use theParser
module. Be sure to check out the RDocs or dig through the source code. I try to keep it well commented/documented, and there's more functionality to the library than is shown here: -
The
Message
object is pretty self explanatory.Message.new
is mostly used internally, but you're better off usingParser.parse
to create them. You probably will want to interact withMessage
objects to get information:
msg = EISCP::Message.new(command: 'PWR', value: '01')
msg.zone => 'main'
msg.command => "PWR"
msg.value => "01"
msg.command_name => "system-power"
msg.command_description => "System Power Command"
msg.value_name => "on"
msg.value_description => "sets System On"
- Discover local receivers (returns an
Array
ofReceiver
objects)
EISCP::Receiver.discover
- Create
Receiver
object from first discovered receiver on the LAN
receiver = EISCP::Receiver.new
- Or create one manually by IP address or hostname
receiver = EISCP::Receiver.new('10.0.0.132')
- When you create a
Receiver
object with a callback block it will connect and call your block on each message received.:
receiver = EISCP::Receiver.new do |msg|
puts msg.command
puts msg.value
end
Receivers
created without a block will not connect automatically. If you try to send a command it will connect transparently, otherwise you can use theconnect
method to explicitly open a socket to the receiver.
receiver.connect
- You can also set or change the callback block later. This will kill the existing callback thread, recreate the socket if necessary and start a new callback thread using the provided block:
receiver.connect do |msg|
puts "Received: #{msg.command_name}:#{msg.value_name}"
end
- You can also disconnect, which will close the socket and kill the connection thread:
receiver.disconnect
- Get information about the Receiver:
receiver.model => "TX-NR609"
receiver.host => "10.0.0.111"
receiver.port => 60128
receiver.mac_address => "001122334455"
receiver.area => "DX"
- Receivers now have a
@state
hash that contains a mapping of commands and values received. You can use this see the Receiver's last known state without querying. Use the#update_state
method to run every 'QSTN' command in the Dictionary and update the state hash, but do note that it will take a few seconds to finish:
receiver.update_state
receiver.state["MVL"] => "22"
receiver.human_readable_state["master-volume"] => 34
- You can use
CommandMethods
to easily send a message and return the reply as a Message object. OnceReceiver#connect
is called, a method is defined for each command listed in theDictionary
using the@command_name
attribute which is 'human readable'. You can check the included yaml file or look at the output ofEISCP::Dictionary.commands
. Here a few examples:
# Turn on receiver
receiver.system_power "on"
# Query current input source
receiver.input_selector "query"
# Turn the master volume up one level
receiver.master_volume "level-up"
# Set the master volume to 45
receiver.master_volume "45"
# Change the input to TV/CD
# Note: when a command value has more than one name (an array in the YAML file)
# we default to using the first entry. So for `['cd', 'tv', 'cd']` you get:
receiver.input_selector "cd"
- Parse ISCP and human readable strings:
# Parse various ISCP strings
iscp_message = EISCP::Parser.parse "PWR01"
iscp_message = EISCP::Parser.parse "PWR 01"
iscp_message = EISCP::Parser.parse "!1PWR01"
iscp_message = EISCP::Parser.parse "!1PWR 01"
# Parse human readable,
EISCP::Parser.parse("main-volume 34")
Parser.parse
is also used internally byReceiver
to parse raw eISCP socket data.
-
Discover local receivers
$ onkyo.rb -d
-
Send a human-readable command
$ onkyo.rb system-power on # uses Parser.parse
-
Or send a raw command
$ onkyo.rb PWRQSTN # Also tries to use Parser.parse
-
Monitor the first discovered receiver to see status updates
$ onkyo.rb -m
-
Start the mock server (only responds to 'ECNQSTN')
$ onkyo-server.rb
-
Turn off the first receiver discovered:
$ onkyo.rb system-power off
-
List all known commands and values:
$ onkyo.rb -L
-
List all known commands known to work with discovered models:
$ onkyo.rb -l
- Open an issue describing bug or feature
- Fork repo
- Create a branch
- Send pull request