aca-device-modules 1.0.0

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.
@@ -0,0 +1,249 @@
1
+ module Extron; end
2
+ module Extron::Switcher; end
3
+
4
+
5
+ # :title:Extron Digital Matrix Switchers
6
+ # NOTE:: Very similar to the XTP!! Update both
7
+ #
8
+ # Status information avaliable:
9
+ # -----------------------------
10
+ #
11
+ # (built in)
12
+ # connected
13
+ #
14
+ # (module defined)
15
+ # video_inputs
16
+ # video_outputs
17
+ # audio_inputs
18
+ # audio_outputs
19
+ #
20
+ # video1 => input (video)
21
+ # video2
22
+ # video3
23
+ # video1_muted => true
24
+ #
25
+ # audio1 => input
26
+ # audio1_muted => true
27
+ #
28
+ #
29
+ # (Settings)
30
+ # password
31
+ #
32
+
33
+
34
+ class Extron::Switcher::Dxp
35
+ include ::Orchestrator::Constants
36
+ include ::Orchestrator::Transcoder
37
+
38
+
39
+ def on_load
40
+ #
41
+ # Setup constants
42
+ #
43
+ defaults({
44
+ :wait => false
45
+ })
46
+ config({
47
+ :clear_queue_on_disconnect => true # Clear the queue as we may need to send login
48
+ })
49
+ end
50
+
51
+ def connected
52
+ @polling_timer = schedule.every('2m') do
53
+ logger.debug "-- Extron Maintaining Connection"
54
+ send('Q', :priority => 0) # Low priority poll to maintain connection
55
+ end
56
+ end
57
+
58
+ def disconnected
59
+ #
60
+ # Disconnected may be called without calling connected
61
+ # Hence the check if timer is nil here
62
+ #
63
+ @polling_timer.cancel unless @polling_timer.nil?
64
+ @polling_timer = nil
65
+ end
66
+
67
+
68
+ def direct(string)
69
+ send(string, :wait => false)
70
+ end
71
+
72
+
73
+ #
74
+ # No need to wait as commands can be chained
75
+ #
76
+ def switch(map)
77
+ map.each do |input, outputs|
78
+ input = input.to_s if input.is_a?(Symbol)
79
+ input = input.to_i if input.is_a?(String)
80
+
81
+ outputs = [outputs] unless outputs.is_a?(Array)
82
+ command = ''
83
+ outputs.each do |output|
84
+ command += "#{input}*#{output}!"
85
+ end
86
+ send(command)
87
+ end
88
+ end
89
+
90
+ def switch_video(map)
91
+ map.each do |input, outputs|
92
+ input = input.to_s if input.is_a?(Symbol)
93
+ input = input.to_i if input.is_a?(String)
94
+
95
+
96
+ outputs = [outputs] unless outputs.is_a?(Array)
97
+ command = ''
98
+ outputs.each do |output|
99
+ command += "#{input}*#{output}%"
100
+ end
101
+ send(command)
102
+ end
103
+ end
104
+
105
+ def switch_audio(map)
106
+ map.each do |input, outputs|
107
+ input = input.to_s if input.is_a?(Symbol)
108
+ input = input.to_i if input.is_a?(String)
109
+
110
+ outputs = [outputs] unless outputs.is_a?(Array)
111
+ command = ''
112
+ outputs.each do |output|
113
+ command += "#{input}*#{output}$"
114
+ end
115
+ send(command)
116
+ end
117
+ end
118
+
119
+ def mute_video(outputs)
120
+ outputs = [outputs] unless outputs.is_a?(Array)
121
+ command = ''
122
+ outputs.each do |output|
123
+ command += "#{output}*1B"
124
+ end
125
+ send(command)
126
+ end
127
+
128
+ def unmute_video(outputs)
129
+ outputs = [outputs] unless outputs.is_a?(Array)
130
+ command = ''
131
+ outputs.each do |output|
132
+ command += "#{output}*0B"
133
+ end
134
+ send(command)
135
+ end
136
+
137
+ def mute_audio(outputs)
138
+ outputs = [outputs] unless outputs.is_a?(Array)
139
+ command = ''
140
+ outputs.each do |output|
141
+ command += "#{output}*1Z"
142
+ end
143
+ send(command)
144
+ end
145
+
146
+ def unmute_audio(outputs)
147
+ outputs = [outputs] unless outputs.is_a?(Array)
148
+ command = ''
149
+ outputs.each do |output|
150
+ command += "#{output}*0Z"
151
+ end
152
+ send(command)
153
+ end
154
+
155
+ def set_preset(number)
156
+ send("#{number},")
157
+ end
158
+
159
+ def recall_preset(number)
160
+ send("#{number}.")
161
+ end
162
+
163
+
164
+ #def response_delimiter
165
+ # [0x0D, 0x0A] # Used to interpret the end of a message
166
+ #end
167
+
168
+
169
+ #
170
+ # Sends copyright information
171
+ # Then sends password prompt
172
+ #
173
+ def received(data, resolve, command)
174
+ logger.debug "Extron Matrix sent #{data}"
175
+
176
+ if command.nil? && data =~ /Copyright/i
177
+ pass = setting(:password)
178
+ if pass.nil?
179
+ device_ready
180
+ else
181
+ do_send(pass) # Password set
182
+ end
183
+ elsif data =~ /Login/i
184
+ device_ready
185
+ elsif command.present? && command[:command] == :information
186
+ data = data.split(' ')
187
+ video = data[0][1..-1].split('X')
188
+ self[:video_inputs] = video[0].to_i
189
+ self[:video_outputs] = video[1].to_i
190
+
191
+ audio = data[1][1..-1].split('X')
192
+ self[:audio_inputs] = audio[0].to_i
193
+ self[:audio_outputs] = audio[1].to_i
194
+ else
195
+ case data[0..1].to_sym
196
+ when :Am # Audio mute
197
+ data = data[3..-1].split('*')
198
+ self["audio#{data[0].to_i}_muted"] = data[1] == '1'
199
+ when :Vm # Video mute
200
+ data = data[3..-1].split('*')
201
+ self["video#{data[0].to_i}_muted"] = data[1] == '1'
202
+ when :In # Input to all outputs
203
+ data = data[2..-1].split(' ')
204
+ input = data[0].to_i
205
+ if data[1] =~ /(All|RGB|Vid)/
206
+ for i in 1..self[:video_outputs]
207
+ self["video#{i}"] = input
208
+ end
209
+ end
210
+ if data[1] =~ /(All|Aud)/
211
+ for i in 1..self[:audio_outputs]
212
+ self["audio#{i}"] = input
213
+ end
214
+ end
215
+ when :Ou # Output x to input y
216
+ data = data[3..-1].split(' ')
217
+ output = data[0].to_i
218
+ input = data[1][2..-1].to_i
219
+ if data[2] =~ /(All|RGB|Vid)/
220
+ self["video#{output}"] = input
221
+ end
222
+ if data[2] =~ /(All|Aud)/
223
+ self["audio#{output}"] = input
224
+ end
225
+ else
226
+ if data == 'E22' # Busy! We should retry this one
227
+ command[:delay_on_receive] = 1 unless command.nil?
228
+ return :failed
229
+ end
230
+ end
231
+ end
232
+
233
+ return :success
234
+ end
235
+
236
+
237
+ private
238
+
239
+
240
+ def device_ready
241
+ send("I", :wait => true, :command => :information)
242
+ do_send("\e3CV", :wait => true) # Verbose mode and tagged responses
243
+ end
244
+
245
+ def do_send(data, options = {})
246
+ send(data << 0x0D, options)
247
+ end
248
+ end
249
+
@@ -0,0 +1,167 @@
1
+ module GlobalCache; end
2
+
3
+
4
+ class GlobalCache::Gc100
5
+ include ::Orchestrator::Constants
6
+
7
+
8
+ def on_load
9
+ self[:num_relays] = 0
10
+ self[:num_ir] = 0
11
+
12
+ config({
13
+ tokenize: true,
14
+ delimiter: "\x0D"
15
+ })
16
+ end
17
+
18
+ def on_update
19
+ self[:config_indexed] = false
20
+ end
21
+
22
+ #
23
+ # Config maps the GC100 into a linear set of ir and relays so models can be swapped in and out
24
+ # config => {:relay => {0 => '2:1',1 => '2:2',2 => '2:3',3 => '3:1'}} etc
25
+ #
26
+ def connected
27
+ unless self[:config_indexed]
28
+ self[:config] = {}
29
+ do_send('getdevices', :max_waits => 100)
30
+ end
31
+
32
+ @polling_timer = schedule.every('60s') do
33
+ logger.debug "-- Polling GC100"
34
+ do_send("get_NET,0:1", :priority => 0) # Low priority sent to maintain the connection
35
+ end
36
+ end
37
+
38
+ def disconnected
39
+ @polling_timer.cancel unless @polling_timer.nil?
40
+ @polling_timer = nil
41
+ end
42
+
43
+
44
+
45
+ def relay(index, state)
46
+ if index < self[:num_relays]
47
+ connector = self[:config][:relay][index]
48
+ if is_affirmative?(state)
49
+ state = 1
50
+ else
51
+ state = 0
52
+ end
53
+
54
+ do_send("setstate,#{connector},#{state}")
55
+ else
56
+ logger.warn "Attempted to set relay on GlobalCache that does not exist: #{index}"
57
+ end
58
+ end
59
+
60
+ def ir(index, command, options = {})
61
+ do_send("sendir,1:#{index},#{command}", options)
62
+ end
63
+
64
+
65
+ def relay_status?(index, &block)
66
+ if index < self[:num_relays]
67
+ connector = self[:config][:relay][index]
68
+ do_send("getstate,#{connector}", {:emit => {"relay#{index}".to_sym => block}})
69
+ else
70
+ logger.warn "Attempted to check IO on GlobalCache that does not exist: #{index}"
71
+ end
72
+ end
73
+
74
+ def io_status?(index, &block)
75
+ if index < self[:num_ir]
76
+ connector = self[:config][:ir][index]
77
+ do_send("getstate,#{connector}", {:emit => {"ir#{index}".to_sym => block}})
78
+ else
79
+ logger.warn "Attempted to check IO on GlobalCache that does not exist: #{index}"
80
+ end
81
+ end
82
+
83
+
84
+
85
+ def received(data, command)
86
+ logger.debug "GlobalCache sent #{data}"
87
+ data = data.split(',')
88
+
89
+ case data[0].to_sym
90
+ when :state, :statechange
91
+ type, index = self[:config][data[1]]
92
+ self["#{type}#{index}"] = data[2] == '1' # Is relay index on?
93
+ when :device
94
+ address = data[1]
95
+ number, type = data[2].split(' ') # The response was "device,2,3 RELAY"
96
+
97
+ type = type.downcase.to_sym
98
+
99
+ update_status(:config) do |value|
100
+ value ||= {}
101
+ value[type] ||= {}
102
+ current = value[type].length
103
+
104
+ dev_index = 1
105
+ (current..(current + number.to_i - 1)).each do |index|
106
+ port = "#{address}:#{dev_index}"
107
+ value[type][index] = port
108
+ value[port] = [type, index]
109
+ dev_index += 1
110
+ end
111
+
112
+ value
113
+ end
114
+ return :ignore
115
+
116
+ when :endlistdevices
117
+ self[:config_indexed] = true
118
+ config = self[:config]
119
+ self[:num_relays] = config[:relay].length unless config[:relay].nil?
120
+ self[:num_ir] = config[:ir].length unless config[:ir].nil?
121
+
122
+ return :success
123
+ end
124
+
125
+
126
+ if data.length == 1
127
+ error = case data[0].split(' ')[1].to_i
128
+ when 1 then 'Command was missing the carriage return delimiter'
129
+ when 2 then 'Invalid module address when looking for version'
130
+ when 3 then 'Invalid module address'
131
+ when 4 then 'Invalid connector address'
132
+ when 5 then 'Connector address 1 is set up as "sensor in" when attempting to send an IR command'
133
+ when 6 then 'Connector address 2 is set up as "sensor in" when attempting to send an IR command'
134
+ when 7 then 'Connector address 3 is set up as "sensor in" when attempting to send an IR command'
135
+ when 8 then 'Offset is set to an even transition number, but should be set to an odd transition number in the IR command'
136
+ when 9 then 'Maximum number of transitions exceeded (256 total on/off transitions allowed)'
137
+ when 10 then 'Number of transitions in the IR command is not even (the same number of on and off transitions is required)'
138
+ when 11 then 'Contact closure command sent to a module that is not a relay'
139
+ when 12 then 'Missing carriage return. All commands must end with a carriage return'
140
+ when 13 then 'State was requested of an invalid connector address, or the connector is programmed as IR out and not sensor in.'
141
+ when 14 then 'Command sent to the unit is not supported by the GC-100'
142
+ when 15 then 'Maximum number of IR transitions exceeded'
143
+ when 16 then 'Invalid number of IR transitions (must be an even number)'
144
+ when 21 then 'Attempted to send an IR command to a non-IR module'
145
+ when 23 then 'Command sent is not supported by this type of module'
146
+ else 'Unknown error'
147
+ end
148
+ logger.warn "GlobalCache error: #{error}\nFor command: #{command[:data]}"
149
+ return :failed
150
+ end
151
+
152
+ return :success
153
+ end
154
+
155
+
156
+ protected
157
+
158
+
159
+ def do_send(command, options = {})
160
+ #logger.debug "-- GlobalCache, sending: #{command}"
161
+
162
+ command << 0x0D
163
+
164
+ send(command, options)
165
+ end
166
+ end
167
+
@@ -0,0 +1,143 @@
1
+ module Kramer; end
2
+ module Kramer::Switcher; end
3
+
4
+
5
+ # :title:Kramer video switches
6
+ #
7
+ # Status information avaliable:
8
+ # -----------------------------
9
+ #
10
+ # (built in)
11
+ # connected
12
+ #
13
+ # (module defined)
14
+ # video_inputs
15
+ # video_outputs
16
+ #
17
+ # video1 => input
18
+ # video2
19
+ # video3
20
+ #
21
+
22
+ #
23
+ # NOTE:: These devices should be marked as make and break!
24
+ #
25
+
26
+ class Kramer::Switcher::VsHdmi
27
+ include ::Orchestrator::Constants
28
+ include ::Orchestrator::Transcoder
29
+
30
+ def on_load
31
+
32
+ #
33
+ # Setup constants
34
+ #
35
+ self[:limits_known] = false
36
+
37
+ defaults({
38
+ :wait => false
39
+ })
40
+
41
+ config = ({
42
+ :inactivity_timeout => 10000 # We wait 10 seconds before the connection is broken (make and break)
43
+ })
44
+ end
45
+
46
+ def connected
47
+ #
48
+ # Get current state of the switcher
49
+ #
50
+ get_machine_type
51
+ end
52
+
53
+
54
+ COMMANDS = {
55
+ :reset_video => 0,
56
+ :switch_video => 1,
57
+ :status_video => 5,
58
+ :define_machine => 62,
59
+ :identify_machine => 61
60
+ }
61
+
62
+
63
+ #
64
+ # Starting at input 1
65
+ #
66
+ def switch(map)
67
+ # instr, inp, outp, machine number
68
+ # Switch video
69
+ command = [1, 0x80, 0x80, 0xFF]
70
+
71
+ map.each do |input, outputs|
72
+ outputs = [outputs] unless outputs.class == Array
73
+ input = input.to_s if input.class == Symbol
74
+ input = input.to_i if input.class == String
75
+ outputs.each do |output|
76
+ command[1] = 0x80 + input
77
+ command[2] = 0x80 + output
78
+ outname = :"video#{output}"
79
+ send(command, name: outname)
80
+ self[outname] = input
81
+ end
82
+ end
83
+ end
84
+ alias :switch_video :switch
85
+
86
+ def received(data, resolve, command)
87
+ logger.debug "Kramer sent 0x#{byte_to_hex(data)}"
88
+
89
+ data = str_to_array(data)
90
+
91
+ return nil if data[0] & 0b1000000 == 0 # Check we are the destination
92
+
93
+ data[1] = data[1] & 0b1111111 # input
94
+ data[2] = data[2] & 0b1111111 # output
95
+
96
+ case data[0] & 0b111111
97
+ when COMMANDS[:define_machine]
98
+ if data[1] == 1
99
+ self[:video_inputs] = data[2]
100
+ elsif data[1] == 2
101
+ self[:video_outputs] = data[2]
102
+ end
103
+ self[:limits_known] = true # Set here in case unsupported
104
+ when COMMANDS[:status_video]
105
+ if data[2] == 0 # Then data[1] has been applied to all the outputs
106
+ logger.debug "Kramer switched #{data[1]} -> All"
107
+
108
+ (1..self[:video_outputs]).each do |i|
109
+ self["video#{i}"] = data[1]
110
+ end
111
+ else
112
+ self["video#{data[2]}"] = data[1]
113
+
114
+ logger.debug "Kramer switched #{data[1]} -> #{data[2]}"
115
+
116
+ #
117
+ # As we may not know the max number of inputs if get machine type didn't work
118
+ #
119
+ self[:video_inputs] = data[1] if data[1] > self[:video_inputs]
120
+ self[:video_outputs] = data[2] if data[2] > self[:video_outputs]
121
+ end
122
+ when COMMANDS[:identify_machine]
123
+ logger.debug "Kramer switcher protocol #{data[1]}.#{data[2]}"
124
+ end
125
+
126
+ return :success
127
+ end
128
+
129
+
130
+ private
131
+
132
+
133
+ #
134
+ # No all switchers implement this
135
+ #
136
+ def get_machine_type
137
+ # id com, video
138
+ command = [62, 0x81, 0x81, 0xFF]
139
+ send(command, name: :inputs) # num inputs
140
+ command[1] = 0x82
141
+ send(command, name: :outputs) # num outputs
142
+ end
143
+ end