0
0

XBox ワイヤレスコントローラーを起動したのに合わせてPCを起動させたい

Posted at

Nintendo Switchやプレイステーションでは、コントローラーからゲーム機のコンソールを起動することができて便利です。
これと同じようなことをパソコンでもできないかと思って実践したことを記したいと思います。
なお、私はプログラムに関しては素人なので、汚いソースコートであることはご容赦ください。

準備するもの

  • Raspberry Pi Pico W (以後「ラズパイ」と表記)
  • Xbox ワイヤレスコントローラー (以後「コントローラー」と表記)

前提

  • ラズパイが接続するWi-Fiネットワークと、起動させたいPCが同じネットワークにいること
  • PCがWake on LAN(WoL)で起動できるような設定になっていること
  • ラズパイの操作方法を知っていること
  • IDEはThonnyを使用する

方針

  1. コントローラーを起動する
  2. ラズパイでコントローラーの起動を検知する
  3. ラズパイからPCに向けてWoLを実行する

ソースコード

先にソースに関する説明ですが、main.pyについて、
Wi-Fiに接続するためのSSIDとパスワード情報をSSIDPWに入力してください。
コントローラーのMACアドレスをXBOX_MACADDRに入力する必要がありますが、このアドレスについては後述します。
マジックパケットを送信する対象のPCのIPアドレスをPC_IPADDRに、MACアドレスをPC_MACADDRに入力してください。
なおPCのMACアドレスは16進数の数値を配列形式で入力してください。

引用

ソースのblegamepad.pyは、以下の動画と、その概要に記載されていたGoogleドライブサイトにある同名のPythonコードを参考にしています
#22 ゲームパッドでRaspberry Pi PicoWを操作しよう~DHAの電子工作教室~【Raspberry Pi PicoW】
https://drive.google.com/drive/folders/1h_aNwIv26q8gpyyus-07lHX0YHY2T57M

また、uping.pyについて、本プログラムではpingを送信する必要があるのですがラズパイで使うMicroPythonはpingを実行することができないので、こちらのµPing(uping.py)を使用しています。
https://gist.github.com/shawwwn/91cc8979e33e82af6d99ec34c38195fb

コントローラーを検知する方法について

まず前提として、コントローラーはすでにPCとBluetoothのペアリングが完了している状態とします。
またコントローラーは複数台の(Xbox以外の)機器とのマルチペアリングを組むことはできません。
そのためラズパイとペアリングを組むことはできないのですが、コントローラーはペアリング相手を探している間は常にアドバタイズを行っています。
このプログラムでは、コントローラーがペアリング相手を探している間に発するアドバタイズパケットを拾い、そのパケットが目的のコントローラーから発しているものであるかどうかを判断して後続処理を行うような仕組みとしています。

コントローラーのMACアドレスを調べる

まずは、プログラムをラズパイに投入します。
その際にですが、最初はコントローラーのMACアドレスを調べたいので、blegamepad.pyのソースコードについて、以下のコメントアウトを外してください。

blegamepad.py
    # interrupt function
    def _irq(self, event, data):
        # check event
        if(event == _IRQ_SCAN_RESULT):
            # get scan result            
            (addr_type, addr, adv_type, rssi, adv_data) = data # get detected device data
            mac = decode_addr(list(bytes(addr)))
-           #print( 'FOUND DEVICE! : TYPE={}\tADDR={}\tNAME={}'.format(addr_type, mac, decode_name(adv_data)) )
+           print( 'FOUND DEVICE! : TYPE={}\tADDR={}\tNAME={}'.format(addr_type, mac, decode_name(adv_data)) )
            # device check
            if(mac == self._controller_mac):
                #print( 'FOUND DEVICE! : TYPE={}\tADDR={}\tNAME={}'.format(addr_type, mac, decode_name(adv_data)) )
                self._is_find_controller = True

その状態でmain.pyを実行すると、アドバタイズをしている端末のスキャンを行い、その結果を以下のようにThonnyのシェル上に表示してくれます。
スクリーンショット 2024-10-06 094931.png
これを利用し、「コントローラーを起動し、ペアリングをさせない状態にしてスキャンした結果」と「コントローラーを停止した状態でスキャンした結果」をそれぞれ取得し、その結果を比較して「コントローラーのMACアドレス」を導き出します。
ちなみに私の所有するコントローラーのMACアドレスは40:8E:2C:79:CD:29でした。
ベンダー検索サイトでMACアドレス検索すると「Microsoft Corporation」と表示されるのではないかと思います。

コントローラーのMACアドレスが特定出来たら、main.pyのXBOX_MACADDR変数に入力してください。
また、必須ではないですが先ほどblegamepad.pyでアンコメントした個所を再びコメントアウトしてください。

処理の流れについて

1. Wi-Fi接続

main.pyに記載したSSIDとパスワード情報をもとにWi-Fi接続を行います。(connect_wifi関数)
Wi-Fi接続中はLEDが点灯します。

2. コントローラー検索

pad.scan()を実行し、アドバタイズパケットをスキャンします。(63-73行目)
目的(XBOX_MACADDR)のMACアドレスが検出されるまでループします。

3. WoLのためのマジックパケット送信

コントローラーが検出されたら、PC(PC_MACADDR)にWoL用のマジックパケットを送信します。(send_magicpacket関数)
その後、10秒ごとにpingでPC(PC_IPADDR)に対し疎通確認を行い、応答が返ってこなければ再度マジックパケットの送信を行う、というループを行います。(80-98行目)
この間、LEDは1秒周期で点滅します

4. PCの終了監視

PCの起動が完了したら、10秒周期でpingによる疎通監視を行います。(103-112行目)
この間、LEDは点灯します

5. PC終了後のコントローラー検出猶予期間

ping応答がなくなってから指定時間(GRACETIME)の間はコントローラーの再スキャンを行いません。(116-123行目)
→PCをシャットダウンするときにコントローラーの電源を落とし忘れてしまい、またWoLが実行されるのを防ぐため
この間、LEDは10秒ごとに点滅します

6. 待機状態へ復帰

猶予期間が終了すると、再びコントローラーの検索フェーズ(ループの先頭)に戻ります。

最後に

Raspberry Piの登場で、かゆいけど手が届かなかったところにだんだん手を伸ばせるようになってきたと実感しています。
今後もなにか自分にとって面白いものが作れたら報告できればいいなと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0