ESP32-S3 WROOM CAM SDカード画像をブラウザで確認



https://qiita.com/hassy131/items/dc229fbff1b81f0478ce

前回記事↑の続編です。

![ESP32S3_WROOM_SD.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806156/2491ab50-679c-f7a4-9b77-e2f287865622.png)


デジカメもどきを作成したものの、1回1回SDカードを外すのがめんどうになってきました。SDカードの内容をブラウザで確認するようにしたものです。


ESP32-S3_WROOM CAM３部作になります。
1. [ESP32-S3 WROOM CAMでデジカメを作る](https://qiita.com/drafts/dc229fbff1b81f0478ce/edit)
GPIO0ボタン押下で静止画撮影、SDカードに保存。EdgeImpulseでのトレーニングデータ収集の為。
2. [SDカード画像をブラウザで確認](https://qiita.com/drafts/45f3e266983a01c2cfc1/edit)
SDカードの取り外しが面倒なため
3. 画像識別ST7789でバウンディングボックス
EdgeImpulseでの学習モデルを元に画像識別


# ２．SDカード画像をブラウザで確認 

```c++
/////////////////// 全ての画像を映すVer ///////////
#include <WiFi.h>
#include <SD_MMC.h>
#include <WebServer.h>

// Wi-FiのSSIDとパスワードを設定
const char* ssid = "XXXXXXXXX";  // 接続するWiFiのSSID
const char* password = "XXXXXXXXX";  // 接続するWiFiのパスワード

// Webサーバーをポート80で作成
WebServer server(80);

// SDカード用のピン定義
#define SD_MMC_CMD 38
#define SD_MMC_CLK 39
#define SD_MMC_D0  40

// ファイルのマウントステータスを示す変数
bool sd_init = false;

// Webサーバーのルートにアクセスされたときの処理
void handleRoot() {
  if (!sd_init) {
    server.send(500, "text/plain", "SD Card not initialized");
    return;
  }

  String html = "<html><body><h1>All Images</h1><div>";

  // SDカードからファイルを取得して表示
  File root = SD_MMC.open("/");
  File file = root.openNextFile();

  while (file) {
    if (!file.isDirectory()) {
      String fileName = String(file.name());
      if (fileName.endsWith(".jpg") || fileName.endsWith(".png")) {
        // URLエンコードした画像ファイルをHTMLに追加して表示
        html += "<div style=\"margin-bottom:20px;\"><img src=\"/image?name=" + urlencode(fileName) + "\" style=\"max-width:300px; display:block;\"><p>" + fileName + "</p></div>";
      }
    }
    file = root.openNextFile();
  }
  
  html += "</div></body></html>";
  server.send(200, "text/html", html);
}

// 画像ファイルにアクセスされたときの処理
void handleImageRequest() {
  if (!sd_init) {
    server.send(500, "text/plain", "SD Card not initialized");
    return;
  }

  String fileName = server.arg("name");

  // パスの先頭にスラッシュを追加（必要に応じて）
  if (!fileName.startsWith("/")) {
    fileName = "/" + fileName;
  }

  // 確認用のデバッグ出力
  Serial.print("Requested file: ");
  Serial.println(fileName);

  if (SD_MMC.exists(fileName.c_str())) {
    File file = SD_MMC.open(fileName.c_str(), FILE_READ);
    if (fileName.endsWith(".jpg")) {
      server.streamFile(file, "image/jpeg");
    } else if (fileName.endsWith(".png")) {
      server.streamFile(file, "image/png");
    }
    file.close();
  } else {
    Serial.println("File not found");
    server.send(404, "text/plain", "File not found");
  }
}

// SDカードの初期化処理
void initSDCard() {
  SD_MMC.setPins(SD_MMC_CLK, SD_MMC_CMD, SD_MMC_D0);
  if (!SD_MMC.begin("/sdcard", true, true, SDMMC_FREQ_DEFAULT, 5)) {
    Serial.println("Card Mount Failed");
    sd_init = false;
  } else {
    Serial.println("SD Card Initialized");
    sd_init = true;
  }
}

// Wi-Fiの接続設定
void connectWiFi() {
  Serial.print("Connecting to WiFi...");
  WiFi.begin(ssid, password);

  // Wi-Fi接続完了まで待機
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
}

// URLエンコード関数
String urlencode(String str) {
  String encodedString = "";
  char c;
  char code0;
  char code1;
  char code2;
  for (int i = 0; i < str.length(); i++) {
    c = str.charAt(i);
    if (c == ' ') {
      encodedString += '+';
    } else if (isalnum(c)) {
      encodedString += c;
    } else {
      code1 = (c & 0xf) + '0';
      if ((c & 0xf) > 9) {
        code1 = (c & 0xf) - 10 + 'A';
      }
      c = (c >> 4) & 0xf;
      code0 = c + '0';
      if (c > 9) {
        code0 = c - 10 + 'A';
      }
      code2 = '\0';
      encodedString += '%';
      encodedString += code0;
      encodedString += code1;
    }
    yield();
  }
  return encodedString;
}

// サーバーの初期化とエンドポイントの設定
void setup() {
  Serial.begin(115200);
  
  // Wi-Fi接続
  connectWiFi();
  
  // SDカードの初期化
  initSDCard();
  
  // Webサーバーのルートにアクセスしたときの処理
  server.on("/", handleRoot);
  
  // 画像ファイルにアクセスされたときの処理
  server.on("/image", handleImageRequest);

  // サーバーを開始
  server.begin();
  Serial.println("HTTP server started");
}

// メインループでWebサーバーを処理
void loop() {
  server.handleClient();
}

```

# 結果
　ｈｔｔｐ://192.168.1.xxでブラウザで確認します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806156/bada25c0-25a4-69ff-6d03-2c1f0f26826e.png)

続編はこちら↓

https://qiita.com/hassy131/items/980fa177a6bca2e39fdc