この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
CX事業本部チームIoTの熊膳です。
リモートワークでのオンライン会議、家族に気を使われることってありませんか?例えば、音を立てないようにとか、カメラに映り込まないようにとか。うちはあります。 でも、私、一日中ヘッドホンしているので、家族からするといつオンライン会議しているのか、すごくわかりにくいです。
というわけで、GWの企画として「オンライン会議中にON AIRライトを点ける」仕組みを作ってみました。
オンライン会議 ON AIRライトシステム
最初に動いている動画を紹介します。
ちょっとだけタイムラグがありますが、会議が始まるとON AIRが点灯し、終了すると消えています。
作ってみた
「オンライン会議中」をどう判断するか?という部分をどうしようかと悩んだのですが、結論としてはWebカメラがONになっている時としました。オンライン会議=カメラONではないのですが、やりたいことはカメラがONになってることを伝えたいということなので問題ないです。
作戦はこうです。
- 何らかの仕組みでカメラの状態を検知する。
- カメラの状態がOFFからONになったらON AIRライトをつける。ONからOFFなら消す。
ON AIRライトのON/OFFは、スマートプラグを使いました。
参考までに、今回使った機材は以下です。
- Webカメラ
- スマートプラグ
- ON AIRライト
カメラの状態の検知
まずはカメラの状態をどうやって取得するかです。
私の使用しているWebカメラは「ロジクールStreamCam」で、MacとはUSB-Cケーブルで接続しています。最初はUSBハブ経由で電気的な違いを取得するとか、カメラONのライトをコンピュータビジョンを用いて検出するとか、出来もしないことを考えていたのですが、カメラ起動中は何かのプロセスが動いているはずとの妄想を元に、アクティビティモニタを「cam」で検索したところ、LogiFacecamServiceというプロセスを見つけました。
カメラをON/OFFしたところ、CPUの値が変化していることを発見。これ使えそうです。
以下のコマンドで、CPUの値を取得できました。
ps -o %cpu -o comm -ax|grep LogiFacecam
14.7 /Library/Application Support/LogiFacecam.bundle/Contents/MacOS/LogiFacecamService
上記の14.7というのがCPUの値です。CPUの値が、0.0より大きい場合をカメラONと判断することにします。
【追記】 実際に何日か運用してみると、カメラONの場合でもタイミングによっては0.0になる場合があるようです。OFFになったと判断する場合は、0.0が2,3回続くという条件にしたほうが良さそうです。
ON AIRライトの点灯
ON AIRライトの点灯、消灯は、スマートプラグを使用します。今回使ったHS105は、tplink-smarthome-apiを用いることで、Macから制御できますのでこれを使います。
セットアップの仕方や、ライブラリの使い方は、山本さんやMiyajimaさんのブログを参考にしました。
ロジックは以下としました。
- 前回のカメラの状態をファイルから読み込む
- プロセスを取得し前回のカメラの状態から変更があったら
- スマートプラグで電源のON/OFFを行う
- カメラの状態をファイルに書き込む
コード
私、エンジニアじゃないのでコードとしては微妙かもしれないですが、一応動いているコードはこちらになります。
const fs = require('fs');
const childProcess = require('child_process');
const client = new (require('tplink-smarthome-api').Client)();
const CMD ='ps -o %cpu -o comm -ax|grep LogiFacecam';
const FILE = '/<ステータスファイルのパス>/state';
const PLUGIP = '192.168.x.x'; // HS105のIPアドレス tplink-smarthome-api searchで事前に調べておく
const lastStatus = fs.readFileSync(FILE, 'utf-8');
const cmd = childProcess.spawn(CMD, [], {shell: true});
cmd.stdout.on('data', (data) => {
console.log(data.toString());
// 1番目の数値をCPU値として取り出す
const cpu = data.toString().trim().split(' ')[0];
// cpuが0より大きい場合は、カメラが起動中と判断する
const cameraStatus = (Number(cpu) > 0 ? 'ON' : 'OFF');
console.log(cameraStatus);
// カメラの起動状態が変更したらファイルを更新しONAIR状態を更新する
if (lastStatus !== cameraStatus) {
// ファイルを更新
fs.writeFile(FILE, cameraStatus, (err) => {
if (err) throw err;
});
// ON AIR ライトの変更
client.getDevice({ host: PLUGIP }).then((device) => {
if (device.deviceType === 'plug') {
device.setPowerState(cameraStatus === 'ON' ? true : false);
}
});
}
});
スクリプト起動
Macを使っているので上記のスクリプトをlaunchdで定期起動することにします。
以下のplistファイルを~/Library/LaunchAgents/xxx.plist
として配置します。ファイル名はjp.classmethod.seisho.kumazen.onair.plist
としました。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>jp.classmethod.seisho.kumazen.onair</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/<スクリプトのパス>/onair.js</string>
</array>
<key>StartInterval</key>
<integer>5</integer>
<key>StandardOutPath</key>
<string>/<スクリプトのパス>/log.out</string>
<key>StandardErrorPath</key>
<string>/<スクリプトのパス>/log.err</string>
</dict>
</plist>
起動間隔は、撮影の都合上5秒にしてますが、そこまでリアルタイムじゃなくていいと考え60秒でもいいかなと思ってます。StartInterval
の値で変更可能です。
ファイルを配置したら、以下のコマンドを実行して完了です。
launchctl load ~/Library/LaunchAgents/jp.classmethod.seisho.kumazen.onair.plist
ちなみに停止は、上記のload
をunload
に変更して実行です。
まとめ
GWの自由研究として、「オンライン会議中にON AIRライトを点ける」をやってみました。 この「オンライン会議中に」というイベントをトリガーに何かを行うというのは、色々応用できそうですね。例えば「LEDライトを点灯する」というのは、すぐに出来そうです。
以上、どなたかの参考になれば幸いです。