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,256 @@
1
+ module Samsung; end
2
+ module Samsung::Displays; end
3
+
4
+
5
+ class Samsung::Displays::MdSeries
6
+ include ::Orchestrator::Constants
7
+ include ::Orchestrator::Transcoder
8
+
9
+ #
10
+ # Control system events
11
+ def on_load
12
+ on_update
13
+
14
+ self[:volume_min] = 0
15
+ self[:volume_max] = 100
16
+ self[:power] = false
17
+
18
+ config({
19
+ tokenize: proc {
20
+ ::UV::AbstractTokenizer.new({
21
+ indicator: "\xAA",
22
+ callback: method(:check_checksum)
23
+ })
24
+ }
25
+ })
26
+
27
+ # Meta data for inquiring interfaces
28
+ self[:type] = :lcd
29
+ self[:input_stable] = true
30
+ end
31
+
32
+ def on_unload
33
+ end
34
+
35
+ def on_update
36
+ @id = setting(:display_id) || 0xFF
37
+ end
38
+
39
+
40
+ #
41
+ # network events
42
+ def connected
43
+ do_poll
44
+
45
+ @polling_timer = schedule.every('30s') do
46
+ logger.debug "-- Polling Display"
47
+ do_poll
48
+ end
49
+ end
50
+
51
+ def disconnected
52
+ #
53
+ # Disconnected may be called without calling connected
54
+ # Hence the check if timer is nil here
55
+ #
56
+ self[:power] = false # As we may need to use wake on lan
57
+ @polling_timer.cancel unless @polling_timer.nil?
58
+ @polling_timer = nil
59
+ end
60
+
61
+
62
+ #
63
+ # Command types
64
+ COMMAND = {
65
+ :hard_off => 0x11, # Completely powers off
66
+ :power => 0xF9, # Technically the panel command
67
+ :volume => 0x12,
68
+ :input => 0x14,
69
+ :mode => 0x18,
70
+ :size => 0x19,
71
+ :pip => 0x3C, # picture in picture
72
+ :auto_adjust => 0x3D,
73
+ :wall_mode => 0x5C, # Video wall mode
74
+ :safety => 0x5D,
75
+ :wall_on => 0x84, # Video wall enabled
76
+ :wall_user => 0x89 # Video wall user control
77
+ }
78
+ COMMAND.merge!(COMMAND.invert)
79
+
80
+ # As true power off disconnects the server we only want to
81
+ # power off the panel. This doesn't work in video walls
82
+ # so if a nominal blank input is
83
+ def power(power, broadcast = nil)
84
+ if is_negatory?(power)
85
+ # Blank the screen before turning off panel
86
+ #if self[:power]
87
+ # blank = setting(:blank)
88
+ # unless blank.nil?
89
+ # switch_to blank
90
+ # end
91
+ #end
92
+ do_send(:power, 1)
93
+ elsif !self[:connected]
94
+ wake(broadcast)
95
+ else
96
+ do_send(:power, 0)
97
+ end
98
+ end
99
+
100
+ def hard_off
101
+ do_send(:hard_off, 0)
102
+ end
103
+
104
+ def power?(options = {}, &block)
105
+ options[:emit] = block unless block.nil?
106
+ do_send(:power, [], options)
107
+ end
108
+
109
+
110
+ INPUTS = {
111
+ :vga => 0x14, # pc in manual
112
+ :dvi => 0x18,
113
+ :dvi_video => 0x1F,
114
+ :hdmi => 0x21,
115
+ :hdmi_pc => 0x22,
116
+ :hdmi2 => 0x23,
117
+ :hdmi2_pc => 0x24,
118
+ :hdmi3 => 0x31,
119
+ :hdmi3_pc => 0x32,
120
+ :display_port => 0x25,
121
+ :dtv => 0x40,
122
+ :media => 0x60,
123
+ :widi => 0x61,
124
+ :magic_info => 0x20
125
+ }
126
+ INPUTS.merge!(INPUTS.invert)
127
+
128
+ def switch_to(input, options = {})
129
+ input = input.to_sym if input.class == String
130
+ self[:input_stable] = false
131
+ self[:input_target] = input
132
+ do_send(:input, INPUTS[input], options)
133
+ end
134
+
135
+ def volume(vol, options = {})
136
+ vol = vol.to_i
137
+ vol = 0 if vol < 0
138
+ vol = 100 if vol > 100
139
+
140
+ do_send(:volume, vol, options)
141
+ end
142
+
143
+
144
+ #
145
+ # Emulate mute
146
+ def mute
147
+ if not self[:audio_mute]
148
+ self[:audio_mute] = true
149
+ self[:previous_volume] = self[:volume] || 50
150
+ volume 0
151
+ end
152
+ end
153
+
154
+ def unmute
155
+ if self[:audio_mute]
156
+ self[:audio_mute] = false
157
+ volume self[:previous_volume]
158
+ end
159
+ end
160
+
161
+
162
+ #
163
+ # Maintain connection
164
+ def do_poll
165
+ power?({:priority => 0}) do
166
+ if self[:power] == On
167
+ do_send(:volume, [], {:priority => 0})
168
+ do_send(:input, [], {:priority => 0})
169
+ end
170
+ end
171
+ end
172
+
173
+
174
+ protected
175
+
176
+
177
+ def wake(broadcast)
178
+ mac = setting(:mac_address)
179
+ if mac
180
+ # config is the database model representing this device
181
+ wake_device(mac, broadcast || '<broadcast>')
182
+ end
183
+ end
184
+
185
+ def received(response, resolve, command)
186
+ data = str_to_array(response)
187
+ if data[2] == 3 # Check for correct data length
188
+ status = data[3]
189
+ command = data[4]
190
+ value = data[5]
191
+
192
+ if status == 0x41 # 'A'
193
+ case COMMAND[command]
194
+ when :power
195
+ self[:power] = value == 0
196
+ when :volume
197
+ self[:volume] = value
198
+ if self[:audio_mute] && value > 0
199
+ self[:audio_mute] = false
200
+ end
201
+ when :input
202
+ self[:input] = INPUTS[value]
203
+ if not self[:input_stable]
204
+ if self[:input_target] == self[:input]
205
+ self[:input_stable] = true
206
+ else
207
+ switch_to(self[:input_target])
208
+ end
209
+ end
210
+ end
211
+
212
+ return :success
213
+ else
214
+ logger.debug "Samsung failed with: #{byte_to_hex(array_to_str(data))}"
215
+ return :failed # Failed response
216
+ end
217
+ else
218
+ logger.debug "Samsung aborted with: #{byte_to_hex(array_to_str(data))}"
219
+ return :abort # unknown result
220
+ end
221
+ end
222
+
223
+ # Called by the Abstract Tokenizer
224
+ def check_checksum(byte_str)
225
+ response = str_to_array(byte_str)
226
+ check = 0
227
+ response[0..-2].each do |byte|
228
+ check = (check + byte) & 0xFF
229
+ end
230
+ response[-1] == check
231
+ end
232
+
233
+ # Called by do_send to create a checksum
234
+ def checksum(command)
235
+ check = 0
236
+ command.each do |byte|
237
+ check = (check + byte) & 0xFF
238
+ end
239
+ command << check
240
+ end
241
+
242
+ def do_send(command, data = [], options = {})
243
+ data = [data] unless data.is_a?(Array)
244
+
245
+ if command.is_a?(Symbol)
246
+ options[:name] = command if data.length > 0 # name unless status request
247
+ command = COMMAND[command]
248
+ end
249
+
250
+ data = [command, 0xFF, data.length] + data # Build request (0xFF is screen id)
251
+ checksum(data) # Add checksum
252
+ data = [0xAA] + data # Add header
253
+ send(array_to_str(data), options)
254
+ end
255
+ end
256
+
@@ -0,0 +1,138 @@
1
+ module Vaddio; end
2
+ module Vaddio::Camera; end
3
+
4
+
5
+ # TCP Port: 23
6
+ class Vaddio::Camera::ClearViewPtzTelnet
7
+ include ::Orchestrator::Constants # these provide optional helper methods
8
+ include ::Orchestrator::Transcoder # (not used in this module)
9
+
10
+
11
+ def on_load
12
+ # Setup tokenisation of connection
13
+ config({
14
+ tokenize: true,
15
+ indicator: "\e[J\r\n",
16
+ delimiter: "\r\n> \e[J", # VT100 string -ESC[J
17
+ wait_ready: "login: "
18
+ })
19
+
20
+ # Default send options
21
+ defaults({
22
+ delay: 150 # time in ms between commands giving the unit time to process
23
+ })
24
+
25
+
26
+ # Constants that are made available to interfaces
27
+ self[:pan_speed_max] = 24
28
+ self[:pan_speed_min] = 1
29
+ self[:tilt_speed_max] = 24
30
+ self[:tilt_speed_min] = 1
31
+ self[:zoom_speed_max] = 7
32
+ self[:zoom_speed_min] = 1
33
+
34
+ # Restart schedule (prevents it crashing)
35
+ # Every night at 01:00am restart the camera unless defined otherwise
36
+ schedule.cron(setting(:restart_time) || '0 1 * * *') do
37
+ reboot
38
+ end
39
+ end
40
+
41
+ def on_unload
42
+ end
43
+
44
+ def on_update
45
+ end
46
+
47
+ def connected
48
+ self[:power] = true
49
+ @polling_timer = schedule.every('60s') do
50
+ logger.debug "-- Polling Vaddio Camera"
51
+ version # Low priority sent to maintain the connection
52
+ end
53
+
54
+ # Send the login password (wait false as not expecting a response)
55
+ send "admin\r", wait: false
56
+ password = setting(:password) ? "#{setting(:password)}\r" : "password\r"
57
+ send password, wait: false
58
+ end
59
+
60
+ def disconnected
61
+ self[:power] = false
62
+
63
+ # Disconnected will be called before connect if initial connect fails
64
+ @polling_timer.cancel unless @polling_timer.nil?
65
+ @polling_timer = nil
66
+ end
67
+
68
+
69
+ def power(state)
70
+ # Here for compatibility with other camera modules
71
+ end
72
+
73
+ def power?(options = nil, &block)
74
+ block.call unless block.nil?
75
+ end
76
+
77
+
78
+ # direction: left, right, stop
79
+ def pan(direction, speed = 16)
80
+ params = direction.to_sym == :stop ? direction : "#{direction} #{speed}"
81
+ send "camera pan #{params}\r", name: :pan
82
+ end
83
+
84
+ # direction: up, down, stop
85
+ def tilt(direction, speed = 16)
86
+ params = direction.to_sym == :stop ? direction : "#{direction} #{speed}"
87
+ send "camera tilt #{params}\r", name: :tilt
88
+ end
89
+
90
+ def home
91
+ send "camera home\r", name: :home
92
+ end
93
+
94
+ # number 1->6 inclusive
95
+ def preset(number, command = :recall)
96
+ send "camera #{command} #{number}\r", name: :preset
97
+ end
98
+
99
+ # direction: in, out, stop
100
+ def zoom(direction, speed = 3)
101
+ params = direction.to_sym == :stop ? direction : "#{direction} #{speed}"
102
+ send "camera zoom #{params}\r", name: :zoom
103
+ end
104
+
105
+ def reboot(from_now = 0)
106
+ # Not named so it won't be stored in the queue when not connected
107
+ # -> Named commands persist disconnect and will execute in order on connect
108
+ send "reboot #{from_now}\r"
109
+ end
110
+
111
+ def version
112
+ send "version\r", priority: 0, wait: false
113
+ end
114
+
115
+
116
+ protected
117
+
118
+
119
+ def received(data, resolve, command)
120
+ logger.debug "Vaddio sent #{data}"
121
+
122
+ # Deals with multi-line responses
123
+ data = data.split("\r\n")[-1]
124
+
125
+ case data.to_sym
126
+ when :OK
127
+ :success
128
+ when :ERROR, :"Syntax error: Unknown or incomplete command"
129
+ warning = "Vaddio issue: #{data}"
130
+ warning << " for command #{command[:data]}" if command
131
+ logger.warn warning
132
+ :abort
133
+ else
134
+ :ignore
135
+ end
136
+ end
137
+ end
138
+
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aca-device-modules
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen von Takach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: orchestrator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Building automation and IoT control modules
42
+ email:
43
+ - steve@cotag.me
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE
49
+ - README.md
50
+ - aca-device-modules.gemspec
51
+ - lib/aca-device-modules.rb
52
+ - lib/aca-device-modules/engine.rb
53
+ - lib/aca-device-modules/version.rb
54
+ - modules/aca/pc_control.rb
55
+ - modules/axis/camera/vapix.rb
56
+ - modules/biamp/nexia.rb
57
+ - modules/bss/blu100.rb
58
+ - modules/clipsal/c_bus.rb
59
+ - modules/epson/projector/esc_vp21.rb
60
+ - modules/extron/mixer/dmp44.rb
61
+ - modules/extron/mixer/dmp64.rb
62
+ - modules/extron/switcher/dxp.rb
63
+ - modules/global_cache/gc100.rb
64
+ - modules/kramer/switcher/vs_hdmi.rb
65
+ - modules/panasonic/camera/he50.rb
66
+ - modules/panasonic/projector/pj_link.rb
67
+ - modules/samsung/displays/md_series.rb
68
+ - modules/vaddio/camera/clear_view_ptz_telnet.rb
69
+ homepage: http://cotag.me/
70
+ licenses:
71
+ - LGPL3
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.2.2
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Open Source Control Modules by ACA
93
+ test_files: []
94
+ has_rdoc: