Created
August 14, 2021 13:04
-
-
Save andrieslouw/a79c11b9827f501e37775b430fa1315e to your computer and use it in GitHub Desktop.
Sony RX0 II camera read
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading.Tasks; | |
using System.Threading; | |
using System.Collections.Generic; | |
using System.Net; | |
using System.Net.Http; | |
using System.Timers; | |
using System.Text.RegularExpressions; | |
using Newtonsoft.Json.Linq; | |
using System.Diagnostics; | |
using Serilog; | |
/* | |
Example: | |
Camera myCamera = new Camera(); | |
myCamera.CameraPowerOnProcedure(); | |
App.myCamera.StartRecording(); | |
myCamera.StopRecording(); | |
await myCamera.CameraTurnOffAsync(); | |
*/ | |
namespace VideoBooth | |
{ | |
public class Camera | |
{ | |
private String cid = ""; | |
private String bid = ""; | |
private String modelName = ""; | |
private String serialNumber = ""; | |
private String browserKey = ""; | |
private Uri baseAddress; | |
private static System.Timers.Timer aTimer; | |
private CookieContainer myCookieContainer = new CookieContainer(); | |
private long timestampInit = 0; | |
public bool connectionBoxConnected = false; | |
public bool cameraConnected = false; | |
public int liveViewPortNumber = 0; | |
//Status | |
public String movieRecordingState = ""; | |
public String recordingSettingMovie = ""; | |
public String batteryLevelIndicator = ""; | |
public String MediaSlot1Status = ""; | |
public int remainingShootingTime = 0; | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public Camera() | |
{ | |
Log.Information("[Camera] constructor called"); | |
baseAddress = new Uri("http://169.254.200.200"); | |
// broadcast address when camera is in stand-by | |
cid = "169.254.200.200:-1:-1"; | |
Log.Information("[Camera] constructor done"); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public void PrepareState() | |
{ | |
// get 169.254.200.200/ | |
// This gets the index page which sets a cookie in the cookie container | |
var responseString = ""; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = this.baseAddress }) | |
{ | |
var response = client.GetAsync("").Result; | |
responseString = response.Content.ReadAsStringAsync().Result; | |
} | |
this.timestampInit = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); | |
// get browser key from values.php | |
this.getBrowserKey().Wait(); // sets the browser key | |
Log.Information("Browserkey set: {0}", this.browserKey); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public Boolean CanRecord() | |
{ | |
if (connectionBoxConnected == false) | |
{ | |
Log.Information("[record check]\tNo connection box"); | |
return false; | |
} | |
else if (cameraConnected == false) | |
{ | |
Log.Information("[record check]\tNo camera"); | |
return false; | |
} | |
else if (MediaSlot1Status == "NO CARD") | |
{ | |
Log.Information("[record check]\tNo card"); | |
return false; | |
} | |
else if (remainingShootingTime < 120) | |
{ | |
Log.Information("[record check]\tShooting time returned from camera API is 0 seconds."); | |
return false; | |
} | |
else | |
{ | |
Log.Information("[record check]\tCamera can record"); | |
return true; | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public void StopRecording() | |
{ | |
this.CameraRecordStopCommand(); | |
} | |
public void Focus() | |
{ | |
this.StartFocus(); | |
this.StopFocus(); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public void StartRecording() | |
{ | |
this.CheckBoxStateExtendedFormData(); | |
this.CheckBoxStateBidsOn(); | |
this.CameraRecordStartCommand(); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public void TurnOff() | |
{ | |
this.CameraTurnOffAsync().Wait(); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
// TODO; create int return value to indicate if camera has been found | |
public void CameraPowerOnProcedure() | |
{ | |
Log.Information("Power on procedure:"); | |
// TODO: Check if connection box is online | |
// Check if camera is attached to connection box | |
this.GetCam0InfoAsyncStartup().Wait(); | |
if (cameraConnected == false) | |
{ | |
Log.Information("\t[Camera] turning on"); | |
CameraTurnOn(); | |
Log.Information("\t[Camera] waiting 10 seconds for powering on"); | |
Thread.Sleep(10000); // wait 10 seconds | |
Log.Information("\t[Camera] checking if powered on"); | |
// Check if camera is attached to connection box | |
this.GetCam0InfoAsyncStartup().Wait(); | |
// Try second time if camera still not found | |
if (cameraConnected == false) | |
{ | |
Log.Information("\t[Camera] camera not found yet"); | |
Log.Information("[Camera] turning on again"); | |
CameraTurnOn(); | |
Log.Information("[Camera] waiting 10 seconds for powering on"); | |
Thread.Sleep(10000); // wait 10 seconds | |
Log.Information("[Camera] checking again if powered on"); | |
// Check if camera is attached to connection box | |
this.GetCam0InfoAsyncStartup().Wait(); | |
} | |
} | |
// Assume camera is on for now; This will be periodically be checked in timed function | |
this.SetTimer(); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void SetTimer() | |
{ | |
// Create a timer with a two second interval. | |
aTimer = new System.Timers.Timer(10_000); | |
// Hook up the Elapsed event for the timer. | |
aTimer.Elapsed += this.OnTimedEvent; | |
aTimer.AutoReset = true; | |
aTimer.Enabled = true; | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void CheckBoxStateBidsOn() | |
{ | |
var values1 = new Dictionary<string, string> | |
{ | |
{ "browser_key", this.browserKey }, | |
{ "bids_on[]", "169.254.200.200" } | |
}; | |
var content1 = new FormUrlEncodedContent(values1); | |
//Log.Information("Sending BOX status request from browser key {0}", this.browserKey); | |
using (var handler = new HttpClientHandler() { CookieContainer = this.myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) | |
{ | |
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Origin", "http://169.254.200.200"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Referer", "http://169.254.200.200"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Connection", "keep-alive"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded"); | |
HttpResponseMessage response; | |
string responseString = ""; | |
try | |
{ | |
response = client.PostAsync("/api.php?v=2&action=check_box_state", content1).Result; | |
responseString = response.Content.ReadAsStringAsync().Result; | |
} | |
catch (Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
Log.Information(responseString); | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void CheckBoxStateExtendedFormData() | |
{ | |
var values1 = new Dictionary<string, string> | |
{ | |
{ "browser_key", this.browserKey }, | |
{ "bids_off[]", "169.254.200.200" }, | |
{ "master_notification", "1" }, | |
{ "ts", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString() }, | |
{ "sync_type", "0x01" }, | |
}; | |
var content1 = new FormUrlEncodedContent(values1); | |
//Log.Information("Sending BOX status request from browser key {0}", this.browserKey); | |
using (var handler = new HttpClientHandler() { CookieContainer = this.myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) | |
{ | |
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("*/*")); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Origin", "http://169.254.200.200"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Referer", "http://169.254.200.200"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Connection", "keep-alive"); | |
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded"); | |
//TODO, catch exceptions (https://forums.xamarin.com/discussion/101202/try-catch-on-httpclient-not-working) | |
try | |
{ | |
var response1 = client.PostAsync("/api.php?v=2&action=check_box_state", content1).Result; | |
var responseString1 = response1.Content.ReadAsStringAsync().Result; | |
//Log.Information(responseString1); | |
} | |
catch (Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void OnTimedEvent(Object source, ElapsedEventArgs e) | |
{ | |
this.UpdateCam0StatusAsync().Wait(); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private async Task UpdateCam0StatusAsync() | |
{ | |
Log.Debug("[Status update] Retrieving latest status from camera... "); | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "check_cam_state" }, | |
{ "param", "1" }, | |
{ "bid", "169.254.200.200" } | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
var camStateInfo = new JObject(); | |
//TODO, catch exceptions (https://forums.xamarin.com/discussion/101202/try-catch-on-httpclient-not-working) | |
try | |
{ | |
var content = new FormUrlEncodedContent(values); | |
var response = await client.PostAsync("http://169.254.200.200/api.php", content); | |
var responseString = await response.Content.ReadAsStringAsync(); | |
JObject allInfo = JObject.Parse(responseString); | |
camStateInfo = (JObject)allInfo["cams"][0]["prop"]["state"]; | |
if (camStateInfo.ContainsKey("Movie_Recording_State")) | |
movieRecordingState = camStateInfo["Movie_Recording_State"][1].ToString(); | |
if (camStateInfo.ContainsKey("Recoding_Setting_Movie")) | |
recordingSettingMovie = camStateInfo["Recoding_Setting_Movie"][1].ToString(); | |
if (camStateInfo.ContainsKey("Battery_Level_Indicator")) | |
batteryLevelIndicator = camStateInfo["Battery_Level_Indicator"][1].ToString(); | |
if (camStateInfo.ContainsKey("Media_SLOT1_Status")) | |
MediaSlot1Status = camStateInfo["Media_SLOT1_Status"][1].ToString(); | |
if (camStateInfo.ContainsKey("Media_SLOT1_Remaining_Shooting_Time")) | |
{ | |
string remainingShootingTimeString = camStateInfo["Media_SLOT1_Remaining_Shooting_Time"][1].ToString(); | |
remainingShootingTime = Convert.ToInt32(remainingShootingTimeString, 16); | |
} | |
connectionBoxConnected = true; | |
} | |
catch (Exception e) | |
{ | |
Log.Information("[Status update]" + e); | |
cameraConnected = false; | |
//Restarting camera | |
Log.Information("[Status update] Trying to start camera again"); | |
Log.Information("[Status update] Temporarily stopping timer"); | |
aTimer.Stop(); | |
Log.Information("[Status update] Power on procedure"); | |
CameraPowerOnProcedure(); | |
Log.Information("[Status update] Starting timer again"); | |
aTimer.Start(); | |
} | |
Log.Information("\t" + movieRecordingState); | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void StopFocus() | |
{ | |
/* On and Off command seems to be working as a toggle switch. Turn the camera on twices, turns | |
the camera on and off. | |
*/ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "half_button_off_um" }, | |
{ "cids[]", this.cid} | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
var content = new FormUrlEncodedContent(values); | |
var response = client.PostAsync("http://169.254.200.200/api.php", content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void StartFocus() | |
{ | |
/* On and Off command seems to be working as a toggle switch. Turn the camera on twices, turns | |
the camera on and off. | |
*/ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "half_button_on_um" }, | |
{ "cids[]", this.cid} | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
var content = new FormUrlEncodedContent(values); | |
var response = client.PostAsync("http://169.254.200.200/api.php", content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void CameraTurnOn() | |
{ | |
/* On and Off command seems to be working as a toggle switch. Turn the camera on twices, turns | |
the camera on and off. | |
*/ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "power_on_um" }, | |
{ "cids[]", this.cid} | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
var content = new FormUrlEncodedContent(values); | |
var response = client.PostAsync("http://169.254.200.200/api.php", content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
//Log.Information(responseString); | |
} | |
} | |
public Uri getLiveStreamUri() | |
{ | |
String baseAddressString = baseAddress.ToString(); | |
baseAddressString = baseAddressString.TrimEnd('/'); | |
return new Uri(baseAddressString + ":" + liveViewPortNumber + "/?action=stream"); | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private async Task GetCam0InfoAsyncStartup() | |
{ | |
/* On and Off command seems to be working as a toggle switch. Turn the camera on twices, turns | |
the camera on and off. | |
*/ | |
Log.Information("[GetCam0InfoAsyncStartup] in method"); | |
// Body to check cam status on bus 169.254.200.200, probably the first camera control box | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "check_cam_state" }, | |
{ "param", "1" }, | |
{ "bid", "169.254.200.200" } | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
Log.Information("[GetCam0InfoAsyncStartup] set dict"); | |
var content = new FormUrlEncodedContent(values); | |
Log.Information("[GetCam0InfoAsyncStartup] URL encoded"); | |
Log.Information(content.ToString()); | |
var camInfo = new JObject(); | |
//TODO, catch exceptions (https://forums.xamarin.com/discussion/101202/try-catch-on-httpclient-not-working) | |
try | |
{ | |
var response = client.PostAsync("http://169.254.200.200/api.php", content).Result; // fix this Result shit (https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html) | |
Log.Information("[GetCam0InfoAsyncStartup] async post send"); | |
var responseString = await response.Content.ReadAsStringAsync(); | |
JObject allInfo = JObject.Parse(responseString); | |
Log.Information("[GetCam0InfoAsyncStartup] content read"); | |
Log.Information("[GetCam0InfoAsyncStartup] JSON parsed"); | |
camInfo = (JObject)allInfo["cams"][0]; | |
connectionBoxConnected = true; | |
} | |
catch(Exception e) | |
{ | |
connectionBoxConnected = false; | |
Log.Information("[GetCam0InfoAsyncStartup] " + e); | |
} | |
/* Example output when no camera is connected | |
{ | |
"dummy": true, | |
"busnumber": -1, | |
"devicebusnumber": -1, | |
"modelname": "", | |
"serialnumber": "", | |
"bid": "169.254.200.200", | |
"cid": "169.254.200.200:-1:-1" | |
} | |
*/ | |
if (camInfo.ContainsKey("liveviewportnumber")) | |
this.liveViewPortNumber = (int)camInfo["liveviewportnumber"]; | |
if (camInfo.ContainsKey("modelname")) | |
this.modelName = camInfo["modelname"].ToString(); | |
if (camInfo.ContainsKey("serialnumber")) | |
this.serialNumber = camInfo["serialnumber"].ToString(); | |
if (camInfo.ContainsKey("bid")) | |
this.bid = camInfo["bid"].ToString(); | |
if (camInfo.ContainsKey("cid")) | |
this.cid = camInfo["cid"].ToString(); | |
/* Check if a camera is connected | |
TODO: explain working of dummy key | |
*/ | |
if (camInfo.ContainsKey("dummy")) | |
{ | |
this.cameraConnected = false; | |
} | |
else | |
{ | |
this.cameraConnected = true; | |
} | |
if (this.cameraConnected) | |
{ | |
Log.Information("\tFound a connected camera"); | |
Log.Information("\t\tLive view port number: {0}", this.liveViewPortNumber); | |
Log.Information("\t\tBID: {0}", bid); | |
Log.Information("\t\tCID: {0}", cid); | |
Log.Information("\t\tModel name: {0}", modelName); | |
Log.Information("\t\tSerial nr: {0}\r\n", serialNumber); | |
} | |
else | |
Log.Information("No camera found"); | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
public async Task CameraTurnOffAsync() | |
{ | |
/* On and Off command seems to be working as a toggle switch. Turn the camera on twices, turns | |
the camera on and off. | |
*/ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "power_off_um" }, | |
{ "cids[]", "169.254.200.200:1:17" } // wanneer camera ingeschakeld is | |
}; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) // TODO: test, probably this can be deleted | |
using (HttpClient client = new HttpClient()) | |
{ | |
var content = new FormUrlEncodedContent(values); | |
try | |
{ | |
var response = await client.PostAsync("http://169.254.200.200/api.php", content); | |
var responseString = await response.Content.ReadAsStringAsync(); | |
} | |
catch (Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void CameraRecordStartCommand() | |
{ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "movie_recording_start_usb" }, | |
{ "cids[]", "169.254.200.200:1:3" }, | |
{ "browser_key", this.browserKey } | |
}; | |
var content = new FormUrlEncodedContent(values); | |
Log.Information("Sending start command to cid: {0}, browser_key: {1}", this.cid, this.browserKey); | |
using (var handler = new HttpClientHandler() { CookieContainer = this.myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) | |
{ | |
try | |
{ | |
var response = client.PostAsync("/api.php", content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
Log.Information(responseString); | |
} | |
catch (Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private void CameraRecordStopCommand() | |
{ | |
var values = new Dictionary<string, string> | |
{ | |
{ "v", "2" }, | |
{ "action", "cam_action" }, | |
{ "action_name", "movie_recording_stop_usb" }, | |
{ "cids[]", "169.254.200.200:1:3" }, | |
{ "browser_key", this.browserKey } | |
}; | |
var content = new FormUrlEncodedContent(values); | |
using (var handler = new HttpClientHandler() { CookieContainer = this.myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) | |
{ | |
try | |
{ | |
var response = client.PostAsync("/api.php", content).Result; | |
var responseString = response.Content.ReadAsStringAsync().Result; | |
Log.Information(responseString); | |
} | |
catch(Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
} | |
} | |
/// <summary> | |
/// TODO | |
/// </summary> | |
/// <returns></returns> | |
private async Task getBrowserKey() | |
{ | |
var responseString = ""; | |
using (var handler = new HttpClientHandler { CookieContainer = myCookieContainer }) | |
using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) | |
{ | |
try | |
{ | |
var response = await client.GetAsync("/values.php?v=" + this.timestampInit); | |
responseString = await response.Content.ReadAsStringAsync(); | |
} | |
catch (Exception e) | |
{ | |
Log.Information(e.ToString()); | |
} | |
} | |
/* Grab the value from browserKey, output is like this: | |
* | |
var serverValues = { | |
"browserKey": "bd198f83", | |
"camParamKeys": ["Compression_Setting", "White_Balance", "Focus_Mode", | |
"Exposure_Metering_Mode", "Flash_Mode", "Exposure_Program_Mode", "Drive_Mode" | |
*/ | |
// TODO; check if a val | |
string pattern = @"(?<=browserKey"":"").+?(?="")"; | |
Match m = Regex.Match(responseString, pattern); | |
//Log.Information("'{0}' found at position {1}", m.Value, m.Index); | |
if (m.Success) | |
{ | |
this.browserKey = m.Value; | |
this.connectionBoxConnected = true; | |
} | |
else | |
{ | |
this.connectionBoxConnected = false; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment