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,248 @@
1
+ module Epson; end
2
+ module Epson::Projector; end
3
+
4
+ #
5
+ # Port: 3629
6
+ #
7
+ class Epson::Projector::EscVp21
8
+ include ::Orchestrator::Constants
9
+ include ::Orchestrator::Transcoder
10
+
11
+ def on_load
12
+ #config({
13
+ # tokenize: true,
14
+ # delimiter: ":"
15
+ #})
16
+
17
+ self[:power] = false
18
+ self[:stable_state] = true # Stable by default (allows manual on and off)
19
+
20
+ # Meta data for inquiring interfaces
21
+ self[:type] = :projector
22
+ end
23
+
24
+ def on_update
25
+
26
+ end
27
+
28
+ def connected
29
+ # Have to init comms
30
+ send("ESC/VP.net\x10\x03\x00\x00\x00\x00")
31
+ do_poll
32
+ @polling_timer = schedule.every('52s', method(:do_poll))
33
+ end
34
+
35
+ def disconnected
36
+ self[:power] = false
37
+ @polling_timer.cancel unless @polling_timer.nil?
38
+ @polling_timer = nil
39
+ end
40
+
41
+
42
+
43
+ #
44
+ # Power commands
45
+ #
46
+ def power(state, opt = nil)
47
+ self[:stable_state] = false
48
+ if is_affirmative?(state)
49
+ self[:power_target] = On
50
+ do_send(:PWR, :ON, {:timeout => 40000, :name => :power})
51
+ logger.debug "-- epson Proj, requested to power on"
52
+ do_send(:PWR, :name => :power_state)
53
+ else
54
+ self[:power_target] = Off
55
+ do_send(:PWR, :OFF, {:timeout => 10000, :name => :power})
56
+ logger.debug "-- epson Proj, requested to power off"
57
+ do_send(:PWR, :name => :power_state)
58
+ end
59
+ end
60
+
61
+ def power?(options = {}, &block)
62
+ options[:emit] = block if block_given?
63
+ options[:name] = :power_state
64
+ do_send(:PWR, options)
65
+ end
66
+
67
+
68
+
69
+ #
70
+ # Input selection
71
+ #
72
+ INPUTS = {
73
+ :hdmi => 0x30 # TODO:: Might need to have a setting for configuring this
74
+ }
75
+ INPUTS.merge!(INPUTS.invert)
76
+
77
+
78
+ def switch_to(input)
79
+ input = input.to_sym
80
+ return unless INPUTS.has_key? input
81
+
82
+ do_send(:SOURCE, INPUTS[input].to_s(16), {:name => :inpt_source})
83
+ do_send(:SOURCE, {:name => :inpt_query})
84
+
85
+ logger.debug "-- epson LCD, requested to switch to: #{input}"
86
+
87
+ self[:input] = input # for a responsive UI
88
+ end
89
+
90
+
91
+
92
+ #
93
+ # Volume commands are sent using the inpt command
94
+ #
95
+ def volume(vol, options = {})
96
+ vol = vol.to_i
97
+ vol = 0 if vol < 0
98
+ vol = 255 if vol > 255
99
+
100
+ do_send(:VOL, vol, options)
101
+ end
102
+
103
+
104
+ #
105
+ # Mute Audio and Video
106
+ #
107
+ def mute
108
+ logger.debug "-- epson Proj, requested to mute"
109
+ do_send(:MUTE, :ON, {:name => :video_mute}) # Audio + Video
110
+ do_send(:MUTE) # request status
111
+ end
112
+
113
+ def unmute
114
+ logger.debug "-- epson Proj, requested to mute"
115
+ do_send(:MUTE, :OFF, {:name => :video_mute})
116
+ do_send(:MUTE)
117
+ end
118
+
119
+
120
+ ERRORS = {
121
+ 0 => '00: no error'.freeze,
122
+ 1 => '01: fan error'.freeze,
123
+ 3 => '03: lamp failure at power on'.freeze,
124
+ 4 => '04: high internal temperature'.freeze,
125
+ 6 => '06: lamp error'.freeze,
126
+ 7 => '07: lamp cover door open'.freeze,
127
+ 8 => '08: cinema filter error'.freeze,
128
+ 9 => '09: capacitor is disconnected'.freeze,
129
+ 10 => '0A: auto iris error'.freeze,
130
+ 11 => '0B: subsystem error'.freeze,
131
+ 12 => '0C: low air flow error'.freeze,
132
+ 13 => '0D: air flow sensor error'.freeze,
133
+ 14 => '0E: ballast power supply error'.freeze,
134
+ 15 => '0F: shutter error'.freeze,
135
+ 16 => '10: peltiert cooling error'.freeze,
136
+ 17 => '11: pump cooling error'.freeze,
137
+ 18 => '12: static iris error'.freeze,
138
+ 19 => '13: power supply unit error'.freeze,
139
+ 20 => '14: exhaust shutter error'.freeze,
140
+ 21 => '15: obstacle detection error'.freeze,
141
+ 22 => '16: IF board discernment error'.freeze
142
+ }
143
+
144
+ #
145
+ # epson Response code
146
+ #
147
+ def received(data, resolve, command) # Data is default received as a string
148
+ logger.debug "epson Proj sent: #{data}"
149
+
150
+ if data == ':'
151
+ return :success
152
+ end
153
+
154
+ data = data.split(/=|\r:/)
155
+ case data[0].to_sym
156
+ when :ERR
157
+ # Lookup error!
158
+ if data[1].nil?
159
+ warning = "Epson PJ sent error response"
160
+ warning << " for #{command[:data].inspect}" if command
161
+ logger.warn warning
162
+ return :abort
163
+ else
164
+ code = data[1].to_i(16)
165
+ self[:last_error] = ERRORS[code] || "#{data[1]}: unknown error code #{code}"
166
+ logger.warn "Epson PJ error was #{self[:last_error]}"
167
+ return :success
168
+ end
169
+ when :PWR
170
+ state = data[1].to_i
171
+ self[:power] = state < 3
172
+ self[:warming] = state == 2
173
+ self[:cooling] = state == 3
174
+ if self[:warming] || self[:cooling]
175
+ schedule.in('5s') do
176
+ power?({:priority => 0})
177
+ end
178
+ end
179
+ if !self[:stable_state] && self[:power_target] == self[:power]
180
+ self[:stable_state] = true
181
+ end
182
+
183
+ when :MUTE
184
+ self[:mute] = data[1] == 'ON'
185
+ when :VOL
186
+ self[:volume] = data[1].to_i
187
+ when :LAMP
188
+ self[:lamp] = data[1].to_i
189
+ when :SOURCE
190
+ self[:source] = INPUTS[data[1].to_i(16)] || :unknown
191
+ end
192
+
193
+ :success
194
+ end
195
+
196
+ def inspect_error
197
+ do_send(:ERR, priority: 0)
198
+ end
199
+
200
+
201
+ protected
202
+
203
+
204
+ def do_poll(*args)
205
+ power?({:priority => 0}) do
206
+ if self[:power]
207
+ if self[:stable_state] == false && self[:power_target] == Off
208
+ power(Off)
209
+ else
210
+ self[:stable_state] = true
211
+ do_send(:SOURCE, {
212
+ :name => :inpt_query,
213
+ :priority => 0
214
+ })
215
+ do_send(:MUTE, {
216
+ :name => :mute_query,
217
+ :priority => 0
218
+ })
219
+ do_send(:VOL, {
220
+ :name => :vol_query,
221
+ :priority => 0
222
+ })
223
+ end
224
+ elsif self[:stable_state] == false
225
+ if self[:power_target] == On
226
+ power(On)
227
+ else
228
+ self[:stable_state] = true
229
+ end
230
+ end
231
+ end
232
+ do_send(:LAMP, {:priority => 0})
233
+ end
234
+
235
+ def do_send(command, param = nil, options = {})
236
+ if param.is_a? Hash
237
+ options = param
238
+ param = nil
239
+ end
240
+
241
+ if param.nil?
242
+ send("#{command}?\x0D", options)
243
+ else
244
+ send("#{command} #{param}\x0D", options)
245
+ end
246
+ end
247
+ end
248
+
@@ -0,0 +1,195 @@
1
+ module Extron; end
2
+ module Extron::Mixer; end
3
+
4
+
5
+ # :title:Extron DSP 44
6
+ #
7
+ # Status information avaliable:
8
+ # -----------------------------
9
+ #
10
+ # (built in)
11
+ # connected
12
+ #
13
+ # (module defined)
14
+ #
15
+
16
+
17
+ class Extron::Mixer::Dmp44
18
+ include ::Orchestrator::Constants
19
+ include ::Orchestrator::Transcoder
20
+
21
+
22
+ def on_load
23
+ #
24
+ # Setup constants
25
+ #
26
+ self[:output_volume_max] = 2168
27
+ self[:output_volume_min] = 1048
28
+ self[:mic_gain_max] = 2298
29
+ self[:mic_gain_min] = 1698
30
+
31
+ config({
32
+ :clear_queue_on_disconnect => true # Clear the queue as we may need to send login
33
+ })
34
+ end
35
+
36
+ def connected
37
+ device_ready
38
+ @polling_timer = schedule.every('2m') do
39
+ logger.debug "-- Extron Maintaining Connection"
40
+ send('Q', :priority => 0) # Low priority poll to maintain connection
41
+ end
42
+ end
43
+
44
+ def disconnected
45
+ #
46
+ # Disconnected may be called without calling connected
47
+ # Hence the check if timer is nil here
48
+ #
49
+ @polling_timer.cancel unless @polling_timer.nil?
50
+ @polling_timer = nil
51
+ end
52
+
53
+
54
+ def call_preset(number)
55
+ if number < 0 || number > 32
56
+ number = 0 # Current configuration
57
+ end
58
+ send("#{number}.") # No Carriage return for presents
59
+ # Response: Rpr#{number}
60
+ end
61
+
62
+ #
63
+ # Input control
64
+ #
65
+ def adjust_gain(input, value) # \e == 0x1B == ESC key
66
+ input -= 1
67
+ do_send("\eG3000#{input}*#{value}AU")
68
+ # Response: DsG3000#{input}*#{value}
69
+ end
70
+
71
+ def adjust_gain_relative(input, value) # \e == 0x1B == ESC key
72
+ input -= 1
73
+ current = do_send("\eG3000#{input}AU", :emit => "mic#{input + 1}_gain")
74
+ do_send("\eG3000#{input}*#{current + (value * 10)}AU")
75
+
76
+ # Response: DsG3000#{input}*#{value}
77
+ end
78
+
79
+ def mute_input(input)
80
+ input -= 1
81
+ do_send("\eM3000#{input}*1AU")
82
+ # Response: DsM3000#{input}*1
83
+ end
84
+
85
+ def unmute_input(input)
86
+ input -= 1
87
+ do_send("\eM3000#{input}*0AU")
88
+ # Response: DsM3000#{input}*0
89
+ end
90
+
91
+
92
+ #
93
+ # Group control
94
+ #
95
+ def mute_group(group)
96
+ do_send("\eD#{group}*1GRPM")
97
+ # Response: GrpmD#{group}*+00001
98
+ end
99
+
100
+ def unmute_group(group)
101
+ do_send("\eD#{group}*0GRPM")
102
+ # Response: GrpmD#{group}*+00000
103
+ end
104
+
105
+ def volume(group, value) # \e == 0x1B == ESC key
106
+ do_send("\eD#{group}*#{value * 10}*GRPM")
107
+ # Response: GrpmD#{group}*#{value}*GRPM
108
+ end
109
+
110
+ def volume_relative(group, value) # \e == 0x1B == ESC key
111
+
112
+ if value < 0
113
+ value = -value
114
+ do_send("\eD#{group}*#{value * 10}-GRPM")
115
+ else
116
+ do_send("\eD#{group}*#{value * 10}+GRPM")
117
+ end
118
+ # Response: GrpmD#{group}*#{value}*GRPM
119
+ end
120
+
121
+
122
+ def response_delimiter
123
+ [0x0D, 0x0A] # Used to interpret the end of a message
124
+ end
125
+
126
+ #
127
+ # Sends copyright information
128
+ # Then sends password prompt
129
+ #
130
+ def received(data, resolve, command)
131
+ logger.debug "Extron DSP 44 sent #{data}"
132
+
133
+ if command.nil? && data =~ /Copyright/i
134
+ device_ready
135
+ else
136
+ case data[0..2].to_sym
137
+ when :Grp # Mute or Volume
138
+ data = data.split('*')
139
+ if data[1][0] == '+' # mute
140
+ self["ouput#{data[0][5..-1].to_i}_mute"] = data[1][-1] == '1' # 1 == true
141
+ else
142
+ self["ouput#{data[0][5..-1].to_i}_volume"] = data[1].to_i
143
+ end
144
+ when :DsG # Input gain
145
+ self["input#{data[7].to_i + 1}_gain"] = data[9..-1].to_i
146
+ when :DsM # Input Mute
147
+ self["input#{data[7].to_i + 1}_mute"] = data[-1] == '1' # 1 == true
148
+ when :Rpr # Preset called
149
+ logger.debug "Extron DSP called preset #{data[3..-1]}"
150
+ else
151
+ if data == 'E22' # Busy! We should retry this one
152
+ command[:delay_on_receive] = 1 unless command.nil?
153
+ return :failed
154
+ elsif data[0] == 'E'
155
+ logger.info "Extron Error #{ERRORS[data[1..2].to_i]}"
156
+ logger.info "- for command #{command[:data]}" unless command.nil?
157
+ end
158
+ end
159
+ end
160
+
161
+ return :success
162
+ end
163
+
164
+
165
+ private
166
+
167
+
168
+ ERRORS = {
169
+ 10 => 'Invalid command',
170
+ 11 => 'Invalid preset',
171
+ 12 => 'Invalid port number',
172
+ 13 => 'Invalid parameter (number is out of range)',
173
+ 14 => 'Not valid for this configuration',
174
+ 17 => 'System timed out',
175
+ 23 => 'Checksum error (for file uploads)',
176
+ 24 => 'Privilege violation',
177
+ 25 => 'Device is not present',
178
+ 26 => 'Maximum connections exceeded',
179
+ 27 => 'Invalid event number',
180
+ 28 => 'Bad filename or file not found'
181
+ }
182
+
183
+
184
+ def device_ready
185
+ do_send("\e3CV") # Verbose mode and tagged responses
186
+ end
187
+
188
+
189
+
190
+
191
+ def do_send(data, options = {})
192
+ send(data << 0x0D, options)
193
+ end
194
+ end
195
+
@@ -0,0 +1,212 @@
1
+ module Extron; end
2
+ module Extron::Mixer; end
3
+
4
+
5
+ # :title:Extron DSP
6
+ #
7
+ # Status information avaliable:
8
+ # -----------------------------
9
+ #
10
+ # (built in)
11
+ # connected
12
+ #
13
+ # (module defined)
14
+ #
15
+ #
16
+ #
17
+ # Volume outputs
18
+ # 60000 == volume 1
19
+ # 60003 == volume 4
20
+ #
21
+ # Pre-mix gain inputs
22
+ # 40100 == Mic1
23
+ # 40105 == Mic6
24
+ #
25
+
26
+
27
+ class Extron::Mixer::Dmp64
28
+ include ::Orchestrator::Constants
29
+ include ::Orchestrator::Transcoder
30
+
31
+
32
+ def on_load
33
+ #
34
+ # Setup constants
35
+ #
36
+ self[:output_volume_max] = 2168
37
+ self[:output_volume_min] = 1048
38
+ self[:mic_gain_max] = 2298
39
+ self[:mic_gain_min] = 1698
40
+
41
+ config({
42
+ :clear_queue_on_disconnect => true # Clear the queue as we may need to send login
43
+ })
44
+ end
45
+
46
+ def connected
47
+
48
+ end
49
+
50
+ def disconnected
51
+ #
52
+ # Disconnected may be called without calling connected
53
+ # Hence the check if timer is nil here
54
+ #
55
+ @polling_timer.cancel unless @polling_timer.nil?
56
+ @polling_timer = nil
57
+ end
58
+
59
+
60
+ def call_preset(number)
61
+ if number < 0 || number > 32
62
+ number = 0 # Current configuration
63
+ end
64
+ send("#{number}.") # No Carriage return for presents
65
+ # Response: Rpr#{number}
66
+ end
67
+
68
+ #
69
+ # Input control
70
+ #
71
+ def adjust_gain(mic, value) # \e == 0x1B == ESC key
72
+ do_send("\eG4010#{mic}*#{value}AU")
73
+ # Response: DsG4010#{mic}*#{value}
74
+ end
75
+
76
+ def adjust_gain_relative(mic, value) # \e == 0x1B == ESC key
77
+ current = do_send("\eG4010#{mic}AU", :emit => "mic#{mic}_gain")
78
+ do_send("\eG4010#{mic}*#{current + (value * 10)}AU")
79
+
80
+ # Response: DsG4010#{mic}*#{value}
81
+ end
82
+
83
+ def mute_mic(mic)
84
+ do_send("\eM4000#{mic}*1AU") # 4000 (input gain), 4010 (pre-mixer gain)
85
+ # Response: DsM4010#{mic}*1
86
+ end
87
+
88
+ def unmute_mic(mic)
89
+ do_send("\eM4000#{mic}*0AU")
90
+ # Response: DsM4010#{mic}*0
91
+ end
92
+
93
+
94
+ #
95
+ # Output control
96
+ #
97
+ def mute_group(group)
98
+ do_send("\eD#{group}*1GRPM", :group_type => :mute)
99
+ # Response: GrpmD#{group}*+00001
100
+ end
101
+
102
+ def unmute_group(group)
103
+ do_send("\eD#{group}*0GRPM", :group_type => :mute)
104
+ # Response: GrpmD#{group}*+00000
105
+ end
106
+
107
+ def volume(group, value) # \e == 0x1B == ESC key
108
+ do_send("\eD#{group}*#{value}GRPM", :group_type => :volume)
109
+ # Response: GrpmD#{group}*#{value}*GRPM
110
+ end
111
+
112
+ def group_status(group, type)
113
+ do_send("\eD#{group}GRPM", :group_type => type)
114
+ end
115
+
116
+ def volume_relative(group, value) # \e == 0x1B == ESC key
117
+ if value < 0
118
+ value = -value
119
+ do_send("\eD#{group}*#{value}-GRPM")
120
+ else
121
+ do_send("\eD#{group}*#{value}+GRPM")
122
+ end
123
+ # Response: GrpmD#{group}*#{value}*GRPM
124
+ end
125
+
126
+
127
+ def response_delimiter
128
+ [0x0D, 0x0A] # Used to interpret the end of a message
129
+ end
130
+
131
+ #
132
+ # Sends copyright information
133
+ # Then sends password prompt
134
+ #
135
+ def received(data, resolve, command)
136
+ logger.debug "Extron DSP sent #{data}"
137
+
138
+ if command.nil? && data =~ /Copyright/i
139
+ pass = setting(:password)
140
+ if pass.nil?
141
+ device_ready
142
+ else
143
+ do_send(pass) # Password set
144
+ end
145
+ elsif data =~ /Login/i
146
+ device_ready
147
+ else
148
+ case data[0..2].to_sym
149
+ when :Grp # Mute or Volume
150
+ data = data.split('*')
151
+ if command.present? && command[:group_type] == :mute
152
+ self["ouput#{data[0][5..-1].to_i}_mute"] = data[1][-1] == '1' # 1 == true
153
+ elsif command.present? && command[:group_type] == :volume
154
+ self["ouput#{data[0][5..-1].to_i}_volume"] = data[1].to_i
155
+ else
156
+ return :failed
157
+ end
158
+ when :DsG # Mic gain
159
+ self["mic#{data[7]}_gain"] = data[9..-1].to_i
160
+ when :DsM # Mic Mute
161
+ self["mic#{data[7]}_mute"] = data[-1] == '1' # 1 == true
162
+ when :Rpr # Preset called
163
+ logger.debug "Extron DSP called preset #{data[3..-1]}"
164
+ else
165
+ if data == 'E22' # Busy! We should retry this one
166
+ command[:delay_on_receive] = 1 unless command.nil?
167
+ return :failed
168
+ elsif data[0] == 'E'
169
+ logger.info "Extron Error #{ERRORS[data[1..2].to_i]}"
170
+ logger.info "- for command #{command[:data]}" unless command.nil?
171
+ end
172
+ end
173
+ end
174
+
175
+ return :success
176
+ end
177
+
178
+
179
+ private
180
+
181
+
182
+ ERRORS = {
183
+ 1 => 'Invalid input number (number is too large)',
184
+ 12 => 'Invalid port number',
185
+ 13 => 'Invalid parameter (number is out of range)',
186
+ 14 => 'Not valid for this configuration',
187
+ 17 => 'System timed out',
188
+ 23 => 'Checksum error (for file uploads)',
189
+ 24 => 'Privilege violation',
190
+ 25 => 'Device is not present',
191
+ 26 => 'Maximum connections exceeded',
192
+ 27 => 'Invalid event number',
193
+ 28 => 'Bad filename or file not found'
194
+ }
195
+
196
+
197
+ def device_ready
198
+ do_send("\e3CV") # Verbose mode and tagged responses
199
+ @polling_timer = schedule.every('2m') do
200
+ logger.debug "-- Extron Maintaining Connection"
201
+ send('Q', :priority => 0) # Low priority poll to maintain connection
202
+ end
203
+ end
204
+
205
+
206
+
207
+
208
+ def do_send(data, options = {})
209
+ send(data << 0x0D, options)
210
+ end
211
+ end
212
+