M5StickCでできること 〜SDカードのファイルをWebサーバーに送信する

先日の調査で、M5StickCとSDカードリーダーをつなぎ、センサで採取したデータを、SDカードに書き込むことができました(記事は こちら)。

今回は、SDカードに保存されているファイルを、Webサーバーに送信してみたいと思います。
こちら のページに、画像データをサーバーに送信する方法が書かれていたので、これを参考にさせていただきました。


まずは、Webサーバーに、以下のPHPプログラム「writefile.php」を設置し、同じ場所に「data_files」というフォルダをつくっておきます。
データを受信したら、「data_files」フォルダの下に、「<UNIX Time>.txt」という名前でファイル保存するプログラムです。

<?php
$data = file_get_contents('php://input');
$filename = "data_files/" .time() .".txt";
file_put_contents($filename, $data);
?>

M5StickCに書き込むスケッチは以下のとおりです。

#include <M5StickC.h>
#include <WiFi.h>
#include "SD.h"
#include "esp_http_client.h"

SPIClass SPI2;
File file;

const char* ssid     = "XXXXXXXX";
const char* password = "XXXXXXXX";

char file_name[20] = "/test1.txt";

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 0, 2);

  M5.Lcd.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
  }
  M5.Lcd.println(" CONNECTED");

  SPI2.begin(0, 36, 26, -1); // SPI初期化
  if(!SD.begin(-1, SPI2)) { // SDカード初期化
    M5.Lcd.println("Card Mount Failed");
    return;
  }
}

void loop() {
  M5.update();

  if(M5.BtnA.wasPressed()) {
    file = SD.open(file_name, FILE_READ);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.print("FILE SIZE : ");
    M5.Lcd.println(file.size());

    char tmp_var[file.size()] = "";

    while(file.available()) {
      sprintf(tmp_var, "%s%c", tmp_var, char(file.read()));
    }
    file.close();

    esp_http_client_config_t config = {0};
    config.url       = "http://XXXXXXXX/writefile.php";
    config.method    = HTTP_METHOD_POST;

    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_set_post_field(client, (const char *)tmp_var, strlen(tmp_var));
    esp_http_client_perform(client);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.println("FINISH");
    esp_http_client_cleanup(client);
  }
}

最初にWi-Fiネットワークに接続し、SDカードの初期化を行います。
ボタンを押すと、SDカード内の「test1.txt」ファイルを開き、その内容を指定したURLに送信します。

データ送信には「esp_http_client.h」というライブラリを使っています。
ほとんど理解できておらず、上記のサイトを参考に、見よう見まねでつくっているのですが、

  • esp_http_client_init()
  • → esp_http_client_set_post_field()
  • → esp_http_client_perform()
  • → esp_http_client_cleanup()

という手順でデータを送信することができるようです。

このスケッチを試してみたところ、小さいファイルは問題なく送信できたのですが、ファイルサイズが大きくなると送信できませんでした(5000バイト程度が上限)。

そのため、スケッチを以下のように変更しました。

#include <M5StickC.h>
#include <WiFi.h>
#include "SD.h"
#include "esp_http_client.h"

SPIClass SPI2;
File file;

const char* ssid     = "XXXXXXXX";
const char* password = "XXXXXXXX";

char file_name[20] = "/test3.txt";
int  var_size = 2000;

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 0, 2);

  M5.Lcd.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
  }
  M5.Lcd.println(" CONNECTED");

  SPI2.begin(0, 36, 26, -1); // SPI初期化
  if(!SD.begin(-1, SPI2)) { // SDカード初期化
    M5.Lcd.println("Card Mount Failed");
    return;
  }
}

void loop() {
  M5.update();

  if(M5.BtnA.wasPressed()) {
    file = SD.open(file_name, FILE_READ);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.print("FILE SIZE : ");
    M5.Lcd.println(file.size());

    char tmp_var[var_size+1] = "";

    esp_http_client_config_t config = {0};
    config.url       = "http://XXXXXXXX/writefile.php";
    config.method    = HTTP_METHOD_POST;

    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_open(client, file.size());
    while(file.available()) {
      sprintf(tmp_var, "%s%c", tmp_var, char(file.read()));
      if(strlen(tmp_var)>=var_size) {
        esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
        sprintf(tmp_var, "");
        M5.Lcd.print("*");
      }
    }
    esp_http_client_write(client, (const char *)tmp_var, strlen(tmp_var));
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 0, 2);
    M5.Lcd.println("FINISH");
    esp_http_client_close(client);
    esp_http_client_cleanup(client);

    file.close();
  }
}

ボタンを押すと、SDカード内の「test3.txt」ファイルを開き、その内容を送信します。
このスケッチでは、

  • esp_http_client_init()
  • → esp_http_client_open()
  • → esp_http_client_write()
  • → esp_http_client_close()
  • → esp_http_client_cleanup()

という手順でデータを送信します。「esp_http_client_write()」を複数回繰り返すことで、ファイルサイズの大きなファイルも送信できます。

このスケッチを試してみたところ、250Kバイト程度のファイルを送信することができました。

なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。


このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。

他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。