それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Rapiをリモコン操作して、omxplayer をTVのリモコンで操作する。

この記事は Raspberry Pi Advent Calendar 2017 にあわせて書きました。

https://qiita.com/advent-calendar/2017/raspberry-pi

Raspberry Pi をTVのリモコンで操作する。

最近、Raspi で 動画を見てるんですよ。AppleTVやChromeCastやFireTVもあるんだけど、不自由なOSより自由にカスタマイズ出来るやつがやっぱり嬉しい。

Raspi は リモコンで操作するが出来る

これも以前試したんだけど、KODIならリモコンで操作が出来るんですね。

takuya-1st.hatenablog.jp

リモコンの操作をもっと自由に割当てたい。

TVのリモコンはもっと自由に使えたら良いんでですよ。

cec を使えば、TVのリモコンから信号が送れるよ!

f:id:takuya_1st:20171227172117p:plain

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を強引に使うクライアント書いたよ!

gist.github.com

omxplayerとCECラッピングしたもの

書いたよ ごめんなさい、時間無くて作れてません。 年末年始で作るのでよろしくお願いします。

python のsubprocessでomxplayer をテレビリモコンから使うやつ

gist.github.com

github にレポジトリ作った

https://github.com/takuya/omxplayer-with-tvremote

まとめ

RaspiをHDMIでテレビと繋いでると、テレビのリモコンでRaspiを操作できる。

どのボタンが押されてるか取得できる。

押されたボタンによって、起動するコマンドを変えて遊べる。

動画再生と組合せるとメッチャ便利。

組合せは使う人の発想次第でいくらでも、可能性は無限大。自由なソフトウェアは素晴らしい!!!

更新

2018-01-03 作りました

2018/01/03 github にレポジトリ作った

tcpdump で IPv6 のping(icmp)を取り出す

tcpdump で ping6 のパケットを取り出す。

icmp じゃなくて icmp6 を使う。

$ sudo tcpdump icmp6
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:55:58.371580 IP6 ::1:6203:8ff:fea1:820c > ::1:ba27:ebff:feac:e381: ICMP6, echo request, seq 22, length 16

ping6 だし、tcpdump6 かな?と一瞬思ったけど、 tcptcp なのでv6 じゃないよねと思った。

iptablesで224.0.0.251のApple Bonjour で通信ができなかった問題を解決した

224.0.0.251 のパケットまで止まってしまった。

iptables を設定したら、 ホスト名でSSHができなくなった。

sshできなかったので、最初は、iptablesssh を止めてしまったのかと青ざめたけど、ログを見たら224.0.0.251 宛のパケットが来てた。コレなんだと思ったらBonjourIPアドレスだった

Bonjour をdig コマンドラインから使う。

Bonjour の名前解決を、dig コマンドラインから行ってみる。

takuya@~$ dig +short raspi3.local. @224.0.0.251 -p 5353
192.168.20.3

iptablesBonjour のパケットを通してあげる。

dig でパケットの仕組みが少しわかったので、この仕組みを使って、iptablesを設定したRaspberry Pi に設定してあげる。

-A INPUT -p udp -m udp --dport 5353 -j ACCEPT

Bonjourあると便利だと思っていた、なるほどこうなってるのか。

参考資料

Netatalk - ArchWiki

mDNS を使いローカルマシン内の仮想環境に接続する - 破棄されたブログ