🕰

macOS Sequoia 15.0以降で平日の定時にチャイムを鳴らす方法

2024/09/22に公開

これまでのあらすじ

macOSで平日の定時にチャイムを鳴らす方法では以下の手順でチャイム音源を定時に鳴らす設定を行いました。

  1. Garagebandでチャイム音を作成
  2. afplayでチャイム音を再生
  3. crontabで定期実行を登録

macOS Sequoia 15.0以降ではcronがうまく動かないので手順3をlaunchctlで行います。

手順1と2については上記記事を参照してください。

サウンドファイルを空白を含まないパスにコピーする(2024.9.25追記)

launchdによるサウンド再生ではパス名に空白を含むサウンドファイルでI/Oエラーが発生しました。plistファイルのProgramArgumentsの値はexecvpに渡されて実行されるため空白を含むパス名はそのまま書けば良いはずですが、私の環境ではうまく動作しませんでした。

なので空白を含まないパスにサウンドファイルをコピーします。

cp /Users/yasuyuki/Music/iTunes/iTunes\ Music/Music/Yasuyuki\ ENDO/School\ Sounds/Chime.m4a /Users/yasuyuki/Music/.

これでProgramArgumentsには空白を含まないサウンドファイルのパスが記述できるようになりました。

$ ls -l /Users/yasuyuki/Music/Chime.m4a 
-rw-r--r--@ 1 yasuyuki  staff  605224  9 25 13:35 /Users/yasuyuki/Music/Chime.m4a

plistファイルを作成する

launchctlで自動実行するには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>org.javaopen.chime</string>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/bin/afplay</string>
            <string>/Users/yasuyuki/Music/Chime.m4a</string></array>
        <key>SessionCreate</key>
        <true/>
        <key>StartCalendarInterval</key>
        <array>
            <!-- 月曜から金曜までの8:45 -->
            <dict>
                <key>Weekday
                </key>
                <integer>1</integer>
                <!-- 月曜日 -->
                <key>Hour</key>
                <integer>8</integer>
                <key>Minute</key>
                <integer>45</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>2</integer>
                <!-- 火曜日 -->
                <key>Hour</key>
                <integer>8</integer>
                <key>Minute</key>
                <integer>45</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>3</integer>
                <!-- 水曜日 -->
                <key>Hour</key>
                <integer>8</integer>
                <key>Minute</key>
                <integer>45</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>4</integer>
                <!-- 木曜日 -->
                <key>Hour</key>
                <integer>8</integer>
                <key>Minute</key>
                <integer>45</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>5</integer>
                <!-- 金曜日 -->
                <key>Hour</key>
                <integer>8</integer>
                <key>Minute</key>
                <integer>45</integer>
            </dict>
            <!-- 同じ要領で、9:00, 12:00, 13:00, 17:00 の設定 -->
            <dict>
                <key>Weekday</key>
                <integer>1</integer>
                <key>Hour</key>
                <integer>9</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>2</integer>
                <key>Hour</key>
                <integer>9</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>3</integer>
                <key>Hour</key>
                <integer>9</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>4</integer>
                <key>Hour</key>
                <integer>9</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>5</integer>
                <key>Hour</key>
                <integer>9</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <!-- 同様に 12:00, 13:00, 17:00 も設定します -->
            <dict>
                <key>Weekday</key>
                <integer>1</integer>
                <key>Hour</key>
                <integer>12</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>2</integer>
                <key>Hour</key>
                <integer>12</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>3</integer>
                <key>Hour</key>
                <integer>12</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>4</integer>
                <key>Hour</key>
                <integer>12</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>5</integer>
                <key>Hour</key>
                <integer>12</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <!-- 13:00 -->
            <dict>
                <key>Weekday</key>
                <integer>1</integer>
                <key>Hour</key>
                <integer>13</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>2</integer>
                <key>Hour</key>
                <integer>13</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>3</integer>
                <key>Hour</key>
                <integer>13</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>4</integer>
                <key>Hour</key>
                <integer>13</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>5</integer>
                <key>Hour</key>
                <integer>13</integer>
                <key>Minute</key>
                <integer>0</integer>
            </dict>
            <!-- 17:30 -->
            <dict>
                <key>Weekday</key>
                <integer>1</integer>
                <key>Hour</key>
                <integer>17</integer>
                <key>Minute</key>
                <integer>30</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>2</integer>
                <key>Hour</key>
                <integer>17</integer>
                <key>Minute</key>
                <integer>30</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>3</integer>
                <key>Hour</key>
                <integer>17</integer>
                <key>Minute</key>
                <integer>30</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>4</integer>
                <key>Hour</key>
                <integer>17</integer>
                <key>Minute</key>
                <integer>30</integer>
            </dict>
            <dict>
                <key>Weekday</key>
                <integer>5</integer>
                <key>Hour</key>
                <integer>17</integer>
                <key>Minute</key>
                <integer>30</integer>
            </dict>
        </array>
        <key>StandardOutPath</key>
        <string>/Users/yasuyuki/log/chime.log</string>
        <key>StandardErrorPath</key>
        <string>/Users/yasuyuki/log/chime-error.log</string>
    </dict>
</plist>

これで以下のcrontabと等価になるはずです。

45 8 * * 1,2,3,4,5 /usr/bin/afplay /Users/yasuyuki/Music/iTunes/iTunes\ Music/Music/Yasuyuki\ ENDO/School\ Sounds/Chime.m4a
0 9,12,13 * * 1,2,3,4,5 /usr/bin/afplay /Users/yasuyuki/Music/iTunes/iTunes\ Music/Music/Yasuyuki\ ENDO/School\ Sounds/Chime.m4a
30 17 * * 1,2,3,4,5 /usr/bin/afplay /Users/yasuyuki/Music/iTunes/iTunes\ Music/Music/Yasuyuki\ ENDO/School\ Sounds/Chime.m4a

plistを設置する

plistファイルをユーザーのホームディレクトリの~/Library/LaunchAgentsにコピーします。

cp org.javaopen.chime.plist ~/Library/LaunchAgents/.

ファイルがコピーされると以下の通知が表示されるはずです。

[システム設定]-[一般]-[ログイン項目と機能拡張]で確認してみましょう。

今回作成したplistがログイン項目と機能拡張に登録され有効になっています。

あとは定時に実行されるのを確認しましょう。

うまくいかない場合のデバッグ方法

うまくいかない場合のデバッグ方法としては以下を行いました。

  1. plistでのログの設定
  2. launchctl listでの確認
  3. launchd.logの確認

plistでのログの設定

plistファイルではStandardOutPathStandardErrorPathで標準出力と標準エラー出力をファイルに保存できます。

        <key>StandardOutPath</key>
        <string>/Users/yasuyuki/log/chime.log</string>
        <key>StandardErrorPath</key>
        <string>/Users/yasuyuki/log/chime-error.log</string>

例えば標準エラー出力に以下のエラーが出ていたら、ファイルI/Oに問題がありそうということが分かります。

Error: AudioFileOpen failed (-54)

launchctl listでの確認

launchctl listで起動項目の一覧を表示するとプログラムの終了ステータスが確認できます。

launchctl list | grep javaopen

例えば以下の表示であれば、exit(1)でエラー終了していることが分かります。

-	1	org.javaopen.chime

launchd.logでの確認

[システム設定]-[一般]-[ログイン項目と機能拡張]でバックグラウンド項目をオン/オフしながら、コンソール.appでlaunchd.logを表示するとログから実行状態が確認できます。

検索窓にplistファイルで設定したLabelを入力してフィルタすると分かりやすくなります。

GitHubで編集を提案

Discussion