Class: SonyCameraRemoteAPI::CameraAPIGroupManager

Inherits:
Object
  • Object
show all
Includes:
Logging, Utils
Defined in:
lib/sony_camera_remote_api/camera_api_group.rb,
lib/sony_camera_remote_api/camera_api_group_def.rb

Overview

Camera API group sublayer class, which is included in Camera API layer class. This class handles API groups that get/set specific parameters of the camera.

Defined Under Namespace

Classes: APIGroup

Constant Summary collapse

@@api_groups_all =
{
  ShootMode:            APIGroup.new(:ShootMode,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) { r[21]['currentShootMode'] == v },
                                    ),
  # setLiveviewSize API does not exist: we use startLiveviewWithSize API instead.
  LiveviewSize:         APIGroup.new(:LiveviewSize,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     nil,
                                    ),
  ZoomSetting:          APIGroup.new(:ZoomSetting,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['zoom'] },
                                     ->(v, avl, cond) { [{ 'zoom' => v }] },
                                    ),
  TrackingFocus:        APIGroup.new(:TrackingFocus,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['trackingFocus'] },
                                     ->(v, avl, cond) { [{ 'trackingFocus' => v }] },
                                    ),
  ContShootingMode:     APIGroup.new(:ContShootingMode,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['contShootingMode'] },
                                     ->(v, avl, cond) { [{ 'contShootingMode' => v }] },
                                     end_condition: ->(v, r) { r[38]['contShootingMode'] == v },
                                    ),
  ContShootingSpeed:    APIGroup.new(:ContShootingSpeed,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['contShootingSpeed'] },
                                     ->(v, avl, cond) { [{ 'contShootingSpeed' => v }] },
                                     end_condition: ->(v, r) { r[39]['contShootingSpeed'] == v },
                                    ),
  SelfTimer:            APIGroup.new(:SelfTimer,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  ExposureMode:         APIGroup.new(:ExposureMode,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  FocusMode:            APIGroup.new(:FocusMode,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  # Handle parameter value by EV instead of exposure compensation index value.
  ExposureCompensation: APIGroup.new(:ExposureCompensation,
                                     # Get supported exposure compensation Array by EV.
                                     ->(r, cond) do
                                       ev_list = []
                                       r.transpose.each do | max, min, step |
                                         step = get_exposure_compensation_step step
                                         next if step == 0
                                         ev_list << (min..max).map { |e| (e * step).round(1) }
                                       end
                                       ev_list.size == 1 ? ev_list[0] : ev_list
                                     end,
                                     # Get available exposure compensation Array by EV.
                                     ->(r, cond) do
                                       max, min, step = r[1..-1]
                                       step = get_exposure_compensation_step step
                                       (min..max).map { |e| (e * step).round(1) }
                                     end,
                                     # Get current exposure compensation by EV.
                                     ->(r, cond) do
                                       step = cond[25]['stepIndexOfExposureCompensation']
                                       step = get_exposure_compensation_step step
                                       (r[0] * step).round(1)
                                     end,
                                     # Set exposure compensation By index from EV.
                                     ->(v, avl, cond) do
                                       avl.index(v) - avl.index(0)
                                     end,
                                     # Get exposure compensation step.
                                     start_condition: ->(r) do
                                       r[25]['stepIndexOfExposureCompensation'] != nil
                                     end,
                                    ),
  FNumber:              APIGroup.new(:FNumber,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) { r[27]['currentFNumber'] == v },
                                    ),
  ShutterSpeed:         APIGroup.new(:ShutterSpeed,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) { r[32]['currentShutterSpeed'] == v },
                                    ),
  IsoSpeedRate:         APIGroup.new(:IsoSpeedRate,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) { r[29]['currentIsoSpeedRate'] == v },
                                    ),
  # Enable more intuitive parameter format as followings:
  #  * Hash-1 : { 'whiteBalanceMode' => mode, 'colorTemperature' => color-temperature }
  #  * Hash-2 : { whiteBalanceMode: mode, colorTemperature: color-temperature}
  #  * Array (original): [ mode, temperature-enabled-flag, color-temperature ]
  WhiteBalance:         APIGroup.new(:WhiteBalance,
                                     # Get supported white-balance mode by Array of Hash.
                                     #   * delete 'colorTemperatureRange' key if unneeded.
                                     #   * get color temperature list rather than min/max/step.
                                     ->(r, cond) do
                                       mode_temp_list = []
                                       r[0].map do |e|
                                         mt = {}
                                         mt['whiteBalanceMode'] = e['whiteBalanceMode']
                                         if e['colorTemperatureRange'].present?
                                           max, min, step = e['colorTemperatureRange']
                                           mt['colorTemperature'] = (min..max).step(step).to_a
                                         end
                                         mode_temp_list << mt
                                       end
                                       mode_temp_list
                                     end,
                                     # Get available white-balance mode by Array of Hash, almost same as supported-accessor.
                                     ->(r, cond) do
                                       mode_temp_list = []
                                       r[1].map do |e|
                                         mt = {}
                                         mt['whiteBalanceMode'] = e['whiteBalanceMode']
                                         if e['colorTemperatureRange'].present?
                                           max, min, step = e['colorTemperatureRange']
                                           mt['colorTemperature'] = (min..max).step(step).to_a
                                         end
                                         mode_temp_list << mt
                                       end
                                       mode_temp_list
                                     end,
                                     # Get current white-balance mode and temperature by Hash.
                                     # temperature key is deleted if unneeded.
                                     ->(r, cond) do
                                       r[0].delete_if { |k,v| k == 'colorTemperature' and v == -1 }
                                     end,
                                     # Set white-balance mode, converting Hash-1 to Array.
                                     ->(v, avl, cond) do
                                       temp_flag   = v.key?('colorTemperature') ? true : false
                                       temperature = v.key?('colorTemperature') ? v['colorTemperature'] : 0
                                       [v['whiteBalanceMode'], temp_flag, temperature]
                                     end,
                                     # Accept the parameter forms as followings:
                                     # Array and Hash-2 is converted to Hash-1.
                                     preprocess_value: ->(v, arg, cond) do
                                       if v.is_a? Array
                                         ret = {}
                                         ret['whiteBalanceMode'] = v[0]
                                         ret['colorTemperature'] = v[2] if v[1] == true
                                         ret
                                       elsif v.is_a? Hash
                                         Hash[v.map { |k, v| [k.is_a?(Symbol) ? k.to_s : k , v] }]
                                       end
                                     end,
                                     # Check the given value is available by
                                     #   * comparing mode
                                     #   * color temperature value is included in 'colorTemperature' array
                                     #     when Color Temperature mode
                                     check_availability: ->(v, avl, cond) do
                                       # check mode
                                       sel = avl.find {|e| v['whiteBalanceMode'] == e['whiteBalanceMode'] }
                                       return false if sel.nil?
                                        if sel.key? 'colorTemperatureRange'
                                         # temperature
                                         return true if sel['colorTemperature'].include? v['colorTemperature']
                                         false
                                       else
                                         true
                                       end
                                     end,
                                    ),
  # ProgramShift:         APIGroup.new(:ProgramShift,
  #                                    ->(v, cond){ v[0] },
  #                                    ->(v, cond){ v[1] },
  #                                    ->(v, cond){ v[0] },
  #                                    ->(v, avl, cond){ [v] },
  #                                   ),
  FlashMode:            APIGroup.new(:FlashMode,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] }
                                    ),
  # Enable more intuitive parameter format as followings:
  #   * Hash-1 :  { 'aspect' => aspect, 'size' => size }
  #   * Hash-2 :  { aspect: aspect, size: size }
  #   * Array (original) : [ aspect, size ]
  # make setStillSize accept Hash as parameter, because getSupported/AvailableStillSize returns Hash
  StillSize:            APIGroup.new(:StillSize,
                                     # Get supported still size and aspect by Array of Hash.
                                     ->(r, cond) { r[0] },
                                     # Get available still size and aspect by Array of Hash.
                                     ->(r, cond) { r[1] },
                                     # Get current still size and aspect by Hash.
                                     ->(r, cond) { r[0] },
                                     # Set still size and aspect, converting Hash-1 to Array.
                                     ->(v, avl, cond) { [v['aspect'], v['size']] },
                                     # Accept the parameter forms as followings:
                                     # Array and Hash-2 is converted to Hash-1.
                                     preprocess_value: ->(v, arg, cond) do
                                       if v.is_a? Array
                                         ret = {}
                                         ret['aspect'] = v[0]
                                         ret['size'] = v[1]
                                         ret
                                       elsif v.is_a? Hash
                                         Hash[v.map { |k, v| [k.is_a?(Symbol) ? k.to_s : k , v] }]
                                       end
                                     end,
                                    ),
  StillQuality:         APIGroup.new(:StillQuality,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['stillQuality'] },
                                     ->(v, avl, cond) { [{ 'stillQuality' => v }] },
                                    ),
  PostviewImageSize:    APIGroup.new(:PostviewImageSize,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  MovieFileFormat:      APIGroup.new(:MovieFileFormat,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['movieFileFormat'] },
                                     ->(v, avl, cond) { [{ 'movieFileFormat' => v }] },
                                     end_condition: ->(v, r) { r[45]['movieFileFormat'] == v },
                                    ),
  MovieQuality:         APIGroup.new(:MovieQuality,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) { r[13]['currentMovieQuality'] == v },
                                    ),
  SteadyMode:           APIGroup.new(:SteadyMode,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  ViewAngle:            APIGroup.new(:ViewAngle,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                    ),
  SceneSelection:       APIGroup.new(:SceneSelection,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['scene'] },
                                     ->(v, avl, cond) { [{ 'scene' => v }] },
                                    ),
  ColorSetting:         APIGroup.new(:ColorSetting,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['colorSetting'] },
                                     ->(v, avl, cond) { [{ 'colorSetting' => v }] },
                                    ),
  IntervalTime:         APIGroup.new(:IntervalTime,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['intervalTimeSec'] },
                                     ->(v, avl, cond) { [{ 'intervalTimeSec' => v }] },
                                    ),
  LoopRecTime:          APIGroup.new(:LoopRecTime,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['loopRecTimeMin'] },
                                     ->(v, avl, cond) { [{ 'loopRecTimeMin' => v }] },
                                    ),
  WindNoiseReduction:   APIGroup.new(:WindNoiseReduction,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['windNoiseReduction'] },
                                     ->(v, avl, cond) { [{ 'windNoiseReduction' => v }] },
                                    ),
  AudioRecording:       APIGroup.new(:AudioRecording,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['audioRecording'] },
                                     ->(v, avl, cond) { [{ 'audioRecording' => v }] },
                                    ),
  FlipSetting:          APIGroup.new(:FlipSetting,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['flip'] },
                                     ->(v, avl, cond) { [{ 'flip' => v }] },
                                    ),
  TvColorSystem:        APIGroup.new(:TvColorSystem,
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['candidate'] },
                                     ->(r, cond) { r[0]['tvColorSystem'] },
                                     ->(v, avl, cond) { [{ 'tvColorSystem' => v }] },
                                    ),
  # 'cameraFunctionResult' does not work depending on the timing of setCameraFunction call...
  CameraFunction:       APIGroup.new(:CameraFunction,
                                     ->(r, cond) { r[0] },
                                     ->(r, cond) { r[1] },
                                     ->(r, cond) { r[0] },
                                     ->(v, avl, cond) { [v] },
                                     end_condition: ->(v, r) do
                                       # r[15]['cameraFunctionResult'] == 'Success'
                                       r[12]['currentCameraFunction'] == v
                                     end
                                    ),
  InfraredRemoteControl: APIGroup.new(:InfraredRemoteControl,
                                      ->(r, cond) { r[0]['candidate'] },
                                      ->(r, cond) { r[0]['candidate'] },
                                      ->(r, cond) { r[0]['infraredRemoteControl'] },
                                      ->(v, avl, cond) { [{ 'infraredRemoteControl' => v }] },
                                    ),
  AutoPowerOff:         APIGroup.new(:AutoPowerOff,
                                      ->(r, cond) { r[0]['candidate'] },
                                      ->(r, cond) { r[0]['candidate'] },
                                      ->(r, cond) { r[0]['autoPowerOff'] },
                                      ->(v, avl, cond) { [{ 'autoPowerOff' => v }] },
                                    ),
  BeepMode:             APIGroup.new(:BeepMode,
                                      ->(r, cond) { r[0] },
                                      ->(r, cond) { r[1] },
                                      ->(r, cond) { r[0] },
                                      ->(v, avl, cond) { [v] },
                                    ),
}

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils

generate_sequencial_filenames, get_next_file_number, partial_and_unique_match, print_array_in_columns

Methods included from Logging

configure_logger_for, #log, log_file, logger_for, #output_to

Constructor Details

#initialize(camera_api_manager) ⇒ CameraAPIGroupManager

Create CameraAPIManager object.

Parameters:



127
128
129
130
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 127

def initialize(camera_api_manager)
  @api_manager = camera_api_manager
  @api_groups = make_api_group_list camera_api_manager.apis
end

Class Method Details

.get_exposure_compensation_step(step) ⇒ Object

Convert exposure compensation step of ExposureCompensation API group into the real step.



5
6
7
8
9
10
11
# File 'lib/sony_camera_remote_api/camera_api_group_def.rb', line 5

def self.get_exposure_compensation_step(step)
  case step
    when 1 then 0.33
    when 2 then 0.5
    else 0
  end
end

Instance Method Details

#get_current(group_name, **opts) ⇒ Object

Get current value of a camera parameter.

Parameters:

  • group_name (Symbol)

    Parameter name

Returns:

  • (Object)

    current value

Raises:

  • APINotSupported, APINotAvailable, IllegalArgument



137
138
139
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 137

def get_current(group_name, **opts)
  get_parameter(group_name, available: false, supported: false, **opts)[:current]
end

#get_current!(group_name, **opts) ⇒ Object

Almost same as get_current, but this method does not raise Exception even if the parameter is not supported, available or its arguments illegal.

Parameters:

  • group_name (Symbol)

    Parameter name

Returns:

  • (Object)

    current value



146
147
148
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 146

def get_current!(group_name, **opts)
  get_parameter!(group_name, available: false, supported: false, **opts)[:current]
end

#get_parameter(group_name, available: true, supported: true, **opts) ⇒ Hash

Get supported/available/current value of a camera parameter.

Parameters:

  • group_name (Symbol)

    Parameter name

  • available (Boolean) (defaults to: true)

    Flag to get available values

  • supported (Boolean) (defaults to: true)

    Flag to get supported values

Returns:

  • (Hash)

    current/available/supported values

Raises:

  • APINotSupported, APINotAvailable, IllegalArgument



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 157

def get_parameter(group_name, available: true, supported: true, **opts)
  result = { current: nil, available: [], supported: [] }
  begin
    grp = search_group group_name
  rescue APIForbidden, APINotSupported => e
    raise e.class.new(result), e.message
  end
  condition = grp.start_condition(@api_manager)
  begin
    result.merge! grp.current_value(@api_manager, condition, **opts)
  rescue APINotAvailable, IllegalArgument => e
    raise e.class.new(result), e.message
  end
  begin
    # Timeout is set shorter than usual for getting hardware-affected parameter.
    result.merge! grp.available_values(@api_manager, condition, timeout: 1, **opts) if available
    result.merge! grp.supported_values(@api_manager, condition, timeout: 1, **opts) if supported
  rescue APINotAvailable, IllegalArgument => e
    # Comes here if the parameter is hardware-affected.
  end
  result
end

#get_parameter!(group_name, **opts) ⇒ Object

Almost same as get_parameter, but this method does not raise Exception even if the parameter is not supported, available or its arguments illegal.



183
184
185
186
187
188
189
190
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 183

def get_parameter!(group_name, **opts)
  get_parameter(group_name, **opts)
rescue APIForbidden, APINotSupported, APINotAvailable, IllegalArgument => e
  log.error e.message
  e.object
rescue HTTPClient::BadResponseError => e
  log.error e.message
end

#set_parameter(group_name, value, *args, **opts) ⇒ Hash

Set a camera parameter to the given value.

Parameters:

  • group_name (Symbol)

    Parameter name

  • value (Object)

    New value to be set

Returns:

  • (Hash)

    current/available/old values

Raises:

  • APINotSupported, APINotAvailable, IllegalArgument



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 198

def set_parameter(group_name, value, *args, **opts)
  result = { current: nil, available: [], old: nil }
  begin
    grp = search_group group_name
  rescue APIForbidden, APINotSupported => e
    raise e.class.new(result), e.message
  end

  condition = grp.start_condition(@api_manager)
  begin
    value = grp.preprocess_value(value, args, condition)
    # If value is equal to current value, do nothing.
    result.merge! grp.current_value(@api_manager, condition, **opts)
    result[:old] = result[:current]
    if grp.eq_current? value, result[:current], condition
      return result
    end
    # If not, check if the value is available.
    result.merge! grp.available_values(@api_manager, condition, **opts)
    if grp.is_available? value, result[:available], condition
      # Save current value and call set API.
      result[:old] = result[:current]
      result.merge! grp.set_value(@api_manager, value, result[:available], condition)
    else
      # If the value is not available, raise error.
      raise IllegalArgument.new, "The value '#{value}' is not available for parameter '#{group_name}'. current: #{result[:current]}, available: #{result[:available]}"
    end
  rescue APINotAvailable, IllegalArgument => e
    raise e.class.new(result), e.message
  end
  result
end

#set_parameter!(group_name, value, **opts) ⇒ Object

Almost same as set_parameter, but this method does not raise Exception even if the parameter is not supported, available or its arguments illegal.



234
235
236
237
238
239
240
241
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 234

def set_parameter!(group_name, value, **opts)
  set_parameter(group_name, value, **opts)
rescue APIForbidden, APINotSupported, APINotAvailable, IllegalArgument => e
  log.error e.message
  e.object
rescue HTTPClient::BadResponseError => e
  log.error e.message
end

#support_group?(group_name) ⇒ Boolean

Returns whether the parameter is supported or not.

Returns:

  • (Boolean)

    true if the parameter is supported, false otherwise.



246
247
248
# File 'lib/sony_camera_remote_api/camera_api_group.rb', line 246

def support_group?(group_name)
  @api_groups.key? group_name
end