sony_camera_remote_api 0.1.1
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/.gitignore +55 -0
- data/.rspec +2 -0
- data/.simplecov +16 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +78 -0
- data/LICENSE +21 -0
- data/README.md +99 -0
- data/Rakefile +145 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/sonycam +6 -0
- data/lib/core_ext/hash_patch.rb +15 -0
- data/lib/sony_camera_remote_api/camera_api.rb +199 -0
- data/lib/sony_camera_remote_api/camera_api_group.rb +281 -0
- data/lib/sony_camera_remote_api/camera_api_group_def.rb +362 -0
- data/lib/sony_camera_remote_api/client/config.rb +266 -0
- data/lib/sony_camera_remote_api/client/main.rb +646 -0
- data/lib/sony_camera_remote_api/error.rb +41 -0
- data/lib/sony_camera_remote_api/logging.rb +76 -0
- data/lib/sony_camera_remote_api/packet.rb +109 -0
- data/lib/sony_camera_remote_api/raw_api.rb +196 -0
- data/lib/sony_camera_remote_api/scripts.rb +64 -0
- data/lib/sony_camera_remote_api/ssdp.rb +72 -0
- data/lib/sony_camera_remote_api/utils.rb +98 -0
- data/lib/sony_camera_remote_api/version.rb +3 -0
- data/lib/sony_camera_remote_api.rb +1044 -0
- data/scripts/Linux/add_ssdp_route.sh +39 -0
- data/scripts/Linux/connect_wifi.sh +114 -0
- data/scripts/connect.sh +36 -0
- data/sony_camera_remote_api.gemspec +35 -0
- metadata +231 -0
@@ -0,0 +1,646 @@
|
|
1
|
+
require 'sony_camera_remote_api'
|
2
|
+
require 'sony_camera_remote_api/logging'
|
3
|
+
require 'sony_camera_remote_api/scripts'
|
4
|
+
require 'sony_camera_remote_api/client/config'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'thor'
|
7
|
+
require 'highline/import'
|
8
|
+
require 'yaml'
|
9
|
+
require 'time'
|
10
|
+
require 'pp'
|
11
|
+
|
12
|
+
|
13
|
+
module SonyCameraRemoteAPI
|
14
|
+
# CLI client module
|
15
|
+
module Client
|
16
|
+
|
17
|
+
# Default config file saved in home directory.
|
18
|
+
GLOBAL_CONFIG_FILE = File.expand_path('~/.sonycamconf')
|
19
|
+
|
20
|
+
class Main < Thor
|
21
|
+
include Utils
|
22
|
+
include Scripts
|
23
|
+
include ConfigUtils
|
24
|
+
|
25
|
+
register Config, 'config', 'config [commands] [options]', 'Configure camera connections'
|
26
|
+
|
27
|
+
# Global options
|
28
|
+
class_option :setting, type: :boolean, desc: 'Show current camera settings'
|
29
|
+
class_option :output, type: :string, desc: 'Output filename', banner: 'FILE'
|
30
|
+
class_option :dir, type: :string, desc: 'Output directory', banner: 'DIR'
|
31
|
+
class_option :config, aliases: '-c', type: :string, desc: 'Config file path', banner: 'FILE'
|
32
|
+
class_option :ssid, type: :string, desc: 'SSID of the camera to connect'
|
33
|
+
class_option :pass, type: :string, desc: 'Password of camera to connect'
|
34
|
+
class_option :interface, type: :string, desc: 'Interface by which camera is connected'
|
35
|
+
class_option :verbose, type: :numeric, desc: 'Increase verbosity', banner: 'LEVEL'
|
36
|
+
|
37
|
+
no_tasks do
|
38
|
+
def config_file
|
39
|
+
options[:config] || GLOBAL_CONFIG_FILE
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_camera_config
|
43
|
+
# Check connection configuration is given by options
|
44
|
+
if [options[:ssid], options[:pass], options[:interface]].any?
|
45
|
+
if [options[:ssid], options[:pass], options[:interface]].all?
|
46
|
+
return { 'ssid' => options[:ssid], 'pass' => options[:pass], 'interface' => options[:interface] }
|
47
|
+
else
|
48
|
+
puts "'--ssid', '--pass', '--interface' must be present all at a time!"
|
49
|
+
return
|
50
|
+
end
|
51
|
+
else
|
52
|
+
config = default_camera config_file
|
53
|
+
config
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Load camera config and connect
|
58
|
+
def load_and_connect
|
59
|
+
config = load_camera_config
|
60
|
+
return if config.nil?
|
61
|
+
# Connect to camera by external script
|
62
|
+
unless Scripts.connect(config['interface'], config['ssid'], config['pass'])
|
63
|
+
puts 'Failed to connect!'
|
64
|
+
return
|
65
|
+
end
|
66
|
+
config
|
67
|
+
end
|
68
|
+
|
69
|
+
# Initialize camera instance
|
70
|
+
def init_camera
|
71
|
+
config = load_and_connect
|
72
|
+
exit(1) if config.nil?
|
73
|
+
|
74
|
+
puts 'Initializing camera...'
|
75
|
+
if config['endpoints'].nil?
|
76
|
+
@cam = SonyCameraRemoteAPI::Camera.new reconnect_by: method(:load_and_connect)
|
77
|
+
save_ssdp_config config_file, @cam.endpoints
|
78
|
+
puts 'SSDP configuration saved.'
|
79
|
+
else
|
80
|
+
@cam = SonyCameraRemoteAPI::Camera.new endpoints: config['endpoints'],
|
81
|
+
reconnect_by: method(:load_and_connect)
|
82
|
+
end
|
83
|
+
puts 'Camera initialization finished.'
|
84
|
+
|
85
|
+
# Change directory if --dir options specified
|
86
|
+
@cwd = Dir.getwd
|
87
|
+
if options[:dir]
|
88
|
+
FileUtils.mkdir_p options[:dir]
|
89
|
+
Dir.chdir options[:dir]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Finalizer
|
94
|
+
def finalize
|
95
|
+
Dir.chdir @cwd
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get supported/available/current camera parameters and show them
|
99
|
+
def get_parameter_and_show(param_name, **opts)
|
100
|
+
param_title = param_name.to_s.split(/(?=[A-Z])/).join(' ')
|
101
|
+
result = @cam.get_parameter! param_name, timeout: 0
|
102
|
+
# nil current value means it is unsupported parameter.
|
103
|
+
return if result[:current].nil?
|
104
|
+
|
105
|
+
puts "#{param_title}:"
|
106
|
+
case param_name
|
107
|
+
when :WhiteBalance
|
108
|
+
show_WhiteBalance result
|
109
|
+
else
|
110
|
+
show_normal result
|
111
|
+
end
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
# Show for other parameter
|
116
|
+
def show_normal(result)
|
117
|
+
array = []
|
118
|
+
if result[:supported].empty?
|
119
|
+
# If current value is present but NO supported value, it is immutable.
|
120
|
+
result[:supported] = [result[:current]]
|
121
|
+
end
|
122
|
+
result[:supported].each_with_index do |v, i|
|
123
|
+
if v == result[:current]
|
124
|
+
array << " => #{v} "
|
125
|
+
elsif result[:available].include? v
|
126
|
+
array << " * #{v} "
|
127
|
+
else
|
128
|
+
array << " x #{v}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
print_array_in_columns(array, 120, 10, 5)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Show for WhiteBalance parameter
|
135
|
+
def show_WhiteBalance(result)
|
136
|
+
array = []
|
137
|
+
if result[:supported].empty?
|
138
|
+
# If current value is present but NO supported value, it is immutable.
|
139
|
+
result[:supported] = [result[:current]]
|
140
|
+
end
|
141
|
+
result[:supported].each_with_index do |v, i|
|
142
|
+
if v.key?('colorTemperature')
|
143
|
+
range = "#{v['colorTemperature'][0]}-#{v['colorTemperature'][-1]}K"
|
144
|
+
step = v['colorTemperature'][1] - v['colorTemperature'][0]
|
145
|
+
if v['whiteBalanceMode'] == result[:current]['whiteBalanceMode']
|
146
|
+
str = "#{v['whiteBalanceMode']}, #{result[:current]['colorTemperature']}K (#{range}, step=#{step})"
|
147
|
+
else
|
148
|
+
str = "#{v['whiteBalanceMode']} (#{range}, step=#{step})"
|
149
|
+
end
|
150
|
+
else
|
151
|
+
str = "#{v['whiteBalanceMode']}"
|
152
|
+
end
|
153
|
+
if v['whiteBalanceMode'] == result[:current]['whiteBalanceMode']
|
154
|
+
array << " => #{str}"
|
155
|
+
elsif result[:available].include? v
|
156
|
+
array << " * #{str}"
|
157
|
+
else
|
158
|
+
array << " x #{str}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
print_array_in_columns(array, 120, 10, 5)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Set parameter if value is set
|
165
|
+
def set_parameter(param_name, value, **opts)
|
166
|
+
return if value.is_a?(Hash) && value.values.none?
|
167
|
+
return unless value
|
168
|
+
@cam.set_parameter! param_name, value, timeout: 0
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
#----------------------------------------PARAMETER CONFIGURATORS----------------------------------------
|
173
|
+
|
174
|
+
no_tasks do
|
175
|
+
# Set common options for all shooting modes
|
176
|
+
def set_common_options
|
177
|
+
set_parameter :ZoomSetting, options[:zoom_mode]
|
178
|
+
set_parameter :FocusMode, options[:focus_mode]
|
179
|
+
set_parameter :ExposureMode, options[:exposure]
|
180
|
+
set_parameter :ExposureCompensation, options[:ev].to_f if options[:ev]
|
181
|
+
set_parameter :FNumber, options[:fnum]
|
182
|
+
set_parameter :ShutterSpeed, options[:shutter]
|
183
|
+
set_parameter :IsoSpeedRate, options[:iso]
|
184
|
+
if options[:temp]
|
185
|
+
set_parameter :WhiteBalance, whiteBalanceMode: options[:wb], colorTemperature: options[:temp]
|
186
|
+
else
|
187
|
+
set_parameter :WhiteBalance, whiteBalanceMode: options[:wb]
|
188
|
+
end
|
189
|
+
|
190
|
+
set_parameter :SceneSelection, options[:scene]
|
191
|
+
set_parameter :FlipSetting, options[:flip]
|
192
|
+
set_parameter :TvColorSystem, options[:tv]
|
193
|
+
set_parameter :InfraredRemoteControl, options[:ir]
|
194
|
+
set_parameter :AutoPowerOff, options[:apo]
|
195
|
+
set_parameter :BeepMode, options[:beep]
|
196
|
+
end
|
197
|
+
|
198
|
+
# Set common options for all shooting modes
|
199
|
+
def get_common_options
|
200
|
+
get_parameter_and_show :ZoomSetting
|
201
|
+
get_parameter_and_show :FocusMode
|
202
|
+
get_parameter_and_show :ExposureMode
|
203
|
+
get_parameter_and_show :ExposureCompensation
|
204
|
+
get_parameter_and_show :FNumber
|
205
|
+
get_parameter_and_show :ShutterSpeed
|
206
|
+
get_parameter_and_show :IsoSpeedRate
|
207
|
+
get_parameter_and_show :WhiteBalance
|
208
|
+
get_parameter_and_show :SceneSelection
|
209
|
+
get_parameter_and_show :FlipSetting
|
210
|
+
get_parameter_and_show :TvColorSystem
|
211
|
+
get_parameter_and_show :InfraredRemoteControl
|
212
|
+
get_parameter_and_show :AutoPowerOff
|
213
|
+
get_parameter_and_show :BeepMode
|
214
|
+
end
|
215
|
+
|
216
|
+
# Set common options for still/intervalstill shooting modes
|
217
|
+
def set_still_common_options
|
218
|
+
set_parameter :TrackingFocus, options[:track]
|
219
|
+
set_parameter :SelfTimer, options[:self]
|
220
|
+
set_parameter :FlashMode, options[:flash]
|
221
|
+
if options[:aspect] && options[:size]
|
222
|
+
set_parameter :StillSize, aspect: options[:aspect], size: options[:size]
|
223
|
+
end
|
224
|
+
set_parameter :StillQuality, options[:quality]
|
225
|
+
set_parameter :PostviewImageSize, options[:postview]
|
226
|
+
set_parameter :ViewAngle, options[:angle]
|
227
|
+
end
|
228
|
+
|
229
|
+
# Get common options for still/intervalstill shooting modes
|
230
|
+
def get_still_common_options
|
231
|
+
get_parameter_and_show :TrackingFocus
|
232
|
+
get_parameter_and_show :SelfTimer
|
233
|
+
get_parameter_and_show :FlashMode
|
234
|
+
get_parameter_and_show :StillSize
|
235
|
+
get_parameter_and_show :StillQuality
|
236
|
+
get_parameter_and_show :PostviewImageSize
|
237
|
+
get_parameter_and_show :ViewAngle
|
238
|
+
end
|
239
|
+
|
240
|
+
# Set common options for movie/looprec shooting modes
|
241
|
+
def set_movie_common_options
|
242
|
+
set_parameter :MovieFileFormat, options[:format]
|
243
|
+
set_parameter :MovieQuality, options[:quality]
|
244
|
+
set_parameter :SteadyMode, options[:steady]
|
245
|
+
set_parameter :ColorSetting, options[:color]
|
246
|
+
set_parameter :WindNoiseReduction, options[:noise]
|
247
|
+
set_parameter :AudioRecording, options[:audio]
|
248
|
+
end
|
249
|
+
|
250
|
+
# Get common options for movie/looprec shooting modes
|
251
|
+
def get_movie_common_options
|
252
|
+
get_parameter_and_show :MovieFileFormat
|
253
|
+
get_parameter_and_show :MovieQuality
|
254
|
+
get_parameter_and_show :SteadyMode
|
255
|
+
get_parameter_and_show :ColorSetting
|
256
|
+
get_parameter_and_show :WindNoiseReduction
|
257
|
+
get_parameter_and_show :AudioRecording
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
#----------------------------------------COMMAND OPTIONS----------------------------------------
|
262
|
+
|
263
|
+
# Common options for all shooting modes
|
264
|
+
def self.common_options
|
265
|
+
option :zoom, type: :numeric, desc: 'Zoom position (0-99)', banner: 'POSITION'
|
266
|
+
option :zoom_mode, type: :string, desc: 'Zoom setting', banner: 'MODE'
|
267
|
+
option :focus_mode, type: :string, desc: 'Focus mode', banner: 'MODE'
|
268
|
+
option :exposure, type: :string, desc: 'Exposure mode', banner: 'MODE'
|
269
|
+
option :ev, type: :string, desc: 'Exposure compensation', banner: 'EV'
|
270
|
+
option :fnum, type: :string, desc: 'F number', banner: 'NUM'
|
271
|
+
option :shutter, type: :string, desc: 'Shutter speed', banner: 'NSEC'
|
272
|
+
option :iso, type: :string, desc: 'ISO speed rate', banner: 'NUM'
|
273
|
+
option :wb, type: :string, desc: 'White balance mode', banner: 'MODE'
|
274
|
+
option :temp, type: :numeric, desc: 'Color temperature', banner: 'K'
|
275
|
+
option :scene, type: :string, desc: 'Scene selection', banner: 'MODE'
|
276
|
+
option :flip, type: :string, desc: 'Flip', banner: 'MODE'
|
277
|
+
option :tv, type: :string, desc: 'TV color system', banner: 'MODE'
|
278
|
+
option :ir, type: :string, desc: 'IR remote control', banner: 'MODE'
|
279
|
+
option :apo, type: :string, desc: 'Auto power off', banner: 'MODE'
|
280
|
+
option :beep, type: :string, desc: 'Beep mode', banner: 'MODE'
|
281
|
+
end
|
282
|
+
|
283
|
+
# Common options for still/intervalstill shooting modes
|
284
|
+
def self.still_common_options
|
285
|
+
option :track, type: :string, desc: 'Tracking focus', banner: 'MODE'
|
286
|
+
option :self, type: :numeric, desc: 'Self timer', banner: 'NSEC'
|
287
|
+
option :flash, type: :string, desc: 'Flash mode', banner: 'MODE'
|
288
|
+
option :size, type: :string, desc: 'Still size', banner: 'PIXEL'
|
289
|
+
option :aspect, type: :string, desc: 'Still aspect', banner: 'MODE'
|
290
|
+
option :quality, type: :string, desc: 'Still quality', banner: 'MODE'
|
291
|
+
option :postview, type: :string, desc: 'Postview image size', banner: 'PIXEL'
|
292
|
+
option :angle, type: :numeric, desc: 'View angle', banner: 'DEGREE'
|
293
|
+
end
|
294
|
+
|
295
|
+
# Common options for movie/looprec shooting modes
|
296
|
+
def self.movie_common_options
|
297
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
298
|
+
option :format, type: :string, desc: 'Movie Format', banner: 'MODE'
|
299
|
+
option :quality, type: :string, desc: 'Movie Quality', banner: 'MODE'
|
300
|
+
option :steady, type: :string, desc: 'Steady Mode', banner: 'MODE'
|
301
|
+
option :color, type: :string, desc: 'Color setting', banner: 'MODE'
|
302
|
+
option :noise, type: :string, desc: 'Wind noise reduction', banner: 'MODE'
|
303
|
+
option :audio, type: :string, desc: 'Audio recording', banner: 'MODE'
|
304
|
+
end
|
305
|
+
|
306
|
+
|
307
|
+
#----------------------------------------COMMAND DEFINITIONS----------------------------------------
|
308
|
+
|
309
|
+
desc 'still [options]', 'Capture still images'
|
310
|
+
option :interval, type: :numeric, desc: 'Interval of capturing (sec)', banner: 'NSEC'
|
311
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
312
|
+
still_common_options
|
313
|
+
common_options
|
314
|
+
option :transfer, type: :boolean, desc: 'Transfer postview image', default: true
|
315
|
+
def still
|
316
|
+
init_camera
|
317
|
+
@cam.change_function_to_shoot 'still', 'Single'
|
318
|
+
|
319
|
+
# Set/Get options
|
320
|
+
set_still_common_options
|
321
|
+
set_common_options
|
322
|
+
if options[:setting]
|
323
|
+
get_still_common_options
|
324
|
+
get_common_options
|
325
|
+
return
|
326
|
+
end
|
327
|
+
|
328
|
+
@cam.act_zoom absolute: options[:zoom]
|
329
|
+
|
330
|
+
# Interval option resembles Intervalrec shooting mode.
|
331
|
+
# The advantage is that we can transfer captured stills each time, meanwhile Intervalrec shooting mode cannot.
|
332
|
+
# However, the interval time tends to be longer than that of Intervalrec mode.
|
333
|
+
if options[:interval]
|
334
|
+
if options[:output]
|
335
|
+
# Generate sequencial filenames based on --output option
|
336
|
+
generator = generate_sequencial_filenames options[:output], 'JPG'
|
337
|
+
end
|
338
|
+
|
339
|
+
# Capture forever until trapped by SIGINT
|
340
|
+
trapped = false
|
341
|
+
trap(:INT) { trapped = true }
|
342
|
+
puts "Capturing stills by #{options[:interval]} sec. Type C-c (SIGINT) to quit capturing."
|
343
|
+
start_time = Time.now
|
344
|
+
loop do
|
345
|
+
loop_start = Time.now
|
346
|
+
if options[:output]
|
347
|
+
@cam.capture_still filename: generator.next, transfer: options[:transfer]
|
348
|
+
else
|
349
|
+
@cam.capture_still transfer: options[:transfer]
|
350
|
+
end
|
351
|
+
if trapped
|
352
|
+
puts 'Trapped!'
|
353
|
+
break
|
354
|
+
end
|
355
|
+
loop_end = Time.now
|
356
|
+
# If total time exceeds, quit capturing.
|
357
|
+
if options[:time] && options[:time] < loop_end - start_time
|
358
|
+
puts 'Time expired!'
|
359
|
+
break
|
360
|
+
end
|
361
|
+
# Wait until specified interval elapses
|
362
|
+
elapsed = loop_end - loop_start
|
363
|
+
if options[:interval] - elapsed > 0
|
364
|
+
sleep(options[:interval] - elapsed)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
trap(:INT, 'DEFAULT')
|
368
|
+
else
|
369
|
+
@cam.capture_still filename: options[:output], transfer: options[:transfer]
|
370
|
+
end
|
371
|
+
finalize
|
372
|
+
end
|
373
|
+
|
374
|
+
|
375
|
+
desc 'cont [options]', 'Capture still images continuously'
|
376
|
+
option :mode, type: :string, desc: 'Continuous shooting mode', banner: 'MODE', default: 'Single'
|
377
|
+
option :speed, type: :string, desc: 'Continuous shooting speed', banner: 'MODE'
|
378
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
379
|
+
still_common_options
|
380
|
+
common_options
|
381
|
+
option :transfer, type: :boolean, desc: 'Transfer postview image', default: false
|
382
|
+
def cont
|
383
|
+
init_camera
|
384
|
+
unless @cam.support_group? :ContShootingMode
|
385
|
+
puts 'This camera does not support continuous shooting mode. Exiting...'
|
386
|
+
exit 1
|
387
|
+
end
|
388
|
+
@cam.change_function_to_shoot('still', options[:mode])
|
389
|
+
|
390
|
+
# Set/Get options
|
391
|
+
set_parameter :ContShootingMode, options[:mode]
|
392
|
+
set_parameter :ContShootingSpeed, options[:speed]
|
393
|
+
set_still_common_options
|
394
|
+
set_common_options
|
395
|
+
if options[:setting]
|
396
|
+
get_parameter_and_show :ContShootingMode
|
397
|
+
# ContShootingSpeed API will fail when ContShootingMode = 'Single'
|
398
|
+
get_parameter_and_show :ContShootingSpeed
|
399
|
+
get_still_common_options
|
400
|
+
get_common_options
|
401
|
+
return
|
402
|
+
end
|
403
|
+
|
404
|
+
@cam.act_zoom absolute: options[:zoom]
|
405
|
+
|
406
|
+
case options[:mode]
|
407
|
+
when 'Single', 'MotionShot', 'Burst'
|
408
|
+
@cam.capture_still filename: options[:output], transfer: options[:transfer]
|
409
|
+
when 'Continuous', 'Spd Priority Cont.'
|
410
|
+
@cam.start_continuous_shooting
|
411
|
+
if options[:time]
|
412
|
+
sleep options[:time]
|
413
|
+
puts 'Time expired!'
|
414
|
+
else
|
415
|
+
# Continue forever until trapped by SIGINT
|
416
|
+
trapped = false
|
417
|
+
trap(:INT) { trapped = true }
|
418
|
+
puts 'Type C-c (SIGINT) to quit recording.'
|
419
|
+
loop do
|
420
|
+
break if trapped
|
421
|
+
sleep 0.1
|
422
|
+
end
|
423
|
+
puts 'Trapped!'
|
424
|
+
trap(:INT, 'DEFAULT')
|
425
|
+
end
|
426
|
+
@cam.stop_continuous_shooting prefix: options[:output], transfer: options[:transfer]
|
427
|
+
end
|
428
|
+
finalize
|
429
|
+
end
|
430
|
+
|
431
|
+
|
432
|
+
desc 'movie [options]', 'Record movies'
|
433
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
434
|
+
movie_common_options
|
435
|
+
common_options
|
436
|
+
option :transfer, type: :boolean, desc: 'Transfer recorded movie immediately'
|
437
|
+
def movie
|
438
|
+
init_camera
|
439
|
+
@cam.change_function_to_shoot('movie')
|
440
|
+
|
441
|
+
# Set/Get options
|
442
|
+
set_movie_common_options
|
443
|
+
set_common_options
|
444
|
+
if options[:setting]
|
445
|
+
get_movie_common_options
|
446
|
+
get_common_options
|
447
|
+
return
|
448
|
+
end
|
449
|
+
|
450
|
+
@cam.act_zoom absolute: options[:zoom]
|
451
|
+
|
452
|
+
@cam.start_movie_recording
|
453
|
+
if options[:time]
|
454
|
+
sleep options[:time]
|
455
|
+
puts 'Time expired!'
|
456
|
+
else
|
457
|
+
# record forever until trapped by SIGINT
|
458
|
+
trapped = false
|
459
|
+
trap(:INT) { trapped = true }
|
460
|
+
puts 'Type C-c (SIGINT) to quit recording.'
|
461
|
+
loop do
|
462
|
+
break if trapped
|
463
|
+
sleep 0.1
|
464
|
+
end
|
465
|
+
puts 'Trapped!'
|
466
|
+
trap(:INT, 'DEFAULT')
|
467
|
+
end
|
468
|
+
@cam.stop_movie_recording filename: options[:output], transfer: options[:transfer]
|
469
|
+
finalize
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
desc 'intrec [options]', 'Do interval recording'
|
474
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
475
|
+
option :interval, type: :string, desc: 'Interval (sec)', banner: 'NSEC'
|
476
|
+
still_common_options
|
477
|
+
common_options
|
478
|
+
option :transfer, type: :boolean, desc: 'Transfer selected contents '
|
479
|
+
def intrec
|
480
|
+
init_camera
|
481
|
+
@cam.change_function_to_shoot('intervalstill')
|
482
|
+
|
483
|
+
# Set/Get options
|
484
|
+
set_parameter :IntervalTime, options[:interval]
|
485
|
+
set_still_common_options
|
486
|
+
set_common_options
|
487
|
+
if options[:setting]
|
488
|
+
get_parameter_and_show :IntervalTime
|
489
|
+
get_still_common_options
|
490
|
+
get_common_options
|
491
|
+
return
|
492
|
+
end
|
493
|
+
|
494
|
+
@cam.act_zoom absolute: options[:zoom]
|
495
|
+
|
496
|
+
@cam.start_interval_recording
|
497
|
+
if options[:time]
|
498
|
+
sleep options[:time]
|
499
|
+
puts 'Time expired!'
|
500
|
+
else
|
501
|
+
# continue forever until trapped by SIGINT
|
502
|
+
trapped = false
|
503
|
+
trap(:INT) { trapped = true }
|
504
|
+
puts 'Type C-c (SIGINT) to quit recording.'
|
505
|
+
loop do
|
506
|
+
break if trapped
|
507
|
+
sleep 0.1
|
508
|
+
end
|
509
|
+
puts 'Trapped!'
|
510
|
+
trap(:INT, 'DEFAULT')
|
511
|
+
end
|
512
|
+
@cam.stop_interval_recording transfer: options[:transfer]
|
513
|
+
finalize
|
514
|
+
end
|
515
|
+
|
516
|
+
|
517
|
+
desc 'looprec [options]', 'Do loop recording'
|
518
|
+
option :time, type: :numeric, desc: 'Recording time (min)', banner: 'NMIN'
|
519
|
+
option :loop_time, type: :string, desc: 'Loop recording time (min)', banner: 'NMIN'
|
520
|
+
movie_common_options
|
521
|
+
common_options
|
522
|
+
option :transfer, type: :boolean, desc: 'Transfer selected contents '
|
523
|
+
def looprec
|
524
|
+
init_camera
|
525
|
+
@cam.change_function_to_shoot('looprec')
|
526
|
+
|
527
|
+
# Set/Get options
|
528
|
+
set_parameter :LoopRecTime, options[:loop_time]
|
529
|
+
set_movie_common_options
|
530
|
+
set_common_options
|
531
|
+
if options[:setting]
|
532
|
+
get_parameter_and_show :LoopRecTime
|
533
|
+
get_movie_common_options
|
534
|
+
get_common_options
|
535
|
+
return
|
536
|
+
end
|
537
|
+
|
538
|
+
@cam.act_zoom absolute: options[:zoom]
|
539
|
+
|
540
|
+
@cam.start_loop_recording
|
541
|
+
if options[:time]
|
542
|
+
sleep(options[:time] * 60)
|
543
|
+
puts 'Time expired!'
|
544
|
+
else
|
545
|
+
# record forever until trapped by SIGINT
|
546
|
+
trapped = false
|
547
|
+
trap(:INT) { trapped = true }
|
548
|
+
puts 'Type C-c (SIGINT) to quit recording.'
|
549
|
+
loop do
|
550
|
+
break if trapped
|
551
|
+
sleep 0.1
|
552
|
+
end
|
553
|
+
puts 'Trapped!'
|
554
|
+
trap(:INT, 'DEFAULT')
|
555
|
+
end
|
556
|
+
@cam.stop_loop_recording filename: options[:output], transfer: options[:transfer]
|
557
|
+
finalize
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
desc 'liveview [options]', 'Stream liveview images'
|
562
|
+
option :time, type: :numeric, desc: 'Recording time (sec)', banner: 'NSEC'
|
563
|
+
option :size, type: :string, desc: 'Liveview size', banner: 'SIZE'
|
564
|
+
common_options
|
565
|
+
def liveview
|
566
|
+
init_camera
|
567
|
+
# Set/Get options
|
568
|
+
set_common_options
|
569
|
+
if options[:setting]
|
570
|
+
get_parameter_and_show :LiveviewSize
|
571
|
+
get_common_options
|
572
|
+
return
|
573
|
+
end
|
574
|
+
|
575
|
+
@cam.act_zoom absolute: options[:zoom]
|
576
|
+
|
577
|
+
th = @cam.start_liveview_thread(time: options[:time], size: options[:size]) do |img, info|
|
578
|
+
filename = "#{img.sequence_number}.jpg"
|
579
|
+
File.write filename, img.jpeg_data
|
580
|
+
puts "Wrote: #{filename}."
|
581
|
+
end
|
582
|
+
trap(:INT) { th.kill }
|
583
|
+
puts 'Liveview download started. Type C-c (SIGINT) to quit.'
|
584
|
+
th.join
|
585
|
+
trap(:INT, 'DEFAULT')
|
586
|
+
puts 'Finished.'
|
587
|
+
finalize
|
588
|
+
end
|
589
|
+
|
590
|
+
|
591
|
+
desc 'contents [options]', 'List contents and transfer them from camera storage'
|
592
|
+
option :type, type: :array, desc: 'Contents types (still/movie_mp4/movie_xavcs)', default: nil
|
593
|
+
option :datelist, type: :boolean, desc: 'List Dates and number of contents'
|
594
|
+
option :date, type: :string, desc: 'Date (yyyyMMdd)'
|
595
|
+
option :sort, type: :string, desc: 'Sorting order [ascend/descend]', default: 'descending'
|
596
|
+
option :count, type: :numeric, desc: 'Number of contents'
|
597
|
+
option :transfer, type: :boolean, desc: 'Transfer selected contents'
|
598
|
+
option :delete, type: :boolean, desc: 'Delete contents'
|
599
|
+
def contents
|
600
|
+
init_camera
|
601
|
+
@cam.change_function_to_transfer
|
602
|
+
|
603
|
+
puts 'Retrieving...'
|
604
|
+
if options[:datelist]
|
605
|
+
dates = @cam.get_date_list date_count: options[:count]
|
606
|
+
num_contents = dates.map { |d, c| c }.inject(:+)
|
607
|
+
puts "#{dates.size} date folders / #{num_contents} contents found."
|
608
|
+
puts "Dates\t\tN-Contents"
|
609
|
+
dates.each do |date, count|
|
610
|
+
puts "#{date['title']}\t#{count}"
|
611
|
+
end
|
612
|
+
return
|
613
|
+
end
|
614
|
+
|
615
|
+
if options[:date]
|
616
|
+
contents = @cam.get_content_list type: options[:type], date: options[:date], sort: options[:sort], count: options[:count]
|
617
|
+
else
|
618
|
+
contents = @cam.get_content_list type: options[:type], sort: options[:sort], count: options[:count]
|
619
|
+
end
|
620
|
+
|
621
|
+
if contents.blank?
|
622
|
+
puts 'No contents!'
|
623
|
+
else
|
624
|
+
puts "#{contents.size} contents found."
|
625
|
+
puts "File name\t\tKind\t\tCreated time\t\tURL"
|
626
|
+
contents.each do |c|
|
627
|
+
filename = c['content']['original'][0]['fileName']
|
628
|
+
kind = c['contentKind']
|
629
|
+
ctime = c['createdTime']
|
630
|
+
url = c['content']['original'][0]['url']
|
631
|
+
puts "#{filename}\t\t#{kind}\t\t#{ctime}\t\t#{url}"
|
632
|
+
end
|
633
|
+
if options[:transfer]
|
634
|
+
@cam.transfer_contents contents
|
635
|
+
end
|
636
|
+
if options[:delete]
|
637
|
+
answer = $terminal.ask('All contents listed above are deleted. Continue? [y/N]') { |q| q.validate = /[yn]/i; q.default = 'n' }
|
638
|
+
@cam.delete_contents contents if answer == 'y'
|
639
|
+
end
|
640
|
+
end
|
641
|
+
finalize
|
642
|
+
end
|
643
|
+
|
644
|
+
end
|
645
|
+
end
|
646
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SonyCameraRemoteAPI
|
2
|
+
# Camera is not compatible to Camera Remote API.
|
3
|
+
class ServerNotCompatible < StandardError; end
|
4
|
+
# Given version for the API is invalid
|
5
|
+
class APIVersionInvalid < StandardError; end
|
6
|
+
# Given service type for the API is invalid
|
7
|
+
class ServiceTypeInvalid < StandardError; end
|
8
|
+
# API is proviced by multiple services, but user did not specified it
|
9
|
+
class ServiceTypeNotGiven < StandardError; end
|
10
|
+
|
11
|
+
# Waiting for event notification of camera parameter change timed out
|
12
|
+
class EventTimeoutError < StandardError; end
|
13
|
+
|
14
|
+
# Base Error class having some information as object.
|
15
|
+
class StandardErrorWithObj < StandardError
|
16
|
+
attr_reader :object
|
17
|
+
def initialize(object = nil)
|
18
|
+
@object = object
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This API is not supported by the camera
|
23
|
+
class APINotSupported < StandardErrorWithObj; end
|
24
|
+
# This API is supported but not available now
|
25
|
+
class APINotAvailable < StandardErrorWithObj; end
|
26
|
+
# Given argument is not available
|
27
|
+
class IllegalArgument < StandardErrorWithObj; end
|
28
|
+
# This API is forbidden to the general users
|
29
|
+
class APIForbidden < StandardErrorWithObj; end
|
30
|
+
|
31
|
+
# API returned error response
|
32
|
+
class APIExecutionError < StandardError
|
33
|
+
attr_reader :method, :request, :err_code, :err_msg
|
34
|
+
def initialize(method, request, response)
|
35
|
+
@method = method
|
36
|
+
@request = request
|
37
|
+
@err_code = response['error'][0]
|
38
|
+
@err_msg = response['error'][1]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|