aca-device-modules 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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