2015年8月27日木曜日

ESP-WROOM-02プログラミング:スリープしながら定期的にツイート

ESP-WROOM-02のDeep-Sleepを使ったツイッター操作プロジェクトのメモ

プロジェクト概要:
 スリープしながら定期的にWakeUPしてツイートを行うプロジェクト

 ツイートにはStewGateUのWebAPIを使用
 ネタ元はESP8266WIFI/WiFiClientサンプルコードとマイクロテクニカESP-WROOM02簡単マニュアル


Deep-Sleep機能とは?:
 低消費電力(消費電流平均10uA)でスリープする機能
 
 スリープ中は以下の機能以外のすべてを停止する
  ・リセット信号の監視と受理
  ・スリープ時間カウント用のタイマ
  ・ウェイクアップ用信号の出力(IO16)

 スリープからの復旧方法はリセットのみ
 リセットするとプログラムの最初から実行される(通常時にリセットをかけたのと同じ)
 
 スリープというとなんだか特定の状態で休止してそこから復旧するように思えるが
 このDeep-Sleepはリセット信号の受理と目覚まし時計以外のすべてを終了してしまう
 目覚まし時計が鳴るとIO16ピンにLパルスが出力されるので
 IO16ピンを自身のリセットピンに接続しておけば、自身のリセットをかけることが出来る

 Arduinoのアドオンなどに用いる場合は、Arduino側からリセットをかけることも可能 

データシートより/最終行がDeep-Sleep

準備すること:
 →基本的に前回までと同じ

 ・ArduinoIDE上でESP8266の開発環境構築(ググろう!)
  ・3V3とGNDに十分な電流が供給可能な3.3V電源を接続
 ・IO16ピンとRSTピンを接続
 ・TX/RXにはデバッグ用にシリアル―USB変換機を接続する
 ・ツイートに用いるTwitterアカウントの準備(新規アカウント推奨)
 ・StewGateUにてTwitterアカウント登録およびトークン取得
 ・ESP-WROOM-02を接続してもよい無線LANルータのSSIDとパスワードをメモ


作成方法:
 ・ソースをコピペして以下の情報を修正する
   ・SSID
   ・SSIDに対するパスワード
   ・StewGateUで取得したトークン
 ・ビルドしてダウンロードモードのESP-WROOM-02に書き込み
  (→過去メモ参照)


実行方法:
 ・ESP-WROOM-02をブートモードで起動
 ・起動→接続→ツイート→(指定時間スリープ)→再起動→接続→ツイート…
  が反復することを確認
  (※止めない限りずっと反復するので注意


うまくいかない場合は以下をチェック:
 無線LANルータの規格
   →ESP-WROOM-02が対応できるのは802.11b/g/n

 ・ダウンロードモードからの設定変更は忘れていないか
   →GPIO0ピンをL→Hに戻し忘れることが多い
    ブートモードにしないと当然ながら起動しない

 ・チップへの給電が十分か
   →今回これで大ハマリした
    当初はaitendoのVBUSキットを用いてノートPCのUSBポートから電源を取っていたのだが
    何回やってもリセット動作に失敗していた
    (リセット後、ブートローダーの段階でハングアップする)

    原因はどうもノートPC側の省電力機能らしい
    スリープから復旧する際の電流が不足するために起動に失敗する
    (ネゴシエーション時の100mA制限に引っかかる?)
    定常状態では十分な電流が供給できていたため気づかなかった

    電源をACアダプタに変更して解決


注意点:
 ・ソースの大半はESP8266WIFI/WiFiClientサンプルコードからの流用
 ・無線LANルータの設定(ステルスID/接続先限定など)によっては動かない

 ・ソース内でanalogRead(17)しているのは
  『結線していないアナログピンの値(不定値)を取得して乱数の種にする』
  ため
  Arduinoで良く使われている処理を真似してみた
  今回はリセット時にカウンタがクリアされてしまうため、これが無いと乱数の値が重複する

 ・ESP.deepSleep()コール後からスリープされるまでに遅延がある
  このため
   loop()末尾でESP.deepSleep()コールするとスリープに入る前にループ先頭に飛んでしまい動作がおかしくなる場合がある
  ESP.deepSleep()後に適当なdelay()を入れること


 
#include <esp8266wifi.h>

//接続先のIDおよびパスワード
const char* ssid     = "XXXXXXXX";
const char* password = "YYYYYYYY";
 
const char* host = "stewgate-u.appspot.com";
//http://stewgate-u.appspot.com/より取得したトークン
const char* token = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
//スリープ時間60秒
const int sleepTimeSec = 60;

void setup() {
  Serial.begin(115200);
  delay(10);

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  String text;
  randomSeed(analogRead(17));
  text += String(random(0,9999), DEC);
  text += ":Hello!ESP-WROOM02";

  postMsg(text);
  
  ESP.deepSleep(sleepTimeSec * 1000 * 1000, WAKE_RF_DEFAULT);
}

bool postMsg(String msg)
{
  Serial.print("connecting to ");
  Serial.println(host);
  
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return false;
  }
  
  client.println("POST /api/post/ HTTP/1.0");

  client.print("Host: ");  
  client.println(host);
  
  int msgLength = 40;
  msgLength += msg.length();
  client.print("Content-length:");
  client.println(msgLength);
  client.println("");

  client.print("_t=");
  client.print(token);
  client.print("&msg=");
  client.println(msg);

  delay(10);
  
  // 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 true;  
}

void loop() 
{
}



0 件のコメント:

コメントを投稿