aca-device-modules 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,125 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
module Biamp; end
|
4
|
+
|
5
|
+
# TELNET port 23
|
6
|
+
|
7
|
+
class Biamp::Nexia
|
8
|
+
include ::Orchestrator::Constants
|
9
|
+
include ::Orchestrator::Transcoder
|
10
|
+
|
11
|
+
def on_load
|
12
|
+
self[:fader_min] = -36 # specifically for tonsley
|
13
|
+
self[:fader_max] = 12
|
14
|
+
|
15
|
+
# max +12
|
16
|
+
# min -100
|
17
|
+
|
18
|
+
config({
|
19
|
+
tokenize: true,
|
20
|
+
delimiter: /\xFF\xFE\x01|\r\n/
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_unload
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_update
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def connected
|
32
|
+
send("\xFF\xFE\x01") # Echo off
|
33
|
+
do_send('GETD', 0, 'DEVID')
|
34
|
+
|
35
|
+
@polling_timer = schedule.every('60s') do
|
36
|
+
do_send('GETD', 0, 'DEVID')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def disconnected
|
41
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
42
|
+
@polling_timer = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def preset(number)
|
47
|
+
#
|
48
|
+
# Recall Device 0 Preset number 1001
|
49
|
+
# Device Number will always be 0 for Preset strings
|
50
|
+
# 1001 == minimum preset number
|
51
|
+
#
|
52
|
+
do_send('RECALL', 0, 'PRESET', number)
|
53
|
+
end
|
54
|
+
|
55
|
+
def fader(fader_id, level)
|
56
|
+
# value range: -100 ~ 12
|
57
|
+
do_send('SETD', self[:device_id], 'FDRLVL', fader_id, 1, level)
|
58
|
+
end
|
59
|
+
|
60
|
+
def mute(fader_id)
|
61
|
+
do_send('SETD', self[:device_id], 'FDRMUTE', fader_id, 1, 1)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unmute(fader_id)
|
65
|
+
do_send('SETD', self[:device_id], 'FDRMUTE', fader_id, 1, 0)
|
66
|
+
end
|
67
|
+
|
68
|
+
def query_fader(fader_id)
|
69
|
+
send("GET #{self[:device_id]} FDRLVL #{fader_id} 1 \n") do |data|
|
70
|
+
if data == "-ERR"
|
71
|
+
:abort
|
72
|
+
else
|
73
|
+
self[:"fader_#{fader_id}"] = data.to_i
|
74
|
+
:success
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def query_mute(fader_id)
|
80
|
+
send("GET #{self[:device_id]} FDRMUTE #{fader_id} 1 \n") do |data|
|
81
|
+
if data == "-ERR"
|
82
|
+
:abort
|
83
|
+
else
|
84
|
+
self[:"fader_#{fader_id}_mute"] = data.to_i == 1
|
85
|
+
:success
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def received(data, resolve, command)
|
92
|
+
data = data.split(' ')
|
93
|
+
|
94
|
+
if data.length == 1
|
95
|
+
if data[-1] == "-ERR"
|
96
|
+
logger.debug "Nexia Invalid Command sent #{command[:data]}" if !!command
|
97
|
+
return :abort
|
98
|
+
end
|
99
|
+
return :success # data[-1] == "+OK" || data == "" # Echo off
|
100
|
+
end
|
101
|
+
|
102
|
+
unless data[2].nil?
|
103
|
+
case data[2].to_sym
|
104
|
+
when :FDRLVL
|
105
|
+
self[:"fader_#{data[3]}"] = data[-2].to_i
|
106
|
+
when :FDRMUTE
|
107
|
+
self[:"fader_#{data[3]}_mute"] = data[-2] == "1"
|
108
|
+
when :DEVID
|
109
|
+
self[:device_id] = data[-2].to_i
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
return :success
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
|
121
|
+
def do_send(*args)
|
122
|
+
send("#{args.join(' ')}\n")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
@@ -0,0 +1,265 @@
|
|
1
|
+
module Bss; end
|
2
|
+
|
3
|
+
# TCP port 1023
|
4
|
+
|
5
|
+
class Bss::Blu100
|
6
|
+
include ::Orchestrator::Constants
|
7
|
+
include ::Orchestrator::Transcoder
|
8
|
+
|
9
|
+
def on_load
|
10
|
+
defaults({
|
11
|
+
:wait => false
|
12
|
+
})
|
13
|
+
config({
|
14
|
+
tokenize: true,
|
15
|
+
delimiter: "\x03",
|
16
|
+
indicator: "\x02"
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_unload
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_update
|
24
|
+
end
|
25
|
+
|
26
|
+
def connected
|
27
|
+
subscribe_percent(1, 60000)
|
28
|
+
@polling_timer = schedule.every('150s') do # Every 2.5 min
|
29
|
+
subscribe_percent(1, 60000) # Request the level of Hybrid I/O Card A
|
30
|
+
end # This works to maintain the connection
|
31
|
+
end
|
32
|
+
|
33
|
+
def disconnected
|
34
|
+
#
|
35
|
+
# Disconnected may be called without calling connected
|
36
|
+
# Hence the check if timer is nil here
|
37
|
+
#
|
38
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
39
|
+
@polling_timer = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
OPERATION_CODE = {
|
44
|
+
:set_state => 0x88,
|
45
|
+
:subscribe_state => 0x89,
|
46
|
+
:unsubscribe_state => 0x8A,
|
47
|
+
:venue_preset => 0x8B,
|
48
|
+
:param_preset => 0x8C,
|
49
|
+
:set_percent => 0x8D,
|
50
|
+
:subscribe_percent => 0x8E,
|
51
|
+
:unsubscribe_percent => 0x8F,
|
52
|
+
:set_relative_percent => 0x90
|
53
|
+
}
|
54
|
+
OPERATION_CODE.merge!(OPERATION_CODE.invert)
|
55
|
+
|
56
|
+
|
57
|
+
def preset(number)
|
58
|
+
number = number.to_i
|
59
|
+
|
60
|
+
do_send([OPERATION_CODE[:venue_preset]] + number_to_data(number))
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# Level controls
|
66
|
+
#
|
67
|
+
def fader(fader, percent)
|
68
|
+
percent = percent.to_i
|
69
|
+
percent = 6553600 if percent > 6553600
|
70
|
+
percent = 0 if percent < 0
|
71
|
+
|
72
|
+
percent = number_to_data(percent)
|
73
|
+
|
74
|
+
do_send([OPERATION_CODE[:set_percent]] + NODE + VIRTUAL + number_to_object(fader.to_i) + CONTROLS[:gain] + percent)
|
75
|
+
subscribe_percent(fader)
|
76
|
+
end
|
77
|
+
|
78
|
+
def mute(fader)
|
79
|
+
do_send([OPERATION_CODE[:set_state]] + NODE + VIRTUAL + number_to_object(fader.to_i) + CONTROLS[:mute] + number_to_data(1))
|
80
|
+
subscribe_state(fader)
|
81
|
+
end
|
82
|
+
|
83
|
+
def unmute(fader)
|
84
|
+
do_send([OPERATION_CODE[:set_state]] + NODE + VIRTUAL + number_to_object(fader.to_i) + CONTROLS[:mute] + number_to_data(0))
|
85
|
+
subscribe_state(fader)
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def query_fader(fader_id)
|
90
|
+
subscribe_percent(fader_id)
|
91
|
+
end
|
92
|
+
|
93
|
+
def query_mute(fader_id)
|
94
|
+
subscribe_state(fader_id)
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
#
|
99
|
+
# Percent controls for relative values
|
100
|
+
#
|
101
|
+
def subscribe_percent(fader, rate = 0, control = CONTROLS[:gain]) # rate must be 0 for non meter controls
|
102
|
+
fader = number_to_object(fader.to_i)
|
103
|
+
rate = number_to_data(rate.to_i)
|
104
|
+
|
105
|
+
do_send([OPERATION_CODE[:subscribe_percent]] + NODE + VIRTUAL + fader + control + rate)
|
106
|
+
end
|
107
|
+
|
108
|
+
def unsubscribe_percent(fader, control = CONTROLS[:gain]) # rate must be 0 for non meter controls
|
109
|
+
fader = number_to_object(fader.to_i)
|
110
|
+
rate = number_to_data(0)
|
111
|
+
|
112
|
+
do_send([OPERATION_CODE[:unsubscribe_percent]] + NODE + VIRTUAL + fader + control + rate)
|
113
|
+
end
|
114
|
+
|
115
|
+
#
|
116
|
+
# State controls are for discrete values
|
117
|
+
#
|
118
|
+
def subscribe_state(fader, rate = 0, control = CONTROLS[:mute]) # 1000 == every second
|
119
|
+
fader = number_to_object(fader.to_i)
|
120
|
+
rate = number_to_data(rate.to_i)
|
121
|
+
|
122
|
+
do_send([OPERATION_CODE[:subscribe_state]] + NODE + VIRTUAL + fader + control + rate)
|
123
|
+
end
|
124
|
+
|
125
|
+
def unsubscribe_state(fader, control = CONTROLS[:mute]) # 1000 == every second
|
126
|
+
fader = number_to_object(fader.to_i)
|
127
|
+
rate = number_to_data(0)
|
128
|
+
|
129
|
+
do_send([OPERATION_CODE[:unsubscribe_state]] + NODE + VIRTUAL + fader + control + rate)
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def received(data, resolve, command)
|
134
|
+
#
|
135
|
+
# Grab the message body
|
136
|
+
#
|
137
|
+
data = data.split("\x02")
|
138
|
+
data = str_to_array(data[-1])
|
139
|
+
|
140
|
+
#
|
141
|
+
# Unescape any control characters
|
142
|
+
#
|
143
|
+
message = []
|
144
|
+
found = false
|
145
|
+
data.each do |byte|
|
146
|
+
if found
|
147
|
+
found = false
|
148
|
+
message << (byte - 0x80)
|
149
|
+
elsif RESERVED_CHARS.include? byte
|
150
|
+
found = true
|
151
|
+
else
|
152
|
+
message << byte
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Process the response
|
158
|
+
#
|
159
|
+
if check_checksum(message)
|
160
|
+
logger.debug "Blu100 sent 0x#{byte_to_hex(array_to_str(message))}"
|
161
|
+
|
162
|
+
data = byte_to_hex(array_to_str(message[-4..-1])).to_i(16)
|
163
|
+
type = message[0] # Always sent
|
164
|
+
|
165
|
+
node = message[1..2]
|
166
|
+
vi = message[3]
|
167
|
+
obj = message[4..6]
|
168
|
+
cntrl = message[7..8]
|
169
|
+
|
170
|
+
case OPERATION_CODE[type]
|
171
|
+
when :set_state # This is the mute response
|
172
|
+
obj = byte_to_hex(array_to_str(obj)).to_i(16)
|
173
|
+
if CONTROLS[cntrl] == :mute
|
174
|
+
self[:"fader_#{obj}_mute"] = data == 1
|
175
|
+
else
|
176
|
+
self[:"fader_#{obj}"] = data
|
177
|
+
end
|
178
|
+
when :subscribe_state
|
179
|
+
when :unsubscribe_state
|
180
|
+
when :venue_preset
|
181
|
+
when :param_preset
|
182
|
+
when :set_percent # This is the fader response
|
183
|
+
obj = byte_to_hex(array_to_str(obj)).to_i(16)
|
184
|
+
self[:"fader_#{obj}"] = data
|
185
|
+
when :subscribe_percent
|
186
|
+
when :unsubscribe_percent
|
187
|
+
when :set_relative_percent
|
188
|
+
end
|
189
|
+
|
190
|
+
return :success
|
191
|
+
else
|
192
|
+
logger.warn "Blu100 Checksum error: 0x#{byte_to_hex(array_to_str(message))}"
|
193
|
+
return :failed
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
protected
|
199
|
+
|
200
|
+
|
201
|
+
def number_to_data(num)
|
202
|
+
str_to_array(hex_to_byte(num.to_s(16).upcase.rjust(8, '0')))
|
203
|
+
end
|
204
|
+
|
205
|
+
def number_to_object(num)
|
206
|
+
str_to_array(hex_to_byte(num.to_s(16).upcase.rjust(6, '0')))
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
RESERVED_CHARS = [0x02, 0x03, 0x06, 0x15, 0x1B]
|
211
|
+
NODE = [0,0] # node we are connected to
|
212
|
+
VIRTUAL = [3] # virtual device is always 3 for audio devices
|
213
|
+
|
214
|
+
CONTROLS = {
|
215
|
+
:gain => [0,0],
|
216
|
+
:mute => [0,1]
|
217
|
+
}
|
218
|
+
CONTROLS.merge!(CONTROLS.invert)
|
219
|
+
|
220
|
+
|
221
|
+
def check_checksum(data)
|
222
|
+
#
|
223
|
+
# Loop through the second to the second last element
|
224
|
+
# Delimiter is removed automatically
|
225
|
+
#
|
226
|
+
check = 0
|
227
|
+
data[0..-2].each do |byte|
|
228
|
+
check = check ^ byte
|
229
|
+
end
|
230
|
+
return check == data.pop # Check the check sum equals the last element
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
def do_send(command, options = {})
|
236
|
+
#
|
237
|
+
# build checksum
|
238
|
+
#
|
239
|
+
check = 0
|
240
|
+
command.each do |byte|
|
241
|
+
check = check ^ byte
|
242
|
+
end
|
243
|
+
command = command + [check]
|
244
|
+
|
245
|
+
#
|
246
|
+
# Substitute reserved characters
|
247
|
+
#
|
248
|
+
substituted = []
|
249
|
+
command.each do |byte|
|
250
|
+
if RESERVED_CHARS.include? byte
|
251
|
+
substituted << 0x1B << (byte + 0x80)
|
252
|
+
else
|
253
|
+
substituted << byte
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
# Add the control characters
|
259
|
+
#
|
260
|
+
substituted.unshift 0x02
|
261
|
+
substituted << 0x03
|
262
|
+
|
263
|
+
send(substituted, options)
|
264
|
+
end
|
265
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
module Clipsal; end
|
2
|
+
|
3
|
+
|
4
|
+
#
|
5
|
+
# Common Headers
|
6
|
+
# 0x03 == point - point -multipoint, low pri
|
7
|
+
# 0x05 == point - multipoint, low pri
|
8
|
+
# 0x06 == point - point, low pri
|
9
|
+
#
|
10
|
+
# 11xxx110 (x == reserved)
|
11
|
+
# -- Priority, 11 == high, 00 == low
|
12
|
+
# --- Destination, 011 = P-P-M, 101 = P-M, 110 = P-P
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# Commands are formatted as: \ + Header + 00 + Data + checksum + <cr>
|
16
|
+
#
|
17
|
+
# Turn group on \ + 05 (MP header) + 38 (lighting) + 00 + 79 (group on) + XX (group number) + checksum + <cr>
|
18
|
+
# Turn group off \ + 05 (MP header) + 38 (lighting) + 00 + 01 (group off) + XX (group number) + checksum + <cr>
|
19
|
+
# Ramp a group \ + 05 (MP header) + 38 (lighting) + 00 + 79 (group on) + XX (group number) + checksum + <cr>
|
20
|
+
#
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
class Clipsal::CBus
|
25
|
+
include ::Orchestrator::Constants
|
26
|
+
include ::Orchestrator::Transcoder
|
27
|
+
|
28
|
+
def on_load
|
29
|
+
defaults({
|
30
|
+
:wait => false
|
31
|
+
})
|
32
|
+
|
33
|
+
config({
|
34
|
+
tokenize: true,
|
35
|
+
delimiter: "\x0D"
|
36
|
+
})
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_unload
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_update
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def connected
|
48
|
+
send("|||\r", :wait => false) # Ensure we are in smart mode
|
49
|
+
@polling_timer = schedule.every('60s') do
|
50
|
+
logger.debug "-- Polling CBUS"
|
51
|
+
send("|||\r", :wait => false) # Ensure we are in smart mode
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def disconnected
|
56
|
+
@polling_timer.cancel unless @polling_timer.nil?
|
57
|
+
@polling_timer = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def lighting(group, state, application = 0x38)
|
62
|
+
group = group & 0xFF
|
63
|
+
application = application & 0xFF
|
64
|
+
|
65
|
+
command = [0x05, application, 0x00]
|
66
|
+
if [On, 1, :on, 'on'].include?(state)
|
67
|
+
state = On
|
68
|
+
command << 0x79 # Group on
|
69
|
+
else
|
70
|
+
state = Off
|
71
|
+
command << 0x01 # Group off
|
72
|
+
end
|
73
|
+
command << group
|
74
|
+
|
75
|
+
self["lighting_group_#{group}"] = state
|
76
|
+
|
77
|
+
do_send(command)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def lighting_ramp(group, level, rate = 0b0001, application = 0x38)
|
82
|
+
|
83
|
+
#
|
84
|
+
# rates:
|
85
|
+
# => 0 == instant
|
86
|
+
# => 1 == 4sec
|
87
|
+
# => 2 == 8sec etc
|
88
|
+
#
|
89
|
+
rate = ((rate & 0x0F) << 3) | 0b010 # The command is structured as: 0b0 xxxx 010 where xxxx == rate
|
90
|
+
group = group & 0xFF
|
91
|
+
level = level & 0xFF
|
92
|
+
application = application & 0xFF
|
93
|
+
|
94
|
+
lighting_term_ramp(group)
|
95
|
+
command = [0x05, application, 0x00, rate, group, level]
|
96
|
+
|
97
|
+
do_send(command)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
def blinds(group, action, application = 0x38)
|
103
|
+
group = group & 0xFF
|
104
|
+
application = application & 0xFF
|
105
|
+
|
106
|
+
command = [0x05, application, 0x00]
|
107
|
+
if is_affirmative?(action)
|
108
|
+
action = Down
|
109
|
+
command += [0x1A, group, 0x00]
|
110
|
+
else
|
111
|
+
command += [0x02, group]
|
112
|
+
|
113
|
+
if is_negatory?(action)
|
114
|
+
action = Up
|
115
|
+
command << 0xFF
|
116
|
+
else
|
117
|
+
# Stop (need to confirm this)
|
118
|
+
command << 0x05
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
do_send(command)
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def trigger(group, action)
|
127
|
+
action = action.to_i
|
128
|
+
group = group.to_i
|
129
|
+
|
130
|
+
group = group & 0xFF
|
131
|
+
action = action & 0xFF
|
132
|
+
command = [0x05, 0xCA, 0x00, 0x02, group, action]
|
133
|
+
|
134
|
+
self["trigger_group_#{group}"] = action
|
135
|
+
|
136
|
+
do_send(command)
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
def trigger_kill(group)
|
141
|
+
group = group.to_i
|
142
|
+
|
143
|
+
group = group & 0xFF
|
144
|
+
command = [0x05, 0xCA, 0x00, 0x01, group]
|
145
|
+
do_send(command)
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def received(data, resolve, command)
|
150
|
+
# Debug here will sometimes have the \n char
|
151
|
+
# This is removed by the hex_to_byte function
|
152
|
+
logger.debug "CBus sent #{data}"
|
153
|
+
|
154
|
+
data = str_to_array(hex_to_byte(data))
|
155
|
+
|
156
|
+
if !check_checksum(data)
|
157
|
+
logger.debug "CBus checksum failed"
|
158
|
+
return :failed
|
159
|
+
end
|
160
|
+
|
161
|
+
# We are only looking at Point -> MultiPoint commands
|
162
|
+
return if data[0] != 0x05
|
163
|
+
# 0x03 == Point -> Point -> MultiPoint
|
164
|
+
# 0x06 == Point -> Point
|
165
|
+
|
166
|
+
application = data[2] # The application being referenced
|
167
|
+
commands = data[4..-2] # Remove the header + checksum
|
168
|
+
|
169
|
+
while commands.length > 0
|
170
|
+
current = commands.shift
|
171
|
+
|
172
|
+
case application
|
173
|
+
when 0xCA # Trigger group
|
174
|
+
case current
|
175
|
+
when 0x02 # Trigger Event (ex: 0504CA00 020101 29)
|
176
|
+
self["trigger_group_#{commands.shift}"] = commands.shift # Action selector
|
177
|
+
when 0x01 # Trigger Min
|
178
|
+
self["trigger_group_#{commands.shift}"] = 0
|
179
|
+
when 0x79 # Trigger Max
|
180
|
+
self["trigger_group_#{commands.shift}"] = 0xFF
|
181
|
+
when 0x09 # Indicator Kill (ex: 0504CA00 0901 23)
|
182
|
+
commands.shift # Group (turns off indicators of all scenes triggered by this group)
|
183
|
+
else
|
184
|
+
break # We don't know what data is here
|
185
|
+
end
|
186
|
+
when 0x30..0x5F # Lighting group
|
187
|
+
case current
|
188
|
+
when 0x01 # Group off (ex: 05043800 0101 0102 0103 0104 7905 33)
|
189
|
+
self["lighting_group_#{commands.shift}"] = Off
|
190
|
+
when 0x79 # Group on (ex: 05013800 7905 44)
|
191
|
+
self["lighting_group_#{commands.shift}"] = On
|
192
|
+
when 0x02 # Blinds up or stop
|
193
|
+
group = commands.shift
|
194
|
+
value = commands.shift
|
195
|
+
if value == 0xFF
|
196
|
+
self["blinds_group_#{group}"] = Up
|
197
|
+
elsif value == 0x05 # Value needs confirmation
|
198
|
+
self["blinds_group_#{group}"] = :stopped
|
199
|
+
end
|
200
|
+
when 0x1A # Blinds down
|
201
|
+
group = commands.shift
|
202
|
+
value = commands.shift
|
203
|
+
self["blinds_group_#{group}"] = Down if value == 0x00
|
204
|
+
when 0x09 # Terminate Ramp
|
205
|
+
commands.shift # Group address
|
206
|
+
else
|
207
|
+
if (current & 0b10000101) == 0 # Ramp to level (ex: 05013800 0205FF BC)
|
208
|
+
commands.shift(2) # Group address, level
|
209
|
+
else
|
210
|
+
break # We don't know what data is here
|
211
|
+
end
|
212
|
+
end
|
213
|
+
else
|
214
|
+
break # We haven't programmed this application
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
return :success
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
protected
|
223
|
+
|
224
|
+
|
225
|
+
def lighting_term_ramp(group)
|
226
|
+
command = [0x05, 0x38, 0x00, 0x09, group]
|
227
|
+
do_send(command)
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
def checksum(data)
|
232
|
+
check = 0
|
233
|
+
data.each do |byte|
|
234
|
+
check += byte
|
235
|
+
end
|
236
|
+
check = check % 0x100
|
237
|
+
check = ((check ^ 0xFF) + 1) & 0xFF
|
238
|
+
return check
|
239
|
+
end
|
240
|
+
|
241
|
+
def check_checksum(data)
|
242
|
+
check = 0
|
243
|
+
data.each do |byte|
|
244
|
+
check += byte
|
245
|
+
end
|
246
|
+
return (check % 0x100) == 0x00
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
def do_send(command, options = {})
|
251
|
+
string = byte_to_hex(array_to_str(command << checksum(command))).upcase
|
252
|
+
send("\\#{string}\r", options)
|
253
|
+
#logger.debug "CBus module sent #{string}"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|