動機
テレワーク時代。夫婦揃ってそれぞれの仕事においてビデオ通話なんてことをやっている日々ではあるが、こんなことは無いだろうか?
- ビデオ通話中なのに近くで声を出してしまった。
- ドア閉めて部屋に入っていると、ビデオ通話中かわからない。(そしてノックされるなど。)
ということで、手始めにビデオ通話中かどうかを知らせるための仕組みとして、ON AIRランプなるものを買ってみた。
Amazon で1,440円也。
大変シンプルなランプで、単3電池3本もしくはUSB-C給電により動く。スイッチも物理的にカチカチするものである。
ビデオ通話をしているときには、これをオンにして周りに知らせるという用途に使えそうだ。
理想としては遠隔かつ自動で制御したい。
この記事では、Mac環境+Zoomでそのような装置を作るという内容になっている。
理想形
理想形は以下のような感じ。何も意識しなくても、ビデオ通話をしているのであれば自動点灯するのが望ましい。
(ON AIR ランプをオンにするのをそもそも忘れるからね。)
結論から言うと、この仕組は現状実現できていない。
Zoom Web API は現状ビデオ通話中かどうかを得ることはできない
Zoom Web APIは現在、自分がビデオ通話中かどうかを取得することはできないようだ。
以下のようなユーザ状態をセットするAPIはある。
ただし、ユーザの状態が変化したときに、WebHookにて通知してくれるものはあるようだが、GETで取得できる方法はなさそうである
- https://marketplace.zoom.us/docs/api-reference/webhook-reference/user-events/presence-status-updated
- https://devforum.zoom.us/t/how-get-user-online-status/4348/3
WebHookでなんとかしてもいいかもしれないが、これでは初期状態がわからないので、
完全に自動で制御するのは諦ることとなった。
ということで、まずは遠隔で気軽にオン・オフできる程度に留める。
MaBeee を使った電池制御
せっかくいいランプを買ったのに、Raspberry PIの配線がむき出しなってかっこ悪くなってしまうのは良くない。
穴をあけるとか、そういうことはしたくないし、そもそもRaspberry PI自体の電力供給について考えるのは面倒くさい。
そこで、今回購入したON AIRランプが電池駆動できるという特性を生かして、Bluetoothで電池を制御 MaBeee を購入してみた。
単純に、単3電池1本を、単4電池の入ったMaBeeに取り替えるだけで良さそうだ。
ただし、液漏れが怖いので、単3電池を、単4電池+ダイソーで買ったスペーサーに切り替えている。
実際には、MaBeee自体が電気を使うことになり、どうしても他の2本との容量差が生まれ、結果として液漏れが起きる危険性がありそうなので、定期的に点検したほうが良さげではある。
iPhoneアプリのMaBeeeライトで制御するとこんな感じになる。
動画: https://twitter.com/ooharabucyou/status/1351127844081045504
MaBeeeAppMac を利用した制御
正式にはサポートしないとしているが、Mac用の接続用のアプリが用意されている。
から情報を確認し、対象のリポジトリをCloneしてドキュメントの指示に従い、MaBeee.app を起動する。
まずは、適当にクライアント的なものを作る。
import requests
import time
import json
class MabeeeClient:
base_url = 'http://localhost:11111'
def __init__(self, options = {}):
self.options = options
def __call_api(self, path):
response = requests.get(MabeeeClient.base_url + path)
if response.status_code == 200:
if response.content:
return json.loads(response.content)
else:
return True
else:
raise RuntimeError('Failed to call MaBeeeAPI')
def start_scan(self):
self.__call_api('/scan/start')
def stop_scan(self):
self.__call_api('/scan/stop')
def search_device(self, device_name, delay=1, limit=30):
for i in range(limit):
time.sleep(delay)
print('Search device...')
response = self.__call_api('/devices')
found_devices = [d for d in response['devices'] if d['name'] == device_name]
if len(found_devices) > 0:
return found_devices[0]
raise RuntimeError('Device not found')
def connect_device(self, device_id):
self.__call_api('/devices/' + str(device_id) + '/connect')
def disconnect_device(self, device_id):
self.__call_api('/devices/' + str(device_id) + '/disconnect')
def wait_connected(self, device_id, delay=1, limit=30):
for i in range(limit):
time.sleep(delay)
print('Wait connected...')
response = self.__call_api('/devices/' + str(device_id))
if response['state'] == 'Connected':
return True
raise RuntimeError('Cannot connect device')
def set_device_pwm_duty(self, device_id, value):
self.__call_api('/devices/' + str(device_id) + '/set?pwm_duty=' + str(value))
そして、ランプをONにするスクリプトと、OFFにするスクリプトを書く。
(エラーが起きた場合は、Macの通知にメッセージが飛ぶようにしている。)
#!/usr/bin/python
from mabeee_client import MabeeeClient
# https://localhost:11111/scan/start -> https://localhost:11111/devices をブラウザやPostmanなどで
# コールして、自分のMaBeeeのデバイス名を探し、こちらに設定します。
device_name = 'MaBeeeXXXXX'
client = MabeeeClient()
try:
client.start_scan()
device = client.search_device(device_name)
device_id = device['id']
client.connect_device(device_id)
client.wait_connected(device_id)
# ScanをStopしないと、デバイスに値を設定できないというエラーが出ます。
client.stop_scan()
client.set_device_pwm_duty(device_id, 100)
except:
import traceback
import os
traceback.print_exc()
# エラーが起きたら、Macの通知に知らせます。
os.system("osascript -e 'display notification \"MaBeee connection error\"'")
#!/usr/bin/python
from mabeee_client import MabeeeClient
# switch_on.py と同様
device_name = 'MaBeeeXXXXX'
client = MabeeeClient()
try:
client.start_scan()
device = client.search_device(device_name)
device_id = device['id']
client.disconnect_device(device_id)
client.stop_scan()
except:
import traceback
import os
traceback.print_exc()
os.system("osascript -e 'display notification \"MaBeee connection error\"'")
上記、3つのスクリプトを適当な場所に起き、switch_on.py
, switch_off.py
について 755 のパーミッションを設定する。
chmod 755 switch_on.py
chmod 755 switch_off.py
ショートカットとして登録
仕上げに、キーボードショートカットで、ON AIRランプをオン・オフできるようにする。
Automatorを開き、クイックアクションを新規作成する。
シェルスクリプトを実行を右のエリアにドラッグ
ワークフローが受ける項目を「入力なし」、検索対象を「すべてのアプリケーション」とする。
シェルスクリプトは、先程作った switch_on.py を実行するようにする。
名前は ONAIRオンとしてファイルを保存する。この作業をオフについても実施する。
システム環境設定 -> キーボード -> ショートカットから、
「ONAIRオン」「ONAIRオフ」が選べるようになっているので、ショートカットを登録しておく。
これで、ビデオ通話開始時には「ONAIRオン」ショートカットを実行することで、ランプを点灯させることができる。
動画: https://twitter.com/ooharabucyou/status/1351132734429802497
まとめ
これでビデオ通話ライフがますます向上すると思われる。
が、Zoom Web APIからビデオ通話中の情報が取得できなかったことは大変痛い。
あとから気づいたが、ブラウザやMacのアプリからZoomを制御するSDKがあるようだ。
SDKからミーティングを起動して、自分のマイク・ビデオの状態をON AIRランプに反映させるという線も試せそうだ。
https://marketplace.zoom.us/docs/sdk/custom/introduction
できたらPART2をやりたい