aca-device-modules 1.0.4 → 1.0.5

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.
@@ -12,7 +12,7 @@ class Panasonic::Camera::He50
12
12
 
13
13
  def on_update
14
14
  defaults({
15
- delay: 130, # As per the manual page 8
15
+ delay: 150, # As per the manual page 8
16
16
  keepalive: false,
17
17
  inactivity_timeout: 1.5, # seconds before closing the connection if no response
18
18
  connect_timeout: 2 # max seconds for the initial connection to the device
@@ -2,249 +2,254 @@ module Panasonic; end
2
2
  module Panasonic::Projector; end
3
3
 
4
4
 
5
+ # Default Web UI Access
6
+ # Username: admin1
7
+ # Password: panasonic
8
+
9
+
5
10
  require 'digest/md5'
6
11
 
7
12
  #
8
13
  # Port: 1024
9
14
  #
10
15
  class Panasonic::Projector::Tcp
11
- include ::Orchestrator::Constants
16
+ include ::Orchestrator::Constants
12
17
  include ::Orchestrator::Transcoder
13
18
 
14
- def on_load
15
- # Response time is slow
16
- defaults({
17
- timeout: 2000,
18
- delay_on_receive: 1000
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
-
31
- # Meta data for inquiring interfaces
32
- self[:type] = :projector
33
-
34
- # The projector drops the connection when there is no activity
35
- schedule.every('60s') do
36
- power?({:priority => 0})
37
- end
38
- end
39
-
40
- def on_update
41
- end
42
-
43
- def connected
44
- end
45
-
46
- def disconnected
47
- end
48
-
49
-
50
- COMMANDS = {
51
- power_on: :PON,
52
- power_off: :POF,
53
- power_query: :QPW,
54
- freeze: :OFZ,
55
- input: :IIS,
56
- mute: :OSH,
57
- lamp: :"Q$S"
58
- }
59
- COMMANDS.merge!(COMMANDS.invert)
60
-
61
-
62
-
63
- #
64
- # Power commands
65
- #
66
- def power(state, opt = nil)
67
- self[:stable_state] = false
68
- if is_affirmative?(state)
69
- self[:power_target] = On
70
- do_send(:power_on, {:retries => 10, :name => :power, delay_on_receive: 8000})
71
- logger.debug "-- panasonic Proj, requested to power on"
72
- do_send(:lamp)
73
- else
74
- self[:power_target] = Off
75
- do_send(:power_off, {:retries => 10, :name => :power, delay_on_receive: 8000})
76
- logger.debug "-- panasonic Proj, requested to power off"
77
- do_send(:lamp)
78
- end
79
- end
80
-
81
- def power?(options = {}, &block)
82
- options[:emit] = block if block_given?
83
- do_send(:lamp, options)
84
- end
85
-
86
-
87
-
88
- #
89
- # Input selection
90
- #
91
- INPUTS = {
92
- :hdmi => :HD1,
93
- :hdmi2 => :HD2,
94
- :vga => :RG1,
95
- :vga2 => :RG2,
96
- :miracast => :MC1
97
- }
98
- INPUTS.merge!(INPUTS.invert)
99
-
100
-
101
- def switch_to(input)
102
- input = input.to_sym
103
- return unless INPUTS.has_key? input
104
-
105
- # Projector doesn't automatically unmute
106
- unmute if self[:mute]
107
-
108
- do_send(:input, INPUTS[input], {:retries => 10, delay_on_receive: 2000})
109
- logger.debug "-- panasonic LCD, requested to switch to: #{input}"
110
-
111
- self[:input] = input # for a responsive UI
112
- end
113
-
114
-
115
- #
116
- # Mute Audio and Video
117
- #
118
- def mute(val = true)
119
- actual = val ? 1 : 0
120
- logger.debug "-- panasonic Proj, requested to mute"
121
- do_send(:mute, actual) # Audio + Video
122
- end
123
-
124
- def unmute
125
- logger.debug "-- panasonic Proj, requested to unmute"
126
- do_send(:mute, 0)
127
- end
128
-
129
-
130
- ERRORS = {
131
- :ERR1 => '1: Undefined control command'.freeze,
132
- :ERR2 => '2: Out of parameter range'.freeze,
133
- :ERR3 => '3: Busy state or no-acceptable period'.freeze,
134
- :ERR4 => '4: Timeout or no-acceptable period'.freeze,
135
- :ERR5 => '5: Wrong data length'.freeze,
136
- :ERRA => 'A: Password mismatch'.freeze,
137
- :ER401 => '401: Command cannot be executed'.freeze,
138
- :ER402 => '402: Invalid parameter is sent'.freeze
139
- }
140
-
141
-
142
- def received(data, resolve, command) # Data is default received as a string
143
- logger.debug "panasonic Proj sent: #{data}"
144
-
145
- # This is the ready response
146
- if data[0] == ' '
147
- @mode = data[1]
148
- if @mode == '1'
149
- @pass = "#{setting(:username) || 'admin1'}:#{setting(:password) || 'panasonic'}:#{data.strip.split(/\s+/)[-1]}"
150
- @pass = Digest::MD5.hexdigest(@pass)
151
- end
152
-
153
- else
154
- data = data[2..-1]
155
-
156
- # Error Response
157
- if data[0] == 'E'
158
- error = data.to_sym
159
- self[:last_error] = ERRORS[error]
160
-
161
- # Check for busy or timeout
162
- if error == :ERR3 || error == :ERR4
163
- logger.warn "Panasonic Proj busy: #{self[:last_error]}"
164
- return :retry
165
- else
166
- logger.error "Panasonic Proj error: #{self[:last_error]}"
167
- return :abort
168
- end
169
- end
19
+ def on_load
20
+ # Response time is slow
21
+ defaults({
22
+ timeout: 2000,
23
+ delay_on_receive: 1000
24
+ })
25
+
26
+ config({
27
+ tokenize: true,
28
+ delimiter: "\r",
29
+ wait_ready: 'NTCONTROL'
30
+ })
31
+
32
+ @check_scheduled = false
33
+ self[:power] = false
34
+ self[:stable_state] = true # Stable by default (allows manual on and off)
35
+
36
+ # Meta data for inquiring interfaces
37
+ self[:type] = :projector
38
+
39
+ # The projector drops the connection when there is no activity
40
+ schedule.every('60s') do
41
+ power?({:priority => 0}) if self[:connected]
42
+ end
43
+ end
44
+
45
+ def on_update
46
+ end
47
+
48
+ def connected
49
+ end
50
+
51
+ def disconnected
52
+ end
53
+
54
+
55
+ COMMANDS = {
56
+ power_on: :PON,
57
+ power_off: :POF,
58
+ power_query: :QPW,
59
+ freeze: :OFZ,
60
+ input: :IIS,
61
+ mute: :OSH,
62
+ lamp: :"Q$S"
63
+ }
64
+ COMMANDS.merge!(COMMANDS.invert)
65
+
66
+
67
+
68
+ #
69
+ # Power commands
70
+ #
71
+ def power(state, opt = nil)
72
+ self[:stable_state] = false
73
+ if is_affirmative?(state)
74
+ self[:power_target] = On
75
+ do_send(:power_on, {:retries => 10, :name => :power, delay_on_receive: 8000})
76
+ logger.debug "-- panasonic Proj, requested to power on"
77
+ do_send(:lamp)
78
+ else
79
+ self[:power_target] = Off
80
+ do_send(:power_off, {:retries => 10, :name => :power, delay_on_receive: 8000})
81
+ logger.debug "-- panasonic Proj, requested to power off"
82
+ do_send(:lamp)
83
+ end
84
+ end
85
+
86
+ def power?(options = {}, &block)
87
+ options[:emit] = block if block_given?
88
+ do_send(:lamp, options)
89
+ end
90
+
91
+
92
+
93
+ #
94
+ # Input selection
95
+ #
96
+ INPUTS = {
97
+ :hdmi => :HD1,
98
+ :hdmi2 => :HD2,
99
+ :vga => :RG1,
100
+ :vga2 => :RG2,
101
+ :miracast => :MC1
102
+ }
103
+ INPUTS.merge!(INPUTS.invert)
104
+
105
+
106
+ def switch_to(input)
107
+ input = input.to_sym
108
+ return unless INPUTS.has_key? input
109
+
110
+ # Projector doesn't automatically unmute
111
+ unmute if self[:mute]
112
+
113
+ do_send(:input, INPUTS[input], {:retries => 10, delay_on_receive: 2000})
114
+ logger.debug "-- panasonic LCD, requested to switch to: #{input}"
115
+
116
+ self[:input] = input # for a responsive UI
117
+ end
118
+
119
+
120
+ #
121
+ # Mute Audio and Video
122
+ #
123
+ def mute(val = true)
124
+ actual = val ? 1 : 0
125
+ logger.debug "-- panasonic Proj, requested to mute"
126
+ do_send(:mute, actual) # Audio + Video
127
+ end
128
+
129
+ def unmute
130
+ logger.debug "-- panasonic Proj, requested to unmute"
131
+ do_send(:mute, 0)
132
+ end
133
+
134
+
135
+ ERRORS = {
136
+ :ERR1 => '1: Undefined control command'.freeze,
137
+ :ERR2 => '2: Out of parameter range'.freeze,
138
+ :ERR3 => '3: Busy state or no-acceptable period'.freeze,
139
+ :ERR4 => '4: Timeout or no-acceptable period'.freeze,
140
+ :ERR5 => '5: Wrong data length'.freeze,
141
+ :ERRA => 'A: Password mismatch'.freeze,
142
+ :ER401 => '401: Command cannot be executed'.freeze,
143
+ :ER402 => '402: Invalid parameter is sent'.freeze
144
+ }
145
+
146
+
147
+ def received(data, resolve, command) # Data is default received as a string
148
+ logger.debug "panasonic Proj sent: #{data}"
149
+
150
+ # This is the ready response
151
+ if data[0] == ' '
152
+ @mode = data[1]
153
+ if @mode == '1'
154
+ @pass = "#{setting(:username) || 'admin1'}:#{setting(:password) || 'panasonic'}:#{data.strip.split(/\s+/)[-1]}"
155
+ @pass = Digest::MD5.hexdigest(@pass)
156
+ end
157
+
158
+ else
159
+ data = data[2..-1]
160
+
161
+ # Error Response
162
+ if data[0] == 'E'
163
+ error = data.to_sym
164
+ self[:last_error] = ERRORS[error]
165
+
166
+ # Check for busy or timeout
167
+ if error == :ERR3 || error == :ERR4
168
+ logger.warn "Panasonic Proj busy: #{self[:last_error]}"
169
+ return :retry
170
+ else
171
+ logger.error "Panasonic Proj error: #{self[:last_error]}"
172
+ return :abort
173
+ end
174
+ end
170
175
 
171
176
  resp = data.split(':')
172
- cmd = COMMANDS[resp[0].to_sym]
173
- val = resp[1]
174
-
175
- case cmd
176
- when :power_on
177
- self[:power] = true
178
- when :power_off
179
- self[:power] = false
180
- when :power_query
181
- self[:power] = val.to_i == 1
182
- when :freeze
183
- self[:frozen] = val.to_i == 1
184
- when :input
185
- self[:input] = INPUTS[val.to_sym]
186
- when :mute
187
- self[:mute] = val.to_i == 1
188
- else
189
- if command && command[:name] == :lamp
190
- ival = resp[0].to_i
191
- self[:power] = ival == 1 || ival == 2
192
- self[:warming] = ival == 1
193
- self[:cooling] = ival == 3
194
-
195
- if (self[:warming] || self[:cooling]) && !@check_scheduled && !self[:stable_state]
196
- @check_scheduled = true
197
- schedule.in('13s') do
198
- @check_scheduled = false
199
- logger.debug "-- checking panasonic state"
200
- power?({:priority => 0}) do
201
- state = self[:power]
202
- if state != self[:power_target]
203
- if self[:power_target] || !self[:cooling]
204
- power(self[:power_target])
205
- end
206
- elsif self[:power_target] && self[:cooling]
207
- power(self[:power_target])
208
- else
209
- self[:stable_state] = true
210
- switch_to(self[:input]) if self[:power_target] == On && !self[:input].nil?
211
- end
212
- end
213
- end
214
- end
215
- end
216
- end
217
- end
218
-
219
- :success
220
- end
221
-
222
-
223
- protected
224
-
225
-
226
- def do_send(command, param = nil, options = {})
227
- if param.is_a? Hash
228
- options = param
229
- param = nil
230
- end
231
-
232
- # Default to the command name if name isn't set
233
- options[:name] = command unless options[:name]
234
-
235
- if param.nil?
236
- pj = "#{COMMANDS[command]}"
237
- else
238
- pj = "#{COMMANDS[command]}:#{param}"
239
- end
240
-
241
- if @mode == '0'
242
- send("00#{pj}\r", options)
243
- else
244
- send("#{@pass}00#{pj}\r", options)
245
- end
246
-
247
- nil
248
- end
177
+ cmd = COMMANDS[resp[0].to_sym]
178
+ val = resp[1]
179
+
180
+ case cmd
181
+ when :power_on
182
+ self[:power] = true
183
+ when :power_off
184
+ self[:power] = false
185
+ when :power_query
186
+ self[:power] = val.to_i == 1
187
+ when :freeze
188
+ self[:frozen] = val.to_i == 1
189
+ when :input
190
+ self[:input] = INPUTS[val.to_sym]
191
+ when :mute
192
+ self[:mute] = val.to_i == 1
193
+ else
194
+ if command && command[:name] == :lamp
195
+ ival = resp[0].to_i
196
+ self[:power] = ival == 1 || ival == 2
197
+ self[:warming] = ival == 1
198
+ self[:cooling] = ival == 3
199
+
200
+ if (self[:warming] || self[:cooling]) && !@check_scheduled && !self[:stable_state]
201
+ @check_scheduled = true
202
+ schedule.in('13s') do
203
+ @check_scheduled = false
204
+ logger.debug "-- checking panasonic state"
205
+ power?({:priority => 0}) do
206
+ state = self[:power]
207
+ if state != self[:power_target]
208
+ if self[:power_target] || !self[:cooling]
209
+ power(self[:power_target])
210
+ end
211
+ elsif self[:power_target] && self[:cooling]
212
+ power(self[:power_target])
213
+ else
214
+ self[:stable_state] = true
215
+ switch_to(self[:input]) if self[:power_target] == On && !self[:input].nil?
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ :success
225
+ end
226
+
227
+
228
+ protected
229
+
230
+
231
+ def do_send(command, param = nil, options = {})
232
+ if param.is_a? Hash
233
+ options = param
234
+ param = nil
235
+ end
236
+
237
+ # Default to the command name if name isn't set
238
+ options[:name] = command unless options[:name]
239
+
240
+ if param.nil?
241
+ pj = "#{COMMANDS[command]}"
242
+ else
243
+ pj = "#{COMMANDS[command]}:#{param}"
244
+ end
245
+
246
+ if @mode == '0'
247
+ send("00#{pj}\r", options)
248
+ else
249
+ send("#{@pass}00#{pj}\r", options)
250
+ end
251
+
252
+ nil
253
+ end
249
254
  end
250
255