2013年4月15日月曜日

PM2.5、黄砂予報をarduinoでネットから受信しLEDで表示



 ※追記:最近データ取得先ページのデザインに変更があったようで、スケッチを修正しました。今後も同じことがあれば対応が遅れ、データの受信がうまくいかないこともありえます。(2015/2/24)

イーサネットシールドを手に入れたので使ってみます。
まずはサンプルスケッチから。
webサーバーのサンプルスケッチ内のIPなどの設定項目を書き込んで、arduinoに書き込み、ブラウザからアクセスするとanalogRead() の結果が表示され動作確認OK。

何しようかなとネットをさまよっていると目に入ったのがこの記事。
気象協会、PM2.5分布予測地図をWeb公開
http://www.itmedia.co.jp/news/articles/1303/22/news110.html

PC開かなくてもarduino+イーサネットシールドでPM2.5予報を受信し、ひと目で予報が分かるようにしたいと思います。
PM2.5や黄砂のピークは過ぎて時期を逃した感がありますが公開します。

(表示中の様子)

上記ページはグラフィカルな情報でそのままでは無理。
使えそうなのが次のページの週間予報。

SPRINTARSエアロゾル予測(簡易版)
http://sprintars.riam.kyushu-u.ac.jp/forecastj.html

”エアロゾル(大気浮遊粒子状物質)は大気の霞みの原因となる物質です。呼吸器系などに影響を及ぼすと言われています。”
”対流圏に存在する自然起源・人為起源の主要エアロゾルを取り扱います(黒色炭素・有機物・硫酸塩・土壌粒子・海塩粒子)。これらは、いわゆるPM10, PM2.5としても分類されます。”
”「大気汚染粒子」はPM2.5 「黄砂」はSPMの環境基準値を参照”


このページは気象庁・環境省発表のデータを元に予測し、毎日朝8時頃に更新。
なので、週間予報のhtml(shift-jis)を受信し、そこから今日、明日、明後日の予報を抜き出し、フルカラーLED2個の色で表現します。
予報は4段階に分類されているので、
青(清浄) → 緑(やや多い) → 橙(多い) → 赤(非常に多い) に割り当てました。




受信するタイミングや、日付が変わる時の表示の切替のために時計が要りますが、リアルタイムクロック(RTC)回路を省略するために、NTPサーバーにアクセスし時刻を合わせます。
イーサネットを使用するためにイーサネットライブラリ(Ethernet.h、SPI.h)、
NTPサーバーへのアクセスのために EthernetUdp.h、
時刻を合わせた後扱いやすいようにするために Timeライブラリ、
文字処理のために stdlib.h、
SRAM節約のためPROGMEMを使うために avr/pgmspace.h、
のライブラリをインポートします。

NTPサーバーへのアクセスにはホストネームでアクセスするべきなようですが、ライブラリでの指定方法がipアドレスになっているので、それを使います。

◆タイムテーブル
毎時0分        NTPサーバーに接続し時刻合わせ
7:30~8:30      10分毎にアクセスし予報更新があれば取得、赤色LED消灯
受信後~24:00    週間予報の1日目、2日目の予報の表示
24:00~翌朝更新まで 週間予報の2日目、3日目の予報の表示、赤色LED点灯


◆表示のためのフルカラーLEDですが、PWM端子が足りないのでRGBそれぞれのON/OFFだけで色を出します。

◆起動直後や予報を受信していないとき、LEDは白色表示になります。

ボタンは2個接続(黄色:ボタン0 赤色:ボタン1)

◆ボタン0 モード1~3の切り替え / 長押しで地域(0~11)の指定
◆ボタン1 LEDデモ(4色の切り替え) / 強制時刻合わせ、強制受信
を担当させます。

◆モードの設定
ボタン0をクリックした回数でモードの設定し、LEDの点滅があります。暗くなる回数で設定したモードが確認できます。
電源が切れると初期値に戻ります。

モード 1:PM2.5予報の1日目、2日目(初期値)
    2:黄砂予報の1日目、2日目
    3:PM2.5予報の1日目、黄砂予報の1日目

表示例 (モード1)
(0時を過ぎると赤LEDが点灯し予報の2日目、3日目の表示し、
モード3ではPM2.5と黄砂予報の2日目を表示します)

◆地域の設定
ボタン0の長押し2秒でLED0(LEDデモモードで点滅するLED)が赤表示になり、その後のボタン0のクリック回数で地域指定になります。
予報ページの上から0~11番に対応しています。(初期値6)
赤表示からボタンを離し1秒以内に1回も押さないと、地域番号0(北海道)となります。こちらもLED点滅の消えた回数で確認できます。
電源が切れると初期値に戻ります。

◆LEDデモモード
ボタン1を1回押しで予報4段階を表示するデモモード。

◆時刻合わせと強制受信
ボタン1を2回押しで実行します。

◆各操作、動作時にシリアル通信で色々送ってくるようにしているので、スケッチがやたら長くなってます。シリアル通信でもコマンドを送れます。
 g:予報の受信。一度でも受信していれば、
  「HTTP/1.1 304 Not Modified」が帰ってきます。
 h:ヘッダのみのリクエスト
 o:各種データのシリアル出力
 t:NTPサーバーでの時刻合わせ
 d:LEDデモモード

朝の8時前後の予報ページへのアクセスは、リクエストヘッダに
If-Modified-Since: + 前回予報受信日時を記述し、更新時だけ予報全体が送られてくるようになっています。

自分のaduinoUnoR3ではNTPサーバーで時刻合わせをしても、1時間5,6秒遅れるようです。

◆予報発表日
htmlソースの1回目の「<br />」の行に予報発表日があり、2個目と3個目の2バイト文字の間の文字を発表日として利用します。

◆予報レベル
「bgcolor=」をキーワードとして検索し、その後ろの色指定から予報のレベルを取得します。
html

配列への格納数値
red 非常に多い 注意喚起レベル 3
darkorange 多い 日本の環境基準値程度 2
lawngreen やや多い 大気が少し霞む程度 1
skyblue 少ない 清浄 0

12地域、7日分、PM2.5予報、黄砂予報の計168個の予報レベルを2次元配列に格納します。
使うのは指定地域の3日分だけですからだいぶ無駄ですね。
また、少しのデザイン変更があっただけで、予報の取得はおかしくなるはずです。

◆消費電流
arduinoUNO + イーサネットシールド + フルカラーLED白点灯x2 + 赤色LEDの合計でだいたい210mA。
arduinoにはスリープモードがありますが、イーサネットシールドの動作は問題ないのでしょうか?未検証です。

◆使用パーツ
イーサネットシールド以外にフルカラーLED x2、赤色LED x1、抵抗220Ω x7、タクトスイッチ x2、白色ピンポン球 x2、ユニバーサル基板、線材、ピンソケットです。
使ったフルカラーLEDはアノードコモンなので、アノードを+5V、各RGB端子から220Ω抵抗を経由してポートに接続しています。ポートをLOWにすると点灯。
カソードコモンのLEDを使うときは回路とスケッチの変更が必要です。

◆回路図

◆スケッチ
はじめての事だらけで、かなり無駄のあるスケッチではないでしょうか。これを改造して他のwebページに応用しようなんて思わないでください。
変数の名前の付け方や、文字列の処理など行き当たりばったり感があり、読みにくいですがバックアップのつもりで公開します。
デバッグ、確認用のSerial.printlnが大量にありますが、削れば半分ぐらいになるかも?

※arduino1.6.0ではコンパイルエラーが出て使えませんでした。
 自分で書いたコードの修正も難しかったので、読みやすい1.6.0用スケッチに書き換えたいですがいつになるやら・・・



/*
PM2.5、黄砂予報をネットから受信しLEDで表示
                             by cranberry
http://cranberrytree.blogspot.jp/
                          2015/02/24

イーサネットシールドはD10,D11,D12,D13ピンを使用
SDカードライブラリを使う場合、D4ピンを使用
*/

#define serverName "sprintars.riam.kyushu-u.ac.jp"
#define reqGet "GET /forecastj_list.html HTTP/1.0"
#define reqHead "HEAD /forecastj_list.html HTTP/1.0"
#define reqHost "HOST: sprintars.riam.kyushu-u.ac.jp"
#define LedZerohour 2                                //0時から朝の更新まで点灯するLEDのピン番号

#include <stdlib.h>
#include <Time.h>
#include <SPI.h>
#include <avr/pgmspace.h> 
#include <Ethernet.h>
#include <EthernetUdp.h>

byte Loc = 6;                                        //受信する地域 ex.北海道:0 近畿:6 沖縄:11 http://sprintars.riam.kyushu-u.ac.jp/forecastj.html の表の上から0~11
byte mode = 1;                                       //どの予報を表示するか  1:汚染予報1,2日目 2:黄砂予報1,2日目 3:汚染1日目,黄砂1日目
PROGMEM prog_char button[] = {A5, A4};               //ボタン接続ピン ボタン0:モード,地域切り替え 1:LEDデモ,強制受信
PROGMEM prog_char pinLed[2][3] = {{3,5,6},
                                  {A0,A1,A2}};       //使用ピンLED0 R,G,B  LED1 R,G,B
                                                     //使用フルカラーLED アノードコモンLED705A1B
PROGMEM prog_char valRgb[4][3] = {{1,1,0},{1,0,1},{0,0,1},{0,1,1}};      //RGBパターン 青、緑、黄、赤
char * dayOfWeek[] = {"Sat", "Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; //weekday();1~7  Day of the week, Sunday is day 1
PROGMEM prog_uchar listColor[] = {'s', 'l', 'd', 'r'};                   //表の汚染レベルの色 skyblue,lawngreen,darkorange,red
String lastRcvDate = "Date: Mon, 01 Apr 2013 00:00:00 GMT";              //最後に受信した日時
byte valLevel[12][14];                                                   //全地域1週間分の予報情報を格納
char cmd;                       //シリアルからのコマンド 1バイト
char c;                         //サーバーから受信した1バイトを格納
byte valShift = 0;              //0時を過ぎると表示する予報をシフトする
byte cntBut = 0;                //ボタンが押された回数
boolean fButLong = false;       //ボタンが長押しされたかのフラグ
String strServResp, strUpdate, strColor;
//String key_update = "<br />";   //発表日がある行
String valDay;                  //発表日の日にち
String key_level = "bgcolor=";  //予報レベルがある行
int cntNewline = 0;             //改行回数のカウント
byte cntLevel = 0;              // "bgcolor=" をカウント
byte ySheet, xSheet;
byte col_1,col_2;
boolean fUpdate = false;        //更新があったかのフラグ
boolean fLevel = false;         //予報を取得し終わったかのフラグ
boolean onClient = false;       //サーバーに接続しているかのフラグ
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };      //イーサネットシールドmacアドレスのサンプル
IPAddress ip(192,168,11,30);                              //イーサネットシールドのip手動設定
EthernetClient client;

unsigned int localPort = 8888;
IPAddress timeServer(133, 243, 238, 163);    //NTPサーバー ntp.nict.jp 
const int NTP_PACKET_SIZE= 48;
byte packetBuffer[ NTP_PACKET_SIZE];
EthernetUDP Udp;

void setup(){
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  pinMode(button[0], INPUT_PULLUP);             //ボタン入力ポート2個の初期化、プルアップ
  pinMode(button[1], INPUT_PULLUP);
  pinMode(LedZerohour, OUTPUT);                 //LED接続ポートの初期化
  digitalWrite(LedZerohour, LOW);
  for(byte i = 0; i < 2; i++){                  //フルカラーLED接続ポートの初期化
    for(byte j = 0; j < 3; j++){
      pinMode(pgm_read_byte(&pinLed[i][j]),OUTPUT);
      digitalWrite(pgm_read_byte(&pinLed[i][j]),HIGH);
    }
  }
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);
  delay(2000);
  Serial.print("data from : ");
  Serial.println(serverName);
  Serial.println("");
  swMode();
  demoLed();
  delay(5000);    //ネット接続の安定待ち
}

void loop(){
  if(fLevel == false){                       //一度も予報取得していない場合
    Serial.println("going to receive data......");
    setDate();
    showDate();
    cmd = 'g';
    connectAndRequest();
    if(fLevel == false){
      Serial.println("failed");
      Serial.println();
    }
    else{
      setLed();
    }
  }
  if(hour() == 7){                           //7:30 7:40 7:50 に予報を取得しに行く
    if(minute() == 30 || minute() == 40 || minute() == 50){
      if(second() == 0 && (String)day() != valDay){
        Serial.println("7:30 7:40 7:50");
        showDate();
        cmd = 'g';
        connectAndRequest();
        setLed();
        delay(1000);
      }
    }
  }
  if( hour() == 8){                           //8:01 8:10 8:20 8:30 に予報を取得しに行く
    if(minute() == 1 || minute() == 10 || minute() == 20 || minute() == 30){
      if(second() == 0 && (String)day() != valDay){
        Serial.println("8:01 8:10 8:20 8:30");
        showDate();
        cmd = 'g';
        connectAndRequest();
        setLed();
        delay(1000);
      }
    }
  }
  if(minute() == 0 && second() == 0){                                                //毎時0分0秒に時刻合わせ
    setDate();
    showDate();
    setLed();
  }
  if(hour() == 0 && minute() == 0 && (String)day() != valDay && fLevel == true){     //午前0時表示データをシフトする
    setLed();
  }
  if(hour() == 7 && minute() >= 30 && (String)day() == valDay && fLevel == true){    //午前7時30分以降 更新されたらシフトを戻す
    setLed();
  }
  if(digitalRead(button[0]) == LOW){      //mode切り替えボタン 長押しで地域指定モード
    pushButton(0);
    if(fButLong == true){
      if(cntBut < 12){
        Loc = cntBut;
        Serial.print("locale you choose : "); //地域番号確認
        Serial.println(Loc);
        Serial.println();
        blinkLed(Loc);                    //点滅回数で確認
      }
      fButLong = false;
    }
    else{
      if(cntBut < 4){
        mode = cntBut;
        swMode();
        blinkLed(mode);                   //点滅回数で確認
      }
    }
    setLed();
  }
  if(digitalRead(button[1]) == LOW){      //1回:LED色確認デモ 2回:強制HTML取得,時刻合わせ
    pushButton(1);
    if(cntBut == 1){
      demoLed();
      output();
      setLed();
    }
    if(cntBut == 2){
      cmd = 'g';
      lastRcvDate = "Date: Mon, 01 Apr 2013 00:00:00 GMT";
      connectAndRequest();
      setDate();
      showDate();
      output();
      setLed();
    }
  }
  if(Serial.available()){
    cmd = Serial.read();       //シリアル通信でのコマンド待ち
    if(cmd == 'g'){             //コマンド 予報の受信開始
      connectAndRequest();
      setLed();
    }
    if(cmd == 'h'){             //コマンド サーバーからのレスポンスヘッダ取得
      connectAndRequest();
    }
    if(cmd == 'd'){             //コマンド LEDの色確認デモ
      demoLed();
      setLed();
    }
    if(cmd == 't'){             //コマンド NTPサーバーに接続し時刻設定
      setDate();
      showDate();
      setLed();
    }
    if(cmd == 'o'){             //コマンド 各種データシリアル出力
      output();
    }
  }
}

void connectAndRequest(){
  fUpdate = false;
  fLevel = false;
  cntLevel = 0;
  cntNewline = 0;
  strServResp = "";
  Serial.print("connecting.....");
  if (client.connect(serverName, 80)) {    //接続したら・・・
    Serial.println("OK");
    onClient = true;
    getOrHeader();
    client.println();
    Serial.println("recieving...");
  }
  else {
    Serial.println("connection failed");  //接続失敗
    onClient = false;
  }
  //レスポンス受信開始
  while(onClient == true){
    if(client.available()){                //バッファに受信データ(1バイト) があれば・・・
      c = client.read();                   //1バイト受信
      if(c == '\n'){                       //改行ごとに処理
        checkLine();
        strServResp = "";
      }
      else{
        strServResp += c;
      }
//      Serial.print(c);
    }
    if (!client.connected()) {             //受信終了ならば
      Serial.println();
      Serial.print("disconnecting.....");
      Serial.println("OK");
      Serial.println();
      client.stop();
      onClient = false;
    }
  }
}

void getOrHeader(){
  if(cmd == 'h'){
    client.println(reqHead);                  //HTTPリクエスト ヘッダーのみ
    client.println(reqHost);
    client.print("If-Modified-Since: ");      //サーバーは指定日時から更新なければ「HTTP/1.1 304 Not Modified」を返す
    client.println(lastRcvDate.substring(6)); //最終受信日時を送信
  }
  if(cmd == 'g'){
    client.println(reqGet);                   //HTTPリクエスト
    client.println(reqHost);
    client.print("If-Modified-Since: ");
    client.println(lastRcvDate.substring(6));
  }
  Serial.print("last recieved at : ");
  Serial.println(lastRcvDate);
  Serial.println(lastRcvDate.substring(6));
}

void checkLine(){
  cntNewline += 1;
  if(cntNewline == 1){                        //レスポンス1行目の処理
    if(cmd == 'g' && strServResp.startsWith("HTTP/1.1 200")){
      fUpdate = true;
    }
    else{
      fUpdate = false;
      fLevel = true;
    }
    Serial.println(strServResp);
  }
  if(cntNewline == 2){                        //レスポンス2行目の処理
    if(fUpdate){
      lastRcvDate = strServResp;
    }
    Serial.println(strServResp);
  }
//if(strServResp.indexOf(key_update) != -1){  //予報発表日の取得
  //予報発表日の取得   //発94AD 表955C
  if(strServResp.indexOf(0x94) != -1 && strServResp.indexOf(0xAD) != -1 && strServResp.indexOf(0x95) != -1 && strServResp.indexOf(0x5C) != -1){
    byte cnt2byte = 0;
    valDay = "";
    for(byte i = 0; i < strServResp.length(); i++){
      if(cnt2byte == 2){
        valDay += strServResp.charAt(i);
        if( (unsigned char)strServResp.charAt(i + 1) < 0x80){
          valDay += strServResp.charAt(i + 1);
        }
        i = strServResp.length();
        Serial.print("forecast update in ");
        Serial.println(valDay);
      }
      if( (unsigned char)strServResp.charAt(i) >= 0x80){   //shift-jis文字コード0x8000~を検索
        i += 1;
        cnt2byte += 1;
      }
    }
  }
  if(strServResp.indexOf(key_level) != -1){                //予報レベルの取得
    strColor = strServResp.substring(strServResp.indexOf(key_level) + 9,strServResp.indexOf(key_level) + 9 + 1);
    if(cntLevel < 168){
      for(byte b = 0; b < 4; b++){
        if(strColor == (String)(char)pgm_read_byte(listColor + b) ){    //4段階の色分けと比較
          ySheet = cntLevel / 14;
          xSheet = cntLevel % 14;
          valLevel[ySheet][xSheet] = b;
          cntLevel += 1;
        }
      }
    }
  }
  if(cntLevel == 167){
    fLevel = true;
  }
}

void swMode(){
  switch(mode){
    case 1:       //汚染予報1日目、2日目の表示
      col_1 = 0;
      col_2 = 1;
      break;
    case 2:       //黄砂予報1日目、2日目の表示
      col_1 = 7;
      col_2 = 8;
      break;
    case 3:       //汚染予報1日目、黄砂予報1日目の表示
      col_1 = 0;
      col_2 = 7;
      break;
    default:
      Serial.println("error : mode number (only 1-3)");
  }
  Serial.print("mode    : ");         //モード確認
  Serial.println(mode);
  Serial.println();
}

void setLed(){                         //予報レベルにあわせてLEDの色を変える
  if((String)day() != valDay){
    valShift = 1;
    digitalWrite(LedZerohour, HIGH);
  }
  else{
    valShift = 0;
    digitalWrite(LedZerohour, LOW);
  }
  if(fLevel){
    for(byte k = 0; k < 3; k++){       //ピン,RGB設定
      digitalWrite(pgm_read_byte(&pinLed[0][k]), pgm_read_byte(&valRgb[valLevel[Loc][col_1 + valShift]][k]));
      digitalWrite(pgm_read_byte(&pinLed[1][k]), pgm_read_byte(&valRgb[valLevel[Loc][col_2 + valShift]][k]));
    }
  }
  else{
    ledWhite(1);                       //予報を取得していないのでLED白表示
  }
}

void demoLed(){                        //LED4色切り替えデモ
  Serial.print("LED demo....");
  ledOff(1);                           //LED0 LED1消灯
  delay(1000);
  for(byte j = 0; j < 4; j++){         //色パターン
    for(byte k = 0; k < 3; k++){       //ピン,RGB設定
        digitalWrite(pgm_read_byte(&pinLed[0][k]), pgm_read_byte(&valRgb[j][k]));
    }
  delay(1000);
  }
  ledWhite(1);                         //LED白表示
  delay(1000);
  Serial.println("Done.");
  Serial.println("");
}

void blinkLed(byte numBlink){          //ボタンの押し下げ回数、点滅
  for(byte i = 0; i < numBlink; i++){
    setLed();
    delay(700);
    ledOff(0);                         //LED0消灯
    delay(300);
  }
}

void ledWhite(byte numLed){                     //LED白点灯 0:LED0のみ 1:LED0とLED1両方
  for(byte i = 0; i < numLed + 1; i++){         //LED切り替え
    for(byte k = 0; k < 3; k++){                //ピン,RGB設定
      digitalWrite(pgm_read_byte(&pinLed[i][k]), LOW);
    }
  }
}

void ledOff(byte numLed){                       //LED消灯 0:LED0のみ 1:LED0とLED1両方
  for(byte i = 0; i < numLed + 1; i++){         //LED切り替え
    for(byte k = 0; k < 3; k++){                //ピン,RGB設定
      digitalWrite(pgm_read_byte(&pinLed[i][k]), HIGH);
    }
  }
}

void pushButton(byte numBut){            //押したボタンと回数の取得
  cntBut = 0;
  fButLong = false;
  boolean fTimeout = false;
  boolean fBut = true;
  unsigned long lastButtonTime;
  Serial.print("button ");
  Serial.print(numBut);
  Serial.println(", pushed");
  delay(50);
  while(!fTimeout){
    if(fBut == true){
      lastButtonTime = millis();
      while(digitalRead(pgm_read_byte(&button[numBut])) == LOW){   //押しっぱなし
        if(millis() - lastButtonTime > 2000){                      //長押し2秒
          if(numBut == 0){                                         //ボタン0の長押しだけ有効
            ledOff(0);
            digitalWrite(pgm_read_byte(&pinLed[0][0]), LOW);       //LED0を赤に
            if(fButLong == false){
              Serial.println("changed to location set mode");
            }
          }
          fButLong = true;
        }
      }
      lastButtonTime = millis();
      fBut = false;
      cntBut += 1;
      delay(50);
    }
    if(fBut == false){
      while(digitalRead(pgm_read_byte(&button[numBut])) == HIGH){  //ボタンから離した状態
        if(millis() - lastButtonTime > 1000){                      //1秒でタイムアウト
          fTimeout = true;
          break;
        }
      }
      fBut = true;
      delay(50);
    }
  }
  delay(1000);
  if(fButLong == true){
    cntBut -= 1;
  }
  Serial.print(cntBut);
  Serial.println(" times");
}

void output(){                  //各種データーの出力
  showDate();
  // 予報レベルを格納した2次元配列変数のシリアル出力
  for(byte a = 0; a < 12; a++){
    Serial.print(a);
    Serial.print(" : ");
    Serial.print("\t");
    for(byte s = 0; s < 14; s++){
      Serial.print(" ");
      Serial.print(valLevel[a][s]);
      Serial.print(" ");
    }
    Serial.println();
  }
  Serial.print("locale you choose : "); //地域番号確認
  Serial.println(Loc);
  Serial.print("mode    : ");           //モード確認
  Serial.println(mode);
  Serial.print("release : ");           //予報発表日
  Serial.println(valDay);
  Serial.print("shift   : ");           //シフト(0時~次の更新まで+1)
  Serial.println(valShift);
  Serial.print("value 1 : ");           //モードに従い抽出した予報レベル
  Serial.println(valLevel[Loc][col_1 + valShift]);
  Serial.print("value 2 : ");
  Serial.println(valLevel[Loc][col_2 + valShift]);
  Serial.print("last recieved at : ");
  Serial.println(lastRcvDate);
  Serial.println();
}

void setDate(){              //NTPサーバーに接続し日時のセット arduinoサンプルスケッチ UdpNtpClientより
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000);  
  if ( Udp.parsePacket() ) {  
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    unsigned long secsSince1900 = highWord << 16 | lowWord;  
    const unsigned long seventyYears = 2208988800UL;     
    unsigned long epoch = secsSince1900 - seventyYears;  
    setTime(epoch + (9 * 60 * 60));                        //arduino Timeライブラリ使用
    Serial.println("updated Date and Time.");
  }
}

unsigned long sendNTPpacket(IPAddress& address){
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

void showDate(){                       //arduino Timeライブラリ使用
    Serial.print("Unix time : ");
    Serial.println(now());
    Serial.print("now (JST) : ");
    Serial.print(year());
    Serial.print('/');
    Serial.print(month());
    Serial.print('/');
    Serial.print(day());
    Serial.print(" (");
    Serial.print(dayOfWeek[weekday()]);
    Serial.print(") ");
    Serial.print(hour());
    Serial.print(':'); 
    Serial.print(minute());
    Serial.print(':'); 
    Serial.println(second());
    Serial.println();
}



パート2ではケースへの組み込みと無線化します。

PM2.5、黄砂予報をarduinoでネットから受信しLEDで表示 -2-http://cranberrytree.blogspot.jp/2013/05/pm25arduinoled-2.html


環境:arduinoUnoR3、arduinoIDE1.0.6、win7










2 件のコメント:

  1. Hi,
    It is Lawrence
    I work for WIZnet which designed Arduino Ethernet shield Chip.
    Your "黄砂予報をarduinoでネットから受信しLEDで表示" is great project for other makers.
    So, If you do not mind, could Ishare this Arduino+Ethernet project to http://wiznetmuseum.com/ for many other makers?
    Thank you
    Please contact lawrence@wiznet.co.kr

    返信削除
  2. Hello!

    This is Lawrence from WIZnet.

    Before, I did post your great project to WIZnet Museum (http://wiznetmuseum.com)

    Now, I want to let you know about IoT Constest.

    I think your poject will be enough to get won.

    That contest is called ‘Curation is Creation’

    And onething you have to concern is using ARM mbed-enabled WIZwiki-W7500 platform & WizFi310 shield.

    Those things are posted in http://www.cybermakerspace.com/ with How To.


    As I know, there are only few participants.

    So I do not want you are missing this change.

    The total price is $15,000 !!


    Hurry to join it!


    All things are in http://www.cybermakerspace.com/



    Sincerely,
    Best Regards

    返信削除