#!/usr/bin/env python3 # auto_capture_jpeg.py # 自动连接 ESP32 串口、触发复位、等待多个 JPEG dump、保存并打开所有图片 # 支持新格式:===JPEG_DUMP_BEGIN fmt= size==== import serial import base64 import re import sys import time import subprocess from pathlib import Path PORT = "/dev/cu.usbmodem834401" BAUD = 115200 OUT_DIR = Path("/Users/rdzleo/Desktop/CogletESP-camera-version/scripts") TIMEOUT_SEC = 90 MAX_FRAMES = 4 BEGIN_RE = re.compile(r"===JPEG_DUMP_BEGIN\s+(?:fmt=(\S+)\s+)?size=(\d+)===") END_RE = re.compile(r"===JPEG_DUMP_END===") B64_RE = re.compile(r"^[A-Za-z0-9+/=]+$") def main(): print(f"[·] 打开串口 {PORT} @ {BAUD}") ser = serial.Serial(PORT, BAUD, timeout=1) print("[·] 复位 ESP32 …") ser.dtr = False ser.rts = True time.sleep(0.1) ser.rts = False time.sleep(0.1) ser.reset_input_buffer() print(f"[·] 等待 JPEG_DUMP 标记(最多 {TIMEOUT_SEC}s,期望 {MAX_FRAMES} 张)…") start = time.time() in_dump = False expected_size = 0 current_fmt = None b64_buf = [] saved_files = [] while time.time() - start < TIMEOUT_SEC and len(saved_files) < MAX_FRAMES: raw = ser.readline() if not raw: continue try: line = raw.decode("utf-8", errors="replace").rstrip("\r\n") except Exception: continue if any(k in line for k in ["FaceTracker", "Camera", "panic", "Guru", "ov3660", "Compile time"]): print(f" {line}") if not in_dump: m = BEGIN_RE.search(line) if m: in_dump = True current_fmt = m.group(1) or "unknown" expected_size = int(m.group(2)) b64_buf = [] print(f"[+] JPEG_BEGIN fmt={current_fmt} size={expected_size}") continue if END_RE.search(line): in_dump = False b64_str = "".join(b64_buf) try: data = base64.b64decode(b64_str) except Exception as e: print(f"[!] base64 decode failed: {e}") continue if len(data) != expected_size: print(f"[!] 字节数差异 got={len(data)} expected={expected_size}") out_path = OUT_DIR / f"frame_{current_fmt}.jpg" out_path.write_bytes(data) print(f"[✓] 保存 {out_path.name} ({len(data)/1024:.1f} KB)") saved_files.append(out_path) continue stripped = line.strip() if B64_RE.match(stripped): b64_buf.append(stripped) ser.close() if not saved_files: print("[!] 没有抓到任何 JPEG 帧") return 1 print(f"\n[✓] 共保存 {len(saved_files)} 张") for p in saved_files: print(f" - {p}") # 用 Finder 打开目录,用户可以并排对比 subprocess.run(["open", str(OUT_DIR)]) # 或者直接打开所有 JPEG for p in saved_files: subprocess.run(["open", str(p)]) return 0 if __name__ == "__main__": sys.exit(main())