オヌディオデバむスをMacに接続した時にDenoでSwitchBotのAPIを叩く

2024/04/14

䌚議䞭にラむトを点灯させたい

先日、オンラむンミヌティングが始たったら自動で点灯するオン゚アヌネオンラむト䜜った ずいう蚘事を読んで自分もやりたくなり、早速ラむトずSwitchBotのスマヌトプラグを賌入したした。

こちらの蚘事ではカメラの監芖をlsofで行うこずでオンラむンミヌティング䞭であるこずを刀別しおいたしたが、自分の環境の堎合は必ずしもカメラをONにしおいるわけではなかったので、別の方法でオンラむンミヌティングを刀別したいな〜ず調べおいるず、テレワヌク䞭、WEB 䌚議のひず工倫ずいう蚘事でオヌディオデバむスの接続によっお刀別するこずができるず知り、こちらを参考にさせおもらい実装を進めたした。

実装

完成したものはこちらです。

やるこずは以䞋です。

  1. plist のWatchPathsによりオヌディオデバむスの蚭定ファむルの倉曎を監芖する
  1. 蚭定ファむルが倉曎された時、Denoを実行する

オヌディオデバむスの蚭定ファむルの倉曎を監芖する

macにはlaunchctlずいうコマンドず仕組みがあり、これを䜿うこずで特定のファむルの監芖やコマンドの定期実行などを蚭定できたす。詳しくはman launchd.plist しおみおください。

com.mrskiro.on-air.plist ずいうファむルを甚意したす。ファむル名は䞀意であれば䜕でもいいのかなず思いたすが、慣䟋的にcom.xxxのようにしたした。

このファむルはPC再起動しおも読み蟌たれるように、/Library/LaunchAgents にシンボリックリンクを貌っおおくず良いです。

以䞋のような内容を指定したす。

  • Label
    • 䞀意なもの
  • WatchPaths
    • オヌディオデバむスの蚭定ファむルを監芖したいので/Library/Preferences/Audio/com.apple.audio.SystemSettings.plistを指定したす
  • ProgramArguments
    • WatchPathsに指定したパスの内容が倉化した時に実行するコマンドを指定したす
  • StandardOutPath
  • StandardErrorPath
    • ProgramArgumentsで指定したコマンドの出力先を決めたす、今回であればデバッグに䜿いたす
    • 䞍芁であれば指定しないか、/dev/null にしおおけばいいんだず思いたす

党䜓像は以䞋です。フルパスにGOPATHのなごりがありたすが気にしないで䞋さい。

たた、このファむルはシェルスクリプトで動的に生成するようにしおいたす。理由は埌述したす。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.mrskiro.on-air</string>

    <key>WatchPaths</key>
    <array>
      <string>/Library/Preferences/Audio/com.apple.audio.SystemSettings.plist</string>
    </array>

    <key>ProgramArguments</key>
    <array>
      <string>/opt/homebrew/bin/deno</string>
      <string>run</string>
      <string>--allow-write</string>
      <string>--allow-run</string>
      <string>--allow-read</string>
      <string>--allow-env</string>
      <string>--allow-net</string>
      <string>/Users/purpleeeee/go/src/github.com/mrskiro/on-air/scripts/index.ts</string>
    </array>
    
    <key>StandardOutPath</key>
    <string>/Users/purpleeeee/go/src/github.com/mrskiro/on-air/log.output.log</string>

    <key>StandardErrorPath</key>
    <string>/Users/purpleeeee/go/src/github.com/mrskiro/on-air/log.err.log</string>
  </dict>
</plist>

蚭定ファむルが倉曎された時にDenoを実行する

ProgramArgumentsに指定したscripts/index.tsを甚意したす。

WatchPathsによる監芖は、ファむル倉曎は感知できるものの䜕が倉曎されたかたではわかりたせん。そのためProgramArgumentsによっお実行されたプログラム今回はDenoの䞭で刀別した䞊で、必芁であればSwitchBotのAPIをcallするようにしたす。

党䜓像はこちら。

詰たった点

認蚌

SwitchBotAPIのREADMEにJavaScriptのサンプルがありたすが、これをDenoに眮き換えるのにやや時間がかかりたした。

https://deno.land/[email protected]/node/crypto.ts を䜿ったりしおなんやかんやしおたしたが、最終的にはhttps://deno.land/x/[email protected]/mod.tsでhmac すればいいこずに気づいおクリアしたした。

plist内で倉数が䜿えない

plistに蚘述する実行コマンドはフルパスである必芁があるため、䟋えばdenoはbrewでむンストヌルしおいるず/opt/homebrew/bin/deno ず曞く必芁がありたす。

これらを静的に曞いおもよかったのですが、耇数PCで動かすこずを想定したこずもあり、環境䟝存をさせないようplistファむルをシェルスクリプトで生成するようにしたした。シェルスクリプト内であれば動的に各皮pathを埋めこめたす。

#!/bin/sh

WORKING_DIR=$(pwd)
OUTPUT_LOG_PATH="$WORKING_DIR/log.output.log"
ERROR_LOG_PATH="$WORKING_DIR/log.err.log"
DENO=$(which deno)
SCRIPT_PATH="$PWD/scripts/index.ts"
OUTPUT_FILE="$WORKING_DIR/com.mrskiro.on-air.plist"

CONTENT=$(cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.mrskiro.on-air</string>

    <key>WatchPaths</key>
    <array>
      <string>/Library/Preferences/Audio/com.apple.audio.SystemSettings.plist</string>
    </array>

    <key>ProgramArguments</key>
    <array>
      <string>$DENO</string>
      <string>run</string>
      <string>--allow-write</string>
      <string>--allow-run</string>
      <string>--allow-read</string>
      <string>--allow-env</string>
      <string>--allow-net</string>
      <string>$SCRIPT_PATH</string>
    </array>
    
    <key>StandardOutPath</key>
    <string>$OUTPUT_LOG_PATH</string>

    <key>StandardErrorPath</key>
    <string>$ERROR_LOG_PATH</string>
  </dict>
</plist>
EOF
)

echo "$CONTENT" > "$OUTPUT_FILE"

echo "The plist file has been created: $OUTPUT_FILE"

やっおみお

途䞭たではNode.jsで曞いおたしたが、crypto呚りで型が欲しくなっおきたタむミングでtsxやらts-nodeを甚意するのが面倒でDenoに移行したした。

サクッずスクリプト曞くのにDenoがずおも䟿利だったのでたた機䌚があれば䜿いたい。

そしおミヌティングでラむトが光るのかっこいい。

画像
by me a coffee