From ee947485d1f5fa565375801965a2a14535b0ea3b Mon Sep 17 00:00:00 2001 From: Joshua King Date: Fri, 5 Jun 2026 15:21:14 -0400 Subject: [PATCH] firmware(esp-01s): real GoPro Hero 3 status read (was the shutter bug) Validated against a Hero 3 Silver: - fetchStatus() now GETs the status endpoint /camera/se (was /bacpac/SH?p=%01, which *started recording* every poll), at the correct host 10.5.5.9. - Read the response from the stream, not getString(): the blob is binary and starts with 0x00, which truncated the Arduino String to empty. - Offsets: recording = byte 29 (confirmed by not-recording vs recording diff), battery_raw = byte 19 (drains with charge; calibrate on the hub), video_remaining = bytes 25-26 (provisional). - Default config set to this camera (goprosilver-1 / 10.5.5.9); per-camera values can still be overridden at runtime via set_config. Co-Authored-By: Claude Opus 4.8 --- firmware/data/esp8266-config.json | 6 ++-- firmware/src/esp8266-camera-bridge.cpp | 41 +++++++++++++++++--------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/firmware/data/esp8266-config.json b/firmware/data/esp8266-config.json index e46d3b2..c06c66b 100644 --- a/firmware/data/esp8266-config.json +++ b/firmware/data/esp8266-config.json @@ -1,6 +1,6 @@ { - "camera_ssid": "GOPRO-BP-", - "camera_password": "goprohero", - "camera_ip": "10.5.5.1", + "camera_ssid": "goprosilver-1", + "camera_password": "Bzyeatn421", + "camera_ip": "10.5.5.9", "poll_interval_sec": 30 } diff --git a/firmware/src/esp8266-camera-bridge.cpp b/firmware/src/esp8266-camera-bridge.cpp index 1cd056c..6e91baf 100644 --- a/firmware/src/esp8266-camera-bridge.cpp +++ b/firmware/src/esp8266-camera-bridge.cpp @@ -41,9 +41,11 @@ // ──────────────────────────────────────────── struct Config { - String camera_ssid = "GOPRO-BP-"; - String camera_password = "goprohero"; - String camera_ip = "10.5.5.1"; + // Defaults validated against a GoPro Hero 3 Silver. Per-camera values can + // be overridden at runtime via the set_config command (no reflash). + String camera_ssid = "goprosilver-1"; + String camera_password = "Bzyeatn421"; + String camera_ip = "10.5.5.9"; // Hero 3 HTTP API host (not .1) int poll_interval_sec = 30; } cfg; @@ -95,27 +97,38 @@ struct CamStatus { CamStatus fetchStatus() { CamStatus s; - - String url = "http://" + cfg.camera_ip + - "/bacpac/SH?t=" + cfg.camera_password + "&p=%01"; - + + // READ status — must NOT be the shutter endpoint. Hero 3 status blob + // (validated on a Hero 3 Silver, ~31 bytes): + // [29] recording flag (0 idle / 1 recording) — confirmed + // [19] battery level (raw; drains with charge) — calibrate on the hub + // [25..26] video-remaining (provisional) + // The body is binary and starts with 0x00, so read the stream directly — + // Arduino String truncates at the first null byte. + String url = "http://" + cfg.camera_ip + "/camera/se?t=" + cfg.camera_password; + HTTPClient http; http.useHTTP10(true); http.begin(goproClient, url); http.setTimeout(5000); int code = http.GET(); - if (code != 200) { http.end(); return s; } - String raw = http.getString(); + uint8_t buf[40] = {0}; + WiFiClient* stream = http.getStreamPtr(); + size_t n = 0; + unsigned long t0 = millis(); + while (n < sizeof(buf) && millis() - t0 < 1500) { + if (stream && stream->available()) buf[n++] = (uint8_t)stream->read(); + else delay(5); + } http.end(); - if (raw.length() < 58) return s; + if (n < 30) return s; - const uint8_t* buf = (const uint8_t*)raw.c_str(); - s.valid = true; + s.valid = true; + s.recording = (buf[29] == 1); + s.battery_raw = buf[19]; s.video_remaining_sec = buf[25] | (buf[26] << 8); - s.recording = (buf[29] == 1); - s.battery_raw = buf[57]; return s; }