/// <summary>
        /// Get Option values
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task <OptionValues> GetOptionsAsync(GetOptionsParam request)
        {
            var optionParams = new GetOptionParams()
            {
                Options = request.OptionNames
            };
            var command = new ThetaRequest <GetOptionParams>()
            {
                Name = "camera.getOptions", Parameters = optionParams
            };

            try
            {
                var response = await ExecuteCommandAsync <GetOptionParams>(command);
                await CheckResponseAsync(response);

                var res = JsonUtil.ToObject <ThetaResponse <SetOptionParams> >(await response.Content.ReadAsStreamAsync());
                return(res.Results.Options);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                return(null);
            }
        }
        /// <summary>
        /// Stop running self-timer. <br />
        /// If self-timer(exposureDelay) is enabled, self-timer shooting(camera.takePicture) is started.
        /// </summary>
        /// <returns></returns>
        async public Task StopSelfTimer()
        {
            var command = new ThetaRequest <Object>()
            {
                Name = "camera._stopSelfTimer"
            };

            using (var response = await ExecuteCommandAsync <Object>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Turns the wireless LAN off.
        /// </summary>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task FinishWlan()
        {
            var command = new ThetaRequest <Object>()
            {
                Name = "camera._finishWlan"
            };

            using (var response = await ExecuteCommandAsync <Object>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Starts session
        /// </summary>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task <StartSessionResponse> StartSessionAsync()
        {
            var command = new ThetaRequest <Object>()
            {
                Name = "camera.startSession"
            };
            var response = await ExecuteCommandAsync <Object>(command);

            await CheckResponseAsync(response);

            return(JsonUtil.ToObject <ThetaResponse <StartSessionResponse> >(await response.Content.ReadAsStreamAsync()).Results);
        }
        /// <summary>
        /// Gets a list of installed plugins.
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        async public Task <ListPluginsResponse> ListPluginsAsync()
        {
            var command = new ThetaRequest <Object>()
            {
                Name = "camera._listPlugins"
            };
            var response = await ExecuteCommandAsync <Object>(command);

            await CheckResponseAsync(response);

            return(JsonUtil.ToObject <ListPluginsResponse>(await response.Content.ReadAsStreamAsync()));
        }
        /// <summary>
        /// List files in the camera device
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task <ListFilesResponse> ListFilesAsync(ListFilesParam param)
        {
            var command = new ThetaRequest <ListFilesParam>()
            {
                Name = "camera.listFiles", Parameters = param
            };
            var response = await ExecuteCommandAsync <ListFilesParam>(command);

            await CheckResponseAsync(response);

            return(JsonUtil.ToObject <ThetaResponse <ListFilesResponse> >(await response.Content.ReadAsStreamAsync()).Results);
        }
        /// <summary>
        /// Close session
        /// </summary>
        async public Task CloseSessionAsync(String sessionId)
        {
            var command = new ThetaRequest <SessionParam>()
            {
                Name = "camera.closeSession", Parameters = new SessionParam()
                {
                    SessionId = sessionId
                }
            };

            using (var response = await ExecuteCommandAsync <SessionParam>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Delete an image on the camera
        /// </summary>
        /// <param name="fileUrl"></param>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task DeleteAsync(String[] fileUrls)
        {
            var command = new ThetaRequest <DeleteParam>()
            {
                Name = "camera.delete", Parameters = new DeleteParam()
                {
                    FileUrls = fileUrls
                }
            };

            using (var response = await ExecuteCommandAsync <DeleteParam>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Starts or stops plugin.
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        async public Task PluginControlAsync(PLUGIN_ACTION action, String pluginName = null)
        {
            var command = new ThetaRequest <PluginControlParam>()
            {
                Name       = "camera._pluginControl",
                Parameters = new PluginControlParam()
                {
                    PluginAction = action, Plugin = pluginName
                }
            };

            using (var response = await ExecuteCommandAsync <PluginControlParam>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Sets the installed pugin for boot. <br />
        /// For RICOH THETA Z1 or later, this command is ignored.Use camera._pluginControl
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        async public Task SetPluginsAsync(String packageName)
        {
            var command = new ThetaRequest <SetPluginParam>()
            {
                Name       = "camera._setPlugin",
                Parameters = new SetPluginParam()
                {
                    PackageName = packageName
                }
            };

            using (var response = await ExecuteCommandAsync <SetPluginParam>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Starts still image shooting
        /// </summary>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task <TakePictureResponse> TakePictureAsync()
        {
            var state = await StateAsync();

            var command = new ThetaRequest <Object>()
            {
                Name = "camera.takePicture"
            };
            var response = await ExecuteCommandAsync <Object>(command);

            await CheckResponseAsync(response);

            return(JsonUtil.ToObject <TakePictureResponse>(await response.Content.ReadAsStreamAsync()));
        }
        /// <summary>
        /// Set option parameters
        /// </summary>
        /// <param name="optionValues"></param>
        /// <param name="sessionId">if current api is 2.0, session ID is required to change to 2.1</param>
        /// <returns></returns>
        /// <exception cref="SerializationException"></exception>
        /// <exception cref="ThetaWifiApiException"></exception>
        async public Task SetOptionsAsync(OptionValues optionValues, String sessionId = null)
        {
            var optionParams = new SetOptionParams()
            {
                Options = optionValues
            };

            if (sessionId != null)
            {
                optionParams.SessionId = sessionId;
            }
            var command = new ThetaRequest <SetOptionParams>()
            {
                Name = "camera.setOptions", Parameters = optionParams
            };

            using (var response = await ExecuteCommandAsync <SetOptionParams>(command))
                await CheckResponseAsync(response);
        }
        /// <summary>
        /// Requesting a video stream to theta <br />
        /// It is using HttpWebRequest because HttpClient.PostAsync never returns.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sendType">POST/GET</param>
        /// <param name="command"></param>
        /// <param name="commandPath"></param>
        /// <returns></returns>
        async private static Task <HttpWebResponse> RequestVideoStreamAsync()
        {
            var command = new ThetaRequest <Object>()
            {
                Name = "camera.getLivePreview"
            };

            HttpWebRequest request = System.Net.WebRequest.Create(Path.Combine(THETA_URL, "osc/commands/execute")) as HttpWebRequest;

            request.Method          = "POST";
            request.Accept          = "application/json";
            request.ContentType     = "application/json";
            request.ContinueTimeout = 3000;

            var jsonString = JsonUtil.ToSring <ThetaRequest <Object> >(command).Replace(":999", ":0");
            var reqStream  = await request.GetRequestStreamAsync();

            byte[] buffer = UTF8Encoding.UTF8.GetBytes(jsonString);
            reqStream.Write(buffer, 0, buffer.Length);
            reqStream.Flush();

            return(await request.GetResponseAsync() as HttpWebResponse);
        }
 /// <summary>
 /// Common function to send a command.
 /// </summary>
 /// <param name="command"></param>
 /// <returns></returns>
 async private Task <HttpResponseMessage> ExecuteStatusAsync <T>(ThetaRequest <T> command)
 {
     return(await SendRequestAsync(SEND_TYPE.POST, command, "osc/commands/status"));
 }
 /// <summary>
 /// Common function to send a command.
 /// </summary>
 /// <param name="command"></param>
 /// <returns></returns>
 async private Task <HttpResponseMessage> ExecuteCommandAsync <T>(ThetaRequest <T> command, int?timeout = null)
 {
     return(await SendRequestAsync(SEND_TYPE.POST, command, "osc/commands/execute", timeout));
 }