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.
- checksums.yaml +7 -0
- data/LICENSE +165 -0
- data/README.md +3 -0
- data/aca-device-modules.gemspec +21 -0
- data/lib/aca-device-modules.rb +2 -0
- data/lib/aca-device-modules/engine.rb +8 -0
- data/lib/aca-device-modules/version.rb +3 -0
- data/modules/aca/pc_control.rb +142 -0
- data/modules/axis/camera/vapix.rb +280 -0
- data/modules/biamp/nexia.rb +125 -0
- data/modules/bss/blu100.rb +265 -0
- data/modules/clipsal/c_bus.rb +256 -0
- data/modules/epson/projector/esc_vp21.rb +248 -0
- data/modules/extron/mixer/dmp44.rb +195 -0
- data/modules/extron/mixer/dmp64.rb +212 -0
- data/modules/extron/switcher/dxp.rb +249 -0
- data/modules/global_cache/gc100.rb +167 -0
- data/modules/kramer/switcher/vs_hdmi.rb +143 -0
- data/modules/panasonic/camera/he50.rb +346 -0
- data/modules/panasonic/projector/pj_link.rb +266 -0
- data/modules/samsung/displays/md_series.rb +256 -0
- data/modules/vaddio/camera/clear_view_ptz_telnet.rb +138 -0
- metadata +94 -0
@@ -0,0 +1,346 @@
|
|
1
|
+
module Panasonic; end
|
2
|
+
module Panasonic::Camera; end
|
3
|
+
|
4
|
+
|
5
|
+
class Panasonic::Camera::He50
|
6
|
+
include ::Orchestrator::Constants
|
7
|
+
include ::Orchestrator::Transcoder
|
8
|
+
|
9
|
+
def on_load
|
10
|
+
on_update
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_update
|
14
|
+
defaults({
|
15
|
+
delay: 130, # As per the manual page 8
|
16
|
+
keepalive: false,
|
17
|
+
inactivity_timeout: 1.5, # seconds before closing the connection if no response
|
18
|
+
connect_timeout: 2 # max seconds for the initial connection to the device
|
19
|
+
})
|
20
|
+
|
21
|
+
self[:pan_max] = 0xD2F5
|
22
|
+
self[:pan_min] = 0x2D08
|
23
|
+
self[:pan_center] = 0x7FFF
|
24
|
+
self[:tilt_max] = 0x8E38
|
25
|
+
self[:tilt_min] = 0x5556
|
26
|
+
self[:tilt_center] = 0x7FFF
|
27
|
+
|
28
|
+
self[:joy_left] = 0x01
|
29
|
+
self[:joy_right] = 0x99
|
30
|
+
self[:joy_center] = 0x50
|
31
|
+
|
32
|
+
self[:zoom_max] = 0xFFF
|
33
|
+
self[:zoom_min] = 0x555
|
34
|
+
|
35
|
+
self[:focus_max] = 0xFFF
|
36
|
+
self[:focus_min] = 0x555
|
37
|
+
|
38
|
+
self[:iris_max] = 0xFFF
|
39
|
+
self[:iris_min] = 0x555
|
40
|
+
|
41
|
+
# {near: {zoom: val, pan: val, tilt: val}}
|
42
|
+
@presets = setting(:presets) || {}
|
43
|
+
self[:presets] = @presets.keys
|
44
|
+
end
|
45
|
+
|
46
|
+
def connected
|
47
|
+
schedule.every('60s', method(:do_poll))
|
48
|
+
do_poll
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
RESP = {
|
53
|
+
power: 'p',
|
54
|
+
installation: 'iNS',
|
55
|
+
|
56
|
+
pantilt: 'aPC',
|
57
|
+
joystick: 'pTS',
|
58
|
+
limit: 'lC',
|
59
|
+
|
60
|
+
zoom: /axz|gz/,
|
61
|
+
manual_zoom: 'zS',
|
62
|
+
link_zoom: 'sWZ',
|
63
|
+
|
64
|
+
focus: /axf|gf/,
|
65
|
+
manual_focus: 'fS',
|
66
|
+
auto_focus: 'd1',
|
67
|
+
|
68
|
+
iris: /axi|gi/,
|
69
|
+
auto_iris: 'd3'
|
70
|
+
}
|
71
|
+
LIMITS = {
|
72
|
+
up: 1,
|
73
|
+
down: 2,
|
74
|
+
left: 3,
|
75
|
+
right: 4
|
76
|
+
}
|
77
|
+
LIMITS.merge!(LIMITS.invert)
|
78
|
+
|
79
|
+
|
80
|
+
# Responds with:
|
81
|
+
# 0 == standby
|
82
|
+
# 1 == power on
|
83
|
+
# 3 == powering on
|
84
|
+
def power(state = nil, &blk)
|
85
|
+
state = (is_affirmative?(state) ? 1 : 0) unless state.nil?
|
86
|
+
|
87
|
+
options = {}
|
88
|
+
options[:emit] = blk if blk
|
89
|
+
options[:delay] = 6000 if state
|
90
|
+
|
91
|
+
logger.debug "Camera requested power #{state}"
|
92
|
+
|
93
|
+
req('O', state, :power, options) do |data, resolve|
|
94
|
+
val = extract(:power, data, resolve)
|
95
|
+
if val
|
96
|
+
self[:power] = val.to_i > 0
|
97
|
+
:success
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def installation(pos = nil)
|
103
|
+
pos = (pos.to_sym == :desk ? 0 : 1) if pos
|
104
|
+
|
105
|
+
req('INS', pos, :installation) do |data, resolve|
|
106
|
+
val = extract(:installation, data, resolve)
|
107
|
+
if val
|
108
|
+
self[:installation] = val == '0' ? :desk : :ceiling
|
109
|
+
:success
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def pantilt(pan = nil, tilt = nil)
|
115
|
+
unless pan.nil?
|
116
|
+
pan = in_range(pan.to_i, self[:pan_max], self[:pan_min]).to_s(16).upcase.rjust(4, '0')
|
117
|
+
tilt = in_range(tilt.to_i, self[:tilt_max], self[:tilt_min]).to_s(16).upcase.rjust(4, '0')
|
118
|
+
end
|
119
|
+
|
120
|
+
req('APC', "#{pan}#{tilt}", :pantilt) do |data, resolve|
|
121
|
+
val = extract(:pantilt, data, resolve)
|
122
|
+
if val
|
123
|
+
comp = []
|
124
|
+
val.scan(/.{4}/) { |com| comp << com.to_i(16) }
|
125
|
+
self[:pan] = comp[0]
|
126
|
+
self[:tilt] = comp[1]
|
127
|
+
:success
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Recall a preset from the database
|
133
|
+
def preset(name)
|
134
|
+
values = @presets[name.to_sym]
|
135
|
+
if values
|
136
|
+
pantilt(values[:pan], values[:tilt])
|
137
|
+
zoom(values[:zoom])
|
138
|
+
true
|
139
|
+
else
|
140
|
+
false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def joystick(pan_speed, tilt_speed)
|
145
|
+
left_max = self[:joy_left]
|
146
|
+
right_max = self[:joy_right]
|
147
|
+
pan_speed = in_range(pan_speed.to_i, right_max, left_max).to_s(16).upcase.rjust(2, '0')
|
148
|
+
tilt_speed = in_range(tilt_speed.to_i, right_max, left_max).to_s(16).upcase.rjust(2, '0')
|
149
|
+
|
150
|
+
is_centered = false
|
151
|
+
if pan_speed == '50' && tilt_speed == '50'
|
152
|
+
is_centered = true
|
153
|
+
end
|
154
|
+
|
155
|
+
options = {}
|
156
|
+
options[:retries] = is_centered ? 1 : 0
|
157
|
+
|
158
|
+
logger.debug("Sending camera: #{pan_speed}#{tilt_speed}");
|
159
|
+
|
160
|
+
req('PTS', "#{pan_speed}#{tilt_speed}", :joystick, options) do |data, resolve|
|
161
|
+
val = extract(:joystick, data, resolve)
|
162
|
+
if val
|
163
|
+
comp = []
|
164
|
+
val.scan(/.{2}/) { |com| comp << com.to_i(16) }
|
165
|
+
self[:joy_pan] = comp[0]
|
166
|
+
self[:joy_tilt] = comp[1]
|
167
|
+
:success
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def limit(direction, state = nil)
|
173
|
+
dir = LIMITS[direction.to_sym]
|
174
|
+
state = (is_affirmative?(set) ? 1 : 0) unless state.nil?
|
175
|
+
|
176
|
+
req('LC', "#{dir}#{state}", :limit) do |data, resolve|
|
177
|
+
val = extract(:limit, data, resolve)
|
178
|
+
if val
|
179
|
+
self[:"limit_#{LIMITS[val[0].to_i]}"] = val[1] == '1'
|
180
|
+
:success
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
def zoom(pos = nil)
|
187
|
+
cmd = 'AXZ'
|
188
|
+
if pos
|
189
|
+
pos = in_range(pos.to_i, self[:zoom_max], self[:zoom_min]).to_s(16).upcase.rjust(3, '0')
|
190
|
+
else
|
191
|
+
cmd = 'GZ'
|
192
|
+
end
|
193
|
+
|
194
|
+
req(cmd, pos, :zoom) do |data, resolve|
|
195
|
+
val = extract(:zoom, data, resolve)
|
196
|
+
if val
|
197
|
+
self[:zoom] = val.to_i(16)
|
198
|
+
:success
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def manual_zoom(speed)
|
204
|
+
speed = in_range(speed.to_i, self[:joy_right], self[:joy_left]).to_s(16).upcase.rjust(3, '0')
|
205
|
+
|
206
|
+
req('Z', speed, :manual_zoom) do |data, resolve|
|
207
|
+
val = extract(:manual_zoom, data, resolve)
|
208
|
+
if val
|
209
|
+
self[:manual_zoom] = val.to_i(16)
|
210
|
+
:success
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def link_zoom(state = nil) # Link pantilt speed to zoom
|
216
|
+
state = (is_affirmative?(state) ? 1 : 0) unless state.nil?
|
217
|
+
|
218
|
+
req('SWZ', state, :link_zoom) do |data, resolve|
|
219
|
+
val = extract(:link_zoom, data, resolve)
|
220
|
+
if val
|
221
|
+
self[:link_zoom] = val == '1'
|
222
|
+
:success
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def focus(pos = nil)
|
229
|
+
cmd = 'AXF'
|
230
|
+
if pos
|
231
|
+
pos = in_range(pos.to_i, self[:focus_max], self[:focus_min]).to_s(16).upcase.rjust(3, '0')
|
232
|
+
else
|
233
|
+
cmd = 'GF'
|
234
|
+
end
|
235
|
+
|
236
|
+
req(cmd, pos, :focus) do |data, resolve|
|
237
|
+
val = extract(:focus, data, resolve)
|
238
|
+
if val
|
239
|
+
self[:focus] = val.to_i(16)
|
240
|
+
:success
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def manual_focus(speed)
|
246
|
+
speed = in_range(speed.to_i, self[:joy_right], self[:joy_left]).to_s(16).upcase.rjust(2, '0')
|
247
|
+
|
248
|
+
req('F', speed, :manual_focus) do |data, resolve|
|
249
|
+
val = extract(:manual_focus, data, resolve)
|
250
|
+
if val
|
251
|
+
self[:manual_focus] = val.to_i(16)
|
252
|
+
:success
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def auto_focus(state = nil)
|
258
|
+
state = (is_affirmative?(state) ? 1 : 0) unless state.nil?
|
259
|
+
|
260
|
+
req('D1', state, :auto_focus) do |data, resolve|
|
261
|
+
val = extract(:auto_focus, data, resolve)
|
262
|
+
if val
|
263
|
+
self[:auto_focus] = val == '1'
|
264
|
+
:success
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
def iris(level = nil)
|
271
|
+
cmd = 'AXI'
|
272
|
+
if level
|
273
|
+
level = in_range(level.to_i, self[:iris_max], self[:iris_min]).to_s(16).upcase.rjust(3, '0')
|
274
|
+
else
|
275
|
+
cmd = 'GI'
|
276
|
+
end
|
277
|
+
|
278
|
+
req(cmd, level, :iris) do |data, resolve|
|
279
|
+
val = extract(:iris, data, resolve)
|
280
|
+
if val
|
281
|
+
self[:iris] = val[0..2].to_i(16)
|
282
|
+
if val.length == 4
|
283
|
+
self[:auto_iris] = val == '1'
|
284
|
+
end
|
285
|
+
:success
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def auto_iris(state = nil)
|
291
|
+
state = (is_affirmative?(state) ? 1 : 0) unless state.nil?
|
292
|
+
|
293
|
+
req('D3', state, :auto_iris) do |data, resolve|
|
294
|
+
val = extract(:auto_iris, data, resolve)
|
295
|
+
if val
|
296
|
+
self[:auto_iris] = val == '1'
|
297
|
+
:success
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
protected
|
304
|
+
|
305
|
+
|
306
|
+
def req(cmd, data, name, options = {}, &blk)
|
307
|
+
if data.nil? || (data.respond_to?(:empty?) && data.empty?)
|
308
|
+
options[:delay] = 0
|
309
|
+
options[:priority] = 0 # Actual commands have a higher priority
|
310
|
+
else
|
311
|
+
options[:name] = name
|
312
|
+
end
|
313
|
+
request_string = "/cgi-bin/aw_ptz?cmd=%23#{cmd}#{data}&res=1"
|
314
|
+
get(request_string, options, &blk)
|
315
|
+
|
316
|
+
logger.debug "requesting #{name}: #{request_string}"
|
317
|
+
end
|
318
|
+
|
319
|
+
def extract(name, data, resp)
|
320
|
+
logger.debug "received #{data} for command #{name}"
|
321
|
+
|
322
|
+
body = data[:body]
|
323
|
+
if body[0] == 'e'
|
324
|
+
notify_error(body, 'invalid command sent', data)
|
325
|
+
resp.call(:failed)
|
326
|
+
nil
|
327
|
+
else
|
328
|
+
body.sub(RESP[name], '')
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def do_poll(*args)
|
333
|
+
power do
|
334
|
+
if self[:power] # only request status if online
|
335
|
+
pantilt
|
336
|
+
zoom
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def notify_error(err, msg, cmd)
|
342
|
+
cmd = cmd[:request]
|
343
|
+
logger.warn "Camera error response: #{err} - #{msg} for #{cmd[:path]} #{cmd[:query]}"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module Panasonic; end
|
2
|
+
module Panasonic::Projector; end
|
3
|
+
|
4
|
+
|
5
|
+
require 'digest/md5'
|
6
|
+
|
7
|
+
#
|
8
|
+
# Port: 1024
|
9
|
+
#
|
10
|
+
class Panasonic::Projector::PjLink
|
11
|
+
include ::Orchestrator::Constants
|
12
|
+
include ::Orchestrator::Transcoder
|
13
|
+
|
14
|
+
def on_load
|
15
|
+
# PJLink is slow
|
16
|
+
defaults({
|
17
|
+
timeout: 4000,
|
18
|
+
delay_on_receive: 400
|
19
|
+
})
|
20
|
+
|
21
|
+
config({
|
22
|
+
tokenize: true,
|
23
|
+
delimiter: "\r",
|
24
|
+
wait_ready: 'NTCONTROL'
|
25
|
+
})
|
26
|
+
|
27
|
+
@check_scheduled = false
|
28
|
+
self[:power] = false
|
29
|
+
self[:stable_state] = true # Stable by default (allows manual on and off)
|
30
|
+
self[:input_stable] = true
|
31
|
+
|
32
|
+
# Meta data for inquiring interfaces
|
33
|
+
self[:type] = :projector
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_update
|
37
|
+
end
|
38
|
+
|
39
|
+
def connected
|
40
|
+
@polling_timer = schedule.every('60s', method(:do_poll))
|
41
|
+
end
|
42
|
+
|
43
|
+
def disconnected
|
44
|
+
self[:power] = false
|
45
|
+
|
46
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
47
|
+
@polling_timer = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
#
|
53
|
+
# Power commands
|
54
|
+
#
|
55
|
+
def power(state, opt = nil)
|
56
|
+
self[:stable_state] = false
|
57
|
+
if is_affirmative?(state)
|
58
|
+
self[:power_target] = On
|
59
|
+
do_send(:POWR, 1, {:retries => 10, :name => :power})
|
60
|
+
logger.debug "-- panasonic Proj, requested to power on"
|
61
|
+
do_send('POWR', '?', :name => :power_state)
|
62
|
+
else
|
63
|
+
self[:power_target] = Off
|
64
|
+
do_send(:POWR, 0, {:retries => 10, :name => :power})
|
65
|
+
logger.debug "-- panasonic Proj, requested to power off"
|
66
|
+
do_send('POWR', '?', :name => :power_state)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def power?(options = {}, &block)
|
71
|
+
options[:emit] = block if block_given?
|
72
|
+
options[:name] = :power_state
|
73
|
+
do_send(:POWR, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
#
|
79
|
+
# Input selection
|
80
|
+
#
|
81
|
+
INPUTS = {
|
82
|
+
:hdmi => 31,
|
83
|
+
:hdmi2 => 32,
|
84
|
+
:digital => 33,
|
85
|
+
:miracast => 52
|
86
|
+
}
|
87
|
+
INPUTS.merge!(INPUTS.invert)
|
88
|
+
|
89
|
+
|
90
|
+
def switch_to(input)
|
91
|
+
input = input.to_sym
|
92
|
+
return unless INPUTS.has_key? input
|
93
|
+
|
94
|
+
do_send(:INPT, INPUTS[input], {:retries => 10, :name => :inpt_source})
|
95
|
+
do_send('INPT', '?', {:name => :inpt_query})
|
96
|
+
logger.debug "-- panasonic LCD, requested to switch to: #{input}"
|
97
|
+
|
98
|
+
self[:input] = input # for a responsive UI
|
99
|
+
self[:input_stable] = false
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
#
|
104
|
+
# Mute Audio and Video
|
105
|
+
#
|
106
|
+
def mute
|
107
|
+
logger.debug "-- panasonic Proj, requested to mute"
|
108
|
+
do_send(:AVMT, 31, {:name => :video_mute}) # Audio + Video
|
109
|
+
end
|
110
|
+
|
111
|
+
def unmute
|
112
|
+
logger.debug "-- panasonic Proj, requested to unmute"
|
113
|
+
do_send(:AVMT, 30, {:name => :video_mute})
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
ERRORS = {
|
118
|
+
:ERR1 => '1: Undefined control command'.freeze,
|
119
|
+
:ERR2 => '2: Out of parameter range'.freeze,
|
120
|
+
:ERR3 => '3: Busy state or no-acceptable period'.freeze,
|
121
|
+
:ERR4 => '4: Timeout or no-acceptable period'.freeze,
|
122
|
+
:ERR5 => '5: Wrong data length'.freeze,
|
123
|
+
:ERRA => 'A: Password mismatch'.freeze
|
124
|
+
}
|
125
|
+
|
126
|
+
|
127
|
+
def received(data, resolve, command) # Data is default received as a string
|
128
|
+
logger.debug "panasonic Proj sent: #{data}"
|
129
|
+
|
130
|
+
# This is the ready response
|
131
|
+
if data[0] == ' '
|
132
|
+
@mode = data[1]
|
133
|
+
if @mode == '1'
|
134
|
+
@pass = "#{setting(:username) || 'admin1'}:#{setting(:password) || 'panasonic'}:#{data.strip.split(/\s+/)[-1]}"
|
135
|
+
@pass = Digest::MD5.hexdigest(@hash)
|
136
|
+
end
|
137
|
+
|
138
|
+
:success
|
139
|
+
|
140
|
+
# Error Response
|
141
|
+
elsif data[0] == 'E'
|
142
|
+
error = data.to_sym
|
143
|
+
#self[:last_error] = ERRORS[error] (for error status query)
|
144
|
+
|
145
|
+
# Check for busy or timeout
|
146
|
+
if error == :ERR3 || error == :ERR4
|
147
|
+
logger.warn "Panasonic Proj busy: #{self[:last_error]}"
|
148
|
+
:retry
|
149
|
+
else
|
150
|
+
logger.error "Panasonic Proj error: #{self[:last_error]}"
|
151
|
+
:abort
|
152
|
+
end
|
153
|
+
|
154
|
+
# Success Response
|
155
|
+
else
|
156
|
+
data = data[2..-1].split('=')
|
157
|
+
|
158
|
+
if data[1] = 'OK'
|
159
|
+
return :success
|
160
|
+
else
|
161
|
+
type = data[0][2..-1].to_sym
|
162
|
+
response = data[1].to_i
|
163
|
+
resolve.call(:success)
|
164
|
+
|
165
|
+
case type
|
166
|
+
when :POWR
|
167
|
+
self[:power] = response >= 1 && response != 2
|
168
|
+
self[:warming] = response == 3
|
169
|
+
self[:cooling] = response == 2
|
170
|
+
if response >= 2 && !@check_scheduled && !self[:stable_state]
|
171
|
+
@check_scheduled = true
|
172
|
+
schedule.in('20s') do
|
173
|
+
@check_scheduled = false
|
174
|
+
logger.debug "-- checking panasonic state"
|
175
|
+
power?({:priority => 0}) do
|
176
|
+
state = self[:power]
|
177
|
+
if state != self[:power_target]
|
178
|
+
if self[:power_target] || !self[:cooling]
|
179
|
+
power(self[:power_target])
|
180
|
+
end
|
181
|
+
elsif self[:power_target] && self[:cooling]
|
182
|
+
power(self[:power_target])
|
183
|
+
else
|
184
|
+
self[:stable_state] = true
|
185
|
+
switch_to(self[:input]) if self[:power_target] == On && !self[:input].nil?
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
when :INPT
|
191
|
+
if INPUTS[response].present?
|
192
|
+
self[:input] = INPUTS[response] if self[:input].nil?
|
193
|
+
self[:actual_input] = INPUTS[response]
|
194
|
+
if self[:input] == self[:actual_input]
|
195
|
+
self[:input_stable] = true
|
196
|
+
elsif self[:input_stable] == false
|
197
|
+
schedule.in('5s') do
|
198
|
+
logger.debug "-- forcing panasonic input"
|
199
|
+
switch_to(self[:input]) if self[:input_stable] == false
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
when :AVMT
|
204
|
+
self[:mute] = response == 31 # 10 == video mute off, 11 == video mute, 20 == audio mute off, 21 == audio mute, 30 == AV mute off
|
205
|
+
when :LAMP
|
206
|
+
self[:lamp] = data[1][0..-2].to_i
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
protected
|
215
|
+
|
216
|
+
|
217
|
+
def do_poll(*args)
|
218
|
+
power?({:priority => 0}) do
|
219
|
+
if self[:power]
|
220
|
+
if self[:stable_state] == false && self[:power_target] == Off
|
221
|
+
power(Off)
|
222
|
+
else
|
223
|
+
self[:stable_state] = true
|
224
|
+
do_send(:INPT, {
|
225
|
+
:name => :inpt_query,
|
226
|
+
:priority => 0
|
227
|
+
})
|
228
|
+
do_send(:AVMT, {
|
229
|
+
:name => :mute_query,
|
230
|
+
:priority => 0
|
231
|
+
})
|
232
|
+
do_send(:LAMP, {
|
233
|
+
:name => :lamp_query,
|
234
|
+
:priority => 0
|
235
|
+
})
|
236
|
+
end
|
237
|
+
elsif self[:stable_state] == false
|
238
|
+
if self[:power_target] == On
|
239
|
+
power(On)
|
240
|
+
else
|
241
|
+
self[:stable_state] = true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def do_send(command, param = nil, options = {})
|
248
|
+
if param.is_a? Hash
|
249
|
+
options = param
|
250
|
+
param = nil
|
251
|
+
end
|
252
|
+
|
253
|
+
if param.nil?
|
254
|
+
pj = "#{command} ?"
|
255
|
+
else
|
256
|
+
pj = "#{command} #{param}"
|
257
|
+
end
|
258
|
+
|
259
|
+
if @mode == '0'
|
260
|
+
send("00#{pj}\r", options)
|
261
|
+
else
|
262
|
+
send("#{@pass}00#{pj}\r", options)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|