Macに接続しているUSB給電のLEDライトを、ディスプレイのON/OFFに合わせて自動で点灯・消灯できるようにしました。
最終的には、以下の動作を実現しています。
- Macの画面をスリープしたらLEDライトを消灯する
- Macの画面が復帰したらLEDライトを点灯する
- ホットコーナーの「ディスプレイをスリープ」にも連動する
地味な自動化ですが、デスク周りの使い勝手がかなり良くなりました。
やりたかったこと
デスク周りでUSB給電のLEDライトを使っています。 これをMacの画面状態に合わせて、自動的にON/OFFしたいと思いました。
理想は次のような動作です。
画面ON → LEDライト点灯 画面OFF → LEDライト消灯
最初は、モニタ側のUSBポートにLEDライトを挿しておけば、モニタのスリープと連動してUSB給電も切れるのではないかと考えていました。
しかし実際には、Mac側で「ディスプレイをスリープ」しても、LEDライトは消えませんでした。 モニタ側の省電力設定を変更しても、今回の構成ではUSB給電は切れませんでした。
そこで、モニタ側の挙動に頼るのではなく、Mac側からUSBハブのポート給電を直接制御する方法にしました。
全体構成
使ったものは以下の2つです。
uhubctl- Hammerspoon
uhubctl は、対応しているUSBハブのポート給電をON/OFFできるコマンドラインツールです。 Hammerspoonは、macOSのイベントを検知してスクリプトを実行できる自動化ツールです。
今回の考え方はシンプルです。
Macのディスプレイがスリープ ↓ Hammerspoonが検知 ↓ uhubctlでUSBポートの給電をOFF ↓ LEDライト消灯 Macのディスプレイが復帰 ↓ Hammerspoonが検知 ↓ uhubctlでUSBポートの給電をON ↓ LEDライト点灯
ポイントは、LEDライトそのものを制御するのではなく、 LEDライトが接続されているUSBハブのポート給電を切ることです。
uhubctlをインストールする
Homebrewで uhubctl をインストールします。
brew install uhubctl
インストール後、USBハブの状態を確認します。
sudo uhubctl
次のような形式で、USBハブとポートの一覧が表示されます。
Current status for hub 0-1.3 [USB Hub, USB 2.10, 5 ports, ppps] Port 1: power enable connect Port 2: power Port 3: power connect Port 4: power highspeed enable connect Port 5: power
ここで注意したいのは、USB LEDライト自体は一覧に出てこないことがあるという点です。
USB LEDライトは給電専用で、データ通信をしないものが多くあります。 その場合、MacからはUSBデバイスとして認識されません。
そのため、探すべきなのはLEDライト本体ではなく、 LEDライトがぶら下がっているUSBハブ、またはその上流ポートです。
LEDライトのポートを特定する
次に、LEDライトを制御するためのUSBポートを特定します。
今回は、LEDライトをUSBハブ経由で接続していました。 そのため、LEDライト本体を直接探すのではなく、まず LEDライトが刺さっている末端のUSBハブが、Macからどのように見えているか を確認しました。
USB LEDライトは給電専用の場合があり、その場合はUSBデバイスとして一覧に表示されません。 一方で、LEDライトを接続しているUSBハブは、Mac側からUSBハブとして認識されることがあります。
そこで、まずLEDライトを接続した状態で uhubctl の一覧を確認します。
sudo uhubctl
たとえば、以下のように複数のUSBハブが表示されます。
Current status for hub 0-1.3 [USB Hub, USB 2.10, 5 ports, ppps]
Port 1: power enable connect
Port 2: power enable connect [USB Hub, 4 ports]
Port 3: power connect
Port 4: power highspeed enable connect
Port 5: power
Current status for hub 3-1 [USB Hub, USB 2.10, 4 ports, ppps]
Port 1: power
Port 2: power
Port 3: power
Port 4: power
次に、LEDライトが刺さっている末端のUSBハブを一度抜きます。 その状態でもう一度 sudo uhubctl を実行します。
sudo uhubctl
抜く前後の表示を見比べます。 たとえば、抜く前は以下のように表示されていたポートが、
Port 2: power enable connect [USB Hub, 4 ports]
末端のUSBハブを抜いた後に、以下のように変わっていれば、
Port 2: power
そのポートが、LEDライト側のUSBハブにつながっていた上流ポートだと分かります。
この例では、まず以下の接続関係が分かります。
hub: 0-1.3
port: 2
↓
LEDライトが刺さっているUSBハブ側
ここまでで分かるのは、「LEDライトが刺さっているUSBハブが、どの経路にぶら下がっているか」です。 ただし、この時点ではLEDライトがハブの何番ポートに刺さっているかまでは分かりません。
そのため、次に対象になりそうなハブのポートを1つずつOFF/ONして、LEDライトが消えるポートを探します。
sudo uhubctl -l 3-1 -p 1 -a off
sudo uhubctl -l 3-1 -p 1 -a on
sudo uhubctl -l 3-1 -p 2 -a off
sudo uhubctl -l 3-1 -p 2 -a on
sudo uhubctl -l 3-1 -p 3 -a off
sudo uhubctl -l 3-1 -p 3 -a on
sudo uhubctl -l 3-1 -p 4 -a off
sudo uhubctl -l 3-1 -p 4 -a on
ここで、実際にLEDライトが消灯・点灯するポートが見つかれば、そのポートが制御対象です。
今回の環境では、最終的に以下のコマンドでLEDライトをON/OFFできました。
sudo uhubctl -l 0-1.3 -p 2 -a off
sudo uhubctl -l 0-1.3 -p 2 -a on
つまり、0-1.3 の Port 2 がLEDライト側につながる制御対象ポートでした。
この作業のポイントは、最初からLEDライト本体を探すのではなく、 LEDライトが刺さっているUSBハブの抜き差しで差分を見て、候補となるハブや経路を絞り込む ことです。
そのうえで、候補になったハブのポートを1つずつ uhubctl でON/OFFし、 LEDライトが反応するポートを特定します。
なお、指定したポートの先に複数のUSB機器が接続されている場合は、それらも同じポートの電源供給にぶら下がります。 LEDライトだけを安全に制御したい場合は、特定したポートの先をLEDライト専用にしておくのが安心です。
Hammerspoonをインストールする
次に、ディスプレイのスリープ/復帰を検知するためにHammerspoonを入れます。
brew install --cask hammerspoon
インストール後、アプリケーションからHammerspoonを起動します。 初回起動時に権限を求められた場合は許可します。
sudoをパスワードなしで実行できるようにする
Hammerspoonから sudo uhubctl を実行する場合、通常はパスワード入力が必要になります。 しかし自動実行ではパスワードを入力できません。
そこで、今回使う uhubctl コマンドだけ、パスワードなしで実行できるようにします。
まず uhubctl のパスを確認します。
which uhubctl
たとえば以下のように表示されます。
/opt/homebrew/bin/uhubctl
次に visudo を開きます。
sudo visudo
末尾に以下を追加します。
<ユーザー名> ALL=(root) NOPASSWD: /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a off, /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a on
<ユーザー名> は自分のmacOSユーザー名に置き換えます。 /opt/homebrew/bin/uhubctl の部分は、which uhubctl の結果に合わせます。
また、0-1.3 と 2 は、自分の環境で特定した値に置き換えます。
設定できたら、以下でパスワードなし実行できるか確認します。
sudo -n /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a off sudo -n /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a on
これでLEDライトがON/OFFできればOKです。
Hammerspoonの設定を書く
Hammerspoonの設定ファイルを作成します。
mkdir -p ~/.hammerspoon nano ~/.hammerspoon/init.lua
以下を貼り付けます。
local ledOff = "/usr/bin/sudo -n /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a off" local ledOn = "/usr/bin/sudo -n /opt/homebrew/bin/uhubctl -l 0-1.3 -p 2 -a on" local function run(cmd) hs.task.new("/bin/zsh", function(exitCode, stdOut, stdErr) if exitCode ~= 0 then hs.notify.new({ title = "LED control failed", informativeText = stdErr }):send() end end, {"-lc", cmd}):start() end local function handlePowerEvent(event) if event == hs.caffeinate.watcher.screensDidSleep or event == hs.caffeinate.watcher.systemWillSleep then run(ledOff) elseif event == hs.caffeinate.watcher.screensDidWake or event == hs.caffeinate.watcher.systemDidWake then run(ledOn) end end powerWatcher = hs.caffeinate.watcher.new(handlePowerEvent) powerWatcher:start()
保存したら、Hammerspoonのメニューから設定を再読み込みします。
Reload Config
これで設定が反映されます。
動作確認
ホットコーナーに「ディスプレイをスリープ」を割り当てている場合は、それでテストできます。
期待する動作は以下です。
ホットコーナーでディスプレイをスリープ ↓ LEDライト消灯 マウスやキーボードで画面復帰 ↓ LEDライト点灯
これで、Macの画面状態に合わせてUSB LEDライトを自動制御できます。
注意点
LEDライトはUSBデバイスとして見えないことがある
給電専用のUSB LEDライトは、MacからUSBデバイスとして認識されない場合があります。
その場合、LEDライト本体を探すのではなく、LEDライトが接続されているハブや上流ポートを探します。
重要な機器を巻き込まないようにする
指定したポート配下に他の機器がある場合、それらも一緒に切れます。 外付けストレージ、キーボード、ネットワークアダプタなどを同じ配下に置くのは避けた方が安全です。
LEDライト専用の小型ハブや、LEDライトだけがぶら下がっているポートを使うのがおすすめです。
まとめ
Macの画面スリープに合わせてUSB LEDライトを自動ON/OFFしたい場合、モニタ側のUSB給電制御だけではうまくいかないことがあります。
その場合は、以下の構成にすると実現できます。
Hammerspoonで画面スリープ/復帰を検知 ↓ uhubctlでUSBハブの対象ポートをON/OFF
今回の環境では、以下のコマンドでLEDライトを制御できました。
sudo uhubctl -l 0-1.3 -p 2 -a off sudo uhubctl -l 0-1.3 -p 2 -a on
あとはこのコマンドをHammerspoonから実行することで、 画面OFFで消灯、画面ONで点灯するUSB LEDライト環境が作れます。
ライトを手動で消し忘れることがなくなり、デスク環境がかなり快適になりました。
こういうスイッチがないタイプでも自動点灯/消灯してくれます。
こちらで十分です。


