onkyo_eiscp_ruby 0.0.3 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../parser'
4
+ require_relative '../dictionary'
5
+
6
+ module EISCP
7
+ class Receiver
8
+ # Iterates through every available command and defines a method to call that
9
+ # command. It's intended to be used through Receiver and uses methods included
10
+ # by Receiver::Connection. Each method accepts a string that should match the
11
+ # human readable name of a valid value for that command.
12
+ #
13
+ module CommandMethods
14
+ def self.generate(&block)
15
+ Dictionary.zones.each do |zone|
16
+ Dictionary.commands[zone].each do |command, _values|
17
+ command_name = Dictionary.command_to_name(command).to_s.gsub(/-/, '_')
18
+ define_method(command_name) do |v|
19
+ instance_exec Parser.parse(command_name.gsub(/_/, '-') + ' ' + v), &block
20
+ end
21
+ rescue StandardError => e
22
+ puts e
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+ require_relative '../message'
5
+ require_relative '../parser'
6
+
7
+ module EISCP
8
+ class Receiver
9
+ # This module discovers receivers on the local LAN.
10
+ #
11
+ module Discovery
12
+ # ISCP Magic Packet for Autodiscovery
13
+ ONKYO_MAGIC = Message.new(command: 'ECN', value: 'QSTN', terminator: "\r\n", unit_type: 'x').to_eiscp
14
+
15
+ # Populates Receiver attributes with info from ECNQSTN response.
16
+ #
17
+ def ecn_string_to_ecn_array(ecn_string)
18
+ hash = {}
19
+ message = Parser.parse(ecn_string)
20
+ array = message.value.split('/')
21
+ hash[:model] = array.shift
22
+ hash[:port] = array.shift.to_i
23
+ hash[:area] = array.shift
24
+ hash[:mac_address] = array.shift
25
+ hash
26
+ end
27
+
28
+ # Returns an array of discovered Receiver objects.
29
+ #
30
+ def discover(discovery_port = Receiver::ONKYO_PORT)
31
+ sock = UDPSocket.new
32
+ sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
33
+ sock.send(ONKYO_MAGIC, 0, '<broadcast>', discovery_port)
34
+ data = []
35
+ loop do
36
+ msg, addr = sock.recvfrom_nonblock(1024)
37
+ data << Receiver.new(addr[2], ecn_string_to_ecn_array(msg))
38
+ rescue IO::WaitReadable
39
+ io = IO.select([sock], nil, nil, 0.5)
40
+ if io.nil?
41
+ return data
42
+ else
43
+ retry
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,27 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = 'onkyo_eiscp_ruby'
3
5
  s.version = File.read(File.expand_path('VERSION', File.dirname(__FILE__))).strip
6
+ s.licenses = ['MIT']
4
7
  s.platform = Gem::Platform::RUBY
5
8
  s.summary = 'Manipulate Onkyo stereos with the eISCP protocol'
6
9
  s.files = Dir.glob('{bin,config,lib,test,doc}/**/*') +
7
- ["VERSION", "onkyo_eiscp_ruby.gemspec", "eiscp-commands.yaml"]
8
- s.extra_rdoc_files = ["README.md"]
10
+ ['VERSION', 'onkyo_eiscp_ruby.gemspec', 'eiscp-commands.yaml']
11
+ s.extra_rdoc_files = ['README.md']
9
12
  s.require_path = 'lib'
10
13
 
11
- s.homepage = "https://github.com/mikerodrigues/onkyo_eiscp_ruby"
14
+ s.homepage = 'https://github.com/mikerodrigues/onkyo_eiscp_ruby'
12
15
 
13
- s.description = %q(
14
- Control Onkyo receivers over the network.Use the provided binary script or
16
+ s.description = '
17
+ Control Onkyo receivers over the network.Use the provided binary or
15
18
  require the library for use in your scripts.
16
- )
19
+ '
17
20
 
18
- s.author = "Michael Rodrigues"
19
- s.email = "mikebrodrigues@gmail.com"
21
+ s.author = 'Michael Rodrigues'
22
+ s.email = 'mikebrodrigues@gmail.com'
20
23
 
21
- s.test_files = Dir[ 'test/tc*.rb' ]
22
- s.executables = %w(
24
+ s.test_files = Dir['test/tc*.rb']
25
+ s.executables = %w[
23
26
  onkyo.rb
24
- onkyo-server.rb
25
- )
26
-
27
+ onkyo_server.rb
28
+ ]
27
29
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/eiscp/dictionary.rb'
4
+ require 'minitest/autorun'
5
+
6
+ class TestDictionary < MiniTest::Test
7
+ def test_zone_from_command
8
+ assert_equal(EISCP::Dictionary.zone_from_command('PWR'), 'main')
9
+ assert_equal(EISCP::Dictionary.zone_from_command('ZPW'), 'zone2')
10
+ assert_equal(EISCP::Dictionary.zone_from_command('CDS'), 'dock')
11
+ end
12
+
13
+ def test_command_to_name
14
+ assert_equal(EISCP::Dictionary.command_to_name('PWR'), 'system-power')
15
+ assert_equal(EISCP::Dictionary.command_to_name('ZPW'), 'power2')
16
+ assert_equal(EISCP::Dictionary.command_to_name('PW3'), 'power3')
17
+ assert_equal(EISCP::Dictionary.command_to_name('PW4'), 'power4')
18
+ end
19
+
20
+ def test_command_name_to_command
21
+ assert_equal(EISCP::Dictionary.command_name_to_command('system-power'), 'PWR')
22
+ assert_equal(EISCP::Dictionary.command_name_to_command('master-volume'), 'MVL')
23
+ assert_equal(EISCP::Dictionary.command_name_to_command('power2'), 'ZPW')
24
+ end
25
+
26
+ def test_command_value_to_value_name
27
+ assert_equal(EISCP::Dictionary.command_value_to_value_name('PWR', '01'), 'on')
28
+ assert_equal(EISCP::Dictionary.command_value_to_value_name('PWR', 'QSTN'), 'query')
29
+ end
30
+
31
+ def test_command_value_name_to_value
32
+ assert_equal(EISCP::Dictionary.command_value_name_to_value('PWR', 'on'), '01')
33
+ assert_equal(EISCP::Dictionary.command_value_name_to_value('ZPW', 'on'), '01')
34
+ end
35
+
36
+ def test_description_from_command_name
37
+ assert_equal(EISCP::Dictionary.description_from_command_name('system-power', 'main'), 'System Power Command')
38
+ assert_equal(EISCP::Dictionary.description_from_command_name('power2', 'zone2'), 'Zone2 Power Command')
39
+ end
40
+
41
+ def test_description_from_command
42
+ assert_equal(EISCP::Dictionary.description_from_command('PWR'), 'System Power Command')
43
+ assert_equal(EISCP::Dictionary.description_from_command('ZPW'), 'Zone2 Power Command')
44
+ end
45
+ end
data/test/tc_message.rb CHANGED
@@ -1,27 +1,26 @@
1
- require_relative "../lib/eiscp/message"
2
- require "test/unit"
1
+ # frozen_string_literal: true
3
2
 
4
- class TestMessage < Test::Unit::TestCase
3
+ require_relative '../lib/eiscp/message'
4
+ require 'minitest/autorun'
5
5
 
6
-
7
- DISCOVERY_PACKET = EISCP::Message.new('ECN', 'QSTN', 'x', '!')
6
+ class TestMessage < MiniTest::Test
7
+ DISCOVERY_PACKET = EISCP::Message.new(command: 'ECN', value: 'QSTN', terminator: "\r\n", unit_type: 'x', start: '!')
8
8
  DISCOVERY_STRING = DISCOVERY_PACKET.to_eiscp
9
9
 
10
-
11
10
  def test_create_discovery_iscp_message
12
- assert_equal(EISCP::Message.new("ECN", "QSTN", "x", "!").to_iscp, "!xECNQSTN")
11
+ assert_equal(EISCP::Message.new(command: 'ECN', value: 'QSTN', terminator: "\r\n", unit_type: 'x', start: '!').to_iscp, '!xECNQSTN')
13
12
  end
14
13
 
15
- def test_parse_discovery_iscp_message
16
- assert_equal(EISCP::Message.parse("!xECNQSTN").to_iscp, "!xECNQSTN")
14
+ def test_create_messages
15
+ assert_equal(EISCP::Message.new(command: 'PWR', value: '01').to_iscp, '!1PWR01')
16
+ assert_equal(EISCP::Message.new(command: 'MVL', value: 'QSTN').to_iscp, '!1MVLQSTN')
17
17
  end
18
18
 
19
19
  def test_create_discovery_packet_string
20
20
  assert_equal(DISCOVERY_PACKET.to_eiscp, DISCOVERY_STRING)
21
21
  end
22
22
 
23
- def test_parse_discovery_packet_string
24
- assert_equal(EISCP::Message.parse(DISCOVERY_STRING).to_eiscp, DISCOVERY_PACKET.to_eiscp)
23
+ def test_validate_valid_message_with_variable
24
+ # Commands that return something unexpected like an artist name
25
25
  end
26
-
27
26
  end
data/test/tc_parser.rb ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/eiscp/parser'
4
+ require_relative '../lib/eiscp/message'
5
+ require 'minitest/autorun'
6
+
7
+ class TestParser < MiniTest::Test
8
+ DISCOVERY_PACKET = EISCP::Message.new(command: 'ECN', value: 'QSTN', terminator: "\r\n", unit_type: 'x', start: '!')
9
+ DISCOVERY_STRING = DISCOVERY_PACKET.to_eiscp
10
+
11
+ def test_parse_discovery_iscp_message
12
+ assert_equal(EISCP::Parser.parse('!xECNQSTN').to_iscp, '!xECNQSTN')
13
+ end
14
+
15
+ def test_parse_iscp_messages
16
+ assert_equal(EISCP::Parser.parse('PWR 01').to_iscp, '!1PWR01')
17
+ assert_equal(EISCP::Parser.parse('PWR01').to_iscp, '!1PWR01')
18
+ assert_equal(EISCP::Parser.parse('!1PWR01').to_iscp, '!1PWR01')
19
+ assert_equal(EISCP::Parser.parse('!1PWR 01').to_iscp, '!1PWR01')
20
+ end
21
+
22
+ def test_parse_discovery_packet_string
23
+ assert_equal(EISCP::Parser.parse(DISCOVERY_STRING).to_eiscp, DISCOVERY_PACKET.to_eiscp)
24
+ end
25
+
26
+ def test_parse_human_readable
27
+ assert_equal(EISCP::Parser.parse('system-power on'), EISCP::Message.new(command: 'PWR', value: '01'))
28
+ assert_equal(EISCP::Parser.parse('main system-power on'), EISCP::Message.new(command: 'PWR', value: '01'))
29
+ end
30
+
31
+ def test_return_nil_for_fake_human_readable
32
+ assert_equal(EISCP::Parser.parse('fake-command value'), nil)
33
+ end
34
+ end
data/test/tc_receiver.rb CHANGED
@@ -1,6 +1,7 @@
1
- require_relative "../lib/eiscp/receiver"
2
- require "test/unit"
1
+ # frozen_string_literal: true
3
2
 
4
- class TestEISCP
3
+ require_relative '../lib/eiscp/receiver'
4
+ require 'minitest/autorun'
5
5
 
6
+ class TestEISCP
6
7
  end
metadata CHANGED
@@ -1,41 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onkyo_eiscp_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Rodrigues
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-20 00:00:00.000000000 Z
11
+ date: 2021-03-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "\n Control Onkyo receivers over the network.Use the provided binary
14
- script or\n require the library for use in your scripts.\n "
14
+ or\n require the library for use in your scripts.\n "
15
15
  email: mikebrodrigues@gmail.com
16
16
  executables:
17
17
  - onkyo.rb
18
- - onkyo-server.rb
18
+ - onkyo_server.rb
19
19
  extensions: []
20
20
  extra_rdoc_files:
21
21
  - README.md
22
22
  files:
23
23
  - README.md
24
24
  - VERSION
25
- - bin/onkyo-server.rb
25
+ - bin/mock_receiver.rb
26
26
  - bin/onkyo.rb
27
+ - bin/onkyo_server.rb
27
28
  - eiscp-commands.yaml
28
29
  - lib/eiscp.rb
29
- - lib/eiscp/command.rb
30
+ - lib/eiscp/dictionary.rb
31
+ - lib/eiscp/dictionary/dictionary_generators.rb
32
+ - lib/eiscp/dictionary/dictionary_helpers.rb
30
33
  - lib/eiscp/message.rb
31
- - lib/eiscp/mock_receiver.rb
34
+ - lib/eiscp/parser.rb
35
+ - lib/eiscp/parser/dynamic_value_parser.rb
36
+ - lib/eiscp/parser/eiscp_parser.rb
37
+ - lib/eiscp/parser/human_readable_parser.rb
38
+ - lib/eiscp/parser/iscp_parser.rb
32
39
  - lib/eiscp/receiver.rb
40
+ - lib/eiscp/receiver/command_methods.rb
41
+ - lib/eiscp/receiver/discovery.rb
33
42
  - onkyo_eiscp_ruby.gemspec
34
- - test/tc_command.rb
43
+ - test/tc_dictionary.rb
35
44
  - test/tc_message.rb
45
+ - test/tc_parser.rb
36
46
  - test/tc_receiver.rb
37
47
  homepage: https://github.com/mikerodrigues/onkyo_eiscp_ruby
38
- licenses: []
48
+ licenses:
49
+ - MIT
39
50
  metadata: {}
40
51
  post_install_message:
41
52
  rdoc_options: []
@@ -52,12 +63,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
63
  - !ruby/object:Gem::Version
53
64
  version: '0'
54
65
  requirements: []
55
- rubyforge_project:
56
- rubygems_version: 2.2.0
66
+ rubygems_version: 3.2.3
57
67
  signing_key:
58
68
  specification_version: 4
59
69
  summary: Manipulate Onkyo stereos with the eISCP protocol
60
70
  test_files:
71
+ - test/tc_dictionary.rb
61
72
  - test/tc_message.rb
73
+ - test/tc_parser.rb
62
74
  - test/tc_receiver.rb
63
- - test/tc_command.rb
data/lib/eiscp/command.rb DELETED
@@ -1,99 +0,0 @@
1
- require 'yaml'
2
- require 'eiscp/receiver'
3
- require 'ostruct'
4
-
5
- module Command
6
-
7
- @@yaml_file_path = File.join(File.expand_path(File.dirname(__FILE__)), '../../eiscp-commands.yaml')
8
- @@yaml_object = YAML.load(File.read(@@yaml_file_path))
9
- @@modelsets = @@yaml_object["modelsets"]
10
- @@yaml_object.delete("modelsets")
11
- @@zones = @@yaml_object.map{|k, v| k}
12
- @@zones.each {|zone| class_variable_set("@@#{zone}", nil) }
13
- @@main = @@yaml_object['main']
14
-
15
- def self.command_to_name(command)
16
- return @@main[command]['name']
17
- end
18
-
19
- def self.command_name_to_command(name)
20
- @@main.each_pair do |command, attrs|
21
- if attrs['name'] == name
22
- return command
23
- end
24
- end
25
- end
26
-
27
- def self.command_value_to_value_name(command, value)
28
- return @@main[command]['values'][value]['name']
29
- end
30
-
31
- def self.command_value_name_to_value(command, name)
32
- @@main[command]['values'].each do |k, v|
33
- if v['name'] == name.to_s
34
- return k
35
- end
36
- end
37
- end
38
-
39
-
40
- def self.description_from_command_name(name)
41
- @@main.each_pair do |command, attrs|
42
- if attrs['name'] == name
43
- return @@main[command]['description']
44
- end
45
- end
46
- end
47
-
48
- def self.description_from_command(command)
49
- return @@main[command]['description']
50
- end
51
-
52
- def self.description_from_command_value(command, value)
53
- return @@main[command]['values'].select do |k, v|
54
- if k == value
55
- return v['description']
56
- end
57
- end
58
- end
59
-
60
- def self.list_all_commands
61
- @@main.each_pair do |command, attrs|
62
- puts "#{command} - #{attrs['name']}: #{attrs['description']}"
63
- attrs['values'].each_pair do |k, v|
64
- puts "--#{k}:#{v}"
65
- end
66
- end
67
- end
68
-
69
- def self.list_compatible_commands(modelstring)
70
- sets = []
71
- @@modelsets.each_pair do |set, array|
72
- if array.include? modelstring
73
- sets << set
74
- end
75
- end
76
- return sets
77
- end
78
-
79
- def self.parse(string)
80
- array = string.split(" ")
81
- zone = 'main'
82
- command_name = ''
83
- parameter_name = ''
84
- if array.count == 3
85
- zone = array.shift
86
- command_name = array.shift
87
- parameter_name = array.shift
88
- elsif array.count == 2
89
- command_name = array.shift
90
- parameter_name = array.shift
91
- end
92
- command = Command.command_name_to_command(command_name)
93
- parameter = Command.command_value_name_to_value(command, parameter_name)
94
- return EISCP::Message.new(command, parameter)
95
- end
96
-
97
- end
98
-
99
-
@@ -1,22 +0,0 @@
1
- require 'socket'
2
- require 'eiscp/receiver'
3
- require 'eiscp/message'
4
-
5
- # Mock server that only responds to ECNQSTN.
6
-
7
- module EISCP
8
- class MockReceiver
9
-
10
- ONKYO_DISCOVERY_RESPONSE = Message.new("ECN", "TX-NR609/60128/DX/001122334455")
11
-
12
- # Create/start the server object.
13
-
14
- def initialize
15
- Socket.udp_server_loop("255.255.255.255", EISCP::ONKYO_PORT) do |msg, msg_src|
16
- msg_src.reply ONKYO_DISCOVERY_RESPONSE.to_eiscp
17
- puts msg
18
- end
19
- end
20
-
21
- end
22
- end