簡単・低予算で「会議中サイン」を作ってみた

![DSC01307.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309088/96f05b87-d2ce-3490-8bea-bc5d5650f8bf.jpeg)

# はじめに

最近ではコロナの影響もあり、家で仕事をされる方も増えてきているかと思います。

部屋にこもって仕事をしていると、オンライン会議の途中に家族が突然部屋に入ってきてしまうなどのアクシデントに見舞われることがあります。
家族の側からしてみても、そっと部屋を覗いてみるとヘッドセットをつけて静かにしていたら、オンライン会議で他の人の話を聞いているのか、ただ音楽を聴きながら作業しているのかがわからず、声をかけていいものか迷ってしまいます。

![スクリーンショット 2022-02-12 20.10.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309088/58fb08ee-0743-373d-af8e-676ac3a85817.png)

このような「リモートワークで会議中なのかわからない問題」を解決するため、部屋の外から会議中か否かを確認できる「会議中サイン」を作りました。

このような発想自体は珍しいものではなく、似た発想で様々なガジェットを実装されている先人の方々がいらっしゃいます[^1][^2][^3][^4][^5]。
先人の方々の投稿を参考としつつ、本稿では「なるべく低予算でお手軽に」を目標にDIYしてみました。





# 点灯制御機構

ライトの制御に Arduino などを使うとどうしても材料費が嵩みますし、何よりもお手軽さが犠牲になります。
要は表示灯のOn/Offを遠隔制御できれば良いだけなので、市販のスマート電球を利用しました。
クラウド経由で制御可能なスマート電球としては Philips Hue が有名ですが、今回は照明として常時使用する訳ではなく、光量や発色の良し悪しなどはあまり気にする必要もありませんので、より安価なもので十分です。

今回は、以前購入したこちらの電球が1つ余っていたので、これを利用しました。
4個で4400円だったので、1個当たり1100円です。

https://www.amazon.co.jp/gp/product/B07XSCY5GN/

この電球を電源ケーブル付きのソケットで本体ケースに固定するだけで点灯制御機構は完成です。

# 会議中か否かの検知

会議中であるか否かを検知するためには、以下のようなアプローチが考えられます。

1. 手動でOn/Offを切り替える [^1][^2][^3]

[^1]: https://qiita.com/aerialist/items/d3721e8a9dd6732f428c
[^2]: https://qiita.com/fly1tkg/items/908531e8e719642c07aa
[^3]: https://qiita.com/3yaka4/items/5765dc5abf547783dc59

2. Zoom や Webex などのWeb会議ツールの状態を監視する [^4]

[^4]: https://qiita.com/samasuda_sm4jan/items/8ee7223a27f11b66bb80

3. カレンダーで予定されたミーティングを検知する [^5]

[^5]: https://qiita.com/kon-sato/items/8e9823627722d8dc7a4d

4. カメラやマイクなどのデバイスの利用状態を監視する


私の場合、1.の手動方式は操作忘れが頻発することが目に見えています。

また、2.のWeb会議ツールを監視する方法は、複数のWeb会議ツールに対応することが難しいという欠点があります。
実際、普段私はWeb会議には Google Meet を使いますが、 たまに Zoom を使ったり、バーチャルオフィス環境(Spatial Chat や Gather)で会話するなど、様々なツールを活用しています。さらには、社外ミーティングでは先方の指定するツールを使う可能性もあります。
会議への参加状態を取得するAPIを提供していないWeb会議ツールもある中で、全ての利用するWeb会議ツールに対応していくことは現実的ではありません。

また、3.のカレンダーを監視する方法では、会議の予定とそれ以外の予定を区別するのが困難ですし、会議が長引いた場合や、予定にないバーチャルオフィスでの会話の場合には ON AIR サインが点灯しないなど「今この瞬間の状態」を反映することができません。


以上のことから、今回は**4.のデバイスの状態を監視するアプローチ** を取ります。

よくよく考えてみると、家族が部屋に入ってきて欲しくないのは「Web会議の音声や映像に入り込んでしまう」からであって、Web会議中でもカメラオフでミュート中の場合には入ってきても問題はありません。逆に、例えば動画のナレーションを録音している時など、Web会議中ではなくとも部屋に入ってきて欲しくない場合もあります。
つまり、今回の要件で本当にやりたかったこと(顧客が本当に必要だったもの)は「会議中か否か」ではなく「音声や映像に入り込んでしまう可能性があるか」を検知することであり、このためにはカメラやマイクのデバイスの状態を監視するのが最も直接的で確実な方法であると考えられます。

カメラとマイクのどちらを監視するかですが、私はWeb会議は基本的にカメラオンで行っているため、まずはカメラの利用状態を監視することにしました。
Macbook のカメラが動作するとカメラの隣の緑のランプが点灯するし、macOSのシステム設定でアプリケーションごとにカメラの利用許可を制御できるので、少なくともOSレベルではカメラの動作状態を監視できているはずですので、この情報さえ取得することができれば目的を達成することができるでしょう。

そんなこんなを考えながらカメラの動作状態を取得する方法を探していたところ、OverSightというちょうど使えそうなオープンソースのアプリがありました。

https://github.com/objective-see/OverSight

このアプリは、カメラデバイスを利用しているプロセスを監視し、カメラの利用開始と終了時に通知を出してくれます。
また、カメラのOn/Offのイベントが発生するたびにあらかじめ設定したコマンドを実行してくれる機能があるため、これを使ってカメラの検知することにしました。

# IFTTT経由での制御


カメラのOn/OffのイベントそのままIFTTT経由でスマート電球のOn/Offに割り当ててやることで、簡易的にカメラの状態とスマート電球を同期します。
OverSight が渡してくる引数に応じてIFTTTのWebHookを叩くスクリプトをPythonで書きました。

```python
#! /usr/bin/python3

import argparse
from urllib import request

# config.py で定義した定数を読み込む
import config

def trigger_ifttt_webhook(event):
    # IFTTT の WebHook イベントを実行
    ifttt_url = f"https://maker.ifttt.com/trigger/{event}/with/key/{config.IFTTT_KEY}"
    request.urlopen(ifttt_url, bytes())

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-device")
    parser.add_argument("-event")
    parser.add_argument("-process")

    args = parser.parse_args()

    if args.device == 'camera':
        if args.event == 'on':
            trigger_ifttt_webhook('on_air_sign_enabled')
        elif args.event == 'off':
            trigger_ifttt_webhook('on_air_sign_disabled')
```


実際に動作させてみた様子がこちらです(本体ケースが未完成の仮止め状態での動作テストの映像です)。

<iframe width="560" height="315" src="https://www.youtube.com/embed/E6ruMBvSrgc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

カメラを起動して実際に撮影が開始されてから電球が点灯するまでに約3~5秒の遅延はありますが、非常に簡単な仕組みの割には十分に実用的なものができました。

# 本体ケース

正直、これに一番時間を使いました。
リビングダイニングに面した私の仕事部屋の入り口に設置するため、リビングダイニングのインテリアに合わせてDIYしました。
ON AIR の文字は、黒画用紙を切り抜き、半透明ポリプロピレン(PP)シートで挟みました。後ろから電球を赤く光らせるとちょうど良い感じです。

![DSC01307.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309088/96f05b87-d2ce-3490-8bea-bc5d5650f8bf.jpeg)

# 総費用

なるべく低予算でお手軽にということで、ケースの材料は100均(Seria)で購入しました。

* スマート電球(HaoDeng): 1100円 (元々家にあったあまり物)
* ソケット(オーム電機製): 660円
* ケース材料: 各110円
    * 木製ウォールシェルフ(箱)
    * PPシート(半透明)
    * ブリキシート


その他、木ねじや釘、黒画用紙などは元々家にあったものを少量使っただけですので、総費用は2200円ほどに抑えることができました。

# 今後の課題と改良点

### 誤動作対策

今回は非常に簡単な仕組みでやりたいことを実現できている反面、カメラのOn/Offを素早く切り替えると誤作動が発生しうるという課題があります。
今回の設計では、カメラのOn/Offのイベントをそのまま IFTTT に投げているため、カメラのOn/Offを繰り返した際に通信遅延によりイベントの発火が前後すると、カメラをオフにしたのに点灯したままになってしまったり、その逆が起きたりすることがあります。

これを回避するためには、カメラの状態管理をちゃんと行った上で、IFTTTのAPIコールの順番が前後しないようにキュー制御をしたり、もしくはカメラのOn/Offイベントの発生時にのみ電球を制御するのではなく一定時間ごとに状態を同期させるなどの方法が考えられます。
前者の方法は後者の方法に比べて遅延が少ないメリットがありますが、後者の方法は通信エラーの場合にも対応できるので、2つの方法を組み合わせるのが確実でしょう。(が、誤動作の頻度も高くないし面倒なのでそこまでやるかは微妙ですが。。)

### マイクの状態検知

また、今回はカメラの動作状態をもとに会議中か否かを検知しましたが、会議中必ずカメラをONにしているとは限らないので、マイクの状態も拾えるようにすることも今後の課題です。
OverSight は Macbook の内臓マイクの状態も監視してくれますが、外部ヘッドセットを使っている場合はうまく検知してくれません。外部ヘッドセットのマイクの状態監視には、別の方法を考える必要がありそうです。

今回使用している HaoDeng というスマート電球は発光色も制御できますので、音声通話の場合は黄色、カメラもオンの場合は赤色、みたいに出し分けることができるとよさそうです。