IoTポスト（スマートポスト：中学校自由研究）紹介

はじめまして、株式会社ROI 開発部です！
隔週持ち回りで勉強会しておりますが、資料などのアウトプットをココに載せることになりました。隔週なのでゆっくりなペースで投稿することになりますが、よろしくお願いします。

# 経緯
2018年夏休み、娘の中学校から自由研究で各科目毎にテーマが来ていて、技術は「創意工夫」だったので、技術科で扱うような素朴なモノが「インターネットに接続されたらこんなに便利になるよ」というような、いわゆるIoTができそうだということになり、「家の郵便受けに投函物が届いたらメールが来る」というものを提出したものを取り上げます。

#### 担当割
* 当人：外箱の制作(木工)・ハンダ付け～配線～取り付け・動作調整
* 父親：マイコン設計・プログラム・外箱の設計

外観１：天板を外して後ろから見る。上部にIR-LED、下部にセンサー穴が見える
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/9a1c4925-1847-94e7-973f-d1ab74118867.jpeg" alt="外観１" width="500" height="500" />

外観２：底面を見る。このあと基盤とバッテリーは木ねじで固定した
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/376e67d9-5d88-ce8f-a3cc-1b5840c26dee.jpeg" alt="外観２" width="500" height="500" />


# マイコン機種選定

## 選定基準・要件と性能目標値
* メジャーであること（割と重要）
* 長期に渡って入手が容易であること
* インターネットにWi-Fiで接続可（Wi-Fiクライアント搭載）
* ハードウェアを扱うのがカンタン
  * ADC内蔵
  * 単一電源で動く
  * 外付け部品を極力少なくしたい
* 環境構築がカンタン
  * USB接続のみで書き込み～デバッグまで出来る
* 安い
  * ＝高価ではない
  * 3000円未満程度でOK。
    * 全体原価を3000円未満にしたいので、できればマイコン単体では1000円未満が望ましい
* 低消費電力
  * 1200mAhのバッテリーで3日間連続稼働が最低限の目標。ながければ長い程よい。
    * 1時間平均で40mW（3.6V表記で1日300mAh弱）以下
    * msオーダーの短期スリープ機構があり、プログラムから任意のタイミングで可能なタイプが望ましい
* プログラマブルIO（PIO）は2～3個は欲しい
* 物理サイズが小さいこと

## 機種比較と評価

### Raspberry Pi Zero W
https://www.raspberrypi.org/products/raspberry-pi-zero-w/
https://www.switch-science.com/catalog/3200/
  * メジャー：◎
  * 入手性：× … 当時は超極端な品薄状態だった。今なら○か？
  * OS／言語：Linux／言語はほぼフリーハンド
  * Wi-Fi：○
  * 電源：USB-Micro 5V 0.5A
  * 平均消費電力：1000mW
  * 待機時消費電力：420mW
  * プログラマブルスタンバイ：△
    * 3秒に1回処理をするようなスタンバイモードは、実現するのは実は結構大変なので限りなく×に近いかも
  * ADC：× 外付け必須
  * 環境構築：カンタン。Linuxの知識が必要かも。
  * 値段：1,200円／台前後
  * PIO：◎ GPIO 27pin！
  * サイズ ： ○
  * 総合評価 △

### ESP8266／ESP32ファミリ
https://ja.wikipedia.org/wiki/ESP8266
以下はAI-Thinker製モジュール ESP8266-12Eのもの
  * メジャー：◎
  * 入手性：◎
  * OS／言語：Arduino／Sketch。カンタン。
  * 値段：695円（中国ECなら300円前後？）
  * Wi-Fi：○
  * 電源：USB-Micro 5V 0.5A
  * 平均消費電力：260mW
  * 待機時消費電力：1mW以下（プログラマブルスタンバイ可。DeepSleepモード時は0.033mW）
  * ADC：○ 10bit x 1pin
  * 環境構築：超カンタン
  * PIO：◎ GPIO 16pin！
  * サイズ ： ○
  * 総合評価 ◎

### IchigoJam
https://ichigojam.net/
  * Jigブラウザを作った社長の趣味での成果物を商品化。教育機関では超メジャー。
  * 言語：古き良きBASIC（JavaScript版もあり）。割とカンタン。
  * 価格：2000円
  * Wi-Fi：×（外付けって手もあるが）
  * 消費電力 ： △～×
  * プログラマブルスタンバイ不可。ARM Cortex-M0 のマシン語経由でならもちろん可能らしい。ｗ
  * 総合評価 ×

### micro:bit
https://microbit.org/ja/
  * 教育機関では超メジャー。英国小学生向けにアプローチされた教育用マイコン。
  * 言語：Scratchブロック／JavaScript／Python。超カンタン。
  * 価格：2000円
  * 消費電力 ： △～×
  * プログラマブルスタンバイ不可
  * bluetooth：○
  * Wi-Fi：×
  * 総合評価 ×

### Mbed系
https://www.mbed.com/en/
  * OS／言語：多数種類あり。リアルタイムOSであるMbed OS＋C言語がメジャーか…。ちょっと難しい。ｗ
  * 開発環境：組み込み向け本格的なものがメジャー（カンタン・簡易版もアリだが…）。
  * バリエーション多すぎｗ
  * 消費電力：◎
  * 総合評価 △ 本格的過ぎ

# 設計方針

### ポストに入る様々な投函物に柔軟に対応させる
  * 投函後、斜めに保持して、どの大きさの投函物でも、想定される素材であれば、確実にセンサーを塞ぐよう底面を斜めにする
  * 直射日光などの影響を最小限になるよう考慮する
    * センサーに日光が直接入らない位置へ

### 投函されたかどうかは、赤外線LED→フォトトランジスタで検知する
  * カメラは投函物の検出だけのためだと、決定的に大仰である。消費電力の点でも×。
    * ただし画像解析をクラウド側に持っていく、何らかの別センサーとの組み合わせで間欠(インターバル)観測ができればアリ。カメラ自体は200万画素・広角レンズ付きのモジュールが500円～程度で調達可能。
    * 今回はクラウド側で大きな処理が必要になるものは、自由研究の観点から範疇を大きく超えてしまうので見送った。
  * ラインCCD：投函物のスキャンするならアリ。投函されたとき、宛先や不在票などを読み取って送れば、より高機能に出来そうだが、今回は見送り。
  * 物理スイッチ：信頼性は高そう。ローテクも魅力。ただし投函物の大きさ・重さ・硬さが不定なので、設計や調整の手間を考えて見送り。
  * 超音波：密閉空間で、素材が紙なので、若干調整が面倒そう。比較的高価。距離測定をするのではないので、今回見送り。
  * 焦電センサー：応答速度が遅いので、消費電力を考慮したスピード測定を目指すなら不利。
  * IR(赤外線)：安価・スピード・部品点数的な有利・低消費電力に優れる。ADCの精度さえ確保できれば感度も◎。
    * フォトダイオード：アンプ回路が必要。要設計・調整。どうせならフォトトランジスタにしたい。
    * カプラ：投函物を間に挟むとき、距離を確保したいので、今回は見送り。
    * フォトトランジスタ：フォトダイオード＋アンプ回路内蔵で調整済み。今回向き。
      * 可視光フィルタは必須：IRのみを通過させる塗料・素材のフォトトランジスタを採用する。今回はデジタル通信や交流信号ではなく、あくまでも光量のみを測定するので、環境光由来のバイアスノイズ成分を極力排除したいため。

### その他の考慮 
* 炎天下・雨天対応
  * 電源・回路は底面側へ格納
  * 撥水塗装
  * 天板を大きめに
* 誤報防止
  * 強い環境光による影響考慮し、IR-LEDをOFFにした状態とONにした状態をそれぞれ計測し、差分から投函物の有無を検出する
  * 風や塵、虫の影響を考慮し、連続3回遮蔽されたときに発報する
* デバッグ（状態把握）を容易に
  * 投函物の検知前後、発報前後なのかを把握できる
  * センサーの値をUSB経由でデバッグする
* 低消費電力化へ
  * 間欠測定：3秒毎に数msレベルの瞬間アクティブで検知処理、それ以外はスタンバイとする。
  * 測定時以外のタイミングは、赤外LEDはOFF。
  * 測定時以外のタイミングは、フォトトランジスタをOFF。
  * 発報時以外はWi-FiはOFFに：最も消費電力が大きいモジュールなので、可能な限りOFFにする。
  * ステータス表示は、オンボードLEDの1msレベルの点滅タイミングのバリエーションで実現
  * TODO：ESP8266の最も低電力なモードは、DeepSleepモードがある。消費電力量が3桁違う別世界らしいので、これを活用するのはアリ。
  * TODO：センサー類の高感度化による省電力化。今回はテスターによる調整や外付け回路などを極力しない方針だったので見送ったが、高感度にすればもっと照度を落としても十分機能するハズ。
  * TODO：RTCが無のでWi-Fi経由でざっくり深夜帯かどうかを検知して、夜間動作停止にする
    * ESP8266はしっかり省電力を意識した設計にすると単三電池3本で半年間～1年間、連続動作させることが出来る
* 回路のシンプル化
  * 外付け部品を可能な限り減らす
  * 調整に可能な限りテスターを利用しない
* PUSH方法の汎用化
  * 今回はサーバサイドに別途プログラムを容易する。
    * サーバ側へはREST API経由で通信し、メール送信はサーバ側で行う。
  * TODO：PUSH通知やSlackへの通知など
    * 今回は自宅サーバ上でperlスクリプトが動いている状態だが、例えばAWS上のlambda経由で電話が掛かってくる（！）とか、PUSH通知専用RestAPI/WebSocketを直接呼ぶような実装も視野に入れることができる
  * TODO：Wi-FiのAP接続情報設定は、別途ESPをAP化、DHCP・Webサーバライブラリを用いた機能経由で設定画面を用意可能
https://iot.keicode.com/esp8266/esp8266-ap.php
    * 今回はDEMOが可能なレベルの実装にとどめて見送り。オンコーディングを許容する

### 今回は考慮しない項目
プロトタイプと言えども、将来的な製品・サービス展開を見据えないので、一切考慮しなくて良い項目
* 部品調達先の安定性、サービスパーツ準備方法
* 大量製造の方法、部品単位の検査、歩留まり管理
* 故障時の対応（故障時の切り分け易さ、リモートでの監視、故障診断ツールの準備対応、良品への交換手法・方法）
* 機種バリエーション展開準備対応
* パッケージ・操作マニュアル・付属品などへの配慮
   * 操作性や問い合わせ対応を考慮すると、ステータスを表示する液晶か、少なくとも追加LEDは必須と思われる。

# ハードウェア設計・実装・調整

## キーデバイス

### 赤外線LED(IR-LED)
  * 購入：マルツ秋葉原本店 20円
  * 型番：TSAL6200
  * 波長：940nm：フォトトランジスタの方が入手難易度が高いので、実際にはフォトトランジスタを選定してからIR-LEDを選定した。
  * GPIO D5からの直ドライブとする
    * ESP8266の各ピンは12mAまで駆動可能。ごく短期(1msのオーダー)であれば3～10倍程度は可能。
      * 3.3V100mA（=330mW） 1ms点灯とする。
      * 3.3V÷R＝100mA なので、R≒300Ω。直列抵抗 300Ωで実現する

### フォトトランジスタ
  * 購入：秋月電子通商八潮店 20円
  * 型番：L-51ROPT1D1
  * 波長：940nm
  * GPIO A0のADCを利用
  * 強い光が入ったとき、A0の電圧が1000mV(=1V)になるようにする
    * 強い光のときのフォトトランジスタの抵抗値：20kΩ、無光時：10MΩとし、抵抗分圧回路で抵抗値Rを算出
      *  R kΩ ÷ (20kΩ + R)= 1.0V ÷ 3.3V。R=8.7≒10kΩ
    * センサ部消費電力の計算
      * 3.3V ÷ 46kΩ ＝ 7.2mA（=2.4mW） … 許容可能（消費電力的＋直ドライブ的）
    * 今回のIR-LEDからの距離で、投函物が無い状態・室内で、A0値が150～200程度（150～200mV）となっていて、15ｍA（=50mW）以下となり、ほぼ理想的な値に無調整で到達したため、追加の省電力化は先送り。

### マイコンボード
* ESP8266-12E
* 購入：Amazon 695円
  https://www.amazon.co.jp/dp/B072K7P4JL/ref=cm_sw_em_r_mt_dp_U_9odSDbXJ6RMK6
  * ESPハンズオン（資料）
  https://www.kmrweb.net/micro/index.html

写真１：回路設計図 手書きｗ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/64e61239-2e25-4916-fb61-1b96e74b63ba.jpeg" alt="回路設計図" width="500" height="500" />
※ A0端子とGND間にある40KΩは、10KΩに変更してあります。
※ グルグル回りくどく配線が見えるのは、実際の実態配線図っぽく使えるように考慮しているためです。
またこのような回路図記号は、30年以上前の書き方らしいです。ｗ

## その他部品表
* バッテリー ダイソー TDB0510-C2A：324円（USBケーブル込）
* ユニバーサル基板：10円
* 1/4W カーボン抵抗 ｘ２（300Ω、40kΩ）：20円
* 撚り線2芯ケーブル 50cm：30円
* 外箱関連
  * MDF材（中密度繊維板）600mm × 300mm × 9mm ： 354円 ｘ 2枚
  * 蝶番 ｘ2 島忠 : 230円
  * 木工ボンド ダイソー：108円
  * 皿頭木ネジ(アルミ) 島忠 20mm ｘ 20本 ： 98円
  * 皿頭木ネジ(アルミ) ダイソー 10～60mm ｘ 50本 ： 108円
  * 撥水ラッカー ダイソー：108円
  * サンドペーパー ダイソー #100、#400 ：108円

### 部品・材料代合計
* 計 2,781円（税込）

## 主な工具
* PC
* ブレッドボード・ジャンパ線など適宜
* 針金
* 鰐口クリップ
* ハンダゴテ30W
* ヤニ入り精密半田（Φ0.6～0.8mm）
* ハンダ吸い取り線
* 木工関連
  * のこぎり
  * きり
  * 電動ドリル／ドライバー
  * 棒ヤスリ
* 万力

# 実装前の試験
* ハンダ付け前に、ブレッドボード上で動作確認をする
* USBケーブルでArduino IDEのコンソールから、フォトトランジスタの電圧を測定し、閾値の調整可能とする

写真２：ブレッドボード上の様子
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/98711e5f-df23-fee7-9a26-edb6019f2f0d.jpeg" alt="ブレッドボード" width="500" height="500" />

図１：ピンアサイン表
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/b5d00f26-fb33-429b-c47b-cf0ea3be1c40.jpeg" alt="ピンアサイン表" width="500" height="500" />
※ 出典：https://blogs.yahoo.co.jp/pdxpopypop/65500263.html


# 外箱工作（木工工程）
* 省略

# ソフト環境構築
Arduino IDEをインストールし、ESP8266ドライバ（ボードマネージャ）を追加して、利用可能にする手順

## Arduino IDE
  https://www.arduino.cc/en/main/software
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/751d67b4-4a7d-8928-b0cc-2f17b97394cd.png" alt="Arduino IDE Download" width="500" height="340" />

## インストール手順 ～ プログラム動作まで
参考：Arduino IDE に Stable ( Staging )版 ESP8266 ボードをインストールする方法
https://www.mgo-tec.com/esp8266-board-install01-html

https://www.arduino.cc/en/Main/Software
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/9a8c3f3d-42aa-cc8a-efb9-77944dd47d6d.png" alt="Arduino IDE Download" width="500" height="340" />


## ボードマネージャを追加登録
![b18ec885-299b-4506-89f6-6d1c4ff8eb88.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/1c4495b1-24ff-73d0-18f0-69442586fc46.jpeg)

* 環境設定でボードマネージャの追加URLを設定
http://arduino.esp8266.com/stable/package_esp8266com_index.json
![e421f77a-bd5e-4389-8d59-caa6603fe05e.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/ce3e8658-0b4e-0677-6f9e-96e4fa09314a.jpeg)

* ボードマネージャで「ESP」を検索して「esp8266」を追加。
![98bc4de6-7f9a-445b-9282-a78f98115268.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/b6400ab8-c6bb-bb75-2bac-37e81b9f2934.jpeg)

![319573d8-3bd6-40c3-90be-7d1365532beb.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/905be5ef-254b-569d-f815-c294682a8070.jpeg)


* 追加後、ボードを「Generic ESP8266 Module」に切り替え。



# ソフトウェア実装
## ソースコード

``` ESP8266-E12_IoTSmartPost.ino 

/*＊
 * IoTポストのソースコード
 *
 * 参考：
 * Arduino IDE（ソフトウェア開発環境） ESP8266 導入手順
 * https://www.mgo-tec.com/esp8266-board-install01-html
 *
 * ESP8266-12E NodeMCU ESP-12 v1.0
 * https://www.ebay.co.uk/itm/Arduino-NodeMcu-Lua-WIFI-Internet-of-Things-development-board-ESP8266-12E-New-UK-/191758723436
 *
 * WiFiクライアント, http通信
 * https://qiita.com/umi_kappa/items/c3c929c6f42c5bdf3143
 *
 * 回路：
 * フォトトランジスタ
 * http://catalina1344.hatenablog.jp/entry/2014/09/21/003848
 *
 * アナログ入力（抵抗分圧回路）
 * https://www.petitmonte.com/robot/esp_wroom_02_analogread.html
 */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>

WiFiClientSecure client;

// 変数の定義
int c = 0;      // 連続何回遮断されているか
int a = 0;      // メールを送信済みか？　0:まだ, 1:送信済み
const int threshold = 3;    // ○回連続検出したら、メールを送信する／解除する

// 接続するWi-Fiアクセスポイントの情報
const char* SSID = "vvvvvvvvvvvvv";
const char* AP_PASS = "wwwwwwwwwww";

// メールサーバ送信用のホスト名
const char* host = "www.example.com";

void setup() {
  // ボード上のLEDの初期化
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
  // 赤外線LED（IR-LED）を繋いだポートの初期化
  pinMode(5, OUTPUT);
  // パソコンでモニターするための通信ポート(シリアルモニタ)の初期化
  Serial.begin(9600);
  // これ以降は『Serial.println(文字列)』となっているところが実行されると、パソコンで情報が読み取れる
}

// the loop function runs over and over again forever
void loop() {
    // IR-LED がOFFの段階で計測する
    int v0 = analogRead(A0);

    // IR-LED を ON にします
    digitalWrite(5, HIGH);

    // センサ可動のタイミングをLEDで知らせます。
    // LED ON
    digitalWrite(LED_BUILTIN, LOW);

    // 計測します。（A0 端子の電圧を計測。1000で1000mVになる）
    delay(1); // wait 1ms
    int v1 = analogRead(A0);
    int v = v1 - v0;

    // シリアルモニタ に 計測した電圧を送信。
    Serial.print(v1);
    Serial.print(" - ");
    Serial.print(v0);
    Serial.print(" = ");
    Serial.println(v);

    // IR-LED OFF
    digitalWrite(5, LOW);
    // LED OFF
    digitalWrite(LED_BUILTIN, HIGH);

    if (v < 70) {
      // IR-LEDをつけたときと消したときの電圧差が70mV未満の場合
      // 投函物が入っていて、IR-LEDの光が見えてない ＝ 投函物を検出した
      c++;

      // 検出中であることを長めのLED点灯で知らせます。
      // LED ON
      digitalWrite(LED_BUILTIN, LOW);
      delay(100);
      // LED OFF
      digitalWrite(LED_BUILTIN, HIGH);

      if (c > threshold) {
        // 連続3回検出したら、メール送信判定を行う
        if (a == 0) {
          // メールを送信していなかったら、実際に送信する

          // Wi-Fi アクセスポイントに接続する
          WiFi.begin(SSID, AP_PASS);

          while (WiFi.status() != WL_CONNECTED) {
            // Wi-Fi接続中は、短め(0.5秒間隔)のLED点滅
            // LED ON
            digitalWrite(LED_BUILTIN, LOW);
            delay(30);
            // LED OFF
            digitalWrite(LED_BUILTIN, HIGH);
            delay(470);
            Serial.print(".");
          }
          Serial.println("");
          Serial.print("Wi-Fi Connected. ");
          Serial.println(SSID);

          // メール送信 httpアクセスすると、設定されたメールアドレスに指定の文章で送信される。
          Serial.println("mail sending...");
          Serial.println(sendMail());
          Serial.println("mail sent");

          // Wi-Fi APの接続を切断する
          WiFi.disconnect();
          Serial.println("Wi-Fi Disonnected.");

          // メール送信成功時のLED表示（100回短く点滅する）
          for (int i = 0; i < 100; i++) {
            // LED ON
            digitalWrite(LED_BUILTIN, LOW);
            delay(30);
            // LED OFF
            digitalWrite(LED_BUILTIN, HIGH);
            delay(30);
          }

          // メールが送信済みであることを記録しておく
          a = 1;
        }

        // 検出済みの状態
        c = threshold * 2;
      }
    } else {
      // 検出状態が終わった場合
      c--;

      if (c < 1) {
        // 連続して検出状態でないことが連続6回したら、投函物がないという認識になる
        a = 0;
        c = 0;
      }
    }

    // 3秒毎に観測するので、3000msお休み
    delay(3000);
}

/**
 * クラウド上のサーバにメール送信を依頼する
 */
String sendMail() {
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return "connection failed";
  }

  // We now create a URI for the request
  String url = "/sendmail/IoTSmartPost.cgi";

  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  int timeout = millis() + 5000;
  while (client.available() == 0) {
    if (timeout - millis() < 0) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return "Client Timeout";
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
  return "http OK.";
}

```

## オンボードLEDの光り方とステータス一覧表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531245/ec53bc97-bfad-ffdf-9028-4c374199d4b5.png)

## デバッグの方法
```
Serial.println(">>> Client Timeout !");
```
マイコンボードをPCにつなげて、Aruduino IDE のシリアルモニター上から、「>>> Client Timeout !」がログのように見えるので、Webプログラマでも馴染みのあるやり方（ログを見るようなやり方）でデバッグが可能です。

---
この投稿には、[続きの記事（IoTポストで投函されたら電話が鳴るようにしてみた）](https://qiita.com/roi-dev/private/419924666965526e67b5) があります。