NTP ST1(JJY)サーバの自動起動

もともと手動でntpdを立ち上げるようにしていたのですが、先日の停電で4台あるおうちST1が全滅してしまい、対応が面倒くさくなったので自動で起動できるようにしてみました。

我が家はインターネットが消滅しても自立して稼動できるIPネットワークを目指しています。

ルーターなどのモジュールにはRTCがないので、再起動すると1970年などになります。

そのままntpdを起動すると時間が1000秒以上ずれているためntpdが終了してしまいます。これは以下の設定で回避できます。

```:ntp.conf
tinker panic 0
```

しかしntpdが終了しないだけで、正しい時間は設定されません。ntpdは15000秒くらい差があると、設定しないようです。

```
# date 2203260900
Sat Mar 26 09:00:00 JST 2022
# ntpd -q        
26 Mar 09:00:01 ntpd[114]: ntpd 4.2.8p15-a (1): Starting
26 Mar 09:00:01 ntpd[114]: Command line: ntpd -q
26 Mar 09:00:01 ntpd[114]: ----------------------------------------------------
26 Mar 09:00:01 ntpd[114]: ntp-4 is maintained by Network Time Foundation,
26 Mar 09:00:01 ntpd[114]: Inc. (NTF), a non-profit 501(c)(3) public-benefit
26 Mar 09:00:01 ntpd[114]: corporation.  Support and training for ntp-4 are
26 Mar 09:00:01 ntpd[114]: available at https://www.nwtime.org/support
26 Mar 09:00:01 ntpd[114]: ----------------------------------------------------
26 Mar 09:00:01 ntpd[114]: proto: precision = 18.700 usec (-16)
26 Mar 09:00:01 ntpd[114]: basedate set to 2018-08-07
26 Mar 09:00:01 ntpd[114]: gps base set to 2018-08-12 (week 2014)
26 Mar 09:00:01 ntpd[114]: Listen and drop on 0 v4wildcard 0.0.0.0:123
26 Mar 09:00:01 ntpd[114]: Listen normally on 1 rt0 10.0.1.8:123
26 Mar 09:00:01 ntpd[114]: Listen normally on 2 lo0 127.0.0.1:123
26 Mar 09:00:01 ntpd[114]: Listening on routing socket on fd #23 for interface updates
26 Mar 09:00:01 ntpd[114]: JJY(0) 8011 81 mobilize assoc 62439
26 Mar 09:00:01 ntpd[114]: 0.0.0.0 c016 06 restart
26 Mar 09:00:02 ntpd[114]: JJY(0) 8014 84 reachable
26 Mar 09:00:02 ntpd[114]: JJY(0) 901a 8a sys_peer
26 Mar 12:29:16 ntpd[114]: ntpd: time set +12553.091564 s
ntpd: time set +12553.091564s
# date 2203260800
Sat Mar 26 08:00:00 JST 2022
# ntpd -q        
26 Mar 08:00:02 ntpd[116]: ntpd 4.2.8p15-a (1): Starting
26 Mar 08:00:02 ntpd[116]: Command line: ntpd -q
26 Mar 08:00:02 ntpd[116]: ----------------------------------------------------
26 Mar 08:00:02 ntpd[116]: ntp-4 is maintained by Network Time Foundation,
26 Mar 08:00:02 ntpd[116]: Inc. (NTF), a non-profit 501(c)(3) public-benefit
26 Mar 08:00:02 ntpd[116]: corporation.  Support and training for ntp-4 are
26 Mar 08:00:02 ntpd[116]: available at https://www.nwtime.org/support
26 Mar 08:00:02 ntpd[116]: ----------------------------------------------------
26 Mar 08:00:02 ntpd[116]: proto: precision = 18.000 usec (-16)
26 Mar 08:00:02 ntpd[116]: basedate set to 2018-08-07
26 Mar 08:00:02 ntpd[116]: gps base set to 2018-08-12 (week 2014)
26 Mar 08:00:02 ntpd[116]: Listen and drop on 0 v4wildcard 0.0.0.0:123
26 Mar 08:00:02 ntpd[116]: Listen normally on 1 rt0 10.0.1.8:123
26 Mar 08:00:02 ntpd[116]: Listen normally on 2 lo0 127.0.0.1:123
26 Mar 08:00:02 ntpd[116]: Listening on routing socket on fd #23 for interface updates
26 Mar 08:00:02 ntpd[116]: JJY(0) 8011 81 mobilize assoc 23454
26 Mar 08:00:02 ntpd[116]: 0.0.0.0 c016 06 restart
26 Mar 08:00:03 ntpd[116]: JJY(0) 801b -8b clock_event clk_bad_time
```

通常はntpdateを使って正しい時間のサーバに合わせた後、ntpdを起動します。しかしせっかくst1なので、st0から時間を拾って設定してその後、ntpdを起動するようにします。

無停電電源を付けるとかI2CのRTCを付けるとかも考えたのですが、この方法が一番簡単そうです。

Arduinoで作った[SEIKO TDC-300もどき](https://github.com/yamori813/JJYS)のデータを拾うスクリプトをmrubyで書いてみました。

```ruby
#!/usr/local/bin/mruby

port = "/dev/cuau0"

ser = SerialPort.new(port, 2400, 8, 1, 0)
ser.flow_control=0

ser.flush

start = 0
count = 0

# SEIKO TimeDataClock Type3 format

while count  < 11 do
  ch = ser.getc
  if ch == "\x02"
    start = 1
  else
    if start == 1
      if count != 6
        print ch
      end
      count = count + 1
    end
  end
end
```

これをdateコマンドで設定後にntpdを起動するようにすれば自動起動できます。

JJYが停波しているとブロックされますので、バックグランドでスクリプトを走らせるのが良いです。

停電後の復旧でST1に接続されてるST2が先に上がるとntpdateに失敗して、ntpdが落ちるケースが考えられます。成功するまで複数のST1にntpdateして成功したら、ntpdをあげるのが良いです。

分単位での設定なのでかなり大きなオフセットになってしまい、安定するまで結構時間がかかります。

![filename-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5db3fd02-8e49-51a9-585c-c0bdd7e14524.png)

分単位での設定は勘違いしていただけで、以下のようにすれば、dateで秒まで指定できます。

```ruby
while count  < 13 do
  ch = ser.getc
  if ch == "\x02"
    start = 1
  else
    if start == 1
      if count != 6 
        print ch
      end
      if count == 10
        print '.'
      end
      count = count + 1
    end
  end
end
```