KonradIT / goprowifihack

Unofficial GoPro WiFi API Documentation - HTTP GET requests for commands, status, livestreaming and media query.
Apache License 2.0
2.12k stars 335 forks source link

GoPro Hero 5 Command Issues #135

Open nespotts opened 5 years ago

nespotts commented 5 years ago

Problem:

I having been working with your list of http commands for a GoPro Hero 3+, Hero 4 Session, Hero+ LCD, and now for the Hero 5 Black using an ESP8266 to send the commands. I have had no major problems with the commands for the first 3 cameras, but I am having issues with the GoPro Hero 5 Black. It is probably something simple, but the client connection works and the commands work right after the connections have been reset on the camera, but if the ESP8266 is reset after a first connection, it connects to the WiFi fine, but all http requests return a -1 HTTP Code and fail to connect.

I've tried calling client.flush() and just about anything else I can think of. The only way to make the commands work again is to reset the connections on the camera. If I connect using my computer, I have not problem sending the commands from Chrome. Any help would be appreciated! Thanks

Details:

Here is the simplest code I wrote to replicate the problem (using Visual Studio Code and Platformio):

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

// Use WiFiclient class to create TCP connections
WiFiClient client;

const char* ssid     = "GP25000830";
const char* password = "dude0062";

String wifi_ssid = "GP25000830";
String wifi_password = "dude0062"; 

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

String PairURL = "/gp/gpControl/command/wireless/pair/complete?success=1&deviceName=RCRemote";
String VideoURL = "/gp/gpControl/command/mode?p=0";
String SingPhotoURL = "/gp/gpControl/command/sub_mode?mode=1&sub_mode=1";
String DefaultModeURL = "/gp/gpControl/setting/53/1";
String StartURL = "/gp/gpControl/command/shutter?p=1";
String StopURL = "/gp/gpControl/command/shutter?p=0";
String NewWifiURL = "/gp/gpControl/command/wireless/ap/ssid?ssid=" + wifi_ssid + "&pw=" + wifi_password;
String camera_status = "http://10.5.5.9/gp/gpControl/status";

void SettoSinglePhoto() {
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    if (!client.connect(host, 8080)) {
      Serial.println("Connection Failed Again");
    }
    return;
  }

  //Command for setting to photo mode
  client.print(String("GET ") + SingPhotoURL + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: RCRemote\r\n" +
               "Connection: close\r\n\r\n");
  Serial.println("Set to Photo");
  delay(20);
  client.stop();
}

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

  //Command for setting to video mode
  client.print(String("GET ") + VideoURL + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: RCRemote\r\n" +
               "Connection: close\r\n\r\n");
  Serial.println("Set To Video");
  delay(20);
  client.stop();
}

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

  //Command for starting recording
  client.print(String("GET ") + StartURL + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: RCRemote\r\n" +
               "Connection: close\r\n\r\n");
  Serial.println("Triggering");
  delay(20);
  client.stop();
}

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

  //Command for stopping recording
  client.print(String("GET ") + StopURL + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: RCRemote\r\n" +
               "Connection: close\r\n\r\n");
  Serial.println("Stopped");
  delay(20);
  client.stop();
}

void PairSuccess() {
  // Needs to be developed/checked for operation for models: Hero (2018), Hero 5,6,7, (Fusion)???
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }

  //Command for setting to video mode
  client.print(String("GET ") + PairURL + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: RCRemote\r\n" +
               "Connection: close\r\n\r\n");
  Serial.println("GoPro Paired to RC Remote");
  delay(20);
  client.stop();
}

void setup() {
  WiFi.disconnect(true);
  WiFi.disconnect();

  Serial.begin(115200);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  client.flush();

  PairSuccess();
  delay(5000);
}

void loop() {

  SettoSinglePhoto();
  delay(5000);
  Trigger();
  delay(5000);
}
KonradIT commented 5 years ago

I happen to have a Hero5 and 7 and also do have issues sending commands on ESP8266HTTPClient, try switching to HTTPClient.

nespotts commented 5 years ago

Okay, I will try. Did it work for you using HTTPClient? Thanks

nespotts commented 5 years ago

Also, which HTTPClient Library are you referring to?

nespotts commented 5 years ago

I tried the HttpClient Library by Adrian McEwen, but could not get the code to work, then I tried the ArduinoHttpClient Library and did not have any better luck getting it to work.

KonradIT commented 5 years ago

https://techtutorialsx.com/2017/05/19/esp32-http-get-requests/

I used an adapted version from that example which worked with my Hero5.

KonradIT commented 5 years ago

Also just as a heads up there's a C++ library for ESP8266/ESP32: https://github.com/aster94/GoProControl

nespotts commented 5 years ago

Hey, thanks for all the help, I'm struggling to get that library to work for an ESP8266 as opposed to the ESP32. Is there any way you could send me the adapted library that worked for you? Thanks.

On a separate note, I have not experimented with your Python API yet. Have you tried using micropython on an esp8266 with your python library to control the cameras (specifically the hero 5)?

KonradIT commented 5 years ago

Hmm, I did look at MicroPython and even have some source code which should work on my ESP32. I'll see if I can port the gopro-py-api to micropython and make it async when I'm free.

nespotts commented 5 years ago

Awesome! Per my first question, do you have a copy of the adapted HttpClient Library that you used? I'm guessing you used it on your ESP32 not an ESP8266 though...

nespotts commented 5 years ago

Hi, I still have not figured this out and have been working on this quite a lot. I've been talking with a few developers on the ESP8266 for Arduino Github page #5552, but I haven't reached a solution. The key details that it comes down to is this:

  1. It is an issue with the TCP Client connection/handshake.
  2. If the esp8266 and gopro are connected and communicating successfully (after the gopro wifi has been reset) and I turn the gopro's wifi off first and either leave the esp8266 on OR reset the esp8266, and then turn the gopro wifi back on, it reconnects and http requests work fine. On the otherhand, if i turn the esp8266 off without turning off the gopro wifi first, client connections always fail thereafter.
  3. Whenever the client connection cannot be made by the ESP8266, the ESP's IP cannot also be pinged. When everything is working, the ESP can be pinged no problem. Also, the GoPro at 10.5.5.9 cannot be pinged anytime.

Does that provide any useful insight? I've been working at this for a long time. Any help is greatly appreciated! Thanks

KonradIT commented 5 years ago

Interesting observation, could it be due to User Agent?

nespotts commented 5 years ago

I don’t think that is the issue, originally, I didn’t even specify a user agent. The issue I believe is before the http GET request, in the tcp client or WiFi connection. Unless somehow the user agent specified in the first connection affects future connections to the GoPro.

volkanunal commented 4 years ago

Hi all, somebody find any solution about this problem. i have the exact problem. But not resolved yet.

Cabbache commented 2 years ago

I have worked around this issue by changing the MAC address of the ESP8266 to a random one in setup.

Here is the full code that takes a picture every 5 seconds:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include "ChangeMac.hpp"

// Replace these with your WiFi network settings
const char* ssid = "SSID"; //replace this with your WiFi network name
const char* password = "Password"; //replace this with your WiFi network password

void setup()
{
  delay(1000);
  Serial.begin(115200);

  Serial.println(WiFi.macAddress());
  WiFi.mode(WIFI_STA);
  uint8_t mac[6];
  makeRandomMac(mac);
  changeMac(mac);
  //WiFi.hostname("random1");

  WiFi.begin(ssid, password);
  Serial.println();
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  Serial.println("success!");
  Serial.print("IP Address is: ");
  Serial.println(WiFi.localIP());
  Serial.print("MAC Address is: ");
  Serial.println(WiFi.macAddress());
}

void loop() {
    HTTPClient http;  //Declare an object of class HTTPClient
    WiFiClient wificlient;

    http.begin(wificlient, "http://10.5.5.9/gp/gpControl/command/shutter?p=1&c1=restart");  //Specify request destination
    int httpCode = http.GET();                                  //Send the request

    if (httpCode > 0) { //Check the returning code
      Serial.println(httpCode);
      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);             //Print the response payload

    } else {
      Serial.println("Error");
      Serial.println(http.errorToString(httpCode));
    }

    http.end();   //Close connection

    delay(5000);
}

The ChangeMac.hpp library used is from https://yoursunny.com/t/2017/change-ESP8266-MAC/