2038年問題 カウントダウン時計

2038年1月19日3時14分7秒(UTC)にUNIX時間が符号つき32ビット整数では0x7fffffff秒になり,次の瞬間オーバーフローしてしまう問題があります.これを2038年問題と呼びます.この問題は2000年問題よりも深刻になる可能性を秘めており,適切な対策が必要です.

このデバイスでは,2038年問題発生までの秒数をカウントダウンします.できるだけ正確を期すため,バックアップ電池内蔵のRTC(DS1307)で時刻を保持しつつ,WiFi経由でNTPサーバに定期的に問い合わせをしながら時刻を補正し続けます.

なお,プログラム内ではUNIX時間をuint32_tで扱っていますが,カウントダウンにバグがあり,2038年問題は発生します

      if (dispmode == MODE_UNIXTIME) {
        dispDigits(now.unixtime()-SECONDS_UTC_TO_JST);
      } else if (dispmode == MODE_COUNTDOWN) {
        dispDigits((0x7FFFFFFF - (now.unixtime()-SECONDS_UTC_TO_JST))); // y 2038!
      } else if (dispmode == MODE_CLOCK) {
        dispClock(now);
      } else if (dispmode == MODE_DATE) {
        dispDate(now);
      }

問題を発生させたくない場合は,dispDigits()の内部を(int32_t)でキャストすればOKです.

なお,ユーザが自由に時刻を指定できるカウントダウンタイマーも搭載しています.
下に示すAPI経由で日時の設定を行うと,秒でのカウントを開始します.

材料

  • マイコン: ESP-WROOM-02
  • LED制御IC: HT16K33
  • 7セグメントx4: OSL40562-IB x 2 (アノードコモン)
  • 7セグメントx1: OSL10561-IB x 2 (アノードコモン)
  • RTC: DS1307
  • 32kHz Crystal
  • タクトスイッチ(縦型)
  • CR2032電池ホルダ
  • PCA9306 I2Cレベル変換
  • 自作PCB

ハードウェア

単純に7セグメントLEDを10桁表示させるデバイスです.

HT16K33はLEDドライバで,アノード16本,カソード8本を持ち,8×8マトリクスを2個まで同時に制御できます.このドライバを使って7セグメントLEDを10桁駆動させるには,アノードコモンのLEDを準備します.数字のどの部品を表示させるのかを指定するのにC0C8を利用し,どの桁を表示させるのかの指定にA0A9を利用します.

10桁出せる7セグLEDは見たことがないので,4桁を2つ,1桁を2つ組み合わせて使います.
スイッチはモード(カウントダウン,UNIX時刻表示,通常時刻表示)の切り替え用です.

一応時計なので,バッテリーバックアップ付のRTCを使います.使うのは定番のDS1307です.

プログラム

プログラムからのLED制御には,AdafruitのHT16K33 Arduinoライブラリ(Adafruit_LEDBackpack)を利用します.ただし,このドライバはカソードコモンのLEDを前提に作られていますので,そのままでは利用できません.
そのため,これを継承したクラス(Anodecommon_7seg)を作成し,アノードコモン用と10桁用の改変部分は全てこちらに記述します.

初期起動時は,WiFiネットワークに参加できないので,自身がアクセスポイントになってCC2038という名前のAP(アクセスポイント)に接続するように促されます.接続するとCaptive Webページで,参加するWiFiの設定をしますと,次回起動時はWiFiに接続します.

ntpサーバに接続すると,時計を自動的に合わせて,動作を開始します.上でも述べたように,意図的に2038年問題に対処していないので,2038年には動作が乱れるところが観察できます.

API

簡易httpサーバになっていますので,REST APIが使えます.

API parameter value effect
mode value int change mode
status show status
config timezone string change local timezone
countdown date string set user-specified countdown timer
time string
timezone string
$ curl http://esp_7seg.local/status
{"unixtime":1517957705,"countdown":629525942,"mode":0}

$ curl "http://esp_7seg.local/mode?value=2"
{"mode":2}

Web Interface

自分で設定したURL (または初期値 http://cc2038.local/ )からアクセスすると,ユーザ設定型カウントダウンタイマーの日時設定が出来ます.上記APIを使いやすくしたものですので,ご利用下さい.

GitHub