本記事で紹介するプログラムは以下の GitHub リポジトリで公開しています
はじめに
前回の記事では、2 台の Raspberry Pi Zero 2 W を使い、1 台を送信機としてキーボード信号を送信し、もう 1 台を受信機としてその信号を受け取り、PC のマウスカーソルを動かす方法を紹介しました。
今回は、さらに進化させて MQTT プロトコルを活用します。EMQX MQTT プラットフォーム上にブローカーを設定し、2 台の Raspberry Pi Zero 2 W を使って、1 台を送信機としてキーボード信号をインターネット経由で送信し、もう 1 台を受信機としてその信号を基に PC のマウスカーソルを操作します。前回は同じ LAN 内に両方の Raspberry Pi が必要でしたが、今回は異なるネットワークにあっても遠隔操作が可能になります。
関連記事
- 【第0回】 Raspberry Pi OS をインストールする
- 【第1回】 LAN経由でマウスを操作する
- 【第2回】 USB キーボード信号の送受信とマウス操作
- 【第3回】 MQTT を使用し、インターネット経由でマウスを遠隔操作
EMQX ブローカーのセットアップ手順
アカウント作成
まずは EMQX のウェブサイト(https://www.emqx.io/)にアクセスし、無料アカウントを作成します。


MQTT ブローカーの作成
アカウントを作成すると新規デプロイメント画面に遷移します。
Serverless タイプを選択し、リージョンAsia-Pacificを選択。

デプロイメント名を入力後、今すぐ導入を選択します。

約款の同意画面が表示されるので文章をスクロールすると読んで同意しましたのチェックボックスが表示されます。
チェックを入れると同意ボタンがクリック可能になります。

同意ボタンクリック後、別の同意画面が表示されるので同様にスクロール後、読んで同意しましたのチェックボックスにチェックを入れ、
今すぐに開始を選択するとデプロイメントが開始され、MQTT ブローカーが作成されます。

ユーザーの作成
MQTT ブローカーの作成が完了したら、ユーザー を作成します。
サイドバーのアクセス制御>認証からユーザー作成画面を開き、追加ボタンをクリックします。

ユーザー名とパスワードを入力し、確認ボタンをクリックします。

これでユーザーが作成されます。
アクセス権限の付与
ユーザーを作成したら、アクセス権限を付与します。
今回の記事では送受信
サイドバーのアクセス制御>アクセス承認からアクセス承認画面を開き、追加ボタンをクリックします。

- クライアント ID:アクセス権限を付与するユーザーを指定します。
- トピック:トピック名を入力します。今回は
keyboard/movementと入力します。 - アクション:
Publish&Subscribe(送受信)を選択します。権限の範囲を限定したい場合はPublish(送信側)またはSubscribe(受信側)を選択してください。 - 許可/拒否:
許可を選択します。
確認ボタンを押すとアクセス権限の付与が完了します。

接続情報の確認
サイドバーの概要をクリックし、ダッシュボードを表示します。
接続情報の接続先をメモし、CA証明書をダウンロードします。

Raspberry Pi にプログラムを実装
次に、2 台の Raspberry Pi Zero 2 W にプログラムを実装します。1 台を送信機、もう 1 台を受信機として使い、それぞれの役割を果たすためのコードを以下に示します。
このサンプルコードではCA証明書を/home/piに配置しています。
またMQTT_BROKERにはメモした接続先を入力してください。
MQTT_USERとMQTT_PASSWORDにはユーザーの作成で設定したユーザー名をパスワードを入力してください。
CA 証明書の権限を確認・設定
CA 証明書の権限が正しいか確認し、必要に応じて設定します。
sudo chmod 644 /home/pi/emqxsl-ca.crt
送信機のプログラム
# mqtt-keyboard-tx.py: キーボードのイベントをMQTTブローカーに送信するプログラムimport evdevimport paho.mqtt.client as mqttimport json# MQTTブローカーの設定MQTT_BROKER = 'xxxx1234.ala.asia-southeast1.emqxsl.com'MQTT_PORT = 8883MQTT_TOPIC = 'keyboard/movement'MQTT_USER = 'zero-1'MQTT_PASSWORD = 'password'MQTT_CAFILE = '/home/pi/emqxsl-ca.crt'# MQTTクライアントの設定client = mqtt.Client()client.username_pw_set(MQTT_USER, MQTT_PASSWORD)client.tls_set(MQTT_CAFILE, tls_version=mqtt.ssl.PROTOCOL_TLSv1_2)client.connect(MQTT_BROKER, MQTT_PORT, 60)# デバイスのevent番号を指定(キーボードのイベントデバイス)device = evdev.InputDevice('/dev/input/event0')# キーボードイベントの読み取りと送信try: for event in device.read_loop(): if event.type == evdev.ecodes.EV_KEY: # データの送信 (JSON形式) data = json.dumps({'type': event.type, 'code': event.code, 'value': event.value}) client.publish(MQTT_TOPIC, data) print(f"Sent: {data}") # 送信したデータを表示except Exception as e: print(f"An error occurred: {e}")finally: client.disconnect()
受信機のプログラム
# mqtt-keyboard-rx.py - MQTTメッセージを受信して、マウスの移動やクリックを行うimport paho.mqtt.client as mqttimport jsonimport sysimport termiosimport tty# MQTTブローカーの設定MQTT_BROKER = 'xxxx1234.ala.asia-southeast1.emqxsl.com'MQTT_PORT = 8883MQTT_TOPIC = 'keyboard/movement'MQTT_USER = 'zero-2'MQTT_PASSWORD = 'password'MQTT_CAFILE = '/home/pi/emqxsl-ca.crt'# HIDファイルのパスMOUSE_DEV = "/dev/hidg0"# 初期設定movement_amount = 10min_movement = 1max_movement = 127# MQTTメッセージのコールバック関数def on_message(client, userdata, msg): global movement_amount # ここでグローバル変数として宣言 try: obj = json.loads(msg.payload) if obj['type'] == 1: # EV_KEY if obj['value'] in (1, 2): # キーが押された、または押し続けられている if obj['code'] == 103: # 上方向キー move_mouse(0, -movement_amount) elif obj['code'] == 108: # 下方向キー move_mouse(0, movement_amount) elif obj['code'] == 105: # 左方向キー move_mouse(-movement_amount, 0) elif obj['code'] == 106: # 右方向キー move_mouse(movement_amount, 0) elif obj['code'] == 44: # Zキー movement_amount = max(min_movement, movement_amount - 4) elif obj['code'] == 45: # Xキー movement_amount = min(max_movement, movement_amount + 4) elif obj['code'] == 30: # Aキーで左クリック move_mouse(0, 0, buttons=1) elif obj['code'] == 31: # Sキーで右クリック move_mouse(0, 0, buttons=2) elif obj['code'] == 16: # Qキー print("Q key pressed. Exiting...") client.disconnect() sys.exit() elif obj['value'] == 0: # キーが離されたとき、クリックを解除 if obj['code'] in (30, 31): # AキーまたはSキー move_mouse(0, 0, buttons=0) print(f"Received: {obj}") except json.JSONDecodeError: pass# マウスの移動やクリックを送信する関数def move_mouse(dx, dy, buttons=0): report = bytearray([buttons, dx & 0xFF, dy & 0xFF]) with open(MOUSE_DEV, "wb") as f: f.write(report)# MQTTクライアントの設定client = mqtt.Client()client.username_pw_set(MQTT_USER, MQTT_PASSWORD)client.tls_set(MQTT_CAFILE, tls_version=mqtt.ssl.PROTOCOL_TLSv1_2)client.on_message = on_message# MQTTブローカーに接続し、トピックを購読client.connect(MQTT_BROKER, MQTT_PORT, 60)client.subscribe(MQTT_TOPIC)try: print("Waiting for MQTT messages...") client.loop_forever()except KeyboardInterrupt: client.disconnect() print("終了しました。")
結果の確認
送信側と受信側の両方の Raspberry Pi に paho-mqtt をインストールします。
直接インストールする場合は以下のコマンドを使用します
sudo apt-get install python3-paho-mqtt
仮想環境を使用する場合は、次のコマンドでインストールします
pip3 install paho-mqtt
インストール後、送信側と受信側それぞれでプログラムを実行します。
sudo python3 mqtt-tx.py
sudo python3 mqtt-rx.py
送信側でキーボードの十字キーを押すと、その信号が受信側に送信され、Raspberry Pi に接続された PC のマウスが動作します。
アイゼック株式会社の IoT ソリューション
アイゼック株式会社では、Raspberry Pi を活用した IoT ソリューションの開発を積極的に進めています。今回のようなマウス操作の遠隔制御に限らず、さまざまな IoT デバイス間の通信技術を応用したシステム開発に取り組んでいます。ご興味がある方は、ぜひお問い合わせください。