2023年8月5日土曜日

ESP32でWiFi SDカードリーダを作ってみた。

 前にESP32でFTPサーバを立てられるようにしていたんだけど、ESP32側で生成したログファイルとかをダウンロードするだけならブラウザ経由でダウンロードしたほうが手っ取り早いんじゃないかということでWeb版のファイルマネージャーを作ってみた。

SDカードはSD_MMC.hで高速にアクセスできる配線にしてある。起動時にプルアップしておけないIOは起動後にプルアップするようにGPIO27でプルアップしてみた。

#include <WiFi.h>
#include <WebServer.h>
#include "SD_MMC.h"
#include "esp_mac.h"  //MACアドレス取得用

#define WiFi_password "12345678"
#define WiFi_ch 3
#define SD_PULLUP 27

WebServer server(80);
File uploadFile;

String htmlHeader() {
  return R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ESP32 SD_MMC File Manager</title>
</head>
<body>
<h2>ESP32 SD_MMC File Manager</h2>

<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="upload">
<input type="submit" value="Upload">
</form>
<hr>
)rawliteral";
}

void listFiles() {
  String html = htmlHeader();
  File root = SD_MMC.open("/");
  File file = root.openNextFile();
  while (file) {
    String name = file.name();
    html += "<p>";
    html += name;
    html += " [<a href=\"/download?name=" + name + "\">Download</a>]";
    html += " [<a href=\"/delete?name=" + name + "\">Delete</a>]";
    html += "</p>";
    file = root.openNextFile();
  }
  html += "</body></html>";
  server.send(200, "text/html", html);
}

void handleDownload() {
  if (!server.hasArg("name")) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }
  String filename = server.arg("name");
  String path = "/" + filename;
  File file = SD_MMC.open(path);
  if (!file) {
    server.send(404, "text/plain", "File Not Found");
    return;
  }
  server.sendHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
  server.sendHeader("Content-Type", "application/octet-stream");
  server.sendHeader("Connection", "close");
  server.streamFile(file, "application/octet-stream");
  file.close();
}

void handleDelete() {
  if (!server.hasArg("name")) {
    server.send(400, "text/plain", "Bad Request");
    return;
  }
  String filename = "/" + server.arg("name");
  if (SD_MMC.exists(filename)) {
    SD_MMC.remove(filename);
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

void handleUpload() {
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    String filename = "/" + upload.filename;
    uploadFile = SD_MMC.open(filename, FILE_WRITE);
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      uploadFile.write(upload.buf, upload.currentSize);
    }
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(SD_PULLUP, OUTPUT);
  digitalWrite(SD_PULLUP, HIGH);
  if (!SD_MMC.begin()) {
    Serial.println("SD_MMC Mount Failed");
    return;
  }
  if (SD_MMC.cardType() == CARD_NONE) {
    Serial.println("No SD card attached");
    return;
  }
  Serial.println("SD_MMC Ready");
  uint8_t macaddr[6];
  esp_read_mac(macaddr, ESP_MAC_WIFI_SOFTAP);  //WiFi Macアドレス読み込み
  char SSID[14];
  sprintf(SSID, "ESP32-%02X%02X", macaddr[4], macaddr[5]);
  WiFi.softAP(SSID, WiFi_password, WiFi_ch);  //SoftAPを起動
  server.on("/", listFiles);
  server.on("/download", handleDownload);
  server.on("/delete", handleDelete);
  server.on(
    "/upload", HTTP_POST, []() {
      server.sendHeader("Location", "/");
      server.send(303);
    },
    handleUpload);
  server.begin();
}

void loop() {
  server.handleClient();
}

一応アップロード機能もついてるのファイルアップロードもできる。ディレクトリは面倒なのでとりあえず非対応で。ログファイルを生成してダウンロードする用途だったら十分使えそうなレベル。スマホとかでもそのまま使えるのでFTPより便利かも…

0 件のコメント:

コメントを投稿