この記事は Raspberry Pi Advent Calendar 2017 にあわせて書きました。
https://qiita.com/advent-calendar/2017/raspberry-pi
Raspberry Pi をTVのリモコンで操作する。
最近、Raspi で 動画を見てるんですよ。AppleTVやChromeCastやFireTVもあるんだけど、不自由なOSより自由にカスタマイズ出来るやつがやっぱり嬉しい。
Raspi は リモコンで操作するが出来る
これも以前試したんだけど、KODIならリモコンで操作が出来るんですね。
リモコンの操作をもっと自由に割当てたい。
TVのリモコンはもっと自由に使えたら良いんでですよ。
cec を使えば、TVのリモコンから信号が送れるよ!
sudo aptitude install cec-utils
CECでRaspi→テレビに命令を送る
cec で使う信号は HDMI を通信ケーブルとして、各種のリンク機構が実現できる。よくビエラリンクだとかファミリリンク機能とか家電メーカーが勝手に名前つけてるアレですね。
テレビ電源をオンにするには
echo 'on 0' | cec-client -s
Raspi 側からテレビに信号を送ることが出来る。今回のエントリはでは、テレビ側からRaspiに信号を送ります。
CECからテレビ→Raspiに命令を送る
通信なんだから、当然逆もできるよね?
Raspi でテレビのリモコンのボタンを受取りする
raspi のSSHにログインして、ターミナルをあけておきます。 そして、おもむろに クライアントを起動します。もちろんTVとHDMI接続をしている前提です。PC用LCDはCEC非対応なので無理です。
$ cec-client
TVのリモコンからボタンをいろいろと押してみます。
すると、テレビのリモコンの押されたボタンが、PRESS/UPなどで表示されるはずです。
TV側でリモコンの連携を設定をしてなければ、上・下・左・右・OK・キャンセル・一時停止くらいでしょうか。
テレビ側で、Raspiの繋がってるHDMIポートをHDDレコーダーとして設定してあげれば、リモコンのチャンネル番号ボタンなども取得できます。
これを強引に監視します。
ほんとうは libcec を使ったプログラミングをしたほうがいいでしょう。 ちゃんとボタンの押下(down)・押上(up)・長押し(press)を取得すれば良いんだろう
けど面倒くさいので、単純化してコンソールの出力を監視します。
仕組みは?こういうことです。
仕組み1:cec-client のデバッグメッセージを監視する
DEBUG: [ 5443] >> TV (0) -> Recorder 1 (1): user control pressed (44) # ←これを取得してgrep でマッチさせる TRAFFIC: [ 5576] >> 01:8b:03 DEBUG: [ 5576] key released: left (3) DEBUG: [ 5577] >> TV (0) -> Recorder 1 (1): vendor remote button up (8B) TRAFFIC: [ 5918] >> 01:44:03
仕組み2:押されたボタンをgrepで強引に取得する。
cec-client のデバッグメッセージを監視、 正規表現で押されたボタンを抜き出します
cec-client | grep --line-buffered -Po '(?<=key pressed: )\w+(?= \(\d, \d\)$)'
仕組み3:ボタンがわかればSwitch/CASE文で何かする。
指定したメッセージが来たら、プログラムにメッセージを送ります。
1行ずつ読み込んで、ボタンが押されたら、なにか関数を実行します。
function onright(){ #「 →:右ボタン」が押されたときの動作 } ## 略 while (略) do case button in right) onright;; left) onleft;; down) ondown;; up) onup;; select) onselect;; play) onplay;; pause) onpause;; forward) onforward;; backward) onbackward;; exit) onexit;; clear) onclear;; *) echo "unrecognized button ($cmd)";; esac done;
実際にやってみる。
だいたい仕組みを考えたところで、TVリモコンの信号を受けてみます。
bash のシェルスクリプトで試してみます。
cec-watcher.sh
button_filter() { \grep --line-buffered -Po '(?<=key pressed: )\w+(?= \(\d, \d\)$)' } echo as | cec-client | button_filter | \ while read cmd; do echo $cmd; done
出来たら実行してみる。
実行し、リモコンを押してみると!
$ bash cec-watcher.sh right left down up pause right right
おおお、ボタンが表示されたよ!
ここまできたら、好きな機能を割当てたい
テレビ側に繋いでいたら、好きな機能をリモコンから呼び出すことが出来ますよね?
たとえば、1押したら、Radiko起動したり、2押したら音声認識が起動してスマート・スピーカーにするとか、3押したらメールを送るとか
なんでもできそうです。
omplayer の制御をする。
omxplayer は raspi でよく使われるプレイヤーです。とても便利です。
御存知の通り omxplayer はキーボードから制御ができます。→ raspberryPi でMP4動画の快適再生するコマンド omxplayer とその使い方(キーボード操作 - それマグで!
omxplayer をコマンドから制御する
omxplayer の標準入力は tty の stdin につながってるので、これを適当なFIFOに繋いであげれば、コマンドから制御ができます。
fifo を作る
mkfifo /tmp/omx-input
omxplayer が fifo から読み込むようにする
omxplayer URL < /tmp/omx-input
omxplayer を遠隔から操作する
p
ボタンは再生・一時停止なので、これを送ってあげたら再生停止が出来るようになります。やったね!
echo -ne p > /tmp/omx-input echo -ne p > /tmp/omx-input echo -ne p > /tmp/omx-input
FIFOとomxplayer のペアと、TVリモコンを取得する仕組みと組み合わせる
omxplayer を起動後に、テレビリモコンから、FIFO に文字を送るように組み合わせてあげれば、omxlayer が FIFO から文字を読み込んで再生・停止早送りをしてくれるようになるのです。やったね!これで制御できるね。
しかもバイナリも出てこないしCライブラリも無い、完全にUNIXのパイプと文字で構成されてる。楽ちんだね。
つまり、このようなコードを書きます
function onright(){ # →が押されたときの動作 } function onplay(){ # play が押されたときの動作 } ## 略 while (略) do case button in right) onright;; play) onplay;; *) echo "unrecognized button ($cmd)";; esac done;
サンプルコード
上記の例を、実際に少し書き加えて動くようなった例です。
omxp-with-cec.sh
このコードのなかでは、 FIFOを /tmp/cmd
としています。
gist.github.com
起動
同動画を再生します。
$omxplayer --hw -o hdmi $URL < /tmp/cmd
別シェルで、リモコンを監視します。
$ bash omxp-with-cec.sh
これで、再生ボタンかOKボタンを押すと再生が始まります!!!!!!!!!!!楽しい
これをPythonのコードにします。
ここまでだと、mkfifo を使って出力を取得しているだけなので、これは単純にパイプ化して、python の subprocess でプロセス制御とSTDIOの監視をしてやれば、完全にリモコンだけで制御出来るようになりますね
Cecを強引に使うクライアント書いたよ!
omxplayerとCECラッピングしたもの
書いたよ
ごめんなさい、時間無くて作れてません。
年末年始で作るのでよろしくお願いします。
python のsubprocessでomxplayer をテレビリモコンから使うやつ
github にレポジトリ作った
https://github.com/takuya/omxplayer-with-tvremote
まとめ
RaspiをHDMIでテレビと繋いでると、テレビのリモコンでRaspiを操作できる。
どのボタンが押されてるか取得できる。
押されたボタンによって、起動するコマンドを変えて遊べる。
動画再生と組合せるとメッチャ便利。
組合せは使う人の発想次第でいくらでも、可能性は無限大。自由なソフトウェアは素晴らしい!!!
更新
2018-01-03 作りました
2018/01/03 github にレポジトリ作った