ラズパイ４録画サーバーの定時診断スクリプト

更新：2023/9/13

[メンテ＆トラブルシューティング](1e439b7cc10822f5ef69)
　∟ ● 定時診断スクリプト Now!
[前編](614c3973cc7d1439865e)
　１．ラズパイとサーバーの概要
　２．録画に必要なものを集める、購入する
　３．OSのインストールとセットアップ
　４．NASの構築
[後編(docker-dvb版)](0d532fe0859779bb729c)
[後編(docker-px4_drv版)](6805564d57860a93169a)
　５．チューナードライバの導入
　６．docker-mirakurun-epgstationの導入
[後編(非docker版)](3bf7e152fbf73c5ca25e)
　５．チューナーの導入、テスト録画
　６．運用のためのツール、mirakurun、epgstation
[運用実践編](dc099b2f1ab39dad07f7)
　７．録画管理方法
　８．エンコードと再生
　９．システムバックアップ
番外．[まとめ版](0ea0f2ee3cfe5cb8e31e)
番外．[Mirakurunのチャンネル手動設定](28e360d8f678159059e8)
番外．[ラズパイ用ケース作成](237fedc55ac79c9d5723)
発展途上スクリプト
[ニチアサが放送されるかどうかを告知してくれるシェルスクリプト](b510315d211b530e7c2f)
[スポーツ中継検出シェルスクリプト](5d3895896ad92feaf6f2)

[memo]スクリプトの改良
1.pi等本体で動かす診断スクリプト(cronで実行)
・各デバイス動作確認コマンド
・mirakurunのpid暴走チェック
・温度および電圧のチェック
・上記について、可能なら不具合時に通知してくれる仕組みを
2.別のデバイスで動かすスクリプト
a.android上で動かす。pythonが有力か
常駐ではなく即時で知りたい項目のみチェック。
(a)現在実行中の録画、直近の録画予約と何分後に終わるかの報告
(b)つながらない場合、ルーターのpingもチェックしネットワークのチェック
(c)pid暴走チェック
(a,b,c)全部実行のスクリプト、(a,b)を実行のスクリプト
b.pi等の非androidのlinux上で動かす。bash確定
常駐でcron実行
 1.と同じスクリプトでほぼOKかと
 　それに加え、日常のネットワーク診断機能も含ませたいか
非常駐の予約等表示のは作らなくてもOKかな？
c.windows上で動かす。powershellが理想か？
常駐で実行 コマンドを定期的に実行するか？
即時で実行。
(a)現在実行中の録画、直近の録画予約と何分後に終わるかの報告
(b)つながらない場合、ルーターのpingもチェックしネットワークのチェック
(c)pid暴走チェック
(a,b,c)全部実行のスクリプト、(a,b)を実行のスクリプト

考え方だけ置いておく。
・録画が近い時は再起動しないスクリプト
・録画の失敗の検出→EPGStationかMirakurunが実装するべきでは
・過去の録画リストの保存、録画済みとの照らし合わせ)

ラズパイ４等を使った録画サーバーの管理で使えるスクリプトを作りました。
・電圧低下をチェックすることにより、電源劣化を発見する。
・直近の温度記録
・ストレージの残り容量を定期的にチェックする(本当は知りたい時だけわかればいい)
・録画中、ストリーム中、次の録画までの時間の表示によりメンテタイミングの決定。(本当は知りたい時だけわかればいい)
を一覧できます。[メンテの記事](1e439b7cc10822f5ef69)に入れてたものの分離＆改良です。ホームフォルダに入れてcronで定期実行することを想定しており、動作としては調査を行い結果をテキストファイルを出力します。
なので、結果の参照は、ブラウザからテキストファイルを読み込む、テキストファイルを直接読む、Androidならホームにショートカットを入れる、などできますね。

```その前にjqコマンドインストール方法を。.
＊recchk_reserve_storage.shの実行にはjqコマンドが必須です
sudo apt -y install jq
```

スクリプトは(どのbashスクリプトでも同じですが)文字コードUTF-8、改行コードLFで保存ですね。Win標準メモ帳だと改行コードが指定できないので、terapadでもsakuraエディタでもその他何でもいいので使うといいでしょう。

```recchk_reserve_storage.sh (次の予約まで等の表示)
#!/bin/bash

# 23.9/13更新
# 現在録画中か、録画終了まで何分か、次の予約まで何分かを調べるスクリプト。
# 何のために使うかって？アプデやメンテするタイミングを計るのにちょうどいいのではないでしょうか。
# 性質上、cronで定期実行が最適だと思います。実行間隔の最適値はわかりませんが5分～1時間に1回くらいがいいとこでしょうか。
# jqコマンド必須です。インストール→sudo apt -y install jq

#● Mirakurun,EPGStationのURL
epgstation_url=http://localhost:8888/
mirakurun_url=http://localhost:40772/
#● 診断結果出力ファイル指定(docker-mirakurun-epgstation/recorded/recorded/recstatus_reserve_storage.txtなど)。↓使用しない場合は=nofileにする。
textfilenotify=docker-mirakurun-epgstation/recorded/recorded/recstatus_reserve_storage.txt

# 現在時刻をUnixで
timenow=$(date +'%s')

# ■ 録画中が何件あるか(+何時現在か)、現在録画中なら何分後に終了かを表示する。
abc=$(echo $(curl -s $epgstation_url"api/recording?offset=0&limit=24&isHalfWidth=true") | rev | cut -c 2-2 |  rev )
echo "録画中の件数："$abc" ("$(date +'%H:%M')"時点" > $textfilenotify
if [ $abc -gt 0 ]; then
# 現在録画中のタイトルを取得
  def=$(curl -s $epgstation_url"api/recording?offset=0&limit=24&isHalfWidth=true" | jq -c '.records[] | [.name]')
  echo "録画中タイトル："${def:2:30} >> $textfilenotify
# あまりスマートではないが録画終了の時刻を取り出し、現在時刻との差を見ている。
  #def=$(curl -s $epgstation_url"api/recording?offset=0&limit=24&isHalfWidth=true" | awk '{print substr($0, index($0, "endAt")+length("endAt")+2, index($0, ",")-8 )}')
  def=$(curl -s $epgstation_url"api/recording?offset=0&limit=24&isHalfWidth=true" | jq -c '.records[] | [.endAt]' | cut -c 2- |  rev | cut -c 2- | rev)
  echo "録画終了までおそらく"$((($def/1000-$timenow)/60))"分 ("$(date --date @$(($def/1000)) +"%H:%M") >> $textfilenotify
fi
if [ $abc = 0 ]; then
# 録画中でなければ、最も近い予約の表示。最初の1件だけ情報を取り寄せている。
# offsetは現在から何番目の予約から開始か(最初0)、limitはそこからの数(最低1)
  def=$(curl -s $epgstation_url"api/reserves?offset=0&limit=1&type=normal&isHalfWidth=true" | jq -c '.reserves[] | [.startAt]' | cut -c 2- |  rev | cut -c 2- | rev)
  if [ $((($def/1000-$timenow)/60)) -gt 120 ]; then
    echo "次の録画予約まで"$((($def/1000-$timenow)/3600))"時間 ("$(date --date @$(($def/1000)) +"%d日%H:%M") >> $textfilenotify
  else
    echo "次の録画予約まで"$((($def/1000-$timenow)/60))"分 ("$(date --date @$(($def/1000)) +"%d日%H:%M") >> $textfilenotify
  fi
  def=$(curl -s $epgstation_url"api/reserves?offset=0&limit=1&type=normal&isHalfWidth=true" | jq -c '.reserves[] | [.name]')
  echo "予約タイトル："${def:2:30} >> $textfilenotify
fi

# ■ epgstationストリームの表示
abc=$(curl $epgstation_url"api/streams?isHalfWidth=true" | jq -c '.items[] | [.type]' | cut -c 3- |  rev | cut -c 3- | rev)
echo $abc
if [ $abc = "LiveStream" ]; then
    echo "EPGStationにてライブストリーム視聴中" >> $textfilenotify
fi

# ■（未実装、というか細かいチェックがいろいろ面倒くさい）mirakurunチューナー使用表示
#curl $mirakurun_url"api/tuners"
#abc=$(curl $mirakurun_url"api/tuners/0" | jq -c '.types[] | [.command]' | cut -c 3- |  rev | cut -c 3- | rev)
#abc=$(curl $mirakurun_url"api/tuners/0" | jq -c '[.command]')
#echo $abc

# ■ 残りストレージ量表示
abc=$(curl -s $epgstation_url"api/storages" | jq -c '.items[] | [.available]' | cut -c 2- |  rev | cut -c 2- | rev)
  echo "録画残りストレージ "$(($abc/1000/1000/1000))"GB" >>$textfilenotify
```

```recchk_hard.sh (チューナー等ハードウェア診断)
#!/bin/bash

# 23.8/12更新
# ラズパイ等Linux録画サーバーの診断スクリプト(ハード関連)です。
# ファイルをホームフォルダにおいてからのbash recchk_hard.sh で実行できます。
# 性質上、cronで定期実行が最適だと思います。実行間隔の最適値はわかりませんが1~2時間に1回くらいがいいとこでしょうか。

#● Mirakurun,EPGStationのURL
epgstation_url="http://localhost:8888/"
mirakurun_url="http://localhost:40772/"
#● LINEトークン。LINE通知で必須になります。↓通知しない場合は=notokenにする。
line_token=notoken
#● 診断結果出力ファイル指定(docker-mirakurun-epgstation/recorded/recstatus_hard.txtなど)。↓使用しない場合は=nofileにする。
textfilenotify=docker-mirakurun-epgstation/recorded/recstatus_hard.txt
#● エラー等の際に実際に再起動するかしないか。offだと再起動しない
rebootonoff=off
#● b-casリーダーの名前。lsusbで表示される。↓softcas使用などチェック不要の場合は=Linuxにする。
bcasreader_name=SCR3310-NTTCom
#● lsusbで表示されるデバイス名の一部。誤認識されなければOK。チェックをスルーする場合は=Linuxとでも書いておく。
# S1UD/Q1UDはVidzMedia、MLT5PEなどはDataBookあたりを指定すればOK。
lsusbtuner_name=DataBook
#● ls /devで表示されるデバイスファイル。誤認識されなければOK
# S1UD/Q1UDはdvb、MLT5PEはpxmlt5video、などなど。チェックをスルーする場合は=nullなどを書いておけばOK
lsdevtuner_name=pxmlt5video
#● 再起動判定に使用。初期状態はfalseで道中で使うのでここではいじらない
rebootflag=false

# pidチェック、暴走時は電圧チェックしてから再起動。
# ls /devで出てこない場合、ドライバ再読み込みして再度ls /devする。
# 大丈夫な場合はそのまま。ダメな場合は再起動する。
# lsusbで出てこない場合は再起動
# カードリーダーチェック、ない場合は再起動
# 温度と電圧は別スクリプトでチェック

if [ $textfilenotify != nofile ]; then
 echo "ハードウェアチェック ("$(date +'%H:%M')"時点" > $textfilenotify
fi

# ■■■ pid暴走チェック ■■■
# pidが増え続ける現象はチューナーが暴走中。
# ただし同軸が外れている時もよく似た反応でソフト上ではほぼ区別できない。外れないようにしろとしか言えないがな..
# チューナー1つ目チェック。
abc=$(curl -s "${mirakurun_url}api/tuners/0/process")
# ↑で{"pid":*****}が出力される
tchk1=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
# ↑でpidの数字部分を抜き出す
sleep 2
# 2秒間隔を開けて同じコマンドを実行し結果を見る
abc=$(curl -s "${mirakurun_url}api/tuners/0/process")
tchk2=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
sleep 2
abc=$(curl -s "${mirakurun_url}api/tuners/0/process")
tchk3=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
sleep 2
abc=$(curl -s "${mirakurun_url}api/tuners/0/process")
tchk4=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
if [ $tchk1 != $tchk2 ] && [ $tchk2 != $tchk3 ] && [ $tchk3 != $tchk4 ]; then
  # 4回の実行結果が全部違う場合はpid暴走状態。
  if [ $line_token != notoken ]; then
    curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖_チューナーが暴走したのでOS再起動予定。電圧も降下している可能性あるので別途チェック推奨です。解決しない場合はチューナー電源も一度落としてください。' https://notify-api.line.me/api/notify
  fi
  if [ $textfilenotify != nofile ]; then
    echo "pid暴走状態" >> $textfilenotify
  fi
  rebootflag=true
else
  # 1つ目が大丈夫な場合、2つ目をチェック。何等かで最初のチューナーが非動作時かもしれませんし
  abc=$(curl -s "${mirakurun_url}api/tuners/1/process")
  tchk1=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
  sleep 2
  abc=$(curl -s "${mirakurun_url}api/tuners/1/process")
  tchk2=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
  sleep 2
  abc=$(curl -s "${mirakurun_url}api/tuners/1/process")
  tchk3=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
  sleep 2
  abc=$(curl -s "${mirakurun_url}api/tuners/1/process")
  tchk4=`echo $abc | cut -c 8- |  rev | cut -c 2- | rev`
  if [ $tchk1 != $tchk2 ] && [ $tchk2 != $tchk3 ] && [ $tchk3 != $tchk4 ]; then
  # 4回の実行結果が全部違う場合はpid暴走状態。
    if [ $line_token != notoken ]; then
      curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖_チューナーが暴走したのでOS再起動予定。電圧も降下している可能性あるので別途チェック推奨です。解決しない場合はチューナー電源も一度落としてください。' https://notify-api.line.me/api/notify
    fi
    if [ $textfilenotify != nofile ]; then
      echo "pid暴走状態" >> $textfilenotify
    fi
    rebootflag=true
  fi
fi

# ■■■ チューナーの存在をチェック(lsdev) ■■■
lsdevtuner1=`ls /dev | grep $lsdevtuner_name`
sleep 5
lsdevtuner2=`ls /dev | grep $lsdevtuner_name`
if [ -z "$lsdevtuner1" ] && [ "-z $lsusbtuner2" ]; then
  # 念のため2回チェック。
  # 見えない場合はドライバ読み込みを行う。
  cd px4_drv;cd driver;sudo modprobe px4_drv;cd ~
  # 再度lsdevでチェック。sudo必須だがきちんと動くか？
  lsdevtuner1=`ls /dev | grep $lsdevtuner_name`
  sleep 5
  lsdevtuner2=`ls /dev | grep $lsdevtuner_name`
  if [ -z "$lsdevtuner1" ] && [ "-z $lsusbtuner2" ]; then
    if [ $line_token != notoken ]; then
      curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖チューナーを見失った,lsdev,のでOSを再起動予定。解決しない場合はドライバ導入をやり直す必要があるかも。' https://notify-api.line.me/api/notify
    fi
    if [ $textfilenotify != nofile ]; then
      echo "チューナーを見失った(lsdev)" >> $textfilenotify
    fi
    rebootflag=true
  else
    if [ $line_token != notoken ]; then
      curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖チューナーを見失った,lsdev,がドライバ読み込んだのでOK。' https://notify-api.line.me/api/notify
    fi
    if [ $textfilenotify != nofile ]; then
      echo "チューナーを見失った(lsdev)が再読み込みで復旧した" >> $textfilenotify
    fi
  fi
fi

# ■■■ チューナーの存在をチェック(lsusb) ■■■
lsusbtuner1=`lsusb | grep $lsusbtuner_name`
sleep 5
lsusbtuner2=`lsusb | grep $lsusbtuner_name`
if [ -z "$lsusbtuner1" ] && [ "-z $lsusbtuner2" ]; then
  # 念のため2回チェック。
  # 見つからない場合はとりあえず再起動
  if [ $line_token != notoken ]; then
    curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖チューナーを見失った,lsusb,のでOSを再起動予定。解決しない場合はチューナー電源も一度落としてください。' https://notify-api.line.me/api/notify
  fi
  if [ $textfilenotify != nofile ]; then
    echo "チューナー見失った(lsusb)" >> $textfilenotify
  fi
  rebootflag=true
fi

# ■■■ bcasカードリーダーの存在をチェックする ■■■
readerchk1=`lsusb | grep $bcasreader_name`
sleep 5
readerchk2=`lsusb | grep $bcasreader_name`
if [ -z "$readerchk1" ] && [ "-z $readerchk2" ]; then
  # 処理はとりあえず再起動にしているが、接続が緩んでいるなど解決するとは限らないことは注意。
  if [ $line_token != notoken ]; then
    curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖カードリーダーが不明なのでOSを再起動予定。' https://notify-api.line.me/api/notify
  fi
  if [ $textfilenotify != nofile ]; then
    echo "bcasリーダー見失った" >> $textfilenotify
  fi
  rebootflag=true
fi

# ■■■ 再起動処理 ■■■
if [ $rebootflag = true ]; then
  abc=`cat /proc/uptime`
  treboot=`echo "${abc:0:6}"`
  # 1日以内に起動が行われている場合は再起動しない。
  if [ $treboot -lt 87000 ]; then
    if [ $line_token != notoken ]; then
      curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=OSを再起動します。' https://notify-api.line.me/api/notify
    fi
    if [ $rebootonoff = on ]; then
      sudo reboot
    fi
    if [ $textfilenotify != nofile ]; then
      echo "(本来ここで再起動)" >> $textfilenotify
    fi
  else
    if [ $line_token != notoken ]; then
      curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=前回再起動から24時間以内は自動再起動は行いません。' https://notify-api.line.me/api/notify
    fi
  fi
fi
```

```recchk_tmprt_volt.sh (温度や電圧の表示)
#!/bin/bash

# 23.9/14更新
# ラズパイ等Linux録画サーバーの診断スクリプト(温度と電圧関連)です。
# 無改造のままではvcgencmdを使うため、このスクリプトはおそらくラズパイ専用になるかと思います。
# ラズパイ以外で実行してもその部分がエラーで値が出てこないだけで害はないと思います。
# ファイルをホームフォルダにおいてからのbash recchk_tmprt_volt.sh で実行できます。
# 性質上、cronで定期実行が最適だと思います。実行間隔の最適値はわかりませんが1時間に1回か2回実行してもいいでしょう。

#● Mirakurun,EPGStationのURL
epgstation_url="http://localhost:8888/"
mirakurun_url="http://localhost:40772/"
#● LINEトークン。LINE通知で必須になります。↓通知しない場合は=notokenにする。
line_token=notoken
#● 診断結果出力ファイル指定(docker-mirakurun-epgstation/recorded/recorded/recstatus_tmprt_volt.txtなど)。↓使用しない場合は=nofileにする。
textfilenotify=docker-mirakurun-epgstation/recorded/recorded/recstatus_tmprt_volt.txt
#● エラー等の際に実際に再起動するかしないか。offだと再起動しない
rebootonoff=off
#● 再起動判定に使用。初期状態はfalseで道中で使うのでここではいじらない
rebootflag=false

if [ $textfilenotify != nofile ]; then
 echo "" >> $textfilenotify
fi

# ■■■ 温度チェック ■■■
abc=`vcgencmd measure_temp`
tchk1=`echo $abc | cut -c 6- |  rev | cut -c 5- | rev`
# 再起動処理はありません
if [ $tchk1 -gt 70 ]; then
  if [ $line_token != notoken ]; then
    curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖の温度が高くなっています。' https://notify-api.line.me/api/notify
  fi
  # 温度が高いときのみ警告
  if [ $textfilenotify != nofile ]; then
    sed -i "温度が高くなっています(70℃以上)"$abc $textfilenotify
  fi
fi
# 温度を記録
if [ $textfilenotify != nofile ]; then
  sed -i '1i'$(date +'%H:%M')" "$abc $textfilenotify
fi

# ■■■ 電圧チェック ■■■
abc=`vcgencmd get_throttled`
tchk1=`echo $abc | cut -c 11- |  rev | cut -c 1- | rev`
# 再起動処理はありません
if [ $tchk1 = 0x50005 ]; then
  if [ $line_token != notoken ]; then
    curl -X POST -H 'Authorization: Bearer [line_token]' -F 'message=録画鯖本体の電圧が降下しています。' https://notify-api.line.me/api/notify
  fi
  # 電圧低下時のみ警告
  if [ $textfilenotify != nofile ]; then
    sed -i '1i'$(date +'%H:%M')" 電圧低下中"$abc $textfilenotify
  fi
fi

# ■■■ ログ肥大化を防ぐ ■■■
# 60行以降は削除
sed -i -e '60,$d' $textfilenotify
```

せっかく情報をテキストファイルに出力しても、バラバラだと見にくいので別途統合ファイルを作ります。なお、ならなぜ最初から1つのスクリプトにしないかというと、ただ単に項目によってチェックしたい頻度が違うからです。面倒なら1つにまとめてしまってもいいっちゃいいです。

```recchk_unite.sh (統合するだけのファイル)
#!/bin/bash

# 予約情報の表示、ハードウェア診断、温度と電圧情報を一つのファイルにするだけのスクリプト

textfilenotify="docker-mirakurun-epgstation/recorded/各種診断結果ファイル.txt"

cat docker-mirakurun-epgstation/recorded/recstatus_reserve_storage.txt > $textfilenotify
cat docker-mirakurun-epgstation/recorded/recstatus_hard.txt >> $textfilenotify
cat docker-mirakurun-epgstation/recorded/recstatus_tmprt_volt.txt >> $textfilenotify
```

cronによる自動実行登録

```crontabでの実行例.
各ファイル実行間隔は決まりはないですが、私は、録画予約チェックは1時間に1度、ハードチェックは数時間に1度、温度と電圧調査は1時間に2度程度実行しています。
＜編集はcrontab -e、内容表示はcrontab -l＞
25,55 * * * * bash recchk_tmprt_volt.sh
26 4,6,10,13,17-23 * * * bash recchk_hard.sh
27 * * * * bash recchk_reserve_storage.sh
28 * * * * bash recchk_unite.sh
```

ちなみに統合したファイルを開くと↓こんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/5a4530f4-2671-a931-73ca-b8966b43469f.png)
ブラウザのブクマに入れて定期的に確認する、Androidならsamba上のこのファイルに対してショートカットを作るなどするといいのではないでしょうか。