M5PaperにiPhoneから画像を送れるようにする
前、電子ペーパーでカレンダーを表示しておける端末がほしいということを書きました。
このときはInkCaseを切り刻むという猟奇手段に走ったけど、今はいいのがあるんですよ。M5Paperです!
ただ問題はM5Paperというのがプロトタイピング用のマイコンボードに近い端末なので、買ったままでは求める機能がついていないということです。つけていきましょう。
目的:M5PaperにiPhoneから無線で画像を転送する
いやまあ仕事用のOutlookに同期してカレンダー表示が最高ですけど、仕事用のアカウントをこの機械に教えるのもアレだし…画像表示するだけなら割と楽にできそうじゃない?それにカレンダーのスクショを送れればInkCaseと同じように使えるからヨシ!さっそく手段の目的化に成功しました。
1. M5Paperの開発環境を用意する
私はこの類のマイコンボードで何か作ったことはないので、まずはここからです。M5PaperはM5Stackシリーズの一種で、このM5StackはArduinoの開発環境でいけるらしいので、それを用意しました。というか下記をそのままやった。
2. SDカードの画像を表示する
M5Paperには16GBまでのmicro SDカードを入れることができるので、まずはこのSDカードから画像を表示できればと思いました。これはそういうAPIがあるので、すぐできる。
canvasが…きっと…オフスクリーンバッファみたいなやつで、そこにdrawJpgUrlとかdrawPngFileとかできる。でcanvasをpushすると表示される。こういう感じ
canvas.drawPngFile(SD, "/image.png");
canvas.pushCanvas(0, 0, UPDATE_MODE_GC16);
3. WiFiに接続し、Webサーバーを起動する
M5PaperはWiFiとBluetoothを持っているので、InkCaseみたいにBluetoothを使っても出来るかもしれない。ただここで気づいたんですけど、そうするとInkCaseみたいに転送用の専用アプリを作る必要が出てきて、シンプルではない。
ここで、M5Paper側でWebサーバーを動かして、そこにiPhoneからPOSTすれば簡単なのではないかと…思って…そうしました。
ここをメチャクチャ参考にした。所詮HTTPなのでWebサーバーといっても大したことはしなくてよく…GETが来たらSDカードに用意したhtmlを返し、POSTが来たらその内容をSDカードに保存していけばいい。出来そうじゃない?
さらにM5Paperにはせっかく電子ペーパー画面があるので、そこに自身のIPアドレスをQRコードで表示させることにしました。こうすればiPhoneのカメラを向けてタップするだけでWebサーバーに繋がる。
WiFi.begin("SSID", "PASS");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
// Get IP Address and create URL
IPAddress address = WiFi.localIP();
String addressString = address.toString();
String urlString = "http://" + addressString + "/";
// Start web server
server.begin();
// Display SSID, IP Address and QR code for this M5Paper
canvas.drawString(urlString, 540, 40);
canvas.qrcode(urlString, 20, 20, 500, 2);
canvas.pushCanvas(0, 0, UPDATE_MODE_GC16);
実際にはSSIDとパスワードをハードコードするのも嫌なのでSDカード上のテキストファイルから取得するようにしています。QRコード描画も標準のcanvas.qrcodeで簡単にできる。
こう。
4. HTMLを用意する
で、iPhoneからPOSTを送ってもらうためには、M5Paperから送信するhtmlにformを作っておけばいいわけです。こういうやつね
ただ、テキストならともかくファイルの場合は、このままこれを使うとPOSTを受信するときにContent-Type: multipart/form-dataが送られてきます。これの何が面倒かというと、HTTPヘッダの後にバイナリ以外も送られてきてしまう。
さらに、iPhoneの写真はそのまま送ろうとすると5MBとかあります。iPhoneならともかくM5Paperにこれを受信してリサイズして…とかやらせるのは面倒。
そこで、写真を選ばせるhtml上で画像もリサイズしてから送ればいいわけですよ!
これをjQuery使わない版にしながら書きました。base64のまま送ってM5Paperで復号してもいいんだけども、どうせならiPhone側でバイナリにしておきます。
で出来たバイナリをXMLHTTPRequestで送ります。
これは既にグレイスケールにしてコントラストを上げた画像ですけど……こういう画像処理もJavaScriptでやればいいはずなので、次はそうしたい。あとフォームのボタンをiPhoneから押しやすくデザインしないといけない
5. 受信したファイルをSDカードに保存する
Content-Type: multipart/form-dataだとここで面倒くさいことがあって、HTTPヘッダを飛ばした後もboudaryをカットしなければいけません。実は初期版ではそれをやっていたんですが、上記のようにバイナリをXMLHTTPRequestで送る場合はContent-Type: image.pngとかなので、ヘッダより後の部分をそのままファイルとして保存していけば画像ファイルができます。
void receivePostFile(WiFiClient client, String fileName)
{
SD.remove(fileName);
File receivedFile = SD.open(fileName, FILE_WRITE);
while (client.available())
{
byte buffer[256];
size_t bufferLength = client.readBytes(buffer, 256);
if (bufferLength > 0)
{
receivedFile.write(buffer, bufferLength);
}
else
break;
}
receivedFile.close();
receivedFileName = fileName;
}
こういう感じで。256バイト毎にしてるけど特に意味はないです。
受信できたら2. に戻って表示すればいいわけですね。出来た!
未来へ…
このようにありものを繋ぎ合わせるだけで白黒デジタルフォトフレームみたいなやつができるわけですね。いいじゃんM5Paper。一応できたもの置いときますね。
GitHubをほぼ使ったことがないのでREADMEとかを書いてないんですけど、上記のFactoryTestと同じくM5StackとM5Paperのライブラリに依存しています。あと「SD Card」ってフォルダがmicroSDに入れるべきファイルで、wifi.txtはお使いのSSIDとパスワードに書き換えます。
次はまず送信ボタンとかをちゃんとiPhoneで見えるようにしましょう。