make the smart speaker smarter 16

05/12

モルモット

Index

USB Devices have reset

ときどき、KURO-RSが全く動かなくなるときが
あって、どうしてかなぁと調べてたら
USBコントローラ(?)でリセットが発生しており
USBデバイスがいつもは/dev/ttyUSB0で認識していたのが
それが発生したときに/dev/ttyUSB1として再認識していた
ようでKURO-RSへのコマンドが失敗するという事象があった。
同様の理由でPasoriも使えない。

こりゃどうしたもんかと。

今まではKURO-RS側は2度目のリセットが発生したときに
/dev/ttyUSB0で認識されいつの間にか直っていたのだが
Pasoriは頑固で元に戻らない。
ケーブル抜き差しで事なきを得ていた。

Watching kernel message

簡単な対処として監視プログラムを動かすことにした。
/var/log/kern.logにリセットのログが出力されたら
意図的にもう一度リセットさせて認識するデバイスファイルを
強引に書き換える。

sequenceDiagram
  Kernel ->> Kernel : Something occured
  Kernel ->> device file : ttyUSB0->ttsUSB1
  Kernel ->> kern.log : Reset event occured
  Watch Program ->> kern.log : Watching
  Watch Program ->> Watch Program : The event was found!
  Watch Program ->> Kernel : ioctl USBDEVFS_RESET
  Kernel ->> device file : ttyUSB1->ttsUSB0
  Kernel ->> kern.log : Reset event occured
  Watch Program ->> Watch Program : Was the device file changed into ttyUSB0?

こんな感じのものをつくる。
ただこれだとPasoriは救えないが
とりあえずはKURO-RSだけ救おうかなと。

Reset command

調べると既に同じ体験をされている方がいて
リセットコマンドを作っている先輩がいた。
ありがたく使わせていただく。

使い方は

$ usbdevicereset.sh 054c:06c3
Resetting USB device /dev/bus/usb/xxx/xxx
Reset successful
$

Watch Program

次に監視プログラムを。

#!/bin/bash

LOGFILE=/var/log/kern.log
MESSAGE='usb.*1\-1\.XXX.*reset' #トリガーとなるメッセージ。XXXにUSBポート番号を。
USBDEVCMD=`which lsusb`
AWKCMD=`which awk`
GREPCMD=`which grep`
CATCMD=`which cat`
SUDOCMD=`which sudo`
TAILCMD=`which tail`
FINDCMD=`which find`
RESETCMD=`which usbdevicereset.sh`
USBADDR='XXXX:XXXX' #USBデバイスのID
USBTTYDEV='/dev/ttyUSB0' #期待するデバイスファイル
CHECKFILE=/tmp/${0}.check

#check environment
if [ "x$SUDOCMD" == "x" \
-o "x$CATCMD" == "x" \
-o "x$GREPCMD" == "x" \
-o "x$USBDEVCMD" == "x" \
-o "x$RESETCMD" == "x" \
-o "x$AWKCMD" == "x" \
-o "x$TAILCMD" == "x" \
-o "x$FINDCMD" == "x" ];
then
echo "some comand[s] was/were not found"
exit 1
fi

if [ ! -f $LOGFILE ];
then
echo "log file was not found"
echo "log file is [${LOGFILE}]"
exit 1
fi

#functions
checkaddress () {
$USBDEVCMD |\
$GREPCMD $USBADDR >/dev/null 2>&1 && \
echo -n "OK" || echo -n "!"
}

watchcheckfile () {
if [ ! -f $CHECKFILE ];
then
echo -n "OK"
fi
$FINDCMD `dirname $CHECKFILE` -type f -mtime +1 -print 2>/dev/null |\
$GREPCMD `basename $CHECKFILE` >/dev/null 2>&1 && \
echo -n "OK" || echo -n "!"
}

watchreset () {
$CATCMD $LOGFILE |\
$GREPCMD "${MESSAGE}" >/dev/null 2>&1 && \
echo -n "OK" || echo -n "!"
}

usbreset () {
$RESETCMD $USBADDR |\
$GREPCMD "Reset successful" >/dev/null 2>&1 && \
$CATCMD $LOGFILE |\
$TAIL -1 |\
$GREPCMD $USBTTYDEV >/dev/null 2>&1 && \
echo -n "OK" || echo -n "!"
}

#main

#check usb address
ret=`checkaddress`
if [ "x$ret" == "x!" -o "x$ret" == "x" ];
then
echo "usb device was not found"
exit 1
fi

#watch checkfile
ret=`watchcheckfile`
if [ "x$ret" == "x!" -o "x$ret" == "x" ];
then
exit 0
fi

#watch usbdevice reset
ret=`watchreset`
if [ "x$ret" == "x!" -o "x$ret" == "x" ];
then
exit 0
fi

#reset usbdevice
ret=`usbreset`
if [ "x$ret" == "x!" -o "x$ret" == "x" ];
then
ret=`usbreset`
if [ "x$ret" == "x!" -o "x$ret" == "x" ];
then
echo "FAIL!!!"
exit 1
else
touch $CHECKFILE
exit 0
fi
fi

これをwatchusbdevice.shのようなファイル名で保存。
使い方は

$ ./watchusbdevice.sh

これをcronにでも仕込んでおく。

10 0 * * * /srv/google-home-helper/watchusbdevice.sh

まだテストしてないけど
これでうまくいってもPasoriの方はどうしようも
ないので、こっちは別に考えなくてはいけないな。

Next is…

次は、不在時にあったことをまとめて帰宅時に
教えてくれる仕組みを作りたい。

私「OK Google,ただいま。」
ぐ「おかえりなさい。不在時の5月11日 7時37分から5月11日 22時05分までの出来事は、、、」
ぐ「11時15分、任天堂のつぶやきが更新されました。」
ぐ「19時2分、誰かが部屋に入っていました。」
ぐ「19時5分、電気が付きました。」
ぐ「19時10分、加湿器が付きました。」
ぐ「21時00分、兄者弟者の動画が更新されました。」

このくらいは言えるかな。
ちょっとやってみようかな。


コメント: