macsbug

Just another WordPress.com site

NTPcube ( ESP8266 + OLED )

with 3 comments

NTP(Network Time Protocol) サーバ から、時刻情報を取得しOLEDに表示しました。            2015.11.17



仕組み:NTPcube が 下図の NTPクライアントになります。


準備:
ESP8266 + NTPCliant  で時刻を取得し OLED に表示する
ESP8266+BME280+OLED+BOX
基本スケッチは、Ivan Grokhotkov氏に感謝。
SSIDとPassword は各自で設定の事。
ルーターの設定:ルーターにマックアドレスの設定が必要な場合は、事前にマックアドレスを調べるか
_ 電源ON時、OLEDにマックアドレスが表示されますので確認してください。(命令:WiFi.macAddress())。


感想:
NTPが何かを知りませんでしたが、ネットの時刻情報から時計が作れ小さなケースに入れると楽しいものです。
NTPは、本来PCの時計あわせに使うようですが、家の中の環境では、GPSや電波時計より時刻情報を得やすいです。
ネットにアクセスする為に、秒単位の表示は無理で分単位にしました。アクセスは 10秒ごとです。
ネットの負荷を少なくする為に、内蔵時計を使用し時刻あわせに NTP を使用した方が良いかとも思います。
内蔵時計の時刻あわせは、通信の時間やスケッチ上の時間遅れがあり、秒単位の設定は考慮が必要と思われます。


// Udp NTP Client
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SPI.h>
#include <BME280_MOD_1022.h>
#include <Adafruit_GFX.h>
#include <ESP_Adafruit_SSD1306.h>
#include <Time.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
extern "C" {
  #include "user_interface.h"
}
char ssid[] = "xxxx";                 // your network SSID (name)
char pass[] = "xxxx";                 // your network password
unsigned int localPort = 2390;        // local port to listen for UDP packets
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48;       // NTP time stamp:first 48 bytes
byte packetBuffer[NTP_PACKET_SIZE];   // buffer:incoming and outgoing packets
WiFiUDP udp;                          // UDP:send & receive packets over UDP

void setup(){
  //Serial.begin(115200);
  //---------------------------------------------//
  Wire.begin(13, 14); delay(10);                 // SDA,SCL(GPIO_13,GPIO_14)
  display.begin(SSD1306_SWITCHCAPVCC,0x78>>1);   // I2C_ADDRESS
  display.clearDisplay();                        // all pixels off 
  display.setTextSize(1);                        // printable sizes 1 to 8
  display.setTextColor(WHITE);                   // WHITE, BLACK, INVERSE
  display.setCursor(0,0);                        // location x,y
  display.display();                             // plotted items
  //---------------------------------------------//
  display.print("Mac ");display.println(WiFi.macAddress());display.display();
  display.print("Connecting to ");display.println(ssid);display.display();
  WiFi.begin(ssid, pass); 
  while (WiFi.status() != WL_CONNECTED){
    delay(500);display.print(".");display.display();} display.println("ok");
  display.print("IP: ");display.println(WiFi.localIP());
  udp.begin(localPort);
  display.print("Local port: ");display.println(udp.localPort());
  display.display();dealy(2000);
}

void loop(){
  sendNTPpacket(timeServer);delay(1000);// send NTP packet time server & Wait
  int cb = udp.parsePacket();
  if (!cb) {display.println("no packet yet");display.display();}
  else {
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into 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;   // Convert NTP time
    unsigned long epoch = secsSince1900 - seventyYears;// Unix time
    epoch = epoch + 32400;  // UTC + 9 ( 9 * 60 * 60 ) // JST
    setTime(epoch);         // Date Time set
    display.clearDisplay();display.setTextSize(2);display.setCursor(0,0);
    // Date
    display.print(year());display.print('/');
    display.print(month());display.print('/');
    display.println(day());display.display(); 
    // Time 
    display.setTextSize(4);
    if (((epoch % 86400L)/3600) < 10){display.print('0');}
    display.print((epoch % 86400L)/3600);display.print(':'); // day
    if (((epoch % 3600)/60) < 10 ){display.print('0');}
    display.println((epoch % 3600)/60);                      // minute
    //display.print(':');if ((epoch % 60) < 10 ){display.print('0');}
    //display.println(epoch % 60);                           // second
    display.display();
  }
  delay(10000); // wait 10 seconds before asking for the time again
}

unsigned long sendNTPpacket(IPAddress& address){ // send an NTP request
  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;      // 8 bytes of zero for Root:Delay & Dispersion
  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();
}

広告

Written by macsbug

11月 17, 2015 @ 7:58 am

カテゴリー: ESP8266

コメント / トラックバック3件

Subscribe to comments with RSS.

  1. いろいろ山盛り参考にさせてもらっています.

    NTPを使った時間合わせですが,TimeライブラリのサンプルにあるTimeNTPはいかがでしょう?
    サーバの負担を減らすこともできますし……ESP-WROOM-02なら一日に1~2回で十分……
    内部タイマがメインになるので「時刻ベースでの処理」もしやすくなると思います.

    対象がEthernet ShieldとなっているのでESP8266向けに書き直す部分がそれなりにあったり,
    同期周期がTime.cppの変数値で決まってしまうあたりは不便だったりするかもしれませんが,
    手間かけて「自分用」に書き換えてしまう価値は大有りかと.

    #はじめは300秒周期で勝手にsyncするので「どーしよ?」と悩みました.
    ##確かNTPサーバをIPアドレスだけで探すコードだったので,そこも修正したほうが安全です.

    つ★

    10月 4, 2017 at 8:54 pm

    • つ★さん、サイトの訪問をありがとうございます。
      「自分用」に書き換える アドバイスをありがとうございます。
      正にご指摘の様に NTPの時間合わせは 幾つかの課題があります。
      1. NTPサーバーの負担を減らすにはどうするか。
      2. PC内の時計を使用した時の 時間連れをどうするか(スケッチを書き込む時間分遅れる)。
      3. 自宅外でのネットワーク接続はどうするか。
      4. ネットワーク接続出来ない場合の処理。
      この中で 1. のNTPサーバーの負担を減らす事は大変重要だと思います。
      方法として TimeNTP により時刻ベースの処理ができるとの事。
      ただし TimeNTP は 対象がEthernet Shield でライブラリーの変更が必要なのですね。
      確かこの件で 幾つかのライブラリーを少し見たのですが私の力量では無理かと思いやめました。
      現在 新たな時計作りで この件をどうしようか思案中です。
      時刻ベースでの処理が出来るライブラリーを探して使用するかとか LOOP内で時間処理をするとか なんらかの方法が必要ですね。
      未完成なお返事になってしまいましたが この件はかなり気になっています。

      macsbug

      10月 5, 2017 at 10:18 am

      • いろいろ確認しながら作業し直してみたところ,Timeライブラリでの時計合わせ周期は
        setSyncInterval関数でスケッチから任意秒指定できること,シッカリ確認できました.
        はじめは使い方を間違えていたようで……今はキチンと機能してくれています♪

        まだMCUは年始から触り始めたところで,入口のArduinoから少し進んだだけでして,
        体調管理用に Arduino + RTC + SDcard + センサ類など でデータ収集しはじめて
        数か月たったところのため,WDTとか「使いたいけど使えない機能」が山盛りです.

        RTCの時計合わせですが,スタンドアロンなArduinoだけの時は……
        1)スケッチを TimeSpan関数 で秒単位調整を可能にしておく
        2)ふつーにスケッチをビルドした時の時間を書き込む
        3)シリアルモニタに時刻を表示させて「ズレ」をはかる
        4)スケッチに補正値を入力してビルド→書き込み
        ってな流れでやっていました.
        (構造的にmillis関数に依存しているため,月初に自動再起動かけていたり……
         RTCがDS3231ってのもあってズレが少ないので……上記で間に合っています)

        今は,Ethernet shieldを1枚だけですが入手したため,RTCの時計合わせ用に
        NTPで同期させるスケッチをおこしたので,TimeSpan関数で補正はしていません.
        (実際は,補正値を「0」に固定しているだけです)

        そんなこんなで,キチンとスケッチのクレジットを確認しないと公開できないのですが,
        ライブラリ付属サンプルの寄せ集め+自家改造ですから,自家利用品への組込みは
        問題ないはずなので,ゴソゴソし始めています.

        ご入用でしたら「コメント主のメアド」に『わかりやすいタイトル』で連絡いただければ
        グチャなままとなりますが提供いたしますので,遠慮なくどーぞ.

        であっ,これからもディープな記事,よろしくお願いします.

        #ここのESP-01の記事を参考に3.3V用電源基盤を作ったことが昨夜発覚!
        ##やっぱり,Ethernet shieldもESP8266も「1個」では進みが遅いですね.

        つ★

        10月 6, 2017 at 10:50 pm


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。