解説 temp_upload

依存ライブラリ

解説は各ライブラリ毎にArduinoの基礎で説明します.

ソースコード解説

インスタンス宣言

Arduinoは利用できるRAMが2KBほどから8KBほどと,パソコンに比べ少ないです.また,処理能力もあまり高くないので,頻繁にインスタンスを作成,廃棄することはおすすめしません.

そこで,temp_uploadではグローバル変数としてインスタンスを生成しています.

SerialCLIの宣言,通信インターフェースはSerialを使います.

//cli
SerialCLI      commandline(Serial);

設定パラメータ類,解説はM2Mゲートウェイからのアップロードを見てください.

//  ethernet
MacEntry       mac("MAC", "01:23:45:67:89:AB", "mac address");
//  ip
BoolEntry      dhcp("DHCP", "true", "DHCP enable/disable");
IPAddressEntry ip("IP", "192.168.0.2", "IP address");
IPAddressEntry gw("GW", "192.168.0.1", "default gateway IP address");
IPAddressEntry sm("SM", "255.255.255.0", "subnet mask");
IPAddressEntry dns_server("DNS", "8.8.8.8", "dns server");
//  ntp
StringEntry    ntp("NTP", "ntp.nict.jp", "ntp server");
//  fiap
StringEntry    host("HOST", "fiap-dev.gutp.ic.i.u-tokyo.ac.jp", "host of ieee1888 server end point");
IntegerEntry   port("PORT", "80", "port of ieee1888 server end point");
StringEntry    path("PATH", "/axis2/services/FIAPStorage", "path of ieee1888 server end point");
StringEntry    prefix("PREFIX", "http://taisyo.hongo.wide.ad.jp/MyHome/Node1/", "prefix of point id");

デバッグフラグ.1ならばデバッグモードになります.

//  debug
int debug = 0;

NTPとタイムゾーンの宣言.

//ntp
NTPClient ntpclient;
TimeZone localtimezone = { 9*60*60, 0, "+09:00" };

FIAPUploadAgentの宣言とエレメントの設定.FIAPUploadAgentはエレメント構造体の1番目の要素をプリフィックスの末尾に結合して,2番めの要素に設定されている文字列を送信します.送信する文字列のバッファは毎回再生成する必要はないので,グローバルで宣言します.送信しなければならないポイントを増やすには,エレメントを追加してください.

//fiap
FIAPUploadAgent fiap_upload_agent;
char temperature_str[16];
struct fiap_element fiap_elements [] = {
  { "Temperature", temperature_str, 0, &localtimezone, },
};

ADT74x0の宣言.

//sensor
ADT74x0 tempsensor;

デバッグ切り替え関数,SerialCLIからdebugnodebug受信時に実行されます.

void enable_debug()
{
  debug = 1;
}

void disable_debug()
{
  debug = 0;
}

setup関数

setup関数は起動時に1度だけ実行されます.

SerialCLIへ設定項目とデバッグコマンドを登録します.

void setup()
{
  int ret;
  commandline.add_entry(&mac);

  commandline.add_entry(&dhcp);
  commandline.add_entry(&ip);
  commandline.add_entry(&gw);
  commandline.add_entry(&sm);
  commandline.add_entry(&dns_server);

  commandline.add_entry(&ntp);

  commandline.add_entry(&host);
  commandline.add_entry(&port);
  commandline.add_entry(&path);
  commandline.add_entry(&prefix);

  commandline.add_command("debug", enable_debug);
  commandline.add_command("nodebug", disable_debug);

  commandline.begin(9600, "ADT74x0 Gateway");

ここではDHCPを利用する場合と利用しない場合をDHCPフラグで切り分けます.そこから先はArduinoのEthernetライブラリの使い方を参照してください.

  // ethernet & ip connection
  if(dhcp.get_val() == 1){
    ret = Ethernet.begin(mac.get_val());
    if(ret == 0) {
      restart("Failed to configure Ethernet using DHCP", 10);
    }
  }else{
    Ethernet.begin(mac.get_val(), ip.get_val(), dns_server.get_val(), gw.get_val(), sm.get_val());
  }

NTPで時間を取得します.正常に取得できた場合,Timeライブラリに設定します.

  // fetch time
  uint32_t unix_time;
  ntpclient.begin();
  ret = ntpclient.getTime(ntp.get_val(), &unix_time);
  if(ret < 0){
    restart("Failed to configure time using NTP", 10);
  }
  setTime(unix_time);

FIAPUploadAgentの初期化です.

  // fiap
  fiap_upload_agent.begin(host.get_val(), path.get_val(), port.get_val(), prefix.get_val());

センサーの初期化です.

  // sensor
  Wire.begin();
  tempsensor.begin(0x48);
}

loop関数

loop関数は,無限ループで実行されます.

epochold_epochstaticです.通常ローカル変数は関数呼び出し毎にリセットされますが,staticがついているときは前回の値を記憶します.commandline.process()で溜まっているコマンドを処理します.

void loop()
{
  static unsigned long old_epoch = 0, epoch;

  commandline.process();

epochを更新します.

  epoch = now();

DHCP利用時は定期的にアドレス情報の更新が必要です.

  if(dhcp.get_val() == 1){
    Ethernet.maintain();
  }

この条件式により,このifは1秒に1回だけ実行されます.

  if(epoch != old_epoch){

ADT74x0から温度を取り込み,送信用バッファーへ書き込みます.温度はfloatなので文字列化する必要があります.普通はsprintfを使いますが,Arduinoのsprintffloat非対応なので,dtostrfを使います.dtostrfについてはArduinoの基礎,浮動小数点を文字列にする(dtostrf)を参照してください.

    dtostrf(tempsensor.readTemperature(), -1, 2, temperature_str);
    debug_msg(temperature_str);

epochには現在の秒が入っています.0から59までの間を取るので,この条件が成り立つのは毎分0秒のときです.つまり,1分に1回アップロードの処理を実行できるわけです.

    if(epoch % 60 == 0){
      debug_msg("uploading...");

アップロード処理です.エレメントとしてfiap_elements配列に登録したすべてを送信します.fiap_elements[i].time = epoch;は書き込む値の時刻を現在の時刻に設定します.epochではなくnow()を使うと,秒単位でズレが生じる可能性があるので注意しましょう.ちなみにsizeof(array)/sizeof(array[0])はイディオムで,配列の要素数を取得できます.

      for(int i = 0; i < sizeof(fiap_elements)/sizeof(fiap_elements[0]); i++){
        fiap_elements[i].time = epoch;
      }
      int ret = fiap_upload_agent.post(fiap_elements, sizeof(fiap_elements)/sizeof(fiap_elements[0]));
      if(ret == 0){
        debug_msg("done");
      }else{
        debug_msg("failed");
        Serial.println(ret);
      }
    }

最後にold_epochを更新します.

  }

  old_epoch = epoch;
}

各種ユーティリティ関数

デバッグメッセージを出力します.

void debug_msg(String msg)
{
  if(debug == 1){
    Serial.print("[");
    print_time();
    Serial.print("]");
    Serial.println(msg);
  }
}

デバッグメッセージで時間を出力する部分.

void print_time()
{
  char print_time_buf[32];
  TimeElements* tm;
  tm = localtime();
  sprintf(print_time_buf, "%04d/%02d/%02d %02d:%02d:%02d",
      tm->Year + 1970, tm->Month, tm->Day, tm->Hour, tm->Minute, tm->Second);
  Serial.print(print_time_buf);
}

リスタート関数,再起動します.

void restart(String msg, int restart_minutes)
{
  Serial.println(msg);
  Serial.print("This system will restart after ");
  Serial.print(restart_minutes);
  Serial.print("minutes.");

  unsigned int start_ms = millis();
  while(1){
    commandline.process();
    if(millis() - start_ms > restart_minutes*60UL*1000UL){
      commandline.reboot();
    }
  }
}

results matching ""

    No results matching ""