yamaha 0.0.3 → 0.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
  SHA256:
3
- metadata.gz: '0188bdf2202b494dbd4c2891306a12669720b67a682e8a453b09ee83ea8a5429'
4
- data.tar.gz: d4eac8f6cb79c9e9e2dffc435d6a01dd5b644b2ffcb10cfb05dc6d1dca20fadc
3
+ metadata.gz: 292b70dd67f90f6bf205084ab1bd6de2248c93edc5108acfd1daf798fa9cf320
4
+ data.tar.gz: 14a7cb6c48e62aed373c79c048cc309c09741614f616eb41c43555f8256626b1
5
5
  SHA512:
6
- metadata.gz: 99bbf9e9df184abeba408745ff4bf965138073f02ee1beb49db937ffd0460415c5c272472275b3cb83cde20341377f653a4c88af1a7e06f2a1b8611b22bd8297
7
- data.tar.gz: 217919ae3985b8b746e310cfb017f613a5c26c1fb7f9c2012c8a2093675d4c749bb777d6f64a26fe36a629de3861ae7f29941d08ad961305031b991153b71c6f
6
+ metadata.gz: d5059e62f80e3cdf8e5a21932696a9d2ffa484d050d03646d1e6719cb76ebd7108e22033946cf551296d5c24a8a5ef579d02099ea8ba67752655fcc397659979
7
+ data.tar.gz: dd338e1d1fe2220356d0a2e3c0a7f02388294325385954f7b625773d2aa211d3b9f66db9fde28b48357d852ecae80ae8b76c367509cee19cc1a6ae203cd66eb5
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .yardoc
2
+ *.gem
data/README.md CHANGED
@@ -5,17 +5,18 @@
5
5
  ### RX-V1500 Power Values
6
6
 
7
7
  You might expect the power state to be a bit field, but it isn't - each
8
- combination appears to have been assigned an independent value:
9
-
10
- | Main zone | Zone 2 | Zone 3 | Value | Notes
11
- | On | On | On | 1 | All on
12
- | On | On | Off | 4 |
13
- | On | Off | On | 5 |
14
- | On | Off | Off | 2 |
15
- | Off | On | On | 3 |
16
- | Off | On | Off | 6 |
17
- | Off | Off | On | 7 |
18
- | Off | Off | Off | 0 | All off
8
+ combination is assigned an independent value:
9
+
10
+ | Main zone | Zone 2 | Zone 3 | Value | Notes |
11
+ | --------- | ------ | ------ | ----- | ------- |
12
+ | On | On | On | 1 | All on |
13
+ | On | On | Off | 4 | |
14
+ | On | Off | On | 5 | |
15
+ | On | Off | Off | 2 | |
16
+ | Off | On | On | 3 | |
17
+ | Off | On | Off | 6 | |
18
+ | Off | Off | On | 7 | |
19
+ | Off | Off | Off | 0 | All off |
19
20
 
20
21
  ## Implementation Notes
21
22
 
@@ -62,7 +63,7 @@ Yamaha RS232/serial protocol:
62
63
 
63
64
  - [YRXV1500-MQTT](https://github.com/FireFrei/yrxv1500-mqtt)
64
65
  - [YamahaController](https://github.com/mrworf/yamahacontroller)
65
- - [Homie ESP8266 Yamaha RX-Vxxxx Control]https://github.com/memphi2/homie-yamaha-rs232)
66
+ - [Homie ESP8266 Yamaha RX-Vxxxx Control](https://github.com/memphi2/homie-yamaha-rs232)
66
67
 
67
68
  Serial port communication in Ruby:
68
69
 
data/bin/yamaha CHANGED
@@ -3,118 +3,10 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  begin
6
- require 'yamaha'
6
+ require 'yamaha/cmd'
7
7
  rescue LoadError
8
8
  $: << File.join(File.dirname(__FILE__), '../lib')
9
- require 'yamaha'
9
+ require 'yamaha/cmd'
10
10
  end
11
- require 'optparse'
12
- require 'logger'
13
- require 'pp'
14
11
 
15
- options = {}
16
- OptionParser.new do |opts|
17
- opts.banner = "Usage: yamaha [-d device] command arg..."
18
-
19
- opts.on("-d", "--device DEVICE", "TTY to use (default autodetect)") do |v|
20
- options[:device] = v
21
- end
22
- end.parse!
23
-
24
- logger = Logger.new(STDERR)
25
- client = Yamaha::Client.new(options[:device], logger: logger)
26
-
27
- cmd = ARGV.shift
28
- unless cmd
29
- raise ArgumentError, "No command given"
30
- end
31
-
32
- def parse_on_off(value)
33
- case value&.downcase
34
- when '1', 'on', 'yes', 'true'
35
- true
36
- when '0', 'off', 'no', 'value'
37
- false
38
- else
39
- raise ArgumentError, "Invalid on/off value: #{value}"
40
- end
41
- end
42
-
43
- case cmd
44
- when 'detect'
45
- device = Yamaha::Client.detect_device(*ARGV, logger: logger)
46
- if device
47
- puts device
48
- exit 0
49
- else
50
- STDERR.puts("Yamaha receiver not found")
51
- exit 3
52
- end
53
- when 'power'
54
- which = ARGV.shift&.downcase
55
- if %w(main zone2 zone3).include?(which)
56
- method = "set_#{which}_power"
57
- state = parse_on_off(ARGV.shift)
58
- else
59
- method = 'set_power'
60
- state = parse_on_off(which)
61
- end
62
- client.public_send(method, state)
63
- when 'volume'
64
- which = ARGV.shift
65
- if %w(main zone2 zone3).include?(which)
66
- prefix = "set_#{which}"
67
- value = ARGV.shift
68
- else
69
- prefix = 'set_main'
70
- value = which
71
- end
72
- if %w(. -).include?(value)
73
- method = "#{prefix}_mute"
74
- value = true
75
- else
76
- method = "#{prefix}_volume_db"
77
- if value[0] == ','
78
- value = value[1..]
79
- end
80
- value = Float(value)
81
- end
82
- client.public_send(method, value)
83
- p client.get_main_volume_text
84
- p client.get_zone2_volume_text
85
- p client.get_zone3_volume_text
86
- when 'input'
87
- which = ARGV.shift&.downcase
88
- if %w(main zone2 zone3).include?(which)
89
- method = "set_#{which}_input"
90
- input = ARGV.shift
91
- else
92
- method = 'set_main_input'
93
- input = which
94
- end
95
- client.public_send(method, input)
96
- when 'program'
97
- value = ARGV.shift.downcase
98
- client.set_program(value)
99
- when 'pure-direct'
100
- state = parse_on_off(ARGV.shift)
101
- client.set_pure_direct(state)
102
- when 'status'
103
- pp client.last_status
104
- when 'status_string'
105
- puts client.last_status_string
106
- when 'test'
107
- client.set_power(false)
108
- [true, false].each do |main_state|
109
- [true, false].each do |zone2_state|
110
- [true, false].each do |zone3_state|
111
- client.set_main_power(main_state)
112
- client.set_zone2_power(zone2_state)
113
- client.set_zone3_power(zone3_state)
114
- puts "#{main_state ?1:0} #{zone2_state ?1:0} #{zone3_state ?1:0} #{client.status[:power]}"
115
- end
116
- end
117
- end
118
- else
119
- raise ArgumentError, "Unknown command: #{cmd}"
120
- end
12
+ Yamaha::Cmd.new(ARGV).run
data/lib/yamaha/client.rb CHANGED
@@ -13,37 +13,45 @@ module Yamaha
13
13
  class UnexpectedResponse < Error; end
14
14
  class CommunicationTimeout < Error; end
15
15
 
16
- RS232_TIMEOUT = 9
16
+ RS232_TIMEOUT = 3
17
17
  DEFAULT_DEVICE_GLOB = '/dev/ttyUSB*'
18
18
 
19
- class Client
20
- def self.detect_device(*patterns, logger: nil)
21
- if patterns.empty?
22
- patterns = [DEFAULT_DEVICE_GLOB]
23
- end
24
- devices = patterns.map do |pattern|
25
- Dir.glob(pattern)
26
- end.flatten.uniq
27
- found = nil
28
- threads = devices.map do |device|
29
- Thread.new do
30
- Timeout.timeout(RS232_TIMEOUT) do
31
- logger&.debug("Trying #{device}")
32
- new(device, logger: logger).status
33
- logger&.debug("Found receiver at #{device}")
34
- found = device
35
- end
19
+ module_function def detect_device(*patterns, logger: nil)
20
+ if patterns.empty?
21
+ patterns = [DEFAULT_DEVICE_GLOB]
22
+ end
23
+ devices = patterns.map do |pattern|
24
+ Dir.glob(pattern)
25
+ end.flatten.uniq
26
+ queue = Queue.new
27
+ threads = devices.map do |device|
28
+ Thread.new do
29
+ Timeout.timeout(RS232_TIMEOUT * 3) do
30
+ logger&.debug("Trying #{device}")
31
+ Client.new(device, logger: logger).last_status
32
+ logger&.debug("Found receiver at #{device}")
33
+ queue << device
36
34
  end
35
+ rescue CommunicationTimeout, IOError, SystemCallError => exc
36
+ logger&.debug("Failed on #{device}: #{exc.class}: #{exc}")
37
37
  end
38
+ end
39
+ wait_thread = Thread.new do
38
40
  threads.map(&:join)
39
- found
41
+ queue << nil
42
+ end
43
+ queue.shift.tap do
44
+ threads.map(&:kill)
45
+ wait_thread.kill
40
46
  end
47
+ end
41
48
 
49
+ class Client
42
50
  def initialize(device = nil, logger: nil)
43
51
  @logger = logger
44
52
 
45
53
  if device.nil?
46
- device = Dir[DEFAULT_DEVICE_GLOB].sort.first
54
+ device = Yamaha.detect_device(logger: logger)
47
55
  if device
48
56
  logger&.info("Using #{device} as TTY device")
49
57
  end
@@ -89,35 +97,59 @@ module Yamaha
89
97
  last_status
90
98
  end
91
99
 
100
+ # Turns the receiver on or off.
101
+ #
102
+ # @param [ true | false ] state Desired power state.
92
103
  def set_power(state)
93
104
  remote_command("7A1#{state ? 'D' : 'E'}")
94
105
  end
95
106
 
107
+ # Turns main zone power on or off.
108
+ #
109
+ # @param [ true | false ] state Desired power state.
96
110
  def set_main_power(state)
97
111
  remote_command("7E7#{state ? 'E' : 'F'}")
98
112
  end
99
113
 
114
+ # Turns zone 2 power on or off.
115
+ #
116
+ # @param [ true | false ] state Desired power state.
100
117
  def set_zone2_power(state)
101
118
  remote_command("7EB#{state ? 'A' : 'B'}")
102
119
  end
103
120
 
121
+ # Turns zone 3 power on or off.
122
+ #
123
+ # @param [ true | false ] state Desired power state.
104
124
  def set_zone3_power(state)
105
125
  remote_command("7AE#{state ? 'D' : 'E'}")
106
126
  end
107
127
 
128
+ # Sets main zone volume.
129
+ #
130
+ # @param [ Integer ] value The raw volume value.
108
131
  def set_main_volume(value)
109
132
  system_command("30#{'%02x' % value}")
110
133
  end
111
134
 
135
+ # Sets main zone volume.
136
+ #
137
+ # @param [ Float ] volume The volume in decibels.
112
138
  def set_main_volume_db(volume)
113
139
  value = Integer((volume + 80) * 2 + 39)
114
140
  set_main_volume(value)
115
141
  end
116
142
 
143
+ # Sets zone 2 volume.
144
+ #
145
+ # @param [ Integer ] value The raw volume value.
117
146
  def set_zone2_volume(value)
118
147
  system_command("31#{'%02x' % value}")
119
148
  end
120
149
 
150
+ # Sets zone 2 volume.
151
+ #
152
+ # @param [ Float ] volume The volume in decibels.
121
153
  def set_zone2_volume_db(volume)
122
154
  value = Integer(volume + 33 + 39)
123
155
  set_zone2_volume(value)
@@ -131,6 +163,9 @@ module Yamaha
131
163
  remote_command('7ADB')
132
164
  end
133
165
 
166
+ # Sets zone 3 volume.
167
+ #
168
+ # @param [ Integer ] volume The raw volume value.
134
169
  def set_zone3_volume(volume)
135
170
  remote_command("234#{'%02x' % value}")
136
171
  end
@@ -159,10 +194,35 @@ module Yamaha
159
194
  extract_text(system_command("2005"))[3...].strip
160
195
  end
161
196
 
197
+ # Turns pure direct mode on or off.
198
+ #
199
+ # @param [ true | false ] state Desired state.
162
200
  def set_pure_direct(state)
163
201
  dispatch("#{STX}07E8#{state ? '0' : '2'}#{ETX}")
164
202
  end
165
203
 
204
+ def set_program(value)
205
+ program_code = PROGRAM_SET.fetch(value.downcase.gsub(/[^a-z]/, '_'))
206
+ remote_command("7E#{program_code}")
207
+ end
208
+
209
+ def set_main_input(source)
210
+ source_code = MAIN_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
211
+ remote_command("7A#{source_code}")
212
+ end
213
+
214
+ def set_zone2_input(source)
215
+ source_code = ZONE2_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
216
+ remote_command("7A#{source_code}")
217
+ end
218
+
219
+ def set_zone3_input(source)
220
+ source_code = ZONE3_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
221
+ remote_command("7A#{source_code}")
222
+ end
223
+
224
+ private
225
+
166
226
  PROGRAM_SET = {
167
227
  'munich' => 'E1',
168
228
  'vienna' => 'E5',
@@ -195,11 +255,6 @@ module Yamaha
195
255
  'thx_game' => 'C8',
196
256
  }.freeze
197
257
 
198
- def set_program(value)
199
- program_code = PROGRAM_SET.fetch(value.downcase.gsub(/[^a-z]/, '_'))
200
- remote_command("7E#{program_code}")
201
- end
202
-
203
258
  MAIN_INPUTS_SET = {
204
259
  'phono' => '14',
205
260
  'cd' => '15',
@@ -216,11 +271,6 @@ module Yamaha
216
271
  'xm' => 'B4',
217
272
  }.freeze
218
273
 
219
- def set_main_input(source)
220
- source_code = MAIN_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
221
- remote_command("7A#{source_code}")
222
- end
223
-
224
274
  ZONE2_INPUTS_SET = {
225
275
  'phono' => 'D0',
226
276
  'cd' => 'D1',
@@ -236,11 +286,6 @@ module Yamaha
236
286
  'xm' => 'B8',
237
287
  }.freeze
238
288
 
239
- def set_zone2_input(source)
240
- source_code = ZONE2_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
241
- remote_command("7A#{source_code}")
242
- end
243
-
244
289
  ZONE3_INPUTS_SET = {
245
290
  'phono' => 'F1',
246
291
  'cd' => 'F2',
@@ -256,72 +301,6 @@ module Yamaha
256
301
  'xm' => 'B9',
257
302
  }.freeze
258
303
 
259
- def set_zone3_input(source)
260
- source_code = ZONE3_INPUTS_SET.fetch(source.downcase.gsub(/[^a-z]/, '_'))
261
- remote_command("7A#{source_code}")
262
- end
263
-
264
- private
265
-
266
- def open_device
267
- @f = Backend::SerialPortBackend::Device.new(device, logger: logger)
268
-
269
- tries = 0
270
- begin
271
- do_status
272
- rescue CommunicationTimeout
273
- tries += 1
274
- if tries < 5
275
- logger&.warn("Timeout handshaking with the receiver - will retry")
276
- retry
277
- else
278
- raise
279
- end
280
- end
281
-
282
- yield.tap do
283
- @f.close
284
- end
285
- end
286
-
287
- # ASCII table: https://www.asciitable.com/
288
- DC1 = +?\x11
289
- DC2 = +?\x12
290
- ETX = +?\x03
291
- STX = +?\x02
292
- DEL = +?\x7f
293
-
294
- STATUS_REQ = -"#{DC1}001#{ETX}"
295
-
296
- ZERO_ORD = '0'.ord
297
-
298
- def dispatch(cmd)
299
- open_device do
300
- do_dispatch(cmd)
301
- end
302
- end
303
-
304
- def do_dispatch(cmd)
305
- @f.syswrite(cmd.encode('ascii'))
306
- read_response
307
- end
308
-
309
- def read_response
310
- resp = +''
311
- Timeout.timeout(2, CommunicationTimeout) do
312
- loop do
313
- ch = @f.sysread(1)
314
- if ch
315
- resp << ch
316
- break if ch == ETX
317
- else
318
- sleep 0.1
319
- end
320
- end
321
- end
322
- resp
323
- end
324
-
325
304
  MAIN_INPUTS_GET = {
326
305
  '0' => 'PHONO',
327
306
  '1' => 'CD',
@@ -411,10 +390,69 @@ module Yamaha
411
390
  '40' => 'Enhancer 2ch Low',
412
391
  '41' => 'Enhancer 2ch High',
413
392
  '42' => 'Enhancer 7ch Low',
414
- '43' => 'Enhancer 7ch Higgh',
393
+ '43' => 'Enhancer 7ch High',
415
394
  '80' => 'Straight',
416
395
  }.freeze
417
396
 
397
+ def open_device
398
+ @f = Backend::SerialPortBackend::Device.new(device, logger: logger)
399
+
400
+ tries = 0
401
+ begin
402
+ do_status
403
+ rescue CommunicationTimeout
404
+ tries += 1
405
+ if tries < 5
406
+ logger&.warn("Timeout handshaking with the receiver - will retry")
407
+ retry
408
+ else
409
+ raise
410
+ end
411
+ end
412
+
413
+ yield.tap do
414
+ @f.close
415
+ end
416
+ end
417
+
418
+ # ASCII table: https://www.asciitable.com/
419
+ DC1 = +?\x11
420
+ DC2 = +?\x12
421
+ ETX = +?\x03
422
+ STX = +?\x02
423
+ DEL = +?\x7f
424
+
425
+ STATUS_REQ = -"#{DC1}001#{ETX}"
426
+
427
+ ZERO_ORD = '0'.ord
428
+
429
+ def dispatch(cmd)
430
+ open_device do
431
+ do_dispatch(cmd)
432
+ end
433
+ end
434
+
435
+ def do_dispatch(cmd)
436
+ @f.syswrite(cmd.encode('ascii'))
437
+ read_response
438
+ end
439
+
440
+ def read_response
441
+ resp = +''
442
+ Timeout.timeout(2, CommunicationTimeout) do
443
+ loop do
444
+ ch = @f.sysread(1)
445
+ if ch
446
+ resp << ch
447
+ break if ch == ETX
448
+ else
449
+ sleep 0.1
450
+ end
451
+ end
452
+ end
453
+ resp
454
+ end
455
+
418
456
  def do_status
419
457
  resp = nil
420
458
  loop do
@@ -494,6 +532,34 @@ module Yamaha
494
532
  @status
495
533
  end
496
534
 
535
+ %i(
536
+ model_code firmware_version system_status power main_power zone2_power
537
+ zone3_power input input_name audio_select audio_select_name
538
+ main_volume main_volume_db zone2_volume zone2_volume_db
539
+ zone3_volume zone3_volume_db program program_name sleep night night_name
540
+ format sample_rate
541
+ ).each do |meth|
542
+ define_method(meth) do
543
+ status.fetch(meth)
544
+ end
545
+
546
+ define_method("last_#{meth}") do
547
+ last_status.fetch(meth)
548
+ end
549
+ end
550
+
551
+ %i(
552
+ multi_ch_input effect pure_direct speaker_a speaker_b
553
+ ).each do |meth|
554
+ define_method("#{meth}?") do
555
+ status.fetch(meth)
556
+ end
557
+
558
+ define_method("last_#{meth}?") do
559
+ last_status.fetch(meth)
560
+ end
561
+ end
562
+
497
563
  def remote_command(cmd)
498
564
  dispatch("#{STX}0#{cmd}#{ETX}")
499
565
  end
data/lib/yamaha/cmd.rb ADDED
@@ -0,0 +1,120 @@
1
+ require 'optparse'
2
+ require 'logger'
3
+ require 'pp'
4
+ require 'yamaha/utils'
5
+ require 'yamaha/client'
6
+
7
+ module Yamaha
8
+ class Cmd
9
+ def initialize(args)
10
+ options = {}
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: yamaha [-d device] command arg..."
13
+
14
+ opts.on("-d", "--device DEVICE", "TTY to use (default autodetect)") do |v|
15
+ options[:device] = v
16
+ end
17
+ end.parse!
18
+
19
+ @options = options
20
+
21
+ @logger = Logger.new(STDERR)
22
+ @client = Yamaha::Client.new(options[:device], logger: @logger)
23
+
24
+ @args = args
25
+ end
26
+
27
+ attr_reader :args
28
+ attr_reader :logger
29
+
30
+ def run
31
+ cmd = args.shift
32
+ unless cmd
33
+ raise ArgumentError, "No command given"
34
+ end
35
+
36
+ case cmd
37
+ when 'detect'
38
+ device = Yamaha::Client.detect_device(*args, logger: logger)
39
+ if device
40
+ puts device
41
+ exit 0
42
+ else
43
+ STDERR.puts("Yamaha receiver not found")
44
+ exit 3
45
+ end
46
+ when 'power'
47
+ which = ARGV.shift&.downcase
48
+ if %w(main zone2 zone3).include?(which)
49
+ method = "set_#{which}_power"
50
+ state = parse_on_off(ARGV.shift)
51
+ else
52
+ method = 'set_power'
53
+ state = parse_on_off(which)
54
+ end
55
+ client.public_send(method, state)
56
+ when 'volume'
57
+ which = ARGV.shift
58
+ if %w(main zone2 zone3).include?(which)
59
+ prefix = "set_#{which}"
60
+ value = ARGV.shift
61
+ else
62
+ prefix = 'set_main'
63
+ value = which
64
+ end
65
+ if %w(. -).include?(value)
66
+ method = "#{prefix}_mute"
67
+ value = true
68
+ else
69
+ method = "#{prefix}_volume_db"
70
+ if value[0] == ','
71
+ value = value[1..]
72
+ end
73
+ value = Float(value)
74
+ end
75
+ client.public_send(method, value)
76
+ p client.get_main_volume_text
77
+ p client.get_zone2_volume_text
78
+ p client.get_zone3_volume_text
79
+ when 'input'
80
+ which = ARGV.shift&.downcase
81
+ if %w(main zone2 zone3).include?(which)
82
+ method = "set_#{which}_input"
83
+ input = ARGV.shift
84
+ else
85
+ method = 'set_main_input'
86
+ input = which
87
+ end
88
+ client.public_send(method, input)
89
+ when 'program'
90
+ value = ARGV.shift.downcase
91
+ client.set_program(value)
92
+ when 'pure-direct'
93
+ state = parse_on_off(ARGV.shift)
94
+ client.set_pure_direct(state)
95
+ when 'status'
96
+ pp client.last_status
97
+ when 'status_string'
98
+ puts client.last_status_string
99
+ when 'test'
100
+ client.set_power(false)
101
+ [true, false].each do |main_state|
102
+ [true, false].each do |zone2_state|
103
+ [true, false].each do |zone3_state|
104
+ client.set_main_power(main_state)
105
+ client.set_zone2_power(zone2_state)
106
+ client.set_zone3_power(zone3_state)
107
+ puts "#{main_state ?1:0} #{zone2_state ?1:0} #{zone3_state ?1:0} #{client.status[:power]}"
108
+ end
109
+ end
110
+ end
111
+ else
112
+ raise ArgumentError, "Unknown command: #{cmd}"
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ attr_reader :client
119
+ end
120
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yamaha
4
- VERSION = -'0.0.3'
4
+ VERSION = -'0.0.4'
5
5
  end
data/yamaha.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "yamaha"
5
- spec.version = '0.0.3'
5
+ spec.version = '0.0.4'
6
6
  spec.authors = ['Oleg Pudeyev']
7
7
  spec.email = ['code@olegp.name']
8
8
  spec.summary = %q{Yamaha Receiver Serial Control Interface}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yamaha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Pudeyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-02 00:00:00.000000000 Z
11
+ date: 2022-11-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Library for controlling Yamaha amplifiers via the serial port
14
14
  email:
@@ -19,6 +19,7 @@ executables:
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
+ - ".gitignore"
22
23
  - LICENSE
23
24
  - README.md
24
25
  - bin/yamaha
@@ -28,6 +29,7 @@ files:
28
29
  - lib/yamaha/backend/ffi.rb
29
30
  - lib/yamaha/backend/serial_port.rb
30
31
  - lib/yamaha/client.rb
32
+ - lib/yamaha/cmd.rb
31
33
  - lib/yamaha/utils.rb
32
34
  - lib/yamaha/version.rb
33
35
  - yamaha.gemspec