気の向くままに辿るIT/ICT/IoT
IoT・電子工作

Raspberry Pi 3 Model B+自作スマートスピーカーの自動起動設定

ホーム前へ次へ
Raspberry Piって?

Raspberry Pi 3 Model B+自作スマートスピーカーの自動起動設定

Raspberry Pi 3 Model B+自作スマートスピーカーの自動起動設定

2019/01/04

 以前、作って運用しつつもブラッシュアップ中のRaspberry Pi 3 Model B+/Raspbian StretchとJulius、Open JTalkベースの自作スマートスピーカーがあります。

 主な機能は、

 尚、ラズパイ用ACアダプタを挿したスイッチ付きコンセントでのON/OFFとは別にラズパイ用boot/reboot/shutdown物理ボタン付き。

 音声認識にJuliusを使った自作スマートスピーカーに伝言とメモの機能を実装するにあたり、マイクとスピーカーを専有してしまうOSSやALSAからPulseAudioに移行しました。

 ちなみに便利なのでラズパイだけでなく、PC/Debianにも自作スマートスピーカー機能を搭載しています。

 自ずとモニタ付きとなるPC版スマートスピーカーには、PC及びラズパイ双方のスマートスピーカー機能のデスクトップアプリとしてPyQt5/Qt Designerによる操作パネルも作成しました。

自動起動設定

 今回は、この自作スマートスピーカーを自動で起動するようにしてみることにしました。

 尚、自作スマートスピーカー機能を搭載したPC/Debianでは、/etc/rc.localなどを使って既に自動で起動させており、この時点でRaspberry Pi/Raspbian Stretchでも同じ手法が使えるのかについては未知数でしたが、実際には、他の方法(systemd)を取る必要がありました。

自動起動時に実行するスクリプトの作成

$ chmod +x diy_smartspeaker.sh
$ cat diy_smartspeaker.sh
#!/bin/sh
 
export ALSADEV=plughw:1,0
echo $ALSADEV
 
julius -C /path/to/dictation-kit-v4.4/mydebug.conf -C /path/to/dictation-kit-v4.4/am-gmm.jconf -module &
 
echo "Julius start..."
 
sleep 2
 
/path/to/voicerecieve.pl &
 
echo "Original Script start..."
$

 後述のsystemdの.serviceファイルから起動させるスクリプトdiy_smartspeaker.shは、こんな風にしてみました。

 Raspberry Pi/Julius/Open JTalkで『スマートスピーカー』を作る冒頭で追記した通り、マイク利用にあたり、ossではなくalsaを使うべくconfigureし直す必要のあるRaspberry Pi 3 Model B+/Raspbian Stretch 9.6の場合、そもそも環境変数AUDIODEVの設定は不要、先のノートパソコン版スマートスピーカーでは別途設定を要したALSADEVも自動的に設定される...。

 が、確かにecho $ALSADEVには設定されてはいますが、Juliusの起動タイミングと「微妙に」合わないようでJuliusが起動しない為、あえて自作スクリプトで設定したところ、Juliusも起動しました。

 ちなみにノートPC版のように/etc/environmentにも設定してはみましたが、ラズパイとはタイミングが異なるようでJuliusは起動しませんでした。

 尚、万一の時、再起動しなくても使えるよう、ここからexportとecho文を除いたものを別ファイルとしてホームディレクトリに置いてあります。

#!/bin/sh
 
export ALSADEV=plughw:1,0 && \
 
julius -C /path/to/dictation-kit-v4.4/mydebug.conf -C /path/to/dictation-kit-v4.4/am-gmm.jconf -module &
 
sleep 15
 
/path/to/voicerecieve.pl &
2019/02/08

 &&でつなげた、こっちの方がよいかも?

 sleepも長めの方が良さげ。

2019/06/11

 JuliusのPulseAudio対応によるスクリプト編集・更新しました。

#!/bin/sh
 
# なぜかログが増殖した時の名残
find /var/log/ -type f -name \* -exec cp -f /dev/null {} \;
 
# 実行コマンド
CMD="/home/xxx/.local/bin/youtube-dl --ignore-errors --no-warnings --get-id"
 
# 任意のプレイリスト
chan1="https://www.youtube.com/watch?list=aaa"
chan2="https://www.youtube.com/watch?list=bbb"
chan3="https://www.youtube.com/watch?list=ccc"
chan4="https://www.youtube.com/watch?list=ddd"
 
# プレイリスト保存ファイル
fpath=/home/xxx/path/to/youtube_plist
fchan1="$fpath/aaa.id"
fchan2="$fpath/bbb.id"
fchan3="$fpath/ccc.id"
fchan4="$fpath/ddd.id"
 
# 起算日付保存ファイルと出力結果保存変数
logf="/home/xxx/path/to/dldate"
catlog=`cat $logf`
 
# ファイル存在確認フラグ
isf=0
# ダウンロード要/不要フラグ
dlon=0
 
# プレイリスト保存ファイルの存在とカラでないことをチェック
if [ -s $fchan1 -a -s $fchan2 -a -s $fchan3 -a -s $fchan4 ]
then
  $isf=1
fi
# 前回のダウンロードから7日経過しているかチェック
if [ `date -d "$catlog 7 days" +%s` -gt `date -d "\`date +%Y%m%d\`" '+%s'` ]
then
  :
else
  date +%Y%m%d > $logf
  $dlon=1
fi
# プレイリストがカラか前回ダウンロードから7日以上経っていたらプレイリストをダウンロード
if [ $isf -eq 0 -o $dlon -eq 1 ]
then
  $CMD $chan1 > $fchan1 &
  $CMD $chan2 > $fchan2 &
  $CMD $chan3 > $fchan3 &
  $CMD $chan4 > $fchan4 &
fi
 
# 念の為、既存のプロセスがあった場合、停止
pkill -f voicerecieve.pl && \
pkill -f julius
 
# 音声認識ソフトJuliusの起動
julius -C /path/to/dictation-kit-v4.4/mydebug.conf -C /path/to/dictation-kit-v4.4/am-gmm.jconf -module &
 
sleep 8
 
# 音声応答スクリプトの起動
/path/to/voicerecieve.pl &
 
# PulseAudioの再起動
pulseaudio -k
2019/12/20

 なんだかんだで現在は、こんな感じ。

自動起動させるためのsystemd .serviceファイルの作成

$ cd /etc/systemd/system
$ sudo cp dhcpcd5.service mysmartspeaker.service
$ sudo vi mysmartspeaker.service
[Unit]
Description=My Smart Speaker service
Wants=network-online.target
After=network-online.target
 
[Service]
Type=oneshot
ExecStart=/path/to/.mysmartspeaker_target.sh
RemainAfterExit=yes
 
[Install]
WantedBy=multi-user.target
$

 ノートPC版のように/etc/rc.local他の方法では機能させられなかった為、ラズパイでは、systemdを使うことにしました。

 そのsystemdのmysmartspeaker.serviceファイルは、こんな風にしてみました。

 参考にしたのは、[/etc/systemd/system]、[/usr/lib/systemd]以下のファイル群とsystemd/systemctl本家?ドキュメントsystemd.special.htmlsystemd.service.html

 適当に選んだ元ファイルも参照はしましたが、[Wants=]と[After=]の設定値については、systemd.special.html、他の記述内容については、systemd.service.htmlに詳しく書いてありました。

 ただ、systemdは柔軟に見えるので他にも機能する設定方法はあるのかもしれません。

...
ExecStart=/bin/su - USER /bin/sh -c "/path/to/.mysmartspeaker_target.sh"
...
$

 尚、このままだと結果、Juliusもvoicerecieve.plもroot起動となりますが、ユーザー起動にしたい理由がある場合、ExecStart=の右辺をこのようにすることもできます。

2019/06/11

 JuliusのPulseAudio対応に伴い、ユーザー起動に変更しました。

systemctl操作

$ systemctl status mysmartspeaker.service
...
$ sudo systemctl daemon-reload
$ sudo systemctl start mysmartspeaker.service
$ systemctl status mysmartspeaker.service
...
$ sudo systemctl stop mysmartspeaker.service
$

 作成したサービスの確認には、systemctl status、現在のログイン時のみ有効にするには、systemctl start、停止するには、systemctl stop。

 systemctl start後にsystemctl statusで自作サービスの実行状態を確認できます。

 構成ファイルを変更した場合には、systemctl stop、systemctl disableしてから、systemctl daemon-reload、その後、改めてsystemctl startやsystemctl enable。

 サービスファイル再起動には、現在ログイン中だけに有効なsystemctl restartもあります。

 ちなみにsystemctl startしたサービスをsystemctl statusで確認すると多くの場合、[Active: active (running) ...]となりますが、mysmartspeaker.serviceは、実行するだけで常駐デーモンではないことから[RemainAfterExit=yes]としてあり、[Active: active (exited) ...]となります。

 systemdが、system系のdaemonを意図していることからすると、この使い方が正攻法なのかどうかはわかりませんが、ここでは、期待通りに機能したのでよしとします。

$ sudo systemctl enable mysmartspeaker.service
$ sudo reboot
...

 起動時、再起動時に作成したサービスを実行するには、systemctl enable、取り消すには、systemctl disable、現時点で動いているサービスも止めるには、systemctl stop。

 よって[ExecStart=]で指定したスクリプト等含め、正しく設定できていれば、systemctl enable後、マシンを再起動(毎回起動)することで起動直後からサービスを利用できる状態となります。

 うまく機能しない場合には、systemctl status、journalctlコマンドなどで確認します。

 尤も今回のように起動後には設定済みとなっているALSADEVの設定とJulius起動のタイミングなどについては、あたりを付けるしかないし、ノートPC版の通りじゃうまくいかないから代替手段を...という点は、そうした情報が見つからない限り、試行錯誤するしかありませんが。

Raspberry Piのオートログイン設定

 Raspberry Piの自動ログイン設定は、GUIならメニューから[Raspberry Piの設定]を選択、[システム(System)]タブの[ブート(Boot):]で[デスクトップ(To Desktop)]か[CLI(To CLI)]かを選び、[自動ログイン(Auto Login):]で[現在のユーザーとしてログイン(As current user)]を選択しておけばよいでしょう。

スマートスピーカー用スクリプトの編集

 自動起動時に実行するスクリプト(.serviceファイルのExecStartで設定したもの、例では、.mysmartspeaker_target.sh)で指定したスマートスピーカー用スクリプト(例では、voicerecieve.pl)を確認。

 もし、起動した時に起動音なり、起動メッセージを発するようにしていないのであれば、いつから操作可能になるのかわかりやすいので、そうすべく編集しておくのが賢明。

結果

 ここまでしてあれば、ラズパイの電源を入れるだけでラズパイが自動起動、.serviceファイルで指定した内容が実行され、スマートスピーカーが起動(、そうしておけば、これを知らせる起動メッセージ(音・音声)が流れたり、LEDが点灯したり)し、その時点でスマートスピーカーを使える状態となります。

 もちろん、Web APIなどネット経由で何かするなら事前に有線なり無線なりLANに接続してインターネットに接続できるよう準備しておく必要はあります。

追記

2019/01/17

 時にJuliusと自作スマートスピーカー用スクリプトが正常に起動後、何かの拍子にJuliusだけが落ちた場合、スクリプト側が不慮のエラーにより、端末から起動した場合は、端末上で、自動起動した場合は、シャットダウン時(ラズパイではわかりにくいが、PCだと表示される)にログを吐きまくることがあります。

 結果、/var/log/syslog、/var/log/daemon.logが肥大化、徐々にディスク使用量が増し、酷いと一気に100%にまで達し、起動したように見えて、なぜか、スマートスピーカーが機能しないという事態になります。

/usr/bin/find /var/log/ -type f -name \* -exec /bin/cp -f /dev/null {} \;

 この場合、ラズパイならsystemdの自作スマートスピーカー用.serviceファイルを編集、複数行あっても実行されるので他のExecStart行より前にExecStart行を1行追加し、例えば、全てのログを空にして良ければ、このようなfindコマンドを挿入しておくと良いでしょう。

 もちろん、編集後は、systemctl stop/disable daemon-reload、(start)/enableを忘れずに。

 一方、PCに搭載したスマートスピーカーでは、systemdに変更後、.serviceファイルに追記しても機能せず、自作スマートスピーカー用スクリプト~/.mysmartspeaker_target.shのJuliusを起動する前にsudo付きで、このfindコマンドを入れることで機能しました。(この場合、既にPATHは通っているはずなのでシステムコマンドやシェルコマンドはフルパスである必要はありません。)

ホーム前へ次へ