aca-device-modules 1.0.3 → 1.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 +4 -4
- data/lib/aca-device-modules/version.rb +1 -1
- data/modules/biamp/nexia.rb +45 -26
- data/modules/bss/blu100.rb +49 -31
- data/modules/chiyu/cyt.rb +183 -0
- data/modules/epson/projector/esc_vp21.rb +5 -0
- data/modules/kramer/switcher/protocol3000.rb +243 -0
- data/modules/nec/display/all.rb +482 -0
- data/modules/nec/projector/np_series.rb +648 -0
- data/modules/panasonic/projector/tcp.rb +250 -0
- data/modules/screen_technics/connect.rb +73 -0
- data/modules/sony/display/{gdx_and_fwd.rb → id_talk.rb} +38 -7
- data/modules/sony/projector/pj_talk.rb +300 -0
- data/modules/transmitsms/api.rb +52 -0
- data/modules/vaddio/camera/clear_view_ptz_telnet.rb +3 -3
- metadata +11 -4
- data/modules/panasonic/projector/pj_link.rb +0 -266
@@ -14,6 +14,9 @@ class Epson::Projector::EscVp21
|
|
14
14
|
# delimiter: ":"
|
15
15
|
#})
|
16
16
|
|
17
|
+
self[:volume_min] = 0
|
18
|
+
self[:volume_max] = 255
|
19
|
+
|
17
20
|
self[:power] = false
|
18
21
|
self[:stable_state] = true # Stable by default (allows manual on and off)
|
19
22
|
|
@@ -85,6 +88,7 @@ class Epson::Projector::EscVp21
|
|
85
88
|
logger.debug "-- epson LCD, requested to switch to: #{input}"
|
86
89
|
|
87
90
|
self[:input] = input # for a responsive UI
|
91
|
+
self[:mute] = false
|
88
92
|
end
|
89
93
|
|
90
94
|
|
@@ -178,6 +182,7 @@ class Epson::Projector::EscVp21
|
|
178
182
|
end
|
179
183
|
if !self[:stable_state] && self[:power_target] == self[:power]
|
180
184
|
self[:stable_state] = true
|
185
|
+
self[:mute] = false if !self[:power]
|
181
186
|
end
|
182
187
|
|
183
188
|
when :MUTE
|
@@ -0,0 +1,243 @@
|
|
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::Protocol3000
|
27
|
+
include ::Orchestrator::Constants
|
28
|
+
include ::Orchestrator::Transcoder
|
29
|
+
|
30
|
+
def on_load
|
31
|
+
config({
|
32
|
+
tokenize: true,
|
33
|
+
delimiter: "\x0D\x0A",
|
34
|
+
encoding: "ASCII-8BIT"
|
35
|
+
})
|
36
|
+
|
37
|
+
on_update
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_update
|
41
|
+
@device_id = setting(:kramer_id)
|
42
|
+
@destination = "#{@device_id}@" if @device_id
|
43
|
+
|
44
|
+
@login_level = setting(:kramer_login)
|
45
|
+
@password = setting(:kramer_password) if @login_level
|
46
|
+
end
|
47
|
+
|
48
|
+
def connected
|
49
|
+
#
|
50
|
+
# Get current state of the switcher
|
51
|
+
#
|
52
|
+
protocol_handshake
|
53
|
+
login
|
54
|
+
get_machine_info
|
55
|
+
|
56
|
+
@polling_timer = schedule.every('2m') do
|
57
|
+
logger.debug "-- Kramer Maintaining Connection"
|
58
|
+
do_send('MODEL?', {:priority => 0}) # Low priority poll to maintain connection
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def disconnected
|
63
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
64
|
+
@polling_timer = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
#
|
69
|
+
# Starting at input 1, input 0 == disconnect
|
70
|
+
#
|
71
|
+
def switch(map, out = nil)
|
72
|
+
map = {map => out} if out
|
73
|
+
do_send(CMDS[:switch], build_switch_data(map))
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def switch_video(map, out = nil)
|
78
|
+
map = {map => out} if out
|
79
|
+
do_send(CMDS[:switch_video], build_switch_data(map))
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def switch_audio(map, out = nil)
|
84
|
+
map = {map => out} if out
|
85
|
+
do_send(CMDS[:switch_audio], build_switch_data(map))
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def mute_video(out, state = true)
|
90
|
+
data = is_affirmative?(state) ? 1 : 0
|
91
|
+
do_send(CMDS[:video_mute], out, data)
|
92
|
+
end
|
93
|
+
|
94
|
+
def mute_audio(out, state = true)
|
95
|
+
data = is_affirmative?(state) ? 1 : 0
|
96
|
+
do_send(CMDS[:audio_mute], out, data)
|
97
|
+
end
|
98
|
+
|
99
|
+
def unmute_video(out)
|
100
|
+
mute_video out, false
|
101
|
+
end
|
102
|
+
|
103
|
+
def unmute_audio(out)
|
104
|
+
mute_audio out, false
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def received(data, resolve, command)
|
109
|
+
logger.debug "Kramer sent #{data}"
|
110
|
+
|
111
|
+
# Extract and check the machine number if we've defined it
|
112
|
+
components = data.split('@')
|
113
|
+
if components.length > 1
|
114
|
+
machine = components[0]
|
115
|
+
if @device_id && machine != @device_id
|
116
|
+
return :ignore
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
data = components[-1].strip
|
121
|
+
components = data.split(/\s+|,/)
|
122
|
+
|
123
|
+
cmd = components[0]
|
124
|
+
args = components[1..-1]
|
125
|
+
|
126
|
+
if cmd == 'OK'
|
127
|
+
return :success
|
128
|
+
elsif cmd[0..2] == 'ERR' || args[0][0..2] == 'ERR'
|
129
|
+
if cmd[0..2] == 'ERR'
|
130
|
+
error = cmd[3..-1]
|
131
|
+
errfor = nil
|
132
|
+
else
|
133
|
+
error = args[0][3..-1]
|
134
|
+
errfor = " on #{cmd}"
|
135
|
+
end
|
136
|
+
logger.error "Kramer command error #{error}#{errfor}"
|
137
|
+
self[:last_error] = error
|
138
|
+
return :abort
|
139
|
+
end
|
140
|
+
|
141
|
+
case CMDS[cmd.to_sym]
|
142
|
+
when :info
|
143
|
+
self[:video_inputs] = args[1].to_i
|
144
|
+
self[:video_outputs] = args[3].to_i
|
145
|
+
when :route
|
146
|
+
inout = args[0].split(',')
|
147
|
+
layer = inout[0].to_i
|
148
|
+
dest = inout[1].to_i
|
149
|
+
src = inout[2].to_i
|
150
|
+
self[:"#{LAYERS[layer]}#{dest}"] = src
|
151
|
+
when :switch, :switch_audio, :switch_video
|
152
|
+
# return string like "in>out,in>out,in>out"
|
153
|
+
|
154
|
+
type = :av
|
155
|
+
type = :audio if CMDS[cmd] == :switch_audio
|
156
|
+
type = :video if CMDS[cmd] == :switch_video
|
157
|
+
|
158
|
+
mappings = args[0].split(',')
|
159
|
+
mappings.each do |map|
|
160
|
+
inout = map.split('>')
|
161
|
+
self[:"#{type}#{inout[1]}"] = inout[0].to_i
|
162
|
+
end
|
163
|
+
when :audio_mute
|
164
|
+
output, mute = args[0].split(',')
|
165
|
+
self[:"audio#{output}_muted"] = mute == '1'
|
166
|
+
when :video_mute
|
167
|
+
output, mute = args[0].split(',')
|
168
|
+
self[:"video#{output}_muted"] = mute == '1'
|
169
|
+
end
|
170
|
+
|
171
|
+
return :success
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
CMDS = {
|
176
|
+
info: :"INFO-IO?",
|
177
|
+
login: :"LOGIN",
|
178
|
+
route: :"ROUTE",
|
179
|
+
switch: :"AV",
|
180
|
+
switch_audio: :"AUD",
|
181
|
+
switch_video: :"VID",
|
182
|
+
audio_mute: :"MUTE",
|
183
|
+
video_mute: :"VMUTE"
|
184
|
+
}
|
185
|
+
CMDS.merge!(CMDS.invert)
|
186
|
+
|
187
|
+
LAYERS = {
|
188
|
+
1 => :video,
|
189
|
+
2 => :audio,
|
190
|
+
2 => :data
|
191
|
+
}
|
192
|
+
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
|
197
|
+
def build_switch_data(map)
|
198
|
+
data = ''
|
199
|
+
|
200
|
+
map.each do |input, outputs|
|
201
|
+
outputs = [outputs] unless outputs.class == Array
|
202
|
+
input = input.to_s if input.class == Symbol
|
203
|
+
input = input.to_i if input.class == String
|
204
|
+
outputs.each do |output|
|
205
|
+
data << "#{input}>#{output},"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
data.chop
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
def protocol_handshake
|
214
|
+
do_send('', {priority: 99})
|
215
|
+
end
|
216
|
+
|
217
|
+
def login
|
218
|
+
if @login_level
|
219
|
+
do_send(CMDS[:login], @password, {priority: 99})
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_machine_info
|
224
|
+
do_send(CMDS[:info], {priority: 99})
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def do_send(command, *args)
|
229
|
+
options = {}
|
230
|
+
if args[-1].is_a? Hash
|
231
|
+
options = args.pop
|
232
|
+
end
|
233
|
+
|
234
|
+
cmd = "##{@destination}#{command}"
|
235
|
+
|
236
|
+
if args.length > 0
|
237
|
+
cmd << " #{args.join(',')}"
|
238
|
+
end
|
239
|
+
cmd << "\r"
|
240
|
+
|
241
|
+
send(cmd, options)
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,482 @@
|
|
1
|
+
module Nec; end
|
2
|
+
module Nec::Display; end
|
3
|
+
|
4
|
+
# :title:All NEC Control Module
|
5
|
+
#
|
6
|
+
# Controls all LCD displays as of 1/07/2011
|
7
|
+
# Status information avaliable:
|
8
|
+
# -----------------------------
|
9
|
+
#
|
10
|
+
# (built in)
|
11
|
+
# connected
|
12
|
+
#
|
13
|
+
# (module defined)
|
14
|
+
# power
|
15
|
+
# warming
|
16
|
+
#
|
17
|
+
# volume
|
18
|
+
# volume_min == 0
|
19
|
+
# volume_max
|
20
|
+
#
|
21
|
+
# brightness
|
22
|
+
# brightness_min == 0
|
23
|
+
# brightness_max
|
24
|
+
#
|
25
|
+
# contrast
|
26
|
+
# contrast_min = 0
|
27
|
+
# contrast_max
|
28
|
+
#
|
29
|
+
# audio_mute
|
30
|
+
#
|
31
|
+
# input (video input)
|
32
|
+
# audio (audio input)
|
33
|
+
#
|
34
|
+
#
|
35
|
+
class Nec::Display::All
|
36
|
+
include ::Orchestrator::Constants
|
37
|
+
include ::Orchestrator::Transcoder
|
38
|
+
|
39
|
+
#
|
40
|
+
# Called on module load complete
|
41
|
+
# Alternatively you can use initialize however will
|
42
|
+
# not have access to settings and this is called
|
43
|
+
# soon afterwards
|
44
|
+
#
|
45
|
+
def on_load
|
46
|
+
#
|
47
|
+
# Setup constants
|
48
|
+
#
|
49
|
+
self[:volume_min] = 0
|
50
|
+
self[:brightness_min] = 0
|
51
|
+
self[:contrast_min] = 0
|
52
|
+
#self[:error] = [] TODO!!
|
53
|
+
end
|
54
|
+
|
55
|
+
def response_delimiter # Function required if device could contacts us first
|
56
|
+
0x0D
|
57
|
+
end
|
58
|
+
|
59
|
+
def connected
|
60
|
+
do_poll
|
61
|
+
|
62
|
+
@polling_timer = schedule.every('30s') do
|
63
|
+
logger.debug "-- Polling Display"
|
64
|
+
do_poll
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def disconnected
|
69
|
+
#
|
70
|
+
# Disconnected may be called without calling connected
|
71
|
+
# Hence the check if timer is nil here
|
72
|
+
#
|
73
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
74
|
+
@polling_timer = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
#
|
79
|
+
# Power commands
|
80
|
+
#
|
81
|
+
def power(state)
|
82
|
+
message = "C203D6"
|
83
|
+
|
84
|
+
power? do |result|
|
85
|
+
if is_affirmative?(state)
|
86
|
+
if result == Off
|
87
|
+
message += "0001" # Power On
|
88
|
+
send_checksum(:command, message, {:name => :power})
|
89
|
+
self[:warming] = true
|
90
|
+
self[:power] = On
|
91
|
+
logger.debug "-- NEC LCD, requested to power on"
|
92
|
+
|
93
|
+
power_on_delay
|
94
|
+
mute_status(0)
|
95
|
+
volume_status(0)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
if result == On
|
99
|
+
message += "0004" # Power Off
|
100
|
+
send_checksum(:command, message, {:name => :power})
|
101
|
+
|
102
|
+
self[:power] = Off
|
103
|
+
logger.debug "-- NEC LCD, requested to power off"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def power?(options = {}, &block)
|
110
|
+
options[:emit] = block if block_given?
|
111
|
+
type = :command
|
112
|
+
message = "01D6"
|
113
|
+
send_checksum(type, message, options)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
#
|
118
|
+
# Input selection
|
119
|
+
#
|
120
|
+
INPUTS = {
|
121
|
+
:vga => 1,
|
122
|
+
:rgbhv => 2,
|
123
|
+
:dvi => 3,
|
124
|
+
:hdmi_set => 4, # Set only?
|
125
|
+
:video1 => 5,
|
126
|
+
:video2 => 6,
|
127
|
+
:svideo => 7,
|
128
|
+
|
129
|
+
:tv => 10,
|
130
|
+
:dvd1 => 12,
|
131
|
+
:option => 13,
|
132
|
+
:dvd2 => 14,
|
133
|
+
:display_port => 15,
|
134
|
+
|
135
|
+
:hdmi => 17
|
136
|
+
}
|
137
|
+
def switch_to(input)
|
138
|
+
input = input.to_sym if input.class == String
|
139
|
+
#self[:target_input] = input
|
140
|
+
|
141
|
+
type = :set_parameter
|
142
|
+
message = OPERATION_CODE[:video_input]
|
143
|
+
message += INPUTS[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
|
144
|
+
|
145
|
+
send_checksum(type, message, {:name => :input})
|
146
|
+
brightness_status(60) # higher status than polling commands - lower than input switching
|
147
|
+
contrast_status(60)
|
148
|
+
|
149
|
+
logger.debug "-- NEC LCD, requested to switch to: #{input}"
|
150
|
+
end
|
151
|
+
|
152
|
+
AUDIO = {
|
153
|
+
:audio1 => 1,
|
154
|
+
:audio2 => 2,
|
155
|
+
:audio3 => 3,
|
156
|
+
:hdmi => 4,
|
157
|
+
:tv => 6,
|
158
|
+
:display_port => 7
|
159
|
+
}
|
160
|
+
def switch_audio(input)
|
161
|
+
input = input.to_sym if input.class == String
|
162
|
+
#self[:target_audio] = input
|
163
|
+
|
164
|
+
type = :set_parameter
|
165
|
+
message = OPERATION_CODE[:audio_input]
|
166
|
+
message += AUDIO[input].to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
|
167
|
+
|
168
|
+
send_checksum(type, message, :name => :audio)
|
169
|
+
mute_status(60) # higher status than polling commands - lower than input switching
|
170
|
+
volume_status(60)
|
171
|
+
|
172
|
+
logger.debug "-- NEC LCD, requested to switch audio to: #{input}"
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
#
|
177
|
+
# Auto adjust
|
178
|
+
#
|
179
|
+
def auto_adjust
|
180
|
+
message = OPERATION_CODE[:auto_setup] #"001E" # Page + OP code
|
181
|
+
message += "0001" # Value of input as a hex string
|
182
|
+
|
183
|
+
send_checksum(:set_parameter, message, :delay_on_receive => 4.0)
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
#
|
188
|
+
# Value based set parameter
|
189
|
+
#
|
190
|
+
def brightness(val)
|
191
|
+
val = val.to_i if val.is_a? String
|
192
|
+
val = 100 if val > 100
|
193
|
+
val = 0 if val < 0
|
194
|
+
|
195
|
+
message = OPERATION_CODE[:brightness_status]
|
196
|
+
message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
|
197
|
+
|
198
|
+
brightness_status
|
199
|
+
send_checksum(:set_parameter, message)
|
200
|
+
send_checksum(:command, '0C') # Save the settings
|
201
|
+
end
|
202
|
+
|
203
|
+
def contrast(val)
|
204
|
+
val = val.to_i if val.is_a? String
|
205
|
+
val = 100 if val > 100
|
206
|
+
val = 0 if val < 0
|
207
|
+
|
208
|
+
message = OPERATION_CODE[:contrast_status]
|
209
|
+
message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
|
210
|
+
|
211
|
+
contrast_status
|
212
|
+
send_checksum(:set_parameter, message)
|
213
|
+
send_checksum(:command, '0C') # Save the settings
|
214
|
+
end
|
215
|
+
|
216
|
+
def volume(val)
|
217
|
+
val = val.to_i if val.is_a? String
|
218
|
+
val = 100 if val > 100
|
219
|
+
val = 0 if val < 0
|
220
|
+
|
221
|
+
message = OPERATION_CODE[:volume_status]
|
222
|
+
message += val.to_s(16).upcase.rjust(4, '0') # Value of input as a hex string
|
223
|
+
|
224
|
+
volume_status
|
225
|
+
send_checksum(:set_parameter, message)
|
226
|
+
send_checksum(:command, '0C') # Save the settings
|
227
|
+
|
228
|
+
self[:audio_mute] = false # audio is unmuted when the volume is set
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def mute_audio
|
233
|
+
message = OPERATION_CODE[:mute_status]
|
234
|
+
message += "0001" # Value of input as a hex string
|
235
|
+
|
236
|
+
send_checksum(:set_parameter, message)
|
237
|
+
|
238
|
+
logger.debug "-- NEC LCD, requested to mute audio"
|
239
|
+
end
|
240
|
+
alias_method :mute, :mute_audio
|
241
|
+
|
242
|
+
def unmute_audio
|
243
|
+
message = OPERATION_CODE[:mute_status]
|
244
|
+
message += "0000" # Value of input as a hex string
|
245
|
+
|
246
|
+
send_checksum(:set_parameter, message)
|
247
|
+
|
248
|
+
logger.debug "-- NEC LCD, requested to unmute audio"
|
249
|
+
end
|
250
|
+
alias_method :unmute, :unmute_audio
|
251
|
+
|
252
|
+
#
|
253
|
+
# LCD Response code
|
254
|
+
#
|
255
|
+
def received(data, resolve, command)
|
256
|
+
#
|
257
|
+
# Check for valid response
|
258
|
+
#
|
259
|
+
if !check_checksum(data)
|
260
|
+
logger.debug "-- NEC LCD, checksum failed for command: #{command[:data]}"
|
261
|
+
logger.debug "-- NEC LCD, response was: #{data}"
|
262
|
+
return false
|
263
|
+
end
|
264
|
+
|
265
|
+
#data = array_to_str(data) # Convert bytes to a string (received like this)
|
266
|
+
|
267
|
+
case MSG_TYPE[data[4]] # Check the MSG_TYPE (B, D or F)
|
268
|
+
when :command_reply
|
269
|
+
#
|
270
|
+
# Power on and off
|
271
|
+
# 8..9 == "00" means no error
|
272
|
+
if data[10..15] == "C203D6" # Means power comamnd
|
273
|
+
if data[8..9] == "00"
|
274
|
+
power_on_delay(0) # wait until the screen has turned on before sending commands (0 == high priority)
|
275
|
+
else
|
276
|
+
logger.info "-- NEC LCD, command failed: #{command[:data]}"
|
277
|
+
logger.info "-- NEC LCD, response was: #{data}"
|
278
|
+
return false # command failed
|
279
|
+
end
|
280
|
+
elsif data[10..13] == "00D6" # Power status response
|
281
|
+
if data[10..11] == "00"
|
282
|
+
if data[23] == '1' # On == 1, Off == 4
|
283
|
+
self[:power] = On
|
284
|
+
else
|
285
|
+
self[:power] = Off
|
286
|
+
self[:warming] = false
|
287
|
+
end
|
288
|
+
#if self[:power_target].nil?
|
289
|
+
# self[:power_target] = self[:power]
|
290
|
+
#elsif self[:power_target] != self[:power]
|
291
|
+
# power(self[:power_target])
|
292
|
+
#end
|
293
|
+
else
|
294
|
+
logger.info "-- NEC LCD, command failed: #{command[:data]}"
|
295
|
+
logger.info "-- NEC LCD, response was: #{data}"
|
296
|
+
return false # command failed
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
when :get_parameter_reply, :set_parameter_reply
|
302
|
+
if data[8..9] == "00"
|
303
|
+
parse_response(data, command)
|
304
|
+
elsif data[8..9] == 'BE' # Wait response
|
305
|
+
send(command[:data]) # checksum already added
|
306
|
+
logger.debug "-- NEC LCD, response was a wait command"
|
307
|
+
else
|
308
|
+
logger.info "-- NEC LCD, get or set failed: #{command[:data]}"
|
309
|
+
logger.info "-- NEC LCD, response was: #{data}"
|
310
|
+
return false
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
return true # Command success
|
315
|
+
end
|
316
|
+
|
317
|
+
|
318
|
+
def do_poll
|
319
|
+
power?({:priority => 99}) do |result|
|
320
|
+
if result == On
|
321
|
+
power_on_delay
|
322
|
+
mute_status
|
323
|
+
volume_status
|
324
|
+
brightness_status
|
325
|
+
contrast_status
|
326
|
+
video_input
|
327
|
+
audio_input
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
private
|
334
|
+
|
335
|
+
|
336
|
+
def parse_response(data, command)
|
337
|
+
|
338
|
+
# 14..15 == type (we don't care)
|
339
|
+
max = data[16..19].to_i(16)
|
340
|
+
value = data[20..23].to_i(16)
|
341
|
+
|
342
|
+
case OPERATION_CODE[data[10..13]]
|
343
|
+
when :video_input
|
344
|
+
self[:input] = INPUTS.invert[value]
|
345
|
+
#self[:target_input] = self[:input] if self[:target_input].nil?
|
346
|
+
#switch_to(self[:target_input]) unless self[:input] == self[:target_input]
|
347
|
+
|
348
|
+
when :audio_input
|
349
|
+
self[:audio] = AUDIO.invert[value]
|
350
|
+
#self[:target_audio] = self[:audio] if self[:target_audio].nil?
|
351
|
+
#switch_audio(self[:target_audio]) unless self[:audio] == self[:target_audio]
|
352
|
+
|
353
|
+
when :volume_status
|
354
|
+
self[:volume_max] = max
|
355
|
+
if not self[:audio_mute]
|
356
|
+
self[:volume] = value
|
357
|
+
end
|
358
|
+
|
359
|
+
when :brightness_status
|
360
|
+
self[:brightness_max] = max
|
361
|
+
self[:brightness] = value
|
362
|
+
|
363
|
+
when :contrast_status
|
364
|
+
self[:contrast_max] = max
|
365
|
+
self[:contrast] = value
|
366
|
+
|
367
|
+
when :mute_status
|
368
|
+
self[:audio_mute] = value == 1
|
369
|
+
if(value == 1)
|
370
|
+
self[:volume] = 0
|
371
|
+
else
|
372
|
+
volume_status(0) # high priority
|
373
|
+
end
|
374
|
+
|
375
|
+
when :power_on_delay
|
376
|
+
if value > 0
|
377
|
+
self[:warming] = true
|
378
|
+
schedule.in("#{value}s") do # Prevent any commands being sent until the power on delay is complete
|
379
|
+
power_on_delay
|
380
|
+
end
|
381
|
+
else
|
382
|
+
schedule.in('3s') do # Reactive the interface once the display is online
|
383
|
+
self[:warming] = false # allow access to the display
|
384
|
+
end
|
385
|
+
end
|
386
|
+
when :auto_setup
|
387
|
+
# auto_setup
|
388
|
+
# nothing needed to do here (we are delaying the next command by 4 seconds)
|
389
|
+
else
|
390
|
+
logger.info "-- NEC LCD, unknown response: #{data[10..13]}"
|
391
|
+
logger.info "-- NEC LCD, for command: #{command[:data]}"
|
392
|
+
logger.info "-- NEC LCD, full response was: #{data}"
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
#
|
398
|
+
# Types of messages sent to and from the LCD
|
399
|
+
#
|
400
|
+
MSG_TYPE = {
|
401
|
+
:command => 'A',
|
402
|
+
'B' => :command_reply,
|
403
|
+
:get_parameter => 'C',
|
404
|
+
'D' => :get_parameter_reply,
|
405
|
+
:set_parameter => 'E',
|
406
|
+
'F' => :set_parameter_reply
|
407
|
+
}
|
408
|
+
|
409
|
+
|
410
|
+
OPERATION_CODE = {
|
411
|
+
:video_input => '0060', '0060' => :video_input,
|
412
|
+
:audio_input => '022E', '022E' => :audio_input,
|
413
|
+
:volume_status => '0062', '0062' => :volume_status,
|
414
|
+
:mute_status => '008D', '008D' => :mute_status,
|
415
|
+
:power_on_delay => '02D8', '02D8' => :power_on_delay,
|
416
|
+
:contrast_status => '0012', '0012' => :contrast_status,
|
417
|
+
:brightness_status => '0010', '0010' => :brightness_status,
|
418
|
+
:auto_setup => '001E', '001E' => :auto_setup
|
419
|
+
}
|
420
|
+
#
|
421
|
+
# Automatically creates a callable function for each command
|
422
|
+
# http://blog.jayfields.com/2007/10/ruby-defining-class-methods.html
|
423
|
+
# http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
|
424
|
+
#
|
425
|
+
OPERATION_CODE.each_key do |command|
|
426
|
+
define_method command do |*args|
|
427
|
+
priority = 99
|
428
|
+
if args.length > 0
|
429
|
+
priority = args[0]
|
430
|
+
end
|
431
|
+
message = OPERATION_CODE[command]
|
432
|
+
send_checksum(:get_parameter, message, {:priority => priority}) # Status polling is a low priority
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
|
437
|
+
def check_checksum(data)
|
438
|
+
data = str_to_array(data)
|
439
|
+
|
440
|
+
check = 0
|
441
|
+
#
|
442
|
+
# Loop through the second to the second last element
|
443
|
+
# Delimiter is removed automatically
|
444
|
+
#
|
445
|
+
if data.length >= 2
|
446
|
+
data[1..-2].each do |byte|
|
447
|
+
check = check ^ byte
|
448
|
+
end
|
449
|
+
return check == data[-1] # Check the check sum equals the last element
|
450
|
+
else
|
451
|
+
return true
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
|
456
|
+
#
|
457
|
+
# Builds the command and creates the checksum
|
458
|
+
#
|
459
|
+
def send_checksum(type, command, options = {})
|
460
|
+
#
|
461
|
+
# build header + command and convert to a byte array
|
462
|
+
#
|
463
|
+
command = "" << 0x02 << command << 0x03
|
464
|
+
command = "0*0#{MSG_TYPE[type]}#{command.length.to_s(16).upcase.rjust(2, '0')}#{command}"
|
465
|
+
command = str_to_array(command)
|
466
|
+
|
467
|
+
#
|
468
|
+
# build checksum
|
469
|
+
#
|
470
|
+
check = 0
|
471
|
+
command.each do |byte|
|
472
|
+
check = check ^ byte
|
473
|
+
end
|
474
|
+
|
475
|
+
command << check # Add checksum
|
476
|
+
command << 0x0D # delimiter required by NEC displays
|
477
|
+
command.insert(0, 0x01) # insert SOH byte (not part of the checksum)
|
478
|
+
|
479
|
+
send(command, options)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|