yamaha 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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