Help us understand the problem. What is going on with this article?

トニー・スタークの家にありそうなスマート・テーブル :-)

■はじめに

GoogleHome とか AmazonEcho のスマートスピーカーは便利で楽しいのですが、実用面を考えるとなんでも音声で操作というのは正直面倒に感じるときがあります。
例えば TV の音量上げるとかチャンネル切り替えとか、繰り返しの操作は音声だとかえって煩雑で TV リモコンでやってしまったほうが早いですね。

でも・・・リモコンってよく無くしちゃいますよね~使いたい時に限って見つからない(汗)

いっその事 リビングのテーブルに全部のリモコンまとめて埋め込んじゃえ!ということでスマートテーブルっぽいものを作ってみました。

普通のリモコンをテーブルに固定すると邪魔だし、そもそもかっこ悪いので、薄いタッチパネルみたいなもので机の利便性は損ねずに、でも机を削ってタブレット埋め込みとかプロジェクタ投影とかお金かかりそうな面倒なのは避ける方法で実現しました。

ぱっと見 Iron Man のトニースタークの家にありそうなちょっとだけ SF っぽいテーブルになりました。実用性もなかなかで家族で便利に使っています。。
pad3.png

■デモ動画

何はともあれまずはデモをご覧ください。

テーブルの上のタッチボタンの Amazon ボタンを押すと TV の電源がOnになり、自動的に Amazon FireTV に切り替わります。Youtube ボタンを押すと chromecast に切り替わり Youtube 再生時は一時停止や早送り・巻き戻しなど可能です。PS4 ボタンを押せば PS4 の電源が On になり自動で torne 起動、タッチボタンの再生・カーソルボタンで操作出来てなかなか実用的です。
机には超薄型のパネル・シールを張っているだけなのでもちろん机の実用性は一切損なっていません。
上から透明の防水耐熱フィルムを張っているので、上に熱いものを乗せたり水をこぼしても大丈夫です♪

■全体図

この機能は以下のような機器の組合せで実現しています。
tableqiita.png

■使うデバイス

●タッチボタン・シール(MATRIX KeyPad)

Amazon で以下のタッチボタン・シールを購入し机の上に張っています。
とても薄いシートで 4x4 のマトリックス・ボタンを内蔵しています。(一つ150円という安さも魅力です☆)

https://www.amazon.co.jp/gp/product/B010Q17I8E
pad4.png

●Raspberry Pi

机の下には Raspberry Pi Zero WH を仕込んで机の上に張っているタッチボタン・シールと GPIO で接続しています。

上記のタッチボタン・シールは Python 向けにライブラリが公開されていてラズパイから非常に簡単に利用可能です。

[参考記事] pad4pi [LINK]

●スマートリモコン・黒豆 (Broadlink RM Mini 3)

ラズパイなどから赤外線リモコンを持つ家電などをコントロールできる赤外線送信コマンダーです。スマートホームには欠かせないアイテムです♪
今回は TV や PS4 の制御などで使用しています。

ラズパイからの制御は python-broadlink と IFTTT・IHCアプリを利用した2通りの制御方法を使用しています。(python-broadlink だとローカルでの制御になるので反応速度は早くて良いのですが稀に制御が効かないので そのようなときはクラウド経由で IHC アプリで設定したコマンドを IFTTT 経由で叩いています)

[参考記事] Google Homeに話しかけてエアコンを操作してみる [LINK]

●Google Home

机のタッチボタンの操作に応じて必要な情報を GoogleHome から音声でアナウンスします。アナログなボタンだけだとちゃんと動いているか見た目で判断できないので押したボタンに応じて GoogleHomeがいろいろしゃべるようにしています。(例えばAmazonPrimeを起動しますとか)
興味のある方は google-home-notifier で検索したり以下の参考記事をどうぞ。
任意のテキスト読み上げやMP3を GoogleHome で再生できます。

[参考記事] google-home-notifierを使ってGoogleHomeに喋らせる [LINK]

● PS4 (操作対象機器)

テーブル上のボタンで PS4 の電源をOnにしたり、torne を起動したり操作したりできます。
PS4 は以下参考記事で紹介されている PS4-Waker というコマンドで電源起動やアプリ起動が可能です。起動後の操作は PS4-Waker は限界があるので HDMI-CEC 機能を利用して、TV リモコンの信号を使って torne など操作しています。

[参考記事] Google Homeに話しかけてPS4を操作してみる [LINK]

● Amazon FireTV(操作対象機器)

テーブル上のボタンで FireTV を起動したり、操作することができます。
動画の検索はボタンよりも声が便利なのでそこは Amazon Echo を併用しています。
Amazon FireTV は中身は Android なので Wifi 経由で遠隔操作可能です。
ラズパイに ADB (Android Debug Bridge) という Android 開発ツールをインストールして FireTV 側の USB デバッグを有効にすると使えます。

[参考記事] Is it possible to control android TV with Raspberry pi over wi-fi? [LINK]
[参考記事] Amazon:adbを使用してFire TVに接続する方法 [LINK]

そのほか上記 ADB コマンドを WebAPI 経由で制御できる以下のようなラッパーもあります。ADBコマンドを直接使う場合にも FireTV の制御方法の参考になります。

[参考記事] python-firetv [LINK]

● Google Chromecast(操作対象機器)

chromecast は TV に接続して Youtube などの動画や写真を再生できて、Google Home と一緒に使えばさらに便利なおすすめデバイスです。
テーブル上のボタンで chromecast を起動したり、Youtubeを操作したりできます。
再生動画の指定は声が便利なのでそこは GoogleHome に命令しています。
上でご紹介している google-home-notifier をインストールすると node で chromecast API が使えるようになる castv2-client というものがインストールされるのですが、Google Home をしゃべらせるだけでなく、TV で再生中の Youtube に接続して再生とか一時停止・シークなどの操作も出来るようになります。

■コード

それぞれの機能について以下にコードを貼っておきます。

KeyPad の制御のみで実際の機器制御は別コード(keypad_sub.py)に分離しています。

keypad.py
#!/usr/bin/env python
#-*- coding: utf-8 -*-

from pad4pi import rpi_gpio
import time
import keypad_sub

# Setup Keypad
KEYPAD = [
        ["1","2","3","A"],
        ["4","5","6","B"],
        ["7","8","9","C"],
        ["*","0","#","D"]
]

# same as calling: factory.create_4_by_4_keypad, still we put here fyi:
ROW_PINS = [4, 14, 15, 17]
COL_PINS = [18, 27, 22, 23]

factory = rpi_gpio.KeypadFactory()

keypad = factory.create_keypad(keypad=KEYPAD, row_pins=ROW_PINS, col_pins=COL_PINS)

# 入力キーごとの処理
def printKey(key):
  # 入力されたキーの表示
  print(key)

  #------------------------------------------------------------------
  # TV モード
  if (key=="*"):
    keypad_sub.mode_tv()

  # Ch Up
  elif ( keypad_sub.KeyMode=='tv' and key=="5" ):
    keypad_sub.ch_up()
  # Ch Down
  elif ( keypad_sub.KeyMode=='tv' and key=="B" ):
    keypad_sub.ch_down()
  #---------------
  # Up
  elif ( keypad_sub.KeyMode=='tv' and key=="#" ):
    keypad_sub.tv_up()
  # Down
  elif ( keypad_sub.KeyMode=='tv' and key=="6" ):
    keypad_sub.tv_down()
  # Right
  elif ( keypad_sub.KeyMode=='tv' and key=="8" ):
    keypad_sub.tv_right()
  # Left
  elif ( keypad_sub.KeyMode=='tv' and key=="C" ):
    keypad_sub.tv_left()
  # Enter
  elif ( keypad_sub.KeyMode=='tv' and key=="9" ):
    keypad_sub.tv_enter()
  # Back
  elif ( keypad_sub.KeyMode=='tv' and key=="D" ):
    keypad_sub.tv_back()
  # EPG
  elif ( keypad_sub.KeyMode=='tv' and key=="0" ):
    keypad_sub.tv_epg()

  #------------------------------------------------------------------
  # PS4 モード
  elif (key=="7"):
    keypad_sub.mode_ps4()
  # Up
  elif ( keypad_sub.KeyMode=='ps4' and key=="#" ):
    keypad_sub.ps4_up()
  # Down
  elif ( keypad_sub.KeyMode=='ps4' and key=="6" ):
    keypad_sub.ps4_down()
  # Rigth
  elif ( keypad_sub.KeyMode=='ps4' and key=="8" ):
    keypad_sub.ps4_right()
  # Left
  elif ( keypad_sub.KeyMode=='ps4' and key=="C" ):
    keypad_sub.ps4_left()
  # Enter
  elif ( keypad_sub.KeyMode=='ps4' and key=="9" ):
    keypad_sub.ps4_enter()
  # Back
  elif ( keypad_sub.KeyMode=='ps4' and key=="D" ):
    keypad_sub.ps4_back()
  # Play/Pause
  elif ( keypad_sub.KeyMode=='ps4' and key=="0" ):
    keypad_sub.ps4_play()
  # Menu
  elif ( keypad_sub.KeyMode=='ps4' and key=="5" ):
    keypad_sub.ps4_menu()

  #------------------------------------------------------------------
  # プライムモード
  elif (key=="4"):
    keypad_sub.mode_prime()
  # Up
  elif ( keypad_sub.KeyMode=='prime' and key=="#" ):
    keypad_sub.prime_up()
  # Down
  elif ( keypad_sub.KeyMode=='prime' and key=="6" ):
    keypad_sub.prime_down()
  # Rigth
  elif ( keypad_sub.KeyMode=='prime' and key=="8" ):
    keypad_sub.prime_right()
  # Left
  elif ( keypad_sub.KeyMode=='prime' and key=="C" ):
    keypad_sub.prime_left()
  # Enter
  elif ( keypad_sub.KeyMode=='prime' and key=="9" ):
    keypad_sub.prime_enter()
  # Back
  elif ( keypad_sub.KeyMode=='prime' and key=="D" ):
    keypad_sub.prime_back()
  # Play/Pause
  elif ( keypad_sub.KeyMode=='prime' and key=="0" ):
    keypad_sub.prime_play()
  # Menu
  elif ( keypad_sub.KeyMode=='prime' and key=="5" ):
    keypad_sub.prime_menu()
  # Home
  elif ( keypad_sub.KeyMode=='prime' and key=="B" ):
    keypad_sub.prime_home()

  #------------------------------------------------------------------
  # YouTube モード / Switch モードトグル切替
  elif (key=="1"):
      if ( keypad_sub.KeyMode=='youtube' ):
          keypad_sub.mode_switch()
      else:
          keypad_sub.mode_youtube()
  # Rigth
  elif ( keypad_sub.KeyMode=='youtube' and key=="8" ):
    keypad_sub.youtube_right()
  # Left
  elif ( keypad_sub.KeyMode=='youtube' and key=="C" ):
    keypad_sub.youtube_left()
  # Enter
  elif ( keypad_sub.KeyMode=='youtube' and key=="9" ):
    keypad_sub.youtube_enter()
  # Play/Pause
  elif ( keypad_sub.KeyMode=='youtube' and key=="0" ):
    keypad_sub.youtube_play()

  #------------------------------------------------------------------
  # TVミュート
  elif (key=="3"):
    keypad_sub.mute()
  # TV音量UP
  elif (key=="2"):
    keypad_sub.vol_up()
  # TV音量DOWN
  elif (key=="A"):
    keypad_sub.vol_down()

# printKey will be called each time a keypad button is pressed
keypad.registerKeyPressHandler(printKey)

print('Startup Keypad')

try:
  while(True):
    time.sleep(0.2)
except:
 keypad.cleanup()


  
  
上記のコードから呼ばれる ADB を経由した FireTV の制御や黒豆の制御を実際に行うコードです。

keypad_sub.py
#!/usr/bin/env python
#-*- coding: utf-8 -*-

import time
import os
import subprocess
import threading

#------------------------------------------------------------------
PyBlackPath = '/home/pi/python_code/python-broadlink/cli/'
KeyMode = 'tv'
keyRepeatTimer = time.time()
keyRepeatData = " "

#------------------------------------------------------------------
# 黒豆呼び出し用コマンド
blackBeanCmd = 'sudo ' + PyBlackPath + 'broadlink_cli --device @' + PyBlackPath + 'living/device --send @' + PyBlackPath + 'living/'

# プライムのビデオが再生中ならポーズする ADB コマンド
primePauseCmd = 'adb shell dumpsys window windows | grep mCurrentFocus | grep -q FireTvPlaybackActivity && adb shell dumpsys power | grep Locks | grep -q "size=0" || adb shell input keyevent 127 &'

#------------------------------------------------------------------
# リビングの Home でしゃべる
def googleHomeTalk(message):
    os.system('sudo curl -H \'Content-Type:application/json\' -d \'{ \"mode\":\"talk\", \"command\": \"living\", \"param\": \"' + message + '\", \"param2\": \"??\" }\' -X POST http://192.168.0.128 &' )

#------------------------------------------------------------------
# IFTTT webhook 呼び出し
# 黒豆の設定などは IHC アプリを使用していますが、 
# IFTTT 経由でも IHC で設定した機器を制御できるようにしています。
# python-broadlink からだと稀に制御不能になるので
# バックアップとして IFTTT から制御できるようにしています。
# また Keypad は一度押すとしばらく押しっぱなしになる場合があるので
# チャタリング防止で1秒に1回しか反応しないようにしています。
def iftttWebHook(sendCmd, message=' '):
    global keyRepeatTimer
    global keyRepeatData
    try:
        if( keyRepeatData == sendCmd and (time.time() - keyRepeatTimer) < 1.0 ):
            print("key repeat error")
        else:
            os.system('sudo curl -H \'Content-Type:application/json\' -d \'{ \"value1\": \"' + message + '\" }\' -X POST https://maker.ifttt.com/trigger/' + sendCmd + '/with/key/xxxxxxxxxx &' )
        print("send = " + sendCmd )
        keyRepeatData = sendCmd
        keyRepeatTimer = time.time()
    except:
        print("IFTTT 黒豆エラー 再起動中")

#------------------------------------------------------------------
# 黒豆にコマンド送信
def sendBlackBean(sendCmd):
    global keyRepeatTimer
    global keyRepeatData
    try:
        if( keyRepeatData == sendCmd and (time.time() - keyRepeatTimer) < 1.0 ):
            print("key repeat error")
        else:
            subprocess.check_call( blackBeanCmd + sendCmd, shell=True )
            print("send = " + sendCmd )
        keyRepeatData = sendCmd
        keyRepeatTimer = time.time()
    except:
        # スマートスイッチを持っているなら、黒豆の電源につないで
        # 黒豆への接続がエラーの時には強制電源再起動するのがおすすめです
        # 複雑になるので今回のサンプルからはその部分は割愛しました
        print("黒豆エラー 再起動中")

#------------------------------------------------------------------
# TV モード
# 切り替え
# TV電源状態にかかわらず最初にTV電源Onを送信してその直後に地デジ切り替え送信
# 最後にもう一度地デジ切り替えを送信しています
# TV 電源がOnでもOffでもどちらでも確実に TV を点けて地デジに切り替えるための工夫です。
# 他の方法としては、消費電力測定機能付きのスマートプラグを持っているなら TV 電源に繋ぎ、
# TV電源状態に応じて呼び出すOn/Off処理を切り替えるなども有効です。
# sendBlackBean と iftttWebHook は経路が違うだけでどちらも黒豆にコマンド送信します
# 同じコマンドを2回送信して差支えないものはバックアップかねて両方の経路で呼び出しています。
def mode_tv():
   print('TV mode')
   global KeyMode
   KeyMode = 'tv'
   sendBlackBean( 'tv-on' ) # 最初に TV 電源をOnにする。
   iftttWebHook("living_tv_on") # すでにOn状態ならこれは無視される
   sendBlackBean( 'tv-ch-chideji' ) # TV を地デジモードに切り替える。
   iftttWebHook("living_tv_chideji") # TV電源On直後は無視されるため、最初からTV電源Onだった場合のみ有効
   googleHomeTalk("テレビモードに切り替えました")
   #プライムで動画再生中ならポーズ
   os.system( primePauseCmd )
   time.sleep(5) # TV電源On後 機器が安定するまでしばらく待つ
   sendBlackBean( 'tv-ch-chideji' ) # もう一度地デジモード呼び出し。
   iftttWebHook("living_tv_chideji") # 電源Onされた場合はここで初めて地デジに切り替わる

# Ch Up&TV ON
def ch_up():
    print('TV ch up')
    sendBlackBean( 'tv-ch-up &' )
# Ch Down&TV ON
def ch_down():
    print('TV ch down')
    sendBlackBean( 'tv-ch-down &' )
# Up
def tv_up():
   print('TV up')
   sendBlackBean( 'tv-up' )
# Down
def tv_down():
   print('TV down')
   sendBlackBean( 'tv-down' )
# Right
def tv_right():
   print('TV right')
   sendBlackBean( 'tv-right' )
# Left
def tv_left():
   print('TV left')
   sendBlackBean( 'tv-left' )
# Enter
def tv_enter():
   print('TV enter')
   sendBlackBean( 'tv-enter' )
# Back
def tv_back():
   print('TV back')
   sendBlackBean( 'tv-back' )
# EPG
def tv_epg():
   print('TV EPG')
   sendBlackBean( 'tv-epg' )
# MENU
def tv_menu():
   print('TV menu')
   sendBlackBean( 'tv-menu' )

#------------------------------------------------------------------
# PS4 モード
# 切り替え
def mode_ps4():
   print('ps4 mode')
   global KeyMode
   KeyMode = 'ps4'
   sendBlackBean( 'tv-on' )
   iftttWebHook("living_tv_on")
   sendBlackBean( 'tv-hdmi1' )
   iftttWebHook("living_tv_hdmi1")
   googleHomeTalk("ピーエスフォー モードに切り替えました")
   os.system('/home/pi/ps4boot.sh &' ) # PS4 接続
   #プライムで動画再生中ならポーズ
   os.system( primePauseCmd )
   time.sleep(5)
   sendBlackBean( 'tv-hdmi1' )
   iftttWebHook("living_tv_hdmi1")

# Up
def ps4_up():
   print('ps4 up')
   sendBlackBean( 'tv-up &' )
# Down
def ps4_down():
   print('ps4 down')
   sendBlackBean( 'tv-down &' )
# Right
def ps4_right():
   print('ps4 right')
   sendBlackBean( 'tv-right &' )
# Left
def ps4_left():
   print('ps4 left')
   sendBlackBean( 'tv-left &' )
# Enter
def ps4_enter():
   print('ps4 enter')
   sendBlackBean( 'tv-enter' )
# Back
def ps4_back():
   print('ps4 back')
   sendBlackBean( 'tv-back' )
# Play
def ps4_play():
   print('ps4 play')
   sendBlackBean( 'tv-enter' )
# Menu
def ps4_menu():
   print('ps4 menu')
   sendBlackBean( 'tv-submenu' )

#------------------------------------------------------------------
# Prime モード
# 切り替え
def mode_prime():
   print('Prime mode')
   global KeyMode
   KeyMode = 'prime'
   os.system('/home/pi/fireTVboot.sh &' ) # 接続
   sendBlackBean( 'tv-on' )
   iftttWebHook("living_tv_on")
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi-sw1' ) # TVのHDMI2に接続しているIRリモコン対応HDMI切替機へのコマンド
   iftttWebHook("living_hdmi_sw1")
   googleHomeTalk("プライム モードに切り替えました")
   time.sleep(6)
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi_hdmi_sw1' )
   iftttWebHook("living_hdmi_sw1")

# Up
def prime_up():
   print('prime up')
   os.system('sudo adb shell input keyevent 19 &' ) # up
# Down
def prime_down():
   print('prime down')
   os.system('sudo adb shell input keyevent 20 &' ) # down
# Rigth
def prime_right():
   print('prime right')
   os.system('sudo adb shell input keyevent 22 &' ) # right
# Left
def prime_left():
   print('prime left')
   os.system('sudo adb shell input keyevent 21 &' )# left
# Enter
def prime_enter():
   print('prime enter')
   # os.system('sudo adb shell input keyevent 66 &' ) # enter
   os.system('sudo adb shell input keyevent 23 &' ) # center
# Back
def prime_back():
   print('prime back')
   os.system('sudo adb shell input keyevent 4 &' ) # back
# Play/Pause
def prime_play():
   print('prime play')
   #os.system('sudo adb shell input keyevent 127 &' ) # pause
   os.system('sudo adb shell input keyevent 85 &' ) # play/pause
# Menu
def prime_menu():
   print('prime Menu')
   os.system('sudo adb shell input keyevent 1 &' ) # menu
# Home
def prime_home():
   print('prime home')
   os.system('sudo adb shell input keyevent 3 &' ) # home

#------------------------------------------------------------------
# YouTube モード
def mode_youtube():
   print('youtube mode')
   global KeyMode
   KeyMode = 'youtube'
   sendBlackBean( 'tv-on' )
   iftttWebHook("living_tv_on")
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi-sw2' ) 
   iftttWebHook("living_hdmi_sw2")
   googleHomeTalk("ユーチューブ モードに切り替えました")
   #プライムで動画再生中ならポーズ
   os.system( primePauseCmd )
   time.sleep(5)
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi-sw2' )
   iftttWebHook("living_hdmi_sw2")

# Rigth
def youtube_right():
   print('youtube right')
   os.system('sudo node chromecast-ctrl.js forward')
# Left
def youtube_left():
   print('youtube left')
   os.system('sudo node chromecast-ctrl.js back')
# Enter
def youtube_enter():
   print('youtube enter')
   os.system('sudo node chromecast-ctrl.js play')
# Play/Pause
def youtube_play():
   print('youtube play')
   os.system('sudo node chromecast-ctrl.js play')

#------------------------------------------------------------------
# Switch モード
def mode_switch():
   print('switch mode')
   global KeyMode
   KeyMode = 'switch'
   sendBlackBean( 'tv-on' )
   iftttWebHook("living_tv_on")
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi-sw5' ) 
   iftttWebHook("living_hdmi_sw5")
   googleHomeTalk("スイッチ モードに切り替えました")
   #プライムで動画再生中ならポーズ
   os.system( primePauseCmd )
   time.sleep(5)
   sendBlackBean( 'tv-hdmi2' )
   iftttWebHook("living_tv_hdmi2")
   sendBlackBean( 'hdmi-sw5' )
   iftttWebHook("living_hdmi_sw5")

#------------------------------------------------------------------
# TVミュート&TV ON 
# TV電源がOffの場合には実質 TV On のみが有効になる
# 逆に TV 電源が ON の時には再度 On を送信しても状態変わらずミュートのみ有効
def mute():
  print('TV mute')
  global KeyMode
  iftttWebHook( 'living_tv-mute' )
  iftttWebHook("living_tv_on")

#------------------------------------------------------------------
# TV音量UP 異なる経路で2回コマンド送信ため音量2段階変わる
def vol_up():
  print('TV vol up')
  sendBlackBean("tv_vol_up")
  iftttWebHook("living_tv_vol_up")

# TV音量DOWN
def vol_down():
  print('TV vol down')
  sendBlackBean("tv_vol_down")
  iftttWebHook("living_tv_vol_down")


  
  
上記の python コードから呼ばれるスクリプトです。
Amazon FireTV を制御するときに最初に呼び出されます。
事前に ADB をインストールしておく必要があります。
ADB 経由で FireTV の接続確認や電源復帰、Homeに戻る処理など制御に必要な処理をまとめて行っています。
FireTV は長時間使用しないと元電源から消えて以下では接続できないときがあるので、スマートスイッチを電源との間に挟んでおいて、FireTV から反応無い時は強制的に電源再起動などの機能を入れるとより確実です。
※LAN 経由での機器接続を簡単にするために DHCP 設定で FireTV の MAC アドレスに固定の IP アドレスを割り当てる設定をしておくと便利です。

fireTVboot.sh
#!/bin/bash

sudo adb devices
sudo adb connect 192.168.0.210:5555

sleep 2

adb devices | grep -q 192

if [ $? = 0 ]; then
  echo "接続成功"
else
  echo "接続失敗"
  # スマートスイッチを持っているならここに FireTV 電源強制再起動のコードを追加してください☆
  sleep 30
  sudo adb connect 192.168.0.210:5555
fi

# power key (スリープから復帰)
adb shell dumpsys power | grep 'Display Power' | grep -q 'state=ON' || adb shell input keyevent 26
sleep 1
# home key(動画再生中でなければ Home 画面に戻す)
adb shell dumpsys window windows | grep mCurrentFocus | grep -q FireTvPlaybackActivity || adb shell input keyevent 3

  
  
上記の python コードから呼ばれるスクリプトです。
PS4 を起動したり、ゲームが起動中でなければ(誰かがPS4で遊んでいなければ)torne アプリを自動起動したりします。
事前に PS4-Waker をインストールしておく必要があります。
ps4-waker は PS4 とアプリの起動でだけ使用して実際の PS4 の操作(↑↓←→移動とかOX)は HDMI-CEC 機能を使って TV のリモコン信号を送信して制御しています。
ちなみに PS4-Waker には node 用の API もあって、コマンドを繰り返し呼び出い時はそちらを使えば毎回ログインしないので便利です。

ps4boot.sh
#!/bin/bash

sudo ps4-waker check | grep -q "running-app-name" || sudo ps4-waker start CUSA00442


  
  
cast API を利用して TV に接続された chromecast 上で再生されている youtube などの動画の制御をおこなうためのコードです。上記 Python コードから呼び出される想定です。
事前に google-home-notifier をインストールしておく必要があります。
※LAN 経由での機器接続を簡単にするために DHCP 設定で chromecast の MAC アドレスに固定の IP アドレスを割り当てる設定をしておくと便利です。

chromecast-ctrl.js
var Client               = require('castv2-client').Client;
var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;

// 引数チェック
var argExe = process.argv[0];
var argScr = process.argv[1];
if (process.argv.length < 3) {
    console.log('use: ' + argExe + ' ' + argScr + ' [play/back/forward]');
    return;
}

var modeArg = process.argv[2];

ondeviceup("192.168.0.103");

function ondeviceup(host) {

  var client = new Client();
  client.connect(host, function() {

    console.log('Connected');
    client.getSessions(function(err, sessions) {
        const session = sessions[0];
        client.join(session, DefaultMediaReceiver, function(err, app) {
            if (!app.media.currentSession){
                app.getStatus(function(err, status) {
                    console.log( status.playerState );
                    console.log( status.currentTime );
                    if( modeArg == 'play' ){
                        if( status.playerState == 'PLAYING' ){
                           app.pause();
                        } else {
                           app.play();
                        }
                    } else if(modeArg == 'forward' ){
                        app.seek( status.currentTime + 15.0);
                    } else if(modeArg == 'back' ){
                        app.seek( status.currentTime - 15.0);
                    }
                    process.exit(0);
                });
            } else {
                app.play();
               process.exit(0);
            }
         });
      });
   });
}

■最後に

机を一部切り抜いてタブレットを埋め込んだり、天井にプロジェクタとセンサー設置した、より未来感のある実現方法もありますが(トニースタークは多分こっちの方法ですねw)。

・すごい頑張って机くりぬいてるカッコいい例 [LINK]
・お金かかりそうなテーブル全面を巨大タブレットにしちゃってる例 [LINK]
・展示会とかでありがちなプロジェクタ&センサー使用例 [LINK]
 これは SONY から製品出てますね :D

※あとは電子ペーパーとか液晶モニタ向け後付けタッチパネルとかも考えましたが、割と大きなサイズの物しかないのでテーブルに貼るには邪魔なので止めました。

今回は家庭環境で日常利用することや、コンパクトさ、費用なども考えて、かなり現実的な形で実装できたかなと思います。
タッチパネル・シールは非常に薄いのでテーブルの利用を阻害せず(しかも一枚150円という激安価格!!!)かつリビングで利用する AV 機器などを一括してコントロールできるのでとても実用的なスマート・テーブルになりました。

このタッチパネルから制御できるのと同じコマンドを GoogleHome などにも用意しておくと、タッチパネルでも声でもそれぞれの機器のリモコンでもどれでも操作できるので状況や気分に応じて好きなほうから利用できるのでさらに便利になります。
(例えば「OK Google 、Amazonプライムにして」というとアマゾンボタン押したのと同じ処理を実行とか)

今回は一つのボタンを押すと(一部機器の使用状況を見つつも)ある程度マクロ的にまとまった処理が実行されますが、IoT はより進んでいくと、人間が操作しなくても環境や人間の生活の動きに合わせて自動/半自動で機器を制御するのが本命ですね。こーゆー自作スマートホームをやっているとだんだんそーゆーアプローチが増えていきます。
(例えばサーモセンサーでお風呂上がりの火照った体を検出して自動的にエアコンや扇風機を点けたりとか(笑))

※投稿記事一覧

他にも 自分で「おうちハック」した内容を以下に投稿しているので、よろしければ合わせてご覧ください☆

・GoogleHome/AmazonEcho とラズパイでやった事・やりたい事一覧[LINK]
・Google Home でちょっと未来風のスマート TV を作ってみたよ☆[LINK]
・黒豆 (Broadlink RM Mini 3) の IR 信号解析してみたよ♪ [LINK]
・スマートロック SESAME の WEB API が便利だった![LINK]
・Amazon Echo の沢山ある面白スキルを気軽に遊ぶ方法[LINK]
・LINEを「ラズパイのターミナル化&スマートホームのフロントエンド化(ChatOps風)」してみた♪[LINK]
・LINE と Firebase とラズパイを繋いでみたよ☆[LINK]
・GoogleHome と Chromecast でキーワード&画像&Wikipedia検索~TV表示[LINK]
・スマホ ハック&スマートホーム連携 [LINK]
・ラズパイとサーモセンサーで自宅のガスコンロ監視(火の用心) [LINK]
・トニー・スタークの家にありそうなスマート・テーブル(笑) [LINK]

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした