WiFi Remote for Sony Camera

  • PROJECT

I’ve been using a Sony WX350 compact camera for a few years now, it comes pretty handy while traveling and when the phone’s camera isn’t enough. One of the features that I really like is its built-in WiFi, I can control the camera remotely using the Imaging Edge Mobile application; this functionality is ideal for group photos or while using a tripod. However, the timelapse functionality isn’t included on the functions of the camera. So, looking for options to create timelapses with the camera, I found the Timelapse – Sony Camera application. The application uses the Sony Remote API to send commands to the camera, but I can’t use the phone for other things while the application is taking pictures, however, it’s a good solution. And in order to free my phone, I’m going to implement some parts of the API on a ESP8266 microcontroller, that should be enough to get some good timelapses.

The API documentation says the commands should be sent in JSON format to the camera’s URL using HTTP requests. The API has two main funtions, one is to capture images or video, and the other is to transfer images. The capture function belongs to the camera service, and the transfer function to the avContent service. These services are mutually exclusive, and now we are interested on the capture function.

The API functions are structured into two main parts, one is how all requests are sent to the camera, and the other is how the camera reply is received. To send a request we must use a method, that describes the command or the action, it has a defined name that can be found on the API documentation. This method is followed by one or mores parameters whose values depends directly on the method; finally an id and a version number are sent. The following example shows the command to change the capture mode from still to movie or video recording.

{
  "method": "setShootMode",
  "params": ["movie"],
  "id": 1,
  "version": "1.0"
}

The structure for the reply messages has only two fields, the result and the id. The most important field is the result, if the request is successful this field will have a value of 0 or the corresponding requested data, otherwise the error field appears along with a code to identify the failure. The following message is the reply to the capture mode change request, and shows that the camera made the change successfully.

{
  "result": [0],
  "id": 1
}

After having an idea about how the API works, the next step was to implement some of its functions on the ESP8266. Using the information from the API and some examples from Arduino it was possible to write a program that connects to the camera and sends the commands to do the timelapse.

The program starts creating an Access Point and shows a webpage where is posible to setup the SSID and password from the camera’s Access Point, the webpage also allows to set the timelapse duration and the time between shoots. Once the parameters are saved, the ESP8266’s AP is deactivated and the microcontrollers try to connect to that camera’s AP. After a successful connection, the program waits for button press (low pulson on GPIO0) to start the timelapse.

The code uses the ESP8266WiFi, ESP8266WebServer and ESP8266HTTPClient libraries to enable the AP, to create the webpage server, and to handle the HTTP requests.

const char* ssid_ap = "SonyRemoteAP";
const char* password_ap = "sony1234";
ESP8266WebServer server(80); // Create WebServer on port 80
WiFiClient  client; // Create a client to access the camera
String ssid = {};
String password = {};

The ESP8266’s AP name and password, and the web server and web client classes are defined. On the other hand, the variables ssid and password are declared, but they are empty because the values are written from the webpage.

const int start_button = 0;         // GPIO0 to start capture
const String host = "10.0.0.1";     // Camera IP, defined on API documentation
const String http_port = "10000";   // Camera port, defined on API documentation
const String url = "/sony/camera";  // URL to send htto request, defined on API documentation
int timelapse_span;                 // Timelapse span
int shot_period;                    // Time between shots (in seconds)
int shot_period_ms;                 // Time between shots (in milliseconds)
int picture_number = 0;             // Max number of pictures on the timelapse
int op_mode = 0;                    // Operation mode

After that, I defined the button, the host IP address and port, and the URL where the HTTP request are going to be posted. The values may vary depending on the camera model, and this values can be checked on the API documentation. The other variables define the timelapse duration and the amount of pictures to shoot.

char setShootMode[] = "{\"method\":\"setShootMode\",\"params\":[\"still\"],\"id\":1,\"version\":\"1.0\"}"; // Set shot mode to "still"
char actTakePicture[] = "{\"method\":\"actTakePicture\",\"params\":[],\"id\":1,\"version\":\"1.0\"}"; // Take a picture
char setFocusMode[] = "{\"method\":\"setFocusMode\",\"params\":[\"AF-S\"],\"id\":1,\"version\":\"1.0\"}"; // Set focus mode to Single AF
char setAutoPowerOff[] = "{\"method\":\"setAutoPowerOff\",\"params\":[{\"autoPowerOff\":60}],\"id\":1,\"version\":\"1.0\"}"; // Set automatic power off after 60 seconds

The four strings are the API functions used in the project, and are written using the JSON format. Arduino has a library to code and decode JSON, but I’m not going to use it because as the parameters doesn’t change its not needed.

const char index_html[] PROGMEM = R"rawliteral(<!DOCTYPE html>...</html>)rawliteral";
const char save_html[] PROGMEM = R"rawliteral(<!DOCTYPE html>...</html>)rawliteral";

The two constant contains the webpages HTML code, as the code is long I didn’t post it here, but it’s available on GitHub. On the first webpage I can setup the Access Point’s SSID and password, and timelapse duration and the amount of pictures to shoot. The second webpage just confirms that the parameters were saved.

void setup() {
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(ssid_ap);
  server.on("/", HTTP_GET, handleRoot);
  server.on("/save", HTTP_POST, handleSave);
  server.begin();
  pinMode(start_button, INPUT_PULLUP);
}

On the setup loop the code starts the Access Point and the web server. The default IP address for the webpages is 192.168.4.1.

void loop()
{
  switch (op_mode)
  {
    case 0:
      while (picture_number == 0) {
        server.handleClient();
      }
      op_mode = 1;
      Serial.println();
      break;
    case 1:
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
      }
      httpPost(setShootMode);
      op_mode = 2;
      break;
    case 2:
      while (digitalRead(start_button) != 0) {
        delay(100);
      }
      op_mode = 3;
    case 3:
      httpPost(setFocusMode);
      for (int i = 0; i < picture_number; i++) {
        httpPost(actTakePicture);
        delay(shoot_period_ms);
      }
      op_mode = 4;
      httpPost(setAutoPowerOff);
      break;
    case 4:
      delay(100);
      break;
  }
}

In the loop function, a switch case is configured using the variable op_mode, to alternate the operation mode between the web server, the connection to the Access Point of the camera, the wait for the button push and the timelapse capture.

The function server.handleClient() allows the connection from a computer or a phone to the Access Point, and shows the webpages. When the parameters are saved it stops.

void httpPost(char* j_request);
void handleRoot();
void handleSave();

The function httpPost(char* j_request) post the HTTP request. The argument of this function are the API function written on JSON format. The function handleRoot() posts the main webpage, and the function handleSave() posts the confirmation webpage.

I used an ESP-01 module and the ESP8266 Breakout Board to ease the ESP8266 flashing. The code with comments is available on GitHub.

GitHub: SonyRemoteTimelapse

More information:
Sony Camera Remote API
WX350 Compact Camera
Arduino core for ESP8266
A Beginner’s Guide to the ESP8266
Update ESP-01 Firmware

If you have any question, feel free to ask.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.