Proper steps for working on Theta API v2.1

Hello,
I’m creating an application that take a picture using the Theta and then process it.
However I’m confused about the proper steps of changing the API to 2.1 then take picture.

The current process I’m working with is a button that do the following:
1\ start session
2\ change API level to 2.1
3\ take a picture
4\ show the image

However, with this, if the user didn’t like the taken image and wanted to take another image and pressed the button again. It would produced an error.

How do I handle this ?

Don’t set the version before the second picture. the version will stay at 2.1 for the entire session.

https://developers.theta360.com/en/docs/v2.0/api_reference/options/client_version.html

You don’t need to set the version again until you stop the session (the camera is disconnected from Wi-Fi).

Are you running the application on a mobile device or desktop?

What language are you writing your application in?

Ok, the problem is that I don’t know how many pictures the user will take. So I don’t know when to change the version. Is there is a way to detect if the user is still connected or disconnected ?

I’m using ionic framework. The application is running on a mobile device.

The laungage is typescript.

Change the API version once at the beginning of the session. You don’t need to have this in the same command as takePicture.

You can use info or state to check to see the camera is still connected. info uses GET and may be easier.

Set API Version

setApiV2 = function() {
    var args = {
    data: { "name": "camera.setOptions",
          "parameters":{
            "sessionId": "SID_0001",
            "options": {
              "clientVersion": 2
            }
          } 
        },
    headers: { "Content-Type": "application/json" }
};
    client.post("http://192.168.1.1:80/osc/commands/execute", args, function (data, response) {
      console.log(data);
    var thetaResponse = document.getElementById('thetaResponse');
    thetaResponse.innerHTML = JSON.stringify(data);
    });
  }

Take Picture

takePicture = function() {
    var args = {
    data: { "name": "camera.takePicture"},
    headers: { "Content-Type": "application/json" }
};
    client.post("http://192.168.1.1:80/osc/commands/execute", args, function (data, response) {
      console.log(data);
    var thetaResponse = document.getElementById('thetaResponse');
    thetaResponse.innerHTML = JSON.stringify(data);
    });
  }

Get File

getImage = function() {
    var lastImageUrl;
    var args = {
      data: {
        "name": "camera.listFiles",
        "parameters": {
          "fileType": "image",
          "entryCount": 1,
          "maxThumbSize": 0
        }
      },
      headers: {"Content-Type": "application/json"}
    }
    client.post("http://192.168.1.1/osc/commands/execute", args, function (data, response) {
     lastImageUrl = data.results.entries[0].fileUrl;
       var download = function(uri, filename, callback){
    request.head(uri, function(err, res, body){
     console.log('content-type:', res.headers['content-type']);
     console.log('content-length:', res.headers['content-length']);

    request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
  });
};
    console.log(lastImageUrl);
    // download('http://192.168.1.1/files/744a605553442020024b0202cb00f201/100RICOH/R0012006.JPG', '360_images/lastFile.jpg', function(){
    download(lastImageUrl, '360_images/lastFile.jpg', function(){

    });
  });
  }

I have not tried this in over a year. The problems described may be resolved now.

this community example takes multiple pictures.

function startSession() {
	// console.log("hello world");
	var args = {
		data: { "name": "camera.startSession" },
		headers: { "Content-Type": "application/json" }
	};
	client.post("http://192.168.1.1:80/osc/commands/execute", args, function (data, response) {
		console.log(data);
	});

};

function setVersion() {
	var args = {
		data: {     
			"name": "camera.setOptions",
		    "parameters": {
		        "sessionId": "SID_0001",
		        "options": {
		            "clientVersion": 2 
			        }
			    }
	        }, 
		headers: { "Content-Type": "application/json" }
	};
	client.post("http://192.168.1.1:80/osc/commands/execute", args, function (data, response) {
		console.log(data);
	})
}

function getState() {
	var args = {
		data: { }, 
		headers: { }
	};
	client.post("http://192.168.1.1:80/osc/state", args, function (data, response) {
		console.log(data);
	});
};

function takePicture() {
	var args = {
		data: { "name": "camera.takePicture" }, 
		headers: { "Content-Type": "application/json" }
	};
	client.post("http://192.168.1.1:80/osc/commands/execute", args, function (data, response) {
		console.log(data);
	})
	var warning = document.getElementById("output");
	warning.innerHTML = ("Camera is synthesizing image...");
	setTimeout(
		function() {
			var output = document.getElementById("output");
			output.style.display = "none";

			var view = document.getElementById("downloadButton");
			if (view.style.display==="none") {
				view.style.display = "block";
			}
			else {
				view.style.display = "none";
			}

		}, cameraSynth);
}

function checkStatus() {
	var args = {
		data: { "stateFingerprint": "FIG_0003" },
		headers: { "Content-Type": "application/json" }
	};
	client.post("http://192.168.1.1:80/osc/checkForUpdates", args, function (data, response) {
		console.log(data);
	})
};

Thanks for the help @codetricity !
I did the following steps, not sure if it correct but it worked for me. I leave it in case someone needed it.

  1. check connection through /osc/info
    if it returns a response, I initialized a variable describing the state as StartSession.
  2. it would check the state, if it StartSession, it would send a request camera.startSession to /osc/commands/execute
  3. change the API version to 2.1
  4. change the variable state as connected
  5. take picture
  6. acquire the last taken picture.

Now if I’d repeat the process, I’d check the variable state to see if it need a new session or skip that and take a picture.

However, i have noticed that the last taken image using the request camera.listFiles doesn’t return the current taken picture but the last stored picture before. Any help on this matter ?

1 Like

On step 5, when you run takePicture(), does it return the URL of the last image taken?

https://developers.theta360.com/en/docs/v2.1/api_reference/commands/camera.take_picture.html

Another technique is to wait 10 seconds (THETA S) or 5 seconds (THETA V) before you try to download the image to your local device.

I remember talking to another developer about setting up a simple delay between the take you run takePicture() and the time you grab the file from the camera with the URI.

Thanks for posting your updates. I’m getting inspired to take another look at using JavaScript to access the camera API.

On step 5, when you run takePicture(), does it return the URL of the last image taken?

doesn’t look like it. This is the response that I get.

{ “name”: “camera.takePicture”,
“state”: “inProgress”,
“id”: “1”,
“progress”: { “completion”: 0 }}

I remember talking to another developer about setting up a simple delay between the take you run takePicture() and the time you grab the file from the camera with the URI.

So I did that, My theta model is (THETA SC). It seems the wait time to grab the latest image is 7 seconds.

Update:
It seems that the method I wrote in this post Here deson’t work when the app crashes or you close it and reopen it while the connection is still there and already there is an ongoing session.

the problem is that the variable state would be reinitialized and the state would turned to be StartSession. So I decided to do the following steps:

  1. check connection
  2. start session
  3. change API version
  4. take picture and list files

Now by repeating the process, the start session will throw an error. I placed an error handler that do step 4.

1 Like

thanks for the update. Can you grab the last file taken now?

BTW, are you using this library to do the HTTP request or did you build your own?

I looked at several other HTTP get/post libraries, but the one above is the only one that appears to use Digest Authentication, which is needed for Client Mode testing.

I think I’m going to move forward with Electron and the request library above.

Note that when I tried to use Cordova/PhoneGap a year ago, I was not able to display the images in 360 navigation mode on Android/iOS. This problem may be fixed by now. However, if you need to display a 360 image on your mobile device with navigation, you may want to test this first before you get too far.

It’s possible to show the equirectangular image easily, so if that works for your application, it will be easier to implement.

It’s quite possible that Cordova/PhoneGap/Ionic has solved this problem

thanks for the update. Can you grab the last file taken now?

Yes! I have to wait 7 seconds between take picture and list files.

BTW, are you using this library to do the HTTP request or did you build your own?
the one above is the only one that appears to use Digest Authentication, which is needed for Client Mode testing

Thanks for mentioning the Client Mode, I didn’t know about it. I’m directly connecting the Theta using an native plugin in ionic. It is interesting to check out next, I’ll try the library you posted.

I was not able to display the images in 360 navigation mode on Android/iOS.

May I know what do you mean by navigation mode ?

Here’s additional information on client mode.

Note. I have not tried this with JavaScript yet. However, it does seem that the request library does support digest authentication, which is required for client mode.

This is an equirectangular view:

The above image does not rotate.

The type of app below is also easy. It uses Cordova.

image

This type of app was also easy. It uses JavaScript A-Frame. The view will rotate when I move the mobile phone.

image


This worked with A-Frame, but I couldn’t get the buttons to work. The image rotates.


My last attempt was in Sept 2017. At the time, I got this working in Cordova. Back in Sept 2017, I did not have the 360 navigation and buttons working at the same time. I’m assuming that when you show the 360 image or video, you want the user to be able to move to a different part of the image. If this is not a requirement, then your application will be much easier to finish.

image


Look at this video from July of 2017


I suspect, maybe just hope, that the problems with Cordova/A-Frame have been solved.

I remember talking to another developer about this problem. I think the API documentation may be slightly out of date.

Based on your comment and the comment from @strangerism , I’m assuming that takePicture() no longer returns the fileUri and that Ricoh needs to update their API documentation.

1 Like

Thanks for the explanation, I actually use A-frame to view the 360 images from the Theta.

My last attempt was in Sept 2017. At the time, I got this working in Cordova. Back in Sept 2017, I did not have the 360 navigation and buttons working at the same time. I’m assuming that when you show the 360 image or video, you want the user to be able to move to a different part of the image.

I’m building an interactive image, I only use one button in ionic that enable the adding of elements in A-frame. those elements too are buttons that do something such as animation, etc. (sometimes those are difficult clicking on).

so, I don’t think that the buttons are still a problem now.

Based on your comment and the comment from @strangerism , I’m assuming that takePicture() no longer returns the fileUri and that Ricoh needs to update their API documentation.

Yes, that seems the case. The other commands are good. I just remember being confused at CheckForUpdates and I didn’t find the API helpful.

1 Like

Thanks for this update.

I think Ricoh made several changes to the Wi-Fi API (the one you’re using) recently. I need to build another project with it to learn about the changes.

I think checkForUpdates is fairly new. It’s not obvious how to use it from the documentation below.

image

UPDATE:

after further testing, It seems the steps that I have mentioned previously works on Android phones.
when I tested on iPhone, it didn’t even connect.

tried the camera using the official theta app and worked.

I’m not sure, do iPhones require additional steps for it to connect to the api ?