onkyo_eiscp_ruby 0.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be075bcd7a1830e7614b8384d610ea59d0b7160f
4
- data.tar.gz: 40cea299c77c937a786f387cfbf4c11e8696632c
3
+ metadata.gz: ab3d51dea59ba8c99a8782be06c6508cd3b37163
4
+ data.tar.gz: aa346aaa381eda5418f7d7233b475d9f54e04b51
5
5
  SHA512:
6
- metadata.gz: 5066d43a66350cb39e84ddbae87038d4ba04057f2dd884eee1852c3dd108ed4a44842878157dfb854e7802d3e771cbe5789a70af936af0e338a36264e92332d6
7
- data.tar.gz: 6c2c8bb4ba7d3b7e9fee332d448a054cf97480194192252965b363b7efaa8d8b095ae76d2f68ab6f064fbf68ec2bac75c63b2ba53a26e891b055c0751f776cc4
6
+ metadata.gz: 0c75784e4c01fe2ad2031933f5ea5f6204ccf81b543985a93dd2d301dac5e714aff529508d0fc3545013b7723fb84043f0405903e4444b8ca61635dab0ccdde4
7
+ data.tar.gz: 07aba89079c12e05b5eac6d4d475f7818568744d16d9c3196e714efff07b21f8c86308afdd8a6953a9b97045a26a146ca9dbac18f58e03a216368cc78ffdb293
data/README.md CHANGED
@@ -1,21 +1,40 @@
1
1
  onkyo_eiscp_ruby
2
2
  ================
3
3
  [![Gem Version](https://badge.fury.io/rb/onkyo_eiscp_ruby.png)](http://badge.fury.io/rb/onkyo_eiscp_ruby)
4
+ [![GitHub version](https://badge.fury.io/gh/mikerodrigues%2Fonkyo_eiscp_ruby.png)](http://badge.fury.io/gh/mikerodrigues%2Fonkyo_eiscp_ruby)
4
5
 
5
- A Ruby implementation of eISCP for controlling Onkyo receivers.
6
+ *A Ruby implementation of eISCP for controlling Onkyo receivers.*
6
7
 
7
8
  **This code is still under heavy development and using it might make you sick.**
8
- Create ISCP messages and eISCP packets
9
- Automatically discover receiver's in the broadcast domain
10
- Send/Recieve eISCP messages
11
- Open a TCP socket to send commands and receive solicited and non-solicited status updates.
9
+
10
+ Automatically discover receivers in the broadcast domain
11
+
12
+ Send commands to receivers and parse returned messages
13
+
14
+ Open a TCP socket to receive solicited and non-solicited status updates.
15
+
12
16
  Mock reciever (currently only responds to discovery)
13
17
 
18
+ Human-readable commands
19
+
14
20
  **Inspired by https://github.com/miracle2k/onkyo-eiscp
15
21
 
16
22
  **Protocol information from http://michael.elsdoerfer.name/onkyo/ISCP-V1.21_2011.xls
17
23
 
24
+ What's missing?
25
+ ---------------
26
+ * Command validation
27
+
28
+ * Parsing of all human readable commands (run the tests to see some commands that aren't parsable in human readable form yet.
18
29
 
30
+ * Reasonable variants for human-readable commands (ex. `main-volume` or`volume
31
+ ` as opposed to `master-volume`)
32
+
33
+ * Model compatability checking
34
+
35
+ * Logging
36
+
37
+ * Exhaustive testing and documentation
19
38
 
20
39
  Using the Library
21
40
  -----------------
@@ -23,53 +42,155 @@ Using the Library
23
42
 
24
43
  require 'eiscp'
25
44
 
26
- * Discover local receivers
27
-
45
+ * You might want to `include EISCP` if you know you won't pollute your namespace
46
+ with Constants under `EISCP` (`Dictionary`, `Message`, `Parser`, `Receiver`,
47
+ `VERSION`)
48
+
49
+ * You can do most everything through the `Receiver` and `Message` objects. If you
50
+ want to accept user input you will probably want to use the Parser module. Be
51
+ sure to check out the RDocs or dig through the source code. I try to keep it
52
+ well commented/documented, and there's more functionality to the library than
53
+ is shown here:
54
+
55
+ * The `Message` object is pretty self explanatory. `Message.new` is mostly used
56
+ internally, but you're better of using `Parser.parse` to create them. You
57
+ probably will want to interact with `Message` objects to get information:
58
+
59
+ ```ruby
60
+ msg = EISCP::Message.new(command: 'PWR', value: '01')
61
+ msg.zone => 'main'
62
+ msg.command => "PWR"
63
+ msg.value => "01"
64
+ msg.command_name => "system-power"
65
+ msg.command_description => "System Power Command"
66
+ msg.value_name => "on"
67
+ msg.value_description => "sets System On"
68
+ ```
69
+
70
+ * Discover local receivers (returns an `Array` of `Receiver` objects)
71
+
72
+ ```ruby
28
73
  EISCP::Receiver.discover
74
+ ```
29
75
 
30
- * Create Receiver object from first discovered
76
+ * Create `Receiver` object from first discovered Receiver on the LAN
31
77
 
32
- Receiver.new
78
+ ```ruby
79
+ receiver = EISCP::Receiver.new
80
+ ```
33
81
 
34
- * Open a TCP connection to monitor solicited updates
82
+ * Or create one manually by IP address or hostname
35
83
 
36
- receiver = Receiver.new('10.0.0.1')
37
- receiver.connect
84
+ ```ruby
85
+ receiver = EISCP::Receiver.new('10.0.0.132')
86
+ ```
38
87
 
39
- * You can also pass a block and operate on received packet strings:
88
+ * When you create a `Receiver` object, it uses the `Receiver::Connection` module to
89
+ make a connection and monitor incoming messages. By default, the last message
90
+ received can be retrieved with `receiver.last`. You can
91
+ pass your own block at creation time, it will have access to messages as they
92
+ come in. This will let you setup callbacks to run when messages are receivedL
40
93
 
41
- receiver.connect do |data|
42
- puts EISCP::Receiver.parse(data).iscp_message
94
+ ```ruby
95
+ receiver = EISCP::Receiver.new do |msg|
96
+ puts msg.command
97
+ puts msg.value
43
98
  end
99
+ ```
44
100
 
45
- * Turn on the receiver
101
+ * You can also change the block later. This will kill the existing connection
102
+ thread (but not the socket) and start your new one:
46
103
 
47
- message = EISCP::Message.parse("PWR", "01")
48
- message.send(message.to_eiscp)
49
-
50
- * New 'parse' method makes creating EISCP objects more flexible.
51
- This parses messages from command line or raw eiscp data from the socket
52
-
53
- iscp_message = EISCP::Message.parse "PWR01"
54
- iscp_message = EISCP::Message.parse "PWR 01"
55
- iscp_message = EISCP::Message.parse "!1PWR01"
56
- iscp_message = EISCP::Message.parse "!1PWR 01"
57
-
58
- * Parsing raw socket data
104
+ ```ruby
105
+ receiver.update_thread do |msg|
106
+ puts "Received: #{msg.command_name}:#{msg.value_name}"
107
+ end
108
+ ```
109
+
110
+ * Get information about the Receiver:
111
+
112
+ ```ruby
113
+ receiver.model => "TX-NR609"
114
+ receiver.host => "10.0.0.111"
115
+ receiver.port => 60128
116
+ receiver.mac_address => "001122334455"
117
+ receiver.area => "DX"
118
+ ```
119
+
120
+ * Get the last message received from the Receiver:
121
+
122
+ ```ruby
123
+ receiver.last
124
+ ```
125
+
126
+ * You can use `CommandMethods` to easily send a message and return the reply as
127
+ a Message object. A method is defined for each command listed in the
128
+ `Dictionary` using the `@command_name` attribute which is 'human readable'.
129
+ You can check the included yaml file or look at the output of
130
+ `EISCP::Dictionary.commands`. Here a few examples:
131
+
132
+ ```ruby
133
+ # Turn on receiver
134
+ receiver.system_power "on"
135
+
136
+ # Query current input source
137
+ receiver.input_selector "query"
138
+
139
+ # Turn the master volume up one level
140
+ receiver.master_volume "level-up"
141
+
142
+ # Set the master volume to 45
143
+ receiver.master_volume "45"
144
+ ```
145
+
146
+ * Parse ISCP and human readable strings:
147
+
148
+ ```ruby
149
+ # Parse various ISCP strings
150
+ iscp_message = EISCP::Parser.parse "PWR01"
151
+ iscp_message = EISCP::Parser.parse "PWR 01"
152
+ iscp_message = EISCP::Parser.parse "!1PWR01"
153
+ iscp_message = EISCP::Parser.parse "!1PWR 01"
154
+
155
+ # Parse human readable,
156
+ EISCP::Parser.parse("main-volume 34")
157
+ ```
158
+
159
+ * `Parser.parse` is also used internally by `Receiver` to parse raw eISCP socket
160
+ data.
59
161
 
60
- iscp_message_from_raw_eiscp = EISCP::Message.parse iscp_message.to_eiscp
61
162
 
62
163
  Using the Binaries
63
164
  ------------------
64
165
 
65
166
  * Discover local receivers
66
167
 
67
- $ onkyo.rb -d
168
+ `$ onkyo.rb -d`
169
+
170
+ * Send a human-readable command
171
+
172
+ `$ onkyo.rb system-power on # uses Command.parse`
173
+
174
+ * Or send a raw command
68
175
 
69
- * Connect to the first discovered receiver to see status updates
176
+ `$ onkyo.rb PWRQSTN # Also tries to use Message.parse`
70
177
 
71
- $ onkyo.rb -c
178
+ * Monitor the first discovered receiver to see status updates
179
+
180
+ `$ onkyo.rb -m`
72
181
 
73
182
  * Start the mock server (only responds to 'ECNQSTN')
74
183
 
75
- $ onkyo-server.rb
184
+ `$ onkyo-server.rb`
185
+
186
+ * Turn off the first receiver discovered:
187
+
188
+ `$ onkyo.rb system-power off`
189
+
190
+ Contributing
191
+ ------------
192
+
193
+ * Open an issue describing bug or feature
194
+ * Fork repo
195
+ * Create a branch
196
+ * Send pull request
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 1.0.4
@@ -0,0 +1,23 @@
1
+ require 'socket'
2
+ require_relative './receiver'
3
+ require_relative './message'
4
+
5
+ # Mock server that only responds to ECNQSTN.
6
+
7
+ module EISCP
8
+ # This class acts as an Onkyo Stereo. It can be used for testing
9
+ #
10
+ class MockReceiver
11
+ DISCOVERY_IP = '255.255.255.255'
12
+ ONKYO_DISCOVERY_RESPONSE = Message.new('ECN', "TX-NR609/60128/DX/14DAE9E967C8\x19\r\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
13
+
14
+ # Create/start the server object.
15
+
16
+ def initialize
17
+ Socket.udp_server_loop(DISCOVERY_IP, Receiver::ONKYO_PORT) do |msg, src|
18
+ src.reply "ISCP\x00\x00\x00\x10\x00\x00\x00&\x01\x00\x00\x00!1ECNTX-NR609/60128/DX/14DAE9E967C8\x19\r\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
19
+ puts msg
20
+ end
21
+ end
22
+ end
23
+ end
data/bin/onkyo.rb CHANGED
@@ -3,6 +3,9 @@
3
3
  require 'eiscp'
4
4
  require 'optparse'
5
5
  require 'ostruct'
6
+
7
+ # This object parses ARGV and returns an @option hash
8
+ #
6
9
  class Options
7
10
  DEFAULT_OPTIONS = { verbose: true, all: false }
8
11
  USAGE = ' Usage: onkyo_rb [options]'
@@ -34,53 +37,77 @@ class Options
34
37
  @options.list_all = l
35
38
  end
36
39
 
37
- opts.on '-c', '--connect', 'Connect to the first discovered reciever and show updates' do |c|
38
- @options.connect = c
40
+ opts.on '-m', '--monitor', 'Connect to the first discovered reciever and monitor updates' do |m|
41
+ @options.monitor = m
39
42
  end
40
43
 
41
44
  end
42
45
 
43
46
  options.parse!(args)
44
47
 
45
- if @options == nil && ARGV == []
46
- puts options
47
- end
48
+ if @options.nil? && ARGV == [] then puts options end
48
49
 
49
50
  if @options.discover
50
- EISCP::Receiver.discover.each do |receiver|
51
- puts EISCP::Message.parse(receiver[0]).to_iscp
52
- end
51
+ EISCP::Receiver.discover.each {|rec| puts "#{rec.host}:#{rec.port} - #{rec.model} - #{rec.mac_address}"}
53
52
  exit 0
54
53
  end
55
54
 
56
55
  if @options.help
57
56
  puts options
58
- exit 0
57
+ exit 0
59
58
  end
60
59
 
61
- if @options.connect
62
- eiscp = EISCP::Receiver.new(EISCP::Receiver.discover[0][1])
63
- eiscp.connect do |data|
64
- puts msg = EISCP::Receiver.parse(data).to_iscp
60
+ if @options.monitor
61
+ begin
62
+ rec = EISCP::Receiver.new do |reply|
63
+ puts "Response: "\
64
+ "#{reply.zone.capitalize}: "\
65
+ "#{reply.command_description || reply.command} "\
66
+ "-> #{reply.value_description || reply.value}"
67
+ end
68
+ rec.thread.join
69
+ rescue Interrupt
70
+ fail 'Exiting...'
71
+ rescue Exception => e
72
+ puts "bummer..."
73
+ puts e
65
74
  end
66
75
  end
67
76
 
77
+ if @options.list_all
78
+ EISCP::Dictionary.zones.each do |zone|
79
+ EISCP::Dictionary.commands[zone].each do |command, command_hash|
80
+ puts "Command - Description"
81
+ puts "\n"
82
+ puts " '#{Dictionary.name_from_command(command)}' - "\
83
+ "#{Dictionary.description_from_command(command)}"
84
+ puts "\n"
85
+ puts " Value - Description>"
86
+ puts "\n"
87
+ command_hash[:values].each do |value, attr_hash|
88
+ puts " '#{attr_hash[:name]}' - "\
89
+ " #{attr_hash[:description]}"
90
+ end
91
+ puts "\n"
92
+ end
93
+ end
94
+ exit 0
95
+ end
96
+
68
97
  if ARGV == []
69
98
  puts options
70
99
  exit 0
71
100
  end
72
101
  end
73
-
74
102
  end
75
103
 
76
-
77
104
  @options = Options.parse(ARGV)
78
105
 
79
-
80
- receiver = EISCP::Receiver.new(EISCP::Receiver.discover[0][1])
81
- message = (EISCP::Message.parse(ARGV.join(" ")).to_eiscp)
82
- puts receiver.send_recv message
83
-
84
-
85
-
86
-
106
+ receiver = EISCP::Receiver.discover[0]
107
+ begin
108
+ command = EISCP::Parser.parse(ARGV.join(' '))
109
+ rescue
110
+ raise "Couldn't parse command"
111
+ end
112
+ reply = receiver.send_recv(command)
113
+ puts "Response from #{Receiver.host}: #{reply.zone.capitalize} #{reply.command_description || reply.command} -> #{reply.value_description || reply.value}"
@@ -2,6 +2,6 @@
2
2
 
3
3
  require 'eiscp/mock_receiver'
4
4
 
5
- puts "Starting server on 60128..."
5
+ puts 'Starting server on 60128...'
6
6
 
7
7
  EISCP::MockReceiver.new