外出先から家にVPN接続して、家のMac miniをssh接続・vnc接続して使いたいことがあります。その場合、Macがスリープしていると接続できません。そこで、HomebridgeのWake on LAN (WoL)プラグインを使って、HomeKitからMac miniのスリープを解除できるようにしました。
Mac miniのスリープ設定
M4 Mac miniが登場した時、電源スイッチが筐体の底にあって、押しにくいことが話題になりました。Mac miniは省電力なので、デスクトップMacであってもスリープで使ってくださいというメッセージだと思います。私も、Mac miniは電源を落とすことなく、ずっとスリープさせるだけで使用続けてます。
macOSのスリープ設定は、「システム設定」の「エネルギー」から設定します。Mac miniのデフォルト設定は以下です。
このうち「ディスプレイがオフのときに自動でスリープさせない」項目はデフォルトでOffです。わかりにくい表現ですが、これをOnにすると、常時稼働するモードになります。Macを常時稼働サーバーなどにする場合は、これをOnにしておきます。
その下にある「ネットワークアクセスによるスリープ解除」の項目は、デフォルトでOnです。Onの場合、Macはスリープ中にもiMessageやiCloudの情報をネットワークから受信して、メッセージ、メール、ファイルなどの同期を最新に保ちます。
スリープ中のMacに接続したい
自宅のルーターでVPNを動かしているので、外出先から家のネットワークに入ることができています。この時、外出先から、自宅でスリープ中のMacにsshもしくはvnc接続したいことが時々あります。
前述の「システム設定」で、「ディスプレイがオフのときに自動でスリープさせない」設定にしておけば、常時ssh, vncが受け付けられます。ただスリープせず、常時フル稼働するので、電気代がもったいないです。
それならば、「ネットワークアクセスによるスリープ解除」がOnになっていたら、通常はスリープしても、sshアクセスがあった場合にすぐに接続できるような気がします。しかし実際には出来ません。sshやvncアクセスはスリープ解除の条件にならないようです。解除理由のアクセスにより、Macがたまたまスリープ解除して(でも画面は暗いままです)、ネットワークに接続しているタイミングだったら、ssh/vnc接続できます。
一方で、「ネットワークアクセスによるスリープ解除」がOffだったら、スリープ中は絶対にssh接続できないかというと、そうでもありません。ネットワークアクセスによるスリープ解除」がOffであっても、Macは時々密かに目覚めているようで、そのタイミングならssh接続可能です。
ということで、スリープ中でもssh接続できることがあるけど、確実に接続したいのならば、明示的にスリープ解除する必要があります。
Macへの接続をOn/Offするアクセサリ
そこで、遠隔地からボタン操作して、スリープ解除するHomeKitアクセサリを、Homebridgeで作ることにしました。また、スリープしているはずでも、目覚めていることがあるようなので、それをボタンのOn/Offに反映したいと思います。
アクセサリというのはHomeKitの用語で、HomeKitから制御できるスイッチ、電球、センサ、家電などのIoTデバイスのことです。HomeKit Accessory Protocol (HAP)で制御されます。
完成すれば、iPhoneやMacのホームアプリにこんなボタンが現れます。
このボタンは、ssh接続可能な状態ならば、オンになり、接続不可ならオフになります。オフの状態で、ボタンクリックすると、Macのスリープ解除をします。オンの状態でクリックすると、Macをスリープ状態にします。放置しておけば自動でスリープするはずなので、Macをスリープする必要性はあまりないと思います。
実装環境
実装する環境は以下です。Raspberry Pi 3で、Homebridgeを動かしています。これにWOLプラグインをインストールしてあります。
あとは、Raspberry Piから、
- Mac miniをスリープ解除する
- Mac miniをスリープする
- Mac miniがssh受付可能かを知る
方法を決めて、Homebridgeの設定ファイルに書き込むだけです。
Macのスリープ解除
スマートホームの利用の一つに、Wake on LAN (WoL)でパソコンの電源を投入する例がよく紹介されてます。WindowsやLinuxパソコンなら大抵の場合WoLが機能するのですが、Macには制限があります。
まず、電源が完全に遮断された状態からのWoL機能は、Intel Macの時代から、伝統的に提供されていません。UEFIにその機能が無いようです。なので、電源Offの状態のMacをWoLで起動させることはできません。一方で、スリープ状態のMacならば、WoLによってスリープ解除することが可能です。なので、スリープ解除はWoLで行うことにします。
Macをスリープさせる
Macがssh接続可能な状態であるなら、ssh接続してコマンドでスリープできます。Linuxなどと同様に、
sudo shutdown -s now
でスリープさせることができます。macOSならではの方法としては、
osascript -e 'tell application "Finder" to sleep'
というように、AppleScript経由で、ファインダーアプリにsleepを指示することもできます。さらには、電源管理用のユーティリティpmsetを使って
pmset sleepnow
とすることもできます。今回は、アクセス権限がシンプルで、動作の速いpmsetを使うことにします。
Raspberry PiとMacに、公開鍵・秘密鍵を設定してパスワード不要でsshできるようにしておけば、
ssh hoge@192.168.xxx.xxx pmset sleepnow
というコマンドをRaspberry Piから実行するだけで、パスワード入力無しで、Macをスリープできます。
ssh接続可能状態を知る
ssh接続可能かどうかは、nc (netcat) コマンドで調べることにしました。
nc -z 192.168.xxx.xxx 22
とすると、ポート22に接続可能かどうかがわかります。
Homebridge設定ファイル
Homebridgeの設定ファイルのaccessosriesの項目に、以下の内容を追記しました。NetworkDeviceという名前が、このWOLプラグインのアクセサリ名です。
"accessories": [
{
"accessory": "NetworkDevice",
"name": "MacMini",
"host": "192.168.xxx.xxx",
"mac": "aa:bb:cc:dd:ee:ff",
"wakeGraceTime": 20,
"pingCommand": "nc -z 192.168.xxx.xxx 22",
"pingCommandTimeout": 2,
"pingInterval": 10,
"shutdownCommand": "ssh hoge@192.168.xxx.xxx pmset sleepnow",
"shutdownGraceTime": 10,
},
wakeGraceTimeは、WoLした後、目覚めたかどうかをチェックするまでの時間です。pingCommandは、コンピュータが動作しているかどうかをチェックするコマンドで、pingCommandTimeoutはそのコマンドのタイムアウト、PingIntervalはその間隔です。通常は、WoLで電源を入れて、動作状態をpingコマンドでチェックします。今回は、WoLでスリープから復帰するのですが、スリープ中もpingコマンドは有効です。なので、前述のようにncコマンドを使ってます。shutdownCommandは遮断コマンドです。これもスリープさせる機能として使い、前述の通りpmsetを使ってます。
この記述を保存した後、Homebridgeを再起動すると、iPhoneやMacのホームアプリに、前出のボタンが現れ、ssh受付状態に従ってOn/Offしてます。Offの状態で操作したところ、スリープ解除できました。
この方法でスリープ復帰しても、画面は暗いままで、ネットワークだけが接続可能になります。またssh接続可能状態では、vncも可能でした。On状態のボタンを押してスリープさせても、すぐにボタンがOnに戻ってしまうこともあります。Macの都合でネットワークアクセスしているのかと思います。
まとめ
Mac miniをスリープ解除するためのHomeKitボタンを作りました。どのMacでも動作するはずです。通常、この手の自動化では、
- WoLで電源遮断状態から起動する
- pingコマンドで動作状態を検出する
- shutdownコマンドで電源遮断する
という手法が一般的ですが、今回は、
- WoLでスリープ状態から復帰する
- nc -z コマンドでssh可能かどうかを検出する
- pmset sleepnowコマンドでスリープさせる
という手法を使いました。
外出先からsshやvncする場合、MacBookから実行する機会がほとんどです。ホーム.appはiPhoneだけでなく、Macでも動作するので、ターミナルウィンドウの隣で作業できて便利です。

