Arduinoメールチェッカー
Arduinoイーサーネットシールドの発熱量の投稿で予告した、イーサネットシールド(Ethernet Shield)を使用したメールチェッカーを作ってみました。以下に示す機能があります:
- 登録したメールサーバー(POPサーバー)に定期的にアクセスして、着信メール数、送信元(ヘッダーのFrom:フィールド)が登録したアドレスかをチェックする
- 登録したアドレスからメールが着信した際にLEDを点滅してお知らせする
- 着信メール数、登録したアドレスからのメール数、登録したアドレスからのメールの場合どのアドレスかを、LCDに表示する
- 周期チェックに加えて、ボタンによるマニュアル確認
ハード構成
LCDディスプレー、タクトスイッチ、LEDをプロトシールドに載せて、イーサネットシールド上にスタックしました。写真のような3階建て構造になります。
LCDはポピュラーなSC1602Bではなく、プロトシールドの幅にぴったり収まるSD1602HUOBを秋月さんで購入。このLCDはサイズがぴったりなのとオレンジバックライトがきれいでよいのですが、LCDパネルと基板をつなぐリボンケーブルが露出しておりかつこいつが傷つきやすいので注意が必要です。
結構背が高くなったので、写真のように、横において使用中です。
写真の表示は、着信メール数2件(MSG:2)、登録したアドレスからの着信1件(CHK:1)、登録した送信元アドレス"todot"を含むアドレスから着信があったことを示しています。
表示部分を含む全体の回路図は以下です。
電源ケーブルの接続ですが、Arduinoイーサーネットシールドの発熱量で記載したボルテージレギュレーターの発熱対策として、5V ACアダプターの出力をPOWER Pinの+5V(Pin3), GND(Pin4)に接続しました。電源の取り込みはプロトシールドで行い、シールド間の連結を介してイーサネットシールド・Arduino本体に電源を供給しています。
ACアダプタ用ジャックをプロトシールドに載せることができなかったため、パネル取り付け型ジャックから5cmほどケーブルの延ばしてプロトシールドに半田付けしてあります。電源コネクタの取り付けがスマートでないことが不満点です。
スケッチ
スケッチのソースコードはココからダウンロードできます。
POP3はテキスト形式でサーバーとコマンド・レスポンスをやり取りします。Arduinoからは、Ethernet libraryのclient.println()メソッドを使用してコマンドの送信が可能です。POPサーバーからのレスポンス受信はclient.read()メソッドを使用して、改行(LF)までの一行をバッファに格納するgetLine()関数を作って処理しています。
POPサーバーにアクセスしてヘッダーを取得する手順は以下です。
- client.connect()を実行してPOPサーバーとのTCPセッションをオープン
サーバーから、"+OK"レスポンスが返るのを確認 - clinet.println()にてユーザー名を送信(0016以降はclient.write()を使用した方がよい)
→USER xxxx (xxxxがユーザー名)コマンドを送信 - clinet.println()にてパスワードを送信(0016以降はclient.write()を使用した方がよい)
→PASS xxxxxコマンドを送信 - STATコマンドを送信
→"+OK 2 4436"のようなレスポンスが返ります
→2がメッセージ数、次の数字がOctet数になります - TOP 0 0コマンドを送信して1件目のメールヘッダをダウンロード
"+OK Message follows"レスポンスに続いてヘッダーを受信し、"From:"を含む行を受信した際に登録したアドレスに一致するかをチェック - ステップ5をメッセージ数繰り返す(TOP 1 0, TOP 2 0・・・の繰り返し)
ソースの以下のコメントを外してコンパイルすることでPOPサーバーとのやり取りをシリアルポートに出力し、PCにて動作確認ができます。(デバッグ機能です)
//#define DEBUG
シリアルの通信速度(=表示速度)が遅いと、イーサネット通信が不安定になる現象があったため、シリアルの通信速度を最大値(115200bps)に設定してあります。
テスト当初、POPサーバーからヘッダをダウンロードするメールが2件以上になると、起動後最初のチェックはOKなのですが、チェック(サーバーアクセス)を繰り返すとリセットが発生する問題に悩まされました。スタック溢れの可能性を疑い、グローバル変数を使ってスタック領域を使わないようにしたため、少々汚いコードになってしまいました。
最終的には以下に示す通り、メールヘッダのFrom行を検出する処理で呼んでいたメソッドを変更することで解決しました。
当初のコード:ReceiveBuffer.startWith("From:") -- 受信バッファが"From:"で始まるかの判定。当初は、行頭に"From:"が来ることまで含めてマッチングを取ろうとしました
変更後:ReceiveBuffer.contains("From:") -- 受信バッファに"From:"を含むかの判定に変更。原因不明のリセットが解決せず、部分一致のメソッドに変更
ライブラリにバグがあるとも思えず、根本原因は不明です。
使用したライブラリ
IDE-0015標準のライブラリ以外に、以下のライブラリを使用しました。
- WString.h:POPサーバーに送信するTOPコマンドの編集、受信バッファ内の文字列部分一致検索などのテキスト処理
- Debounce.h:スイッチのチャタリング除去
- Metro.h:POPサーバーのチェック周期、LEDの点滅周期など、周期処理の時間を管理
- Sleep.h:致命的なエラーに遭遇した際に、MCUをStandbyモードに遷移して処理を停止するために使用(Haltの代わりに使用)。「なんでも作っちゃう、かも」さんのライブラリを使用させていただきました。
文字列処理などは、AVR Libcのライブラリ呼び出しでも実現できますが、上記のライブラリを使用するとお手軽かつ、Arduinoらしい簡潔なコードになります。既存のライブラリが豊富な点は、やはりArduinoのメリットだと思います。
設定機能
ありません、、
POPサーバーのIPアドレス(nslookupができないため、ドメイン名での指定はできません)、ユーザー名、パスワード、監視するメールアドレスなどはソースコードにハードコーディングです。
Ethrenet Libraryの修正
clinet.connect()メソッドでサーバーにTCPセッションが接続できない(タイムアウトする)ケースが何回かあったため、ArduinoのForumを覗いてみると、Ethernet Libraryの問題がいくつか報告されていました。その中から、以下の修正コードを盛り込みました。
1) 送信時、1文字単位にIPパケットを生成してしまう問題
オリジナルのコードでは、client.println("Hello World");を動かすと、1文字単位にIPパケットを送信するそうです。CR+LFを含めると13パケットも送信してしまいます。本来なら1パケットで済みますし、1文字(1 byte)のデーターを送るために40 byteのTCP/IPヘッダを送っていることになり、非効率この上ないです。
本職はIPネットワーク屋なので、このようにネットワークの帯域を無駄に消費するヤツは許せないため、即刻修正です。。
2) TCP FINの送信処理に問題があり、clinet.stop()で一旦接続を終了した後に再度client.connet()で再接続を行うと接続できない場合がある。
1)2)の対処を盛り込んだ、Libraryのソースはココから ダウンロードできます。
2009/6/7追記
上記1)2)の問題は、最新のIDE-0016で修正されています。1)の問題に対しては、Clientクラスのwrite()関数を使用することで解決します。IDE-0016を使用した最新版をこの記事で紹介しました。
残問題
Ethernet Shieldに関して以下の問題が残っています。
1)電源ONの際に、Link Upしないことが度々ある
Ethernet shieldの初期化(恐らくW5100チップのリセット)が完全に行われていない模様で、リセットボタンを押すとLink upします。Arduino Forumにも関連スレッドがあり、RESET - GNDピン間にコンデンサを追加すると問題が解消すると投稿がありますが、そこまでは踏み切れません。
2)電源ON後の最初の接続で、client.connetc()がタイムアウトする場合がある(Link upはしている)
どうもLCDの初期化と同様に、電源ON時のリセット処理が不十分なようです。商用のハード開発では、リセット回路のドライブ能力・リセット時間やタイミングは、設計の重要ポイントになっているのですが、このあたりがいまいちなのかしら、、
2009/6/6追記
メールサーバーアクセス方法を変更した改良版を公開しました。
2009/6/7追記
Arduinoイーサーネットシールドの接続処理に、リセット後のタイムアウト問題の調査結果を記載しました。
2009/6/8追記
掲載したスケッチにメモリリークがあることが分かりました。サンプルとしてコードは掲載しておきますが、もし使用される場合はご注意下さい。
2009/6/9追記
メモリーリークの対策版を以下の記事で公開しました。
Arduino TexitStringライブラリのメモリーリーク
Arduinoメールチェッカー(その3)




最近のコメント