Access THETA S from Angular (browser) with Reverse Proxy


#1

This information from tolecar.

I am using THETA S with angular, from my web browser. But on PC, not android or ios.
To avoid CORS issue, I defined reverse proxy in Apache so that theta calls are ending on the same domain as the web is.

<VirtualHost *:80> 
        ServerName mylocalweb.com
        DocumentRoot "c:/MyWebProject/www/"
        <location />
                order deny,allow
                allow from all
        </location>
        ProxyPass /osc/   http://192.168.1.1:80/osc/
        ProxyPassReverse /osc/  http://127.0.0.1:80/osc/
</VirtualHost>

So I am accessing Theta over http://mylocalweb.com/osc/… Do not forget to set mylocalweb.com to 127.0.0.1 in windows hosts.

So if you can define hosts on your device and you can setup reverse proxy, it should work. I doubt that you can do it on non jailbreak ios device, but it might work on android.


#2

This was satisfying to work with. I created a few sample commands, including takePicture.

Here’s the code I used in the test.

var Client = require('node-rest-client').Client;

var client = new Client();

  // client.get("http://cube.oda/osc/info", function (data, response) {
  //   console.log(data);
  //   // console.log(response);
  // });

global.getInfo = function() {
    console.log("button clicked")
    client.get("http://cube.oda/osc/info", function (data, response) {
      console.log(data);
      // console.log(response);
    var thetaResponse = document.getElementById('thetaResponse');
    thetaResponse.innerHTML = JSON.stringify(data);
    });
  }

global.state = function() {
      console.log("button clicked")
      client.post("http://cube.oda/osc/state", function (data, response) {
        console.log(data);
        // console.log(response);
      var thetaResponse = document.getElementById('thetaResponse');
      thetaResponse.innerHTML = JSON.stringify(data);
      });
    }

global.startSession = function() {
      console.log("button clicked")

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

global.takePicture = function() {
      console.log("button clicked")

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

The HTML snippet

<meta charset="UTF-8">
<!-- <script src="bundle.js"></script> -->
<script src="bundle.js"></script>

<h1>RICOH THETA API Web Browser Test</h1>
<p>
Uses virtual host to work locally.
</p>

<button onclick="getInfo();">Get THETA Info</button>

<button onclick="state();">THETA state</button>
<br>
<br>
<button onclick="startSession();">Start Session</button>
<button onclick="takePicture();">Take Picture</button>

<p id="thetaResponse">

</p>

In addition, I’m using browserify, which is why I used global variables in the test.

I also used these commands to set up the proxy. I’m using Linux.

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests

Here’s my virtual host configuration

craig@linux-cube:/etc/apache2/sites-available$ cat /etc/apache2/sites-available/cube.oda.conf 
<VirtualHost *:80>

	ServerName cube.oda

	ServerAdmin craig@cube.oda
	DocumentRoot /var/www/cube.oda/public_html
	<location />
		order deny,allow
		allow from all
	</location>
	ProxyPass /osc/ http://192.168.1.1:80/osc/
	ProxyPassReverse /osc/ http://127.0.0.1:80/osc/

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

#3

Using the THETA API v2, I was able to take a picture and connect the browser directly to the last picture taken. This view is within A-Frame.

For the test, I hard-coded the last file taken.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>THETA API v2 A-Frame Test</title>
    <meta name="description" content="Panorama — A-Frame">
    <script src="dist/aframe.js"></script>
  </head>
  <body>
    <a-scene>
      <a-sky src="http://cube.oda/files/744a605553442020024b0202cb00f201/100RICOH/R0011918.JPG" rotation="0 -130 0"></a-sky>
    </a-scene>
  </body>
</html>

You can grab this from the state.

I added these lines to my virtual host config.

ProxyPass /files/ http://192.168.1.1:80/files/
ProxyPassReverse /files/ http://127.0.0.1:80/files/

#4

Here’s a diagram of how A-Frame could be used to pull images directly from the THETA. Right now, this is only working on Linux and Windows, not a mobile phone. Though, it seems possible to get it to work from a mobile device.


#5

I’m using this topic as a build log.

I added a button to pull the list of the last 5 images. I also added a button to pull the last image.

I now have a URL that I can modify for use in A-Frame.

I’m only returning the last image, so I can get the last JSON object from entries[0]

  var lastImageUrl = data.results.entries[0].fileUrl;

This is the original object before parsing:

{"name":"camera.listFiles",
 "state":"done",
 "results":{"entries":[{
     "name":"R0011919.JPG",
     "fileUrl":"http://192.168.1.1/files/744a605553442020024b0202cb00f201/100RICOH/R0011919.JPG",
     "size":3891017,
     "dateTimeZone":"2017:05:20 08:54:29-07:00",
     "width":5376,
     "height":2688,
     "isProcessed":true,"previewUrl":""}

I’m still going to need to split the URL on “/” and substitute my local domain for 192.168.1.1


#6

Quick one: do you have any issues with a “camera.listFiles” command?
In my case it returns just single entry. If I connect with old api, “camera._listAll” runs alright.
I am on 1.82 firmware.


#7

No problems listing 10 entries with camera.listFiles. I’ll run another test. I am using the same firmware.


#8

Checking firmware with API returns this:

"firmwareVersion":"01.82"

Testing list of last 30 images with camera.listFiles showed no problems. Output below.

Code Snippet

Code that I just used for testing.

    var args = {
      data: {
        "name": "camera.listFiles",
        "parameters": {
          "fileType": "image",
          "entryCount": 30,
          "maxThumbSize": 0
        }
      },
      headers: {"Content-Type": "application/json"}
    }
    client.post("http://cube.oda/osc/commands/execute", args, function (data, response) {
      console.log(data);
      // console.log(response);
    var thetaResponse = document.getElementById('thetaResponse');
    thetaResponse.innerHTML = JSON.stringify(data);
    });

Camera State

{"fingerprint":"FIG_0001", "state":{"batteryLevel":0.33, "storageUri":"http://192.168.1.1/files/744a605553442020024b0202cb00f201/", "_captureStatus":"idle","_recordedTime":0,"_recordableTime":0,"_compositeShootingElapsedTime":0,"_latestFileUrl":"","_batteryState":"disconnect","_apiVersion":2}}

Notes

  • Check to make sure the _apiVersion is actually set to 2
  • I’m not pulling any thumbnails. If your test is using thumbnails, I think you can only get one file
  • I can do a test with your parameters if you want to share the parameters with me and I can try to and replicate the error you’re getting

EDIT: 5/22. You probably need to set maxThumbSize to 0 or null.


#9

OMG! Can’t believe how I missed it.
I’ve been probably misled by original Theta S application, which displays files with thumbnails, so I haven’t questioned maxThumbSize parameter even for a moment. Besides that I never re-checked entryCount because it is so simple.
Thanks man!


#10

Really appreciate that you shared the original information on using reverse proxy and virtual hosts. That was a clever idea. If you can share anything about your application like screenshots or code snippets, that would be great.

Your post inspired me to tinker around with JavaScript, but I am fairly new to JavaScript. I think a lot of people are interested in using JavaScript to control the camera.

I’m intending to use this topic as a build log. Hope you post stuff too.

I have not figured out how to use the browser-side JavaScript to download the image file to my local computer. I can view the image off of the THETA camera using the URI. I’ll continue down that path until I figure out something better. I know there are many ways to display the image. I’m using A-Frame now as it’s super easy.


#11

We used a lot of those reverse proxy stuff in my ex company. We were developing tomcat applications and the original urls were like localhost:8123/app, localhost:8233/app and we had to normalize them to be accessible for public use.
Anyway, glad to help.

One thing regarding this browser javascript approach - as it seems, it can be used only as developer tool. There is no easy way of use for eventual production. I was doing this only to get familiar with the camera and api, so I can assist my iOS developers in implementing it in iPhone application.

Upload photo - you can not save it on the local computer without some server side solution. Browser security :frowning:

Displaying - We are using Krpano viewer. Works great but it is not that much easy for manual setup. There is also very good, open source, Marzipano viewer. The code base seems to be much better than krpano, but it is not that much mature and stable.


#12

Thanks for the additional info and pointers to KRpano and Marzipano. I had not used Marzipano before and will give it a shot. I’m moving forward with the my web-based project so I can practice JavaScript.

I do think that there are some business and fun uses for this technique that go beyond self-learning:

  • hackathons (show demo to win prize)
  • corporate maker prototype (show demo to boss to get funding to build real product)
  • customer prototype (show potential customer prototype)

Also, it seems an easy way to experiment with things like different image viewer libraries.

As a future step in a learning path, it could be feasible to move some of the knowledge to Meteor, node, or Cordova. Your technique could be a nice introductory step for people to learn more about 360 images and interaction with the camera.


#13

I moved the tests over to electron. I’m using it as a Windows desktop application, not a browser application. Electron uses node, which gets around the problem of CORS security with JavaScript in a browser. I’m building it with the v2 API.

I’ve started a github repo to get track of my tests.


#14

I added GoogleVR to display the images. The next step will be to download the images from the camera with the API from node.