m5cameraの画像URLを取得する

# はじめに

こんにちは！[@nsd244](https://twitter.com/nsd244)です。
この記事では、m5cameraというm5stacシリーズのカメラの画像URLを取得してみた話をしようと思います。  
この記事は、12/7, 8に行われた、KDDI主催の学生向けハッカソン「[KDG HACKS 2019](https://www.kdghacks.com/)」にて僕が制作したプロダクトの一部をこの記事に書いています。  

m5cameraは、2019/12/8現在、ドキュメントが整っていない部分もあるため、記事にしてみました。

# m5cameraの特徴

まず、m5cameraについて使ったことない人も多いと思うので、簡単に特徴を紹介していきます。    
細かいスペックについては、[公式ドキュメント](https://docs.m5stack.com/#/ja/unit/m5camera)を参照してください。  

* m5camera単体でWi-FiホットスポットAPを生成できる
* 2つのバージョンがある
* グレードアップできる
* 長時間使用は推奨されていない
* 2つのプログラミング手段がある

これらの特徴について、1つずつ説明していきます。  

## m5camera単体でWi-FiホットスポットAPを生成できる

m5camera最大の特徴がこれです。  
m5cameraには単なるカメラだけではなく、esp32も内蔵されているため、Wifiホットスポットを生成することができます。  

## 2つのバージョンがある

m5cameraには、出荷時期によってピン配置の違う「モデルA」と「モデルB」の2つのバージョンがあります。  
この記事では、モデルBをベースに説明していきます。  
（おそらく、発売初期に出荷されたものがモデルA、それ以降のものはモデルBと思われる）  

![m5camera](https://docs.m5stack.com/assets/img/product_pics/unit/unit_m5camera_04.png)

![m5camera](https://docs.m5stack.com/assets/img/product_pics/unit/unit_m5camera_03.png)

## グレードアップできる

m5cameraは、三軸加速度・ジャイロセンサ（MPU6050）のモジュールや、温湿度・気圧センサ（BME280）モジュール、アナログマイクモジュール、バッテリーなどを接続しグレードアップすることができます。  

![m5camera+battery](https://ae01.alicdn.com/kf/HTB1GQiJX4D1gK0jSZFKq6AJrVXal/M5Stack-M5Cameras-M5Camera-M5Camera-X-400-2200mah.jpg_q50.jpg)

## 長時間仕様は推奨されない

[switch-scienceさんの販売ページ](https://www.switch-science.com/catalog/5207/)には、  

>※カメラモジュールの長時間使用は、オーバーヒートしがちなため推奨しません。短時間での撮影をお勧めします。

と書いてあります。  
実際にどの程度の処理でどのくらいの時間かかるか、検証されているブログ記事などを探してみたのですが、ありませんでした。  
もし時間があれば、検証してみたいと思います。  

## 2つのプログラミング手段がある

このm5cameraのプログラミング手段としては、「Arduino IDE」と「ESP-IDF」の2つがあります。
本記事では、Arduino IDEを用いた手段について書いていきます。

# クイックスタート

m5cameraは、デフォルトで動作するプログラムが入っています。  
とりあえずこのプログラムを動かすところから始めてみましょう。  
起動の仕方は、[公式サイト](https://docs.m5stack.com/#/ja/quick_start/m5camera/m5camera_quick_start)を参照してください。  

# 環境構築

Arduino IDEでm5cameraを使うためには、esp32のボードマネージャをインストールする必要があります。  
インストール方法については、[このブログ](https://www.mgo-tec.com/arduino-core-esp32-install)を参照してください。  

m5cameraにプログラムを書き込む際は、Arduino IDEの以下の設定を忘れないようにしましょう。  
* [ツール] -> [ボード] -> [ESP32 Wrover Module]
* [ツール] -> [Partition Scheme] -> [Huge APP (3MB No OTA）]

# m5cameraの画像URLを取得する

それでは、本題である「m5cameraの画像URLを取得する手順」について説明していきます。  
m5cameraの画像URLを取得するための作業手順を以下に記載します。  

1. webサーバーで画像表示する
2. 画像をローカルに保存する
3. htmlに画像を埋め込み、webサーバーを立ち上げ、ngrokで外部公開する

1, 2については、m5cameraで直接画像をとれるのであればそちらでよいのですが、今回はちょうど1のサンプルコードがあったのでこの手順で画像URLを取得しました。  

## webサーバーで画像を表示する

webサーバーで画像を表示するためのリポジトリは[こちら](https://github.com/nishidayoshikatsu/m5cameraB-web_server)です。  
このプログラムは、以下のスケッチ例にあるプログラムを参考にしました。  
[ファイル] -> [スケッチ例] -> [ESP32] -> [Camera] -> [CameraWebServer]  

このスケッチ例のプログラムは、m5cameraのモデルAに対応しているコードです。  
したがって、そのコードをモデルBに対応するように変更しました。  

[こちら](https://github.com/nishidayoshikatsu/m5cameraB-web_server)のプログラムのwifi_config.hにwifiのssidとpasswordを入力し、Arduino IDEでm5cameraに書き込みます。  
（ここのwifiはpcのwifiと同じもの）
書き込んだら、シリアルモニタを見ます。  
正常に起動できていれば、シリアルモニタにwebサーバーのURLが出てくると思います。  
もし出てこなければ、wifiのssid or passwordを見直すか、m5cameraのresetボタンを押してみましょう。  

アクセスできたら、以下のような画面が出てくると思います。  
この画面では、start streamを押すことで動画を表示させたりすることができます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289151/e357dae0-3e9a-289b-24e4-2e9090f8b2a8.png)

画像のみのURLを取得するには、現在のURLに **/capture** をつけます。  
これをつけることで、画像URLを取得することができます。  

## 画像をローカルに保存する

以下のコードを用いてURLの画像をダウンロードします。  
pythonのrequestsを用いることでURL先の画像データをダウンロードします。  
また、timeモジュールを使うことで画像の取得間隔を変更することができます。  

```python:save.py

import requests
import os
import sys
import time
import numpy as np

def download_image(url, timeout = 10):
    response = requests.get(url, allow_redirects=False, timeout=timeout)
    print(response.status_code)
    if response.status_code != 200:
        e = Exception("HTTP status: " + response.status_code)
        raise e

    content_type = response.headers["content-type"]
    if 'image' not in content_type: # 画像データ以外であればエラー
        e = Exception("Content-Type: " + content_type)
        raise e

    return response.content

def save_image(image):
    with open("img.jpg", "wb") as f:
        f.write(image)


# メイン
if __name__ == "__main__":
    url = 'm5cameraのURL'
    cnt = 0

    while(1):
        print("cnt:" + str(cnt))
        img = download_image(url)
        save_image(img)
        time.sleep(1)   # 画像の取得間隔
        cnt+=1
```

## htmlに画像を埋め込み、webサーバーを立ち上げ、ngrokで外部公開する

最後に、先程保存した画像を外部まで公開できるようにしましょう。  

まず、画像を以下のようにhtmlに埋め込みます。  

```index.html
<img src="./img.jpg" alt="m5camera" />
```

次に、ローカルサーバーを立ち上げてindex.htmlを表示します。  
今回は、pythonのhttp.serverクラスを用いて8000番地にローカルサーバーを立ち上げます。

```
$ python3 -m http.server 8000
```

最後に、このローカルサーバーを外部に公開します。  
今回は、ngrokを用います。  
※ngrokをinstallしていない人は[公式サイト](https://ngrok.com/)からinstallしましょう。  
先程立ち上げたローカルサーバの8000番ポートをhttpで公開します。  

```
$ ngrok http 8000
```

これで、URLを知っている人は誰でも画像を見ることができるようになりました！

# まとめ

この記事では、m5cameraについての紹介と、m5cameraの画像URLを取得する方法について記述しました。  
正直、かなり遠回りに回りくどいことをやっているなあと感じている人もいると思います。  
今回は、「無料でなおかつスムーズに」というかんじのもと方法を記述してやってきました。  
他の方法についても、今後また書こうと思います。  


# 参考文献

[1] [M5Stack Docs](https://docs.m5stack.com/#/ja/unit/m5camera)
[2] [M5cameraでWebカメラを作る](https://ambidata.io/samples/m5stack/m5camera/)