はじめに
RaspberryPiに外付けのRTC(Real Time Clock)を載せて、更に起動時に時刻合わせする手順です。
ここでは、systemd
を使って、Raspbianの起動時に自動的に時刻合わせの処理をします。
構成と概要
ハードウェア
I2C通信対応の、DS1307を使用したRTCを使います。I2Cアドレスは0x68番になります。(他のRTCでも、I2C周りの書き方が変わるだけで、基本は同じです)
####(例)
#事前確認
###raspi-config
I2C通信を有効にします。
$ sudo raspi-config
設定は、こちらを参考にしてください。
###必要なパッケージのインストール
以下のパッケージを入れます。
$ sudo apt install i2c-tools -y
$ sudo apt install ntpdate -y
###modulesの追記
/etc/modulesに設定を追記します。
$ cd /etc
$ sudo cp -p modules modules.org
$ sudo nano modules
rtc-ds1307
を追記します。
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-dev
rtc-ds1307
###DS1307の認識状況
DS1307のRTCモジュールを、RaspberryPiのI2C回路に繋いでおくと、0x68にRTCが見えます。
注意:DS1307にはバックアップの電池を繋いでおいてください。繋いでないと下記の一覧に出てきません・・・
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
この時点で、RTCの現在時刻を確認すると、まだRaspbianの管理下になっていないので、下記のエラーメッセージが出ます。
$ sudo /sbin/hwclock
hwclock: Cannot access the Hardware Clock via any known method.
hwclock: Use the --debug option to see the details of our search for an access method.
#RTCに現在の時刻を書き込む
Raspbianのシステムクロックの値を、RTCに書き込みます。
※システムクロックntpときちんと同期して、正しい時刻にしておいてください。
###RTCをRaspbianの管理下に置く
sudo echo
コマンドではPermission denied
になるので、一旦rootになってから操作します。
$ sudo su
# echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
# exit
$
この時点で、RTCの現在時刻を確認すると、まだ時刻を書き込んでいないので、下記のように2000年1月1日の日付になっています。
$ sudo /sbin/hwclock
2000-01-01 09:00:18.046319+0900
RaspberryPi4の場合は、下記のようにread the time failed
というメッセージになります。
$ sudo /sbin/hwclock
hwclock: ioctl(RTC_RD_TIME) to /dev/rtc0 to read the time failed: Invalid argument
$ uname -a
Linux few-kin05 4.19.97-v7l+ #1294 SMP Thu Jan 30 13:21:14 GMT 2020 armv7l GNU/Linux
###システムクロックの時刻をRTCに書き込む
$ date
Fri Feb 15 18:17:53 JST 2019
$ sudo /sbin/hwclock -w
$ sudo /sbin/hwclock
2019-02-15 18:17:57.070420+0900
起動時に時刻合わせをする
時計あわせのスクリプトを準備して、Raspbianの起動時にsystemdから一回だけ起動するようにします。
###時刻合わせのスクリプト
#!/bin/sh
#--------------------------------------------------------------------
# 時刻合わせのスクリプト
# 2019-02 myasu
#--------------------------------------------------------------------
#----------------------------------
#定数
#----------------------------------
#NTPサーバ
NTPSERVER="ntp.nict.jp"
#----------------------------------
#メイン処理
#----------------------------------
#実行中ユーザをチェック
if [ `/usr/bin/id -u` != "0" ]; then
#rootでなければ異常終了
echo " ! Please run as root."
exit 1
fi
#主要コマンドの存在をチェック
if [ ! -x /usr/sbin/i2cdetect ]; then
#見つからなければ異常終了
echo " ! No 'i2cdetect' Command."
exit 1
fi
if [ ! -x /usr/sbin/ntpdate ]; then
#見つからなければ異常終了
echo " ! No 'ntpdate' Command."
exit 1
fi
if [ ! -x /sbin/hwclock ]; then
#見つからなければ異常終了
echo " ! No 'hwclock' Command."
exit 1
fi
#現在時刻を表示
NOW=`date`
echo " now (before sync) > "$NOW
#RTCデバイスがあるかチェック
#(強引ですがgrepを使って、該当アドレス68番かUUの文字があるか確認)
#(複数のデバイスがあって、UUが複数表示されるようなら、ココの記述は要改良)
/usr/sbin/i2cdetect -y 1 | grep "68\|UU" > /dev/null
if [ $? != 0 ]; then
#見つからなければ異常終了
echo " ! No RTC Device."
exit 1
fi
#RTCデバイスがraspbianの管理下にあるかチェック
#(強引ですがgrepを使って、該当アドレス68番があるか確認)
/usr/sbin/i2cdetect -y 1 | grep "68" > /dev/null
if [ $? = 0 ]; then
#未登録なら登録する
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
fi
#まずはNTPに対して時刻合わせする
/usr/sbin/ntpdate -v $NTPSERVER
if [ $? = 0 ]; then
#NTPで正常に時計合わせできたら、RTCの時刻を書き換え
/sbin/hwclock -w # system time --> rtc
echo " Synchronize clock with NTP"
else
#RTCの時刻を読み出してシステムクロックを書き換え
/sbin/hwclock -s # system time <-- rtc
echo " Synchronize clock with RTC"
fi
#現在のシステムクロック時刻を表示
NOW=`date`
echo " now (after sync) > "$NOW
#正常終了
exit 0
systemdの設定
起動時にワンショットだけ動く様にしています。
スクリプトの中の[INSTALL DIR]
は、スクリプトファイルやserviceファイルを置いたフォルダに合わせて修正してください。
###serviceファイル
[Unit]
Description=Synchronize clock with NTP or RTC
After=network.target local-fs.target
ConditionPathExists=/home/pi/[INSTALL DIR]
[Service]
ExecStart=/home/pi/[INSTALL DIR]/setSystimeRTC.sh
Restart=no
KillMode=mixed
Type=oneshot
User=root
Group=root
[Install]
WantedBy=multi-user.target
####簡単に解説
指定 | 設定値 | 説明 |
---|---|---|
After | network.target local-fs.target | networkとファイルシステムが有効になってから起動します |
Restart | no | 一発なので再起動無し |
Type | oneshot | 一発だけ起動 |
systemdへ登録
systemdに登録して、サービスを起動します。
$ sudo ln -s /home/pi/[INSTALL DIR]/setSystimeRTC.service /etc/systemd/system
$ sudo systemctl enable setSystimeRTC.service
$ sudo systemctl start setSystimeRTC.service
####serviceファイルを修正した時
下記のように都度、リロードします。
$ sudo systemctl daemon-reload
起動状態を確認
systemctl status
コマンドで、状態を確認します。
起動したあと、ntpに問い合わせして時刻を合わせた後、RTCにシステムクロックを書き込んで終了しています。
$ systemctl status setSystimeRTC.service
● setSystimeRTC.service - Synchronize clock with NTP or RTC
Loaded: loaded (/home/pi/gitwork/python/rtc/setSystimeRTC.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2019-01-30 05:59:43 JST; 3h 51min ago
Main PID: 373 (code=exited, status=0/SUCCESS)
Jan 29 20:17:28 raspibp systemd[1]: Starting Synchronize clock with NTP or RTC...
Jan 29 20:17:28 raspibp setSystimeRTC.sh[373]: now (before sync) > Tue Jan 29 20:17:28 JST 2019
Jan 29 20:17:29 raspibp setSystimeRTC.sh[373]: 29 Jan 20:17:29 ntpdate[391]: ntpdate 4.2.8p10@1.3728-o Sat Mar 10 18:03:
Jan 30 05:59:41 raspibp setSystimeRTC.sh[373]: 30 Jan 05:59:41 ntpdate[391]: step time server 133.243.238.243 offset 349
Jan 30 05:59:43 raspibp setSystimeRTC.sh[373]: Synchronize clock with NTP
Jan 30 05:59:43 raspibp setSystimeRTC.sh[373]: now (after sync) > Wed Jan 30 05:59:43 JST 2019
Jan 30 05:59:43 raspibp systemd[1]: Started Synchronize clock with NTP or RTC.
逆に、ntpの問い合わせが失敗した場合は、RTCから時刻を合わせます。
下記の例では、わざとNTPサーバのホスト名を間違えています。
$ systemctl status setSystimeRTC.service
● setSystimeRTC.service - Synchronize clock with NTP or RTC
Loaded: loaded (/home/pi/gitwork/python/rtc/setSystimeRTC.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Sat 2019-02-16 10:18:56 JST; 2s ago
Process: 995 ExecStart=/home/pi/gitwork/python/rtc/setSystimeRTC.sh (code=exited, status=0/SUCCESS)
Main PID: 995 (code=exited, status=0/SUCCESS)
Feb 16 10:18:51 raspiap systemd[1]: Starting Synchronize clock with NTP or RTC...
Feb 16 10:18:51 raspiap setSystimeRTC.sh[995]: now (before sync) > Sat Feb 16 10:18:51 JST 2019
Feb 16 10:18:51 raspiap setSystimeRTC.sh[995]: 16 Feb 10:18:51 ntpdate[1002]: ntpdate 4.2.8p10@1.3728-o Sat Mar 10 18:03
Feb 16 10:18:55 raspiap setSystimeRTC.sh[995]: Error resolving ntp.nict1.jp: Name or service not known (-2)
Feb 16 10:18:55 raspiap setSystimeRTC.sh[995]: 16 Feb 10:18:55 ntpdate[1002]: Cant find host ntp.nict1.jp: Name or serv
Feb 16 10:18:55 raspiap setSystimeRTC.sh[995]: 16 Feb 10:18:55 ntpdate[1002]: no servers can be used, exiting
Feb 16 10:18:56 raspiap setSystimeRTC.sh[995]: Synchronize clock with RTC
Feb 16 10:18:56 raspiap setSystimeRTC.sh[995]: now (after sync) > Sat Feb 16 10:18:56 JST 2019
Feb 16 10:18:56 raspiap systemd[1]: Started Synchronize clock with NTP or RTC.
参考
- RTCの導入
- systemdの設定など