Arduino GoPro Wifi Control

13,616

121

8

Published

Introduction: Arduino GoPro Wifi Control

About: My name is Randy and I am a Community Manager in these here parts. In a previous life I had founded and run the Instructables Design Studio (RIP) @ Autodesk's Pier 9 Technology Center. I'm also the author ...

In these steps I show you how to simply control a GoPro Hero 4 and a GoPro Hero Session 5 using an Arduino wifi board. As you will learn, these instructions could easily be adapted for any type of GoPro.

This is useful for when you want to build you own custom controller for a project. Rather than hacking into existing controllers, you can just use the Arduino to communicate with it directly using some basic networking commands. Not only are you able to control the functionality on the GoPro, but you can also receive status updates about the camera. This makes it a versatile solution for a host of different types of projects including custom robots and drones

Step 1: Materials

For this project you will need just a couple of things.

To begin, you will obviously need a GoPro camera. These instructions should work for the most current model (GoPro Hero 6). Albeit, I have only personally tested it with a GoPro Hero 4 and a GoPro Hero Session 5. The Hero Session models are slightly different to control than the other models, but we will cover that in a moment.

You will also need a Arduino MKR1000 or Arduino MKR Zero. In these instructions I use a MKR1000. You may be able to get away with another Arduino-compatible wifi-enabled microcontroller board (such as the Feather), but I have not personally tried.

You will also need a USB cable for the Arduino, a computer running the Arduino development software (which I am going to assume you have), and a smartphone with the GoPro app installed.

If you don't have such a thing, or have never used an Arduino before, I highly recommend you first read the Arduino Class before starting this project!

Step 2: Configure Your Camera's Wifi

The first thing you need to do is to turn on and configure your camera's wifi connection. I'm not going to go into this too deeply because there are already a lot of tutorials out there for doing this.

On the GoPro Hero4, the easiest method for doing this is to connect your camera to your phone by following the directions in the app.

Once the phone is paired with camera, open the settings for the camera using the app and give the wifi network a new name and password of your choosing.

On the GoPro Hero Session 5, the same method also applies. To begin, connect your camera to your phone by following the directions in the app. This will automatically configure the name and password of the wifi network.

To view the wifi network name on your camera, navigate to "Camera Info" which is found under the "Connection Settings" menu.

Step 3: Find Your GoPro's MAC Address

Once the wifi is enabled, you need to figure out what your camera's MAC (media access control) address. This address is a nice-to-have bit of information when dealing with traditional Hero line of GoPros. However, if you are using a GoPro Hero Session, this address is a must-have.

To get it, first connect your computer to your camera's wifi network using the network name and password from the previous step.

Once you are logged into your camera's wifi network, open any old web browser on your computer, and visit the following URL:
http://10.5.5.9/gp/gpControl/info

This URL should print a string of information into your web browser which looks something like:
{"model_number"21,"model_name":"HERO5Session","firmware_version":"HD5.03.02.51.00","serial_number":"C3212365684485","board_type":"0x05","ap_mac":"0641631510c4","ap_ssid":"GP54688615","ap_has_default_credentials":"0","capabilities":"16"}


If it doesn't, make sure that your camera is turned on, and still connected to wifi.

The bit in the string that is of interest to us is the string of numbers following "ap_mac:". This 12-digit string of numbers and digits is the MAC address. In my case, this is 0641631510c4.


Once you have identified the address, break it apart every two characters, and format it as follows:
0x06, 0x41, 0x63, 0x15, 0x10, 0xC4

Step 4: Connect an Arduino to the GoPro Hero

In order for the Arduino to communicate with a GoPro Hero series camera, it needs to be paired using a PIN. To get the pin, navigate in the phone menu to pair the camera with an app. This should generate a 4-digit PIN on all later-model cameras (the Hero 3 and earlier have a 6-digit PIN).

The pin only last for 3-minutes, so time is of the essence.

You need to manually insert the PIN two times into the code below in both places where it says:
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ENTER YOUR PIN HERE WHERE IT SAYS XXXX
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


Once the pin is entered, you have less than three minutes to upload it to the Arduino and make the connection with the camera.


Speaking of which, don't forget to enter the GoPro's wifi credentials where it says:
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ENTER YOUR WIFI NAME AND PASSWORD HERE
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


For all intents and purposes, once you have successfully uploaded the code, nothing will appear to happen. Nevertheless, if you navigate out of the GoPro's setup menu back to the video screen, you should now be able to send it commands (which we will cover shortly).

If in the coming steps you can't seem to send commands to the camera, go back and repeat this step.

Code for pairing the GoPro with the Arduino using its PIN number:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

WiFiClient client;

const char* host = "10.5.5.9";
const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);


  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();


  // START PIN
  StartPin();

  delay(10000);

  // FINISH PIN
  FinishPin();


}


void loop(){

  //Nothing to do here!
  delay(1000);

}


void StartPin(){
  Serial.print("connecting to ");
  Serial.println(host);

  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR PIN HERE WHERE IT SAYS XXXX
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  
  
  String StartUrl = "/gpPair?c=start&pin;=XXXX&mode;=0";
  Serial.print("Requesting URL: ");
  Serial.println(StartUrl);
  client.print(String("GET ") + StartUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Started");
}



void FinishPin(){
  Serial.print("connecting to ");
  Serial.println(host);
  
  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR PIN HERE WHERE IT SAYS XXXX
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  
  String StopUrl = "10.5.5.9/gpPair?c=finish&pin;=XXXX&mode;=0";
  Serial.print("Requesting URL: ");
  Serial.println(StopUrl);
  client.print(String("GET ") + StopUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Finished");
}



void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Step 5: Connect an Arduino to the GoPro Hero Session

The GoPro Session does not have a PIN to contend with. However, it has its own peculiarities that make connecting to it really annoying. As you may have noticed, as soon as you finish recording, or, for that matter, as soon as you finish doing most anything with the camera, it turns off and goes into sleep mode.

Before you can send the GoPro Hero any sort of command, you need to wake it up. The easiest way to do this is to manually press the menu button on the back of the camera and send it commands within the few second window in which it is awake. However, that is annoying and not particularly practical in any way.

The better way to wake up the GoPro is by using a WOL packet or "magic packet." This acronym stands for Wake-on-Lan and is a protocol for waking a computer from sleep mode remotely. It requires sending bytes using a UDP protocol from the Arduino to the GoPro to wake it up. This is a little annoying because it is a different protocol than you send all of the other control commands. The code also is less pretty, and a bit more complicated to deal with if you are new to programming.

Nevertheless, when it works, it really works like magic. It never ceases to amaze me to see my camera wake up by sending it a command from the Arduino.

The WOL command (the CameraInitiate() function in the code) needs to be sent before most other commands, and should typically be followed by a 1-2 second delay. Essentially, you need to send it any time you might need to wake your camera up (which is most times). And after you send the command, you need to pause for a moment to allow the camera to actually wake up.

In the example below, the WOL function is called in the setup, so it will only wake your camera the first time you run it.

Do not forget to enter the GoPro's wifi credentials and MAC address into the code where prompted!

Here is the code for waking your camera:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

int localPort = 7;
byte broadCastIp[] = { 10,5,5,9 };

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR MAC ADDRESS HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!! 

byte remote_MAC_ADD[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int wolPort = 9;


WiFiUDP Udp;

WiFiClient client;

const char* host = "10.5.5.9";
const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);

  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
     status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();

  delay(1000);

  // WAKE UP YOUR SLEEPY CAMERA!
  CameraInitiate(){

  // NOTE: If this does not seem to be working, 
  // turn your camera on and off and try again.

}


void loop(){

  //Nothing to do here!
  delay(1000);

}



// FUNCTION TO WAKE UP THE CAMERA

void CameraInitiate(){

  //Begin UDP communication
  Udp.begin(localPort);

  //Send the magic packet to wake up the GoPro out of sleep
  delay(2000);
  SendMagicPacket();
  delay(5000);  

  // Absolutely necessary to flush port of UDP junk for Wifi client communication
  Udp.flush();
  delay(1000);

  //Stop UDP communication
  Udp.stop();
  delay(1000);

}


// Function to create and send magic packet
// Taken and translated from here:
// https://www.logicaprogrammabile.it/wol-accendere-computer-arduino-wake-on-lan/

void SendMagicPacket(){

  //Create a 102 byte array
  byte magicPacket[102];

  // Variables for cycling through the array
  int Cycle = 0, CycleMacAdd = 0, IndexArray = 0;

  // This for loop cycles through the array
  for( Cycle = 0; Cycle < 6; Cycle++){

    // The first 6 bytes of the array are set to the value 0xFF
    magicPacket[IndexArray] = 0xFF;

    // Increment the array index
    IndexArray++;
  }

  // Now we cycle through the array to add the GoPro address
  for( Cycle = 0; Cycle < 16; Cycle++ ){
    //eseguo un Cycle per memorizzare i 6 byte del
    //mac address
    for( CycleMacAdd = 0; CycleMacAdd < 6; CycleMacAdd++){
      
      magicPacket[IndexArray] = remote_MAC_ADD[CycleMacAdd];
      
      // Increment the array index
      IndexArray++;
    }
  }

  //The magic packet is now broadcast to the GoPro IP address and port
  Udp.beginPacket(broadCastIp, wolPort);
  Udp.write(magicPacket, sizeof magicPacket);
  Udp.endPacket();

}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Step 6: Send GoPro Commands

In this example I am going to show how to send commands to start and stop video recording.

That said, using the same method demonstrated here, you can send commands for just about every functionality within the camera. The GoPro Hero 4 commands seems to be standard set for all subsequent models. However, some of the more recent cameras have new features and camera-specific commands that are worth investigating. You can find the camera specific commands on the Unofficial GoPro WiFi API github page by clicking on the link for you specific camera model.

The example below engages recording for 5 seconds, stops recording, waits for 5 more seconds, and begins again. If you are using a Hero Session, be sure to uncomment the line of code that wakes up the GoPro.

Once again, don't forget to enter your GoPro's wifi credentials and MAC address!

Code to send Start and Stop recording commands:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>



int status = WL_IDLE_STATUS;

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR WIFI NAME AND PASSWORD HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

char ssid[] = "XXXXXXXXXXXX"; //  your network SSID (name)
char pass[] = "XXXXXXXXXXXX";    // your network password (use for WPA, or use as key for WEP)

int localPort = 7;
byte broadCastIp[] = { 10,5,5,9 };

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!
  //ENTER YOUR MAC ADDRESS HERE
  //!!!!!!!!!!!!!!!!!!!!!!!!!!! 

byte remote_MAC_ADD[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int wolPort = 9;


WiFiUDP Udp;

WiFiClient client;

const char* host = "10.5.5.9";

const int httpPort = 80;


void setup(){  

  //Initialize serial and wait for port to open:
  Serial.begin(115200);


  // check for the presence of the wifi module:
  if (WiFi.status() == WL_NO_SHIELD) {
     Serial.println("WiFi not present");
     // don't continue:
     while (true);
  }


// ADD THIS TO LOOP??????????????
// MAKE ITS OWN FUNCTION???????

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
     status = WiFi.begin(ssid, pass);

    // wait 8 seconds for connection:
    delay(8000);
  }

  Serial.println("Connected to wifi");
  printWifiStatus();


}


void loop(){

// Add code to check to see if wifi is still on. If not, stop and keep trying to connect

// WAKE UP CAMERA FROM SLEEP AND CONNECT
CameraInitiate();

// Add code to make sure that camera recognized (status 31)


// START RECORDING
StartRecording();

delay(5000);

// STOP RECORDING
StopRecording();

delay(5000);

}


void StartRecording(){
  Serial.print("connecting to ");
  Serial.println(host);

  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //Command for starting recording
  String StartUrl = "/gp/gpControl/command/shutter?p=1";
  Serial.print("Requesting URL: ");
  Serial.println(StartUrl);
  client.print(String("GET ") + StartUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Recording");
}



void StopRecording(){
  Serial.print("connecting to ");
  Serial.println(host);
  
  if (!client.connect("10.5.5.9", httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //Command for stopping recording
  String StopUrl = "/gp/gpControl/command/shutter?p=0";
  Serial.print("Requesting URL: ");
  Serial.println(StopUrl);
  client.print(String("GET ") + StopUrl + " HTTP/1.1\r\n" +
  "Host: " + host + "\r\n" +
  "Connection: close\r\n\r\n");
  Serial.println("Stopped");
}



// FUNCTION TO WAKE UP THE CAMERA

void CameraInitiate(){

  //Begin UDP communication
  Udp.begin(localPort);

  //Send the magic packet to wake up the GoPro out of sleep
  delay(2000);
  SendMagicPacket();
  delay(5000);  

  // Absolutely necessary to flush port of UDP junk for Wifi client communication
  Udp.flush();
  delay(1000);

  //Stop UDP communication
  Udp.stop();
  delay(1000);

}


// Function to create and send magic packet
// Taken and translated from here:
// https://www.logicaprogrammabile.it/wol-accendere-computer-arduino-wake-on-lan/

void SendMagicPacket(){

  //Create a 102 byte array
  byte magicPacket[102];

  // Variables for cycling through the array
  int Cycle = 0, CycleMacAdd = 0, IndexArray = 0;

  // This for loop cycles through the array
  for( Cycle = 0; Cycle < 6; Cycle++){

    // The first 6 bytes of the array are set to the value 0xFF
    magicPacket[IndexArray] = 0xFF;

    // Increment the array index
    IndexArray++;
  }

  // Now we cycle through the array to add the GoPro address
  for( Cycle = 0; Cycle < 16; Cycle++ ){
    //eseguo un Cycle per memorizzare i 6 byte del
    //mac address
    for( CycleMacAdd = 0; CycleMacAdd < 6; CycleMacAdd++){
      
      magicPacket[IndexArray] = remote_MAC_ADD[CycleMacAdd];
      
      // Increment the array index
      IndexArray++;
    }
  }

  //The magic packet is now broadcast to the GoPro IP address and port
  Udp.beginPacket(broadCastIp, wolPort);
  Udp.write(magicPacket, sizeof magicPacket);
  Udp.endPacket();

}



void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Step 7: Receive GoPro Status Updates

It is possible to receive status updates from the GoPro using this link:
http://10.5.5.9/gp/gpControl/status

When this link is called, it provides a JSON object which can be parsed using this Camera Status guide.

The easiest way to see it is to connect to your GoPro's wifi network with your computer, and load the above link using a web browser.

It will return something which looks like:
{"status"{"1":1,"2":2,"3":0,"4":0,"6":0,"8":0,"9":0,"10":0,"13":0,"14":0,"15":0,"16":0,"17":1,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"26":0,"27":0,"28":82,"29":"","30":"","31":0,"32":0,"33":0,"34":2796,"35":1917,"36":0,"37":1,"38":0,"39":1,"40":"%12%05%13%0C%04%0E","41":0,"42":0,"43":0,"44":0,"45":0,"46":1,"47":1,"48":1,"49":0,"54":15476384,"55":1,"56":0,"57":3927,"58":0,"59":0,"60":500,"61":2,"62":0,"63":0,"64":0,"69":1,"71":12,"72":19,"73":20,"74":0}, "settings":{"1":0,"2":1,"3":8,"4":0,"5":0,"6":1,"7":1,"8":1,"9":0,"10":0,"11":0,"12":0,"13":1,"14":0,"15":4,"16":0,"17":4,"18":1,"19":0,"20":0,"21":1,"22":0,"23":0,"24":0,"25":0,"26":4,"27":0,"28":4,"29":5,"30":0,"31":0,"32":3601,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":4,"40":0,"41":13,"42":8,"43":0,"44":8,"45":8,"46":0,"47":0,"48":0,"52":1,"54":1,"57":0,"58":1,"59":6,"60":8,"61":1,"62":2500000,"63":7,"64":4,"65":0,"66":0,"67":0,"68":0,"69":1,"70":0,"71":0,"73":0,"74":0,"75":3,"76":3,"78":1,"84":0,"85":0,"86":1,"87":40,"89":12,"91":0,"92":12,"95":1,"96":0}}

To be entirely honest, every single time I tried to make this work with my Arduino it would somehow crash my GoPro. Since I didn't really need this functionality for the larger project that I was working on, I stopped spinning my wheels on this part.

If someone wants to create an Arduino sketch that I can share in this instructable that grabs GoPro status updates without crashing the camera, I'll mail you some Instructables swag!

Share

    Recommendations

    • Water Contest

      Water Contest
    • Oil Contest

      Oil Contest
    • Clocks Contest

      Clocks Contest

    8 Discussions

    anybody who can make this for a WEMOS D1 or the NODEMCU esp8266 ????

    that is the cheapest way of using thisMOD.

    Should work with ESP 8266 or ESP 32 but way more cheaper!

    Nice project!

    What would be cool is to control multiple cameras. There are times where you don't have access to the cameras, but would like to switch mode. A sort of director's shot.

    Mode 1: Camera 1 off, Camera 2, time lapse + wide angle, Camera 3 Off

    Mode 2: All off

    Mode 3: All on, slow motion.

    Then you just select which mode.

    1 reply

    This would be a little tricky because it would require connecting and disconnecting from each camera's wifi network (as needed), but totally doable!

    Will it be possible to use an Arduino uno with a WIFI shield is stead of the Arduino MRK 1000.

    2 more answers

    I have not tried that, but I don't see why not.

    0
    user
    vaxus

    25 days ago

    very very very usefull post, thanks. definitely worth trying it.