Macはスリープで使う人が多いらしいです。スリープならばすぐに復帰するので便利です。ただし、外出先から家のLANにVPN接続して、スリープ中のMacを使おうとすると受け付けられません。そこで、HomeKitに「MacのスリープをOn/Off」するボタンを作りました。これで世界中のどこからでも、家のMacのスリープをOn/Offできます。
M4 Mac miniはスリープ運用
M4 Mac miniを買いました。今までは、M1のMacbookとIntelのデスクトップを使ってました。AppleのApple Silicon移行が進捗して、Intelで使えない機能が増えてきたので、そろそろデスクトップもApple Siliconにすべきかと思いました。
iMac以外のヘッドレスデスクトップMacの現行機種は、Mac mini, Mac Studio, Mac Proの3機種です。Proは流石に高価すぎて無理でした。Studioは、適度なサイズで、SSDがソケットで拡張性があって良いのですが、 全部バラさないと、ファンの埃を掃除できない設計が嫌かと思いました。筐体上面板が外れるようになっていれば掃除が簡単なのですが、見た目重視のデザインなので無理なのでしょう。miniは、長らく筐体デザインが昔のままでした。画期的で美しいデザインなのですが、DVDドライブ内蔵を前提とした設計なので、最近のminiでは持て余して、中がスカスカだったりしました。底の開口部が丸いのもオシャレですが、そのおかげでパーツの取り出し・取り付けが、知恵の輪パズルのように困難でした。ところが、新型M4 Mac miniはこうした不満を一掃してくれました。コンパクトになって、裏蓋は全て外れて、さらにSSDがソケットになって拡張可能になりました。
唯一の問題点は、巷で話題になっているように、電源スイッチが底にあって押しにくいことです。ただ、いまどきの省電力なコンピュータは、電源On/Offでなくてスリープ解除/開始で運用するので、電源スイッチは使いにくくても構わないという意見もあります。iPhoneはスリープしか使わないので、同じ部品を使っているMacもスリープ運用で良いのかと思います。スリープなら、一瞬で復帰するので、使いやすいです。
HomeKitでスリープ制御
私の家のルーターはYAMAHA RTX 1200の中古を使っていて、これでL2TP over IPSec方式のVPNサーバを動かしています。なので外出先から家のLANに入って、Raspberry PiやMacを操作できます。でもスリープ中のMacには、ssh接続(リモートログイン)や、VNC接続(画面共有)ができません。
Macがスリープしている時は、ターミナルからsshコマンドを打っても返答がありません。画面共有 (VNC) を試みても、しばらく待たされた後、下のようにエラーダイアログが出ます。
こういうサーバー的な用途に使いたい場合は、本来ならばスリープさせない設定で使うべきです。「システム環境設定」「エネルギー」から、「ディスプレイがオフの時に自動でスリープさせない」の項目をOnにしておくと、スリープしない設定になります。ただ、外出先から接続することは滅多にないので、電気代がもったいない気がします。
そこでHomeKitからスリープ解除できれば、リモートアクセスが必要な場合に、どこからでも対応できるかと考えました。
スリープ解除する
Macのスリープは、WOL (Wake On LAN) の仕組みでスリープ解除できます。以前、WindowsマシンをHomeKitからWOL起動する記事を書きました。

Windowsマシンの場合は、電源Offの状態からの起動ができました。Macでは、電源OffからのWOLをサポートしていません。スリープからの復帰のみ可能です。そこで前回記事と同様に、Homebridgeに、Homebridge WoLプラグインを導入して設定します。HomebridgeはRaspberry Piで動かしているので、以下のような構成になります。
Homebridgeの設定ファイルのaccessoriesの項目には、以下の内容を追記します。hostはMacのIPアドレス、macはMACアドレスです。
"accessories": [
{
"accessory": "NetworkDevice",
"name": "MacMini",
"host": "192.168.1.66",
"mac": "aa:bb:cc:dd:ee:ff"
}
]
これでHomebridgeを再起動すると、MacやiPhoneのホーム.appに以下のようなスイッチが現れます。
Macがスリープしている時に、このスイッチをOnにすれば、WOLのマジックパケットがMacに送られて、スリープ解除します。Macの画面は復帰しませんが、sshやVCNを受け付けてくれるようになります。
スリープ状態を検知する
上記の設定では、Macがスリープ状態になっても、HomeKitの表示はいつもオンのままでした。
この原因は、WOLプラグインのデフォルト動作では、pingへの反応を見て、コンピュータのOn/Offを検知しているからです。M4 Mac miniで調べた限り、Macはスリープ状態でもpingには応答します。なので、表示がオンのままなのです。(WOLプラグインは、電源On/Offさせるのが目的なので、pingでOn/Off判定するのが妥当でした。)
今回、スリープ状態で使えなくて困っている機能は、sshとVNCです。なので、これらに反応する・しないを調べて、HomeKitの表示に反映させることにします。実際にはsshへの応答でスリープ検知することにしました。そこで、Raspberry Piからncコマンドを使うことにしました。
nc -z 192.168.1.66 22
ncコマンドは、上記の書式で、指定したIPアドレス(Macのアドレス)、sshのポート番号22が応答しているかどうかを教えてくれます。Homebridge設定ファイルの中で、pingコマンドの代わりにこれを使うことを、以下のようにして指定しました。
"accessories": [
{
"accessory": "NetworkDevice",
"name": "MacMini",
"host": "192.168.1.66",
"mac": "aa:bb:cc:dd:ee:ff",
"wakeGraceTime": 20,
"pingCommand": "nc -z 192.168.1.66 22",
"pingCommandTimeout": 2,
"pingInterval": 10
}
]
wakeGraceTimeは、WOLのマジックパケットを送った後、pingコマンドを使うまでの時間です。wakeに時間がかかる場合、ボタンのOn/Off表示が安定しないことを避けるための設定です。デフォルトは45秒ですが、スリープ解除は高速なので、20秒に設定しました。pingCommandTimeoutは、pingコマンド失敗判定の時間です。デフォルトは0秒なのですが、余裕を見て2秒にしました。pingIntervalは、pingコマンド間隔です。Mac動作の邪魔にならないように、デフォルト2秒より長くしておきました。
この結果、sshが受け付けられない状態になると、HomeKitのボタンがOff表示になりました。これで、Macがsshに応答することを、HomeKitボタンの状態で知ることができました。Macのスリープメニューを操作しても、ボタン状態が変化します。
スリープ状態の変化
このボタンを観察していると、WOL操作やMacのスリープメニュー操作に関わらず、スリープ状態が勝手に変化する現象に気づきました。
例えば、Macのメニューからスリープさせた後、しばらくするとボタンがOn状態になることがあります。おそらくは、「システム環境設定」「エネルギー」で、
「ネットワークアクセスによるスリープ解除」をOnにしていることが原因です。これにより、定期的にスリープ解除して、ネットワーク機能を動作させているものと思われます。この期間中は、sshもVCNも接続可能です。
逆に、HomeKitのボタンからスリープ解除してOn状態にした後、最短で30秒くらい放置すると、ボタンがOff状態になります。スリープ解除後に、すぐにssh接続すれば、ssh接続中はスリープ解除状態が保持されます。ネットワークアクセスが無い場合は、30秒程度でスリープ状態に戻るようです。
このように、スリープ状態で放置したMacが、リモートアクセス可能状態なのかどうかは、色々な条件で変化するようです。HomeKitのボタンからそれが検知できるのは、便利だと思いました。
スリープ開始する
ここまでで、
- ボタンOnでスリープを解除すること
- スリープ状態をボタンOn/Offに反映すること
ができましたので、最後に
- ボタンOffでスリープ開始すること
も作り込むことにしました。時間が経てば自動的にスリープするので、必須な機能ではありません。でも、HomeKitボタンのOff操作に対応する機能も作っておきたかったです。
Raspberry Piから手動でMacをスリープさせるためには、sshで接続して、
sudo shutdown -s now
などすれば良いようでした。-sでスリープを指定します。ただこのためには、sshコマンドを打って、パスワードを入れて、shutdownコマンドを打って、パスワードを入れるなどの操作が必要です。
そういう操作を自動化するために、expectというツールがあるらしいです。そこで、Raspberry Piにexpectをインストールしました。
sudo apt install expect
そして、以下のようなシェルスクリプトファイルを作って、
#!/bin/bash expect -c " spawn ssh 192.168.1.66 expect \"Password:\" send \"hogehoge\n\" expect \"~ %\" send \"sudo shutdown -s +3s\n\" expect \"Password:\" send \"hogehoge\n\" expect \"~ %\" send \"exit\n\" "
これを実行すれば、上記の手順を自動化できました。expectの行は、画面に表示されるプロンプトで、それが表示されたらsendの行を入力するという仕組みのようです。ここではshutdownでスリープするまでの時間を3秒にしてます。このショルスクリプトファイル名を、例えばsleep_macとして、ホームディレクトリに置いておきます。Homebridgeの設定ファイルに、以下のように追記すれば、HomeKitボタンをOffにした場合に、このファイルが実行されて、Mac側でshutdownコマンドを発行できるようになります。
"accessories": [
{
"accessory": "NetworkDevice",
"name": "MacMini",
"host": "192.168.1.66",
"mac": "aa:bb:cc:dd:ee:ff",
"wakeGraceTime": 20,
"pingCommand": "nc -z 192.168.1.66 22",
"pingCommandTimeout": 2,
"pingInterval": 10,
"shutdownCommand": "/home/hoge/sleep_mac",
"shutdownGraceTime": 10
}
]
まとめ
スリープ状態のMacをWOLでスリープ解除し、動作状態のMacをshutdownコマンドでスリープさせるボタンを、HomeKit上に作成しました。Macがssh受け入れ可能かどうかを検知して、ボタンのOn/Off状態に反映しています。これで、自宅でスリープしているMacに、外出先からアクセスできるようになりました。
コメント