PLEX server should keep Mac awake after wake-on-lan

I’m running Plex 1.1.4 on Sierra and had noticed that Caffeinate was constantly caffeinating with the original script, since Plex Server is always busy as you’ve said. However, I do NOT get any “authenticated user” lines in my log. This might have something to do with the fact I don’t use the Plex client app, but rather a Cambridge Audio Minx Xi, which relies on Plex’s standard DLNA server function.

So anyhow, I see there is also another log file “Plex DLNA Server.log” which seems to be getting updated only when I’m actually browsing / listening to music. I’m going to try using the original, simpler version of the script but with the following instead:

plexLog=~/Library/Logs/Plex\ Media\ Server/Plex\ DLNA\ Server.log

Hopefully this will work, and might be of help for anyone else who connects with a generic DLNA client instead of Plex itself.

Hi.
When I paste
echo “” >> ~/Library/LaunchAgents/PlexCaffeinate.plist && open -a TextEdit ~/Library/LaunchAgents/PlexCaffeinate.plist

terminal say
-bash: syntax error near unexpected token `&’

Why?

@rickenplex Difficult to say for sure. I’m guessing copying-and-pasting those commands into Terminal has caused the && characters to be escaped / differently-encoded. Are you running an old version of OS X?

I have been working hard to get WOL to work. I had several issues to fix before the script worked great, but now it is al running smoothly :slight_smile: I started with a script which is running on a DD-WRT router. This router needs to support TCPdump. More info about this script is available on the Windows forum: https://forums.plex.tv/discussion/comment/1428700#Comment_1428700

First of all I’d like to say that setting up the router correctly is very important to prevent issues later while using the WOL script. I’ve had help setting up my DD-WRT router as a second router because I am bound to mu ISP router. Unfortunately the help I got was on a Dutch forum so not everybody will be able to follow this, for those who do: page 36/37 on the following site:

After setting up the router WOL worked, and using the script from jaoptc, it also worked when opening PLEX apps. The first two problems followed. 1) after a few minutes of sleep, the Plex apps didn’t trigger WOL anymore. Manual WOL still worked. 2) Opening the PLEX app on my LG WebOS 3 tv didn’t trigger WOL at all.
The problem seemed to be that the Mac address disappeared from the router ARP table. Long story short: the solution to this problem was to add another line to the script under Purgecount (see script at the bottom of the post).

# To Broad cast the WOL when Server is out of the ARP table. 
arp -i br0 -s $TARGET $MAC 

While testing this solution another problem came up (don’t worry if this happens to you also, the added line works). The following problem was that the Mac woke up after a minute of sleep. It would then fall asleep after another minute and so forth.

While this seemed to be one problem, the sleep and wake where separate problems. Due to the fact that both of these problems need you to disable SIP (System Integrity Protection) I will explain the solutions of both here. The reason you need to disable SIP is to enable you to edit system files you normally can’t edit.

The first solution is for the sudden wakes of the Mac. I looked deeper in to the reason why the Mac waked by entering the following command in Terminal:

syslog | grep -i "Wake reason”

The reason my Mac waked was “RTC (Alarm)”. After research I found the solution on the following site: https://comunix.info/fix-os-x-10-11-el-capitan-2-hour-wakeup-issue/

Step 1 is to disable SIP:
To disable SIP you start up the Mac in Recovery Mode. This is achieved by shutting down the Mac. When powering the Mac back on hold the CMD + R buttons until the Apple logo appears. From there go to Utilities > Terminal and enter the following

csrutil enable

Hit enter and when you see the confirmation restart the Mac and let the Mac boot normally.

After SIP is disabled and the Mac has restarted open Terminal and enter the following command:

sudo nano /System/Library/LaunchDeamons/com.apple.mDNSResponder.plist

Go to the line /usr/sbin/mDNSResponder and insert the following line:

<string>-NoMulticastAdvertisements</string>

After a reboot the wake reason RTC (Alarm) should be fixed.

The second problem which requires SIP to be disabled is the problem that the Mac fell asleep after a short wake period (< 1 minute). The core problem appeared to be that the Mac didn’t fully wake, but did a Dark Wake. The Mac checked if there was a valid reason for the WOL. If not, the Mac returned to the sleeping state. The solution is:
1 Open a Terminal window.
2 Type the following: cd /Library/Preferences/SystemConfiguration
and hit enter
3 Edit com.apple.Boot.plist by typing: sudo nano com.apple.Boot.plist
4 Move the insertion point down to the associated with the Kernel Flags
5 Type darkwake=0
6 Hit CTR + X, enter Y and hit Enter to save and quit the file.
7 Reboot the system.

After a reboot you need to enable SIP again.

This is done the same as disabling it, but by typing

csrutil enable

After these modifications my Mac sleeps and wakes perfectly.
In the process I found a lot of information about Sleep modes on the Mac and on Hibernation.
WOL also works when Hibernation is enabled. Since this is not a standard setting there is another command needed.

More info about Sleep vs Hibernate is on those two sites:

For setting up Hibernation correctly on the Mac visit the following site:
http://bendeegan.com/2016/04/19/how-to-make-a-mac-hibernate-properly-and-consistently/

Beneath you can find my final DD-WRT script. The TARGET, BROADCAST and MAC sections need to be edited according to your setup.
Hope this helps some of you!!

Regards

Patrick

———————————————————————————————————————————

#!/bin/sh 
#Enable JFFS2 and place script in /jffs/ then run on startup in web interface. 
#You can check the log from http://192.168.1.1/user/wol.html 

INTERVAL=2 
PINGTIME=1 
OLD_TIME="" 
PORT=32400 
WOLPORT=9 
TARGET=192.168.1.252 
BROADCAST=192.168.1.255 
MAC=XX:XX:XX:XX:XX
WOL=/usr/sbin/wol 
LOGFILE="/tmp/www/wol.html" 
# Never change LOGLINESTOSTORE to under 100. It will create pretty much a loop on the cleanup log procedure 
LOGLINESTOSTORE=500 
PURGECOUNT=0 

# To Broad cast the WOL when Server is out of the ARP table. 
arp -i br0 -s $TARGET $MAC 


echo "<meta http-equiv=\"refresh\" content=\"10\">" > $LOGFILE 
echo "["`date`"] AUTO WOL Script started. <br>" >> $LOGFILE 
echo "For server: $TARGET:$PORT and MAC: $MAC on port $WOLPORT <br>" >> $LOGFILE 

tcpdump -q -n -i any -p -P out -K -l -O -U 'dst host '$TARGET' and dst port '$PORT'' 2>/dev/null | while read NEW ; do 
# Get the line in seconds, to minimize the number of processed commands. 
NEW_TIME=`echo $NEW | awk -F'.' '{print $1}'` 
if [ "$NEW_TIME" != "$OLD_TIME" ]; then 
# Get the source IP for logging 
SRC=`echo $NEW | awk -F'[.| ]' '{print $4"."$5"."$6"."$7}'` 
# If box is alive (responding to ping) 
if ping -qw $PINGTIME $TARGET >/dev/null; then 
echo "[`date`] NOWAKE - $TARGET accessed by $SRC <br>">> $LOGFILE 
#touch /dev/null 
else 
echo "[`date`] _WAKE_ - $TARGET accessed by $SRC <br>">> $LOGFILE 
$WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE 
echo "<br>" >> $LOGFILE 
fi 
OLD_TIME=$NEW_TIME 
# Cleanup log file procedure, keeping the header and the last 10 last WAKE log lines 
if [ "`wc -l $LOGFILE | awk -F'[ ]' '{print $1}'`" -gt "$LOGLINESTOSTORE" ]; then 
head -n 3 $LOGFILE > /tmp/www/wol.tmp 
PURGECOUNT=$((PURGECOUNT+1)) 
echo "Log File purged $PURGECOUNT times, last one at $NEW_TIME <br> " >> /tmp/www/wol.tmp 
grep _WAKE_ $LOGFILE | tail -n 10 >> /tmp/www/wol.tmp 
mv /tmp/www/wol.tmp $LOGFILE 
echo "<br>" >> $LOGFILE 
fi 
sleep $INTERVAL 
fi 
done

I’ve again updated my script. The original version had the benefit of being very simple, so was easy to understand. The new version is more complex, but has two key benefits:

  1. It prevents sleep more reliably (because instead of calling caffeinate every 5 minutes, it calls caffeinate once but keeps it active until you’ve stopped using Plex).
  2. It prevents its log files from growing forever (because it discards old logs every day).

Here are the steps to update your script:


  1. From the Dock, click Launchpad > Other > Terminal

  2. In the Terminal window that pops up, copy-paste the following (and hit return):

echo "" >> ~/Library/Scripts/PlexCaffeinate.sh && open -a TextEdit ~/Library/Scripts/PlexCaffeinate.sh
  1. In the TextEdit window that pops up, delete all of the existing text, then copy-paste the following:
#!/bin/bash

# Put Plex into debug logging mode
defaults write com.plexapp.plexmediaserver logDebug true

# Paths
plexLog=~/Library/Logs/Plex\ Media\ Server/Plex\ Media\ Server.log
caffLog=~/Library/Logs/Plex\ Media\ Server/Plex\ Caffeinate.log

# Kill subprocess on exit
trap '[[ -z "$(jobs -p)" ]] || kill $(jobs -p)' EXIT

# Functions
timestamp()      { date "+%b %d %H:%M:%S"; }
today()          { date "+%d"; }
plexUpdateTime() { stat -f %m "$plexLog" 2>/dev/null; }
plexUserAction() { tail -20 "$plexLog" | \
                   grep "authenticated user" | \
                   tail -1 2>/dev/null; }

# Init globals
initDay()        { day=$(today); }
initPlexState()  { updateTime=$(plexUpdateTime);
                   userAction=$(plexUserAction); }

# Day check
isSameDay()
{
    local myDay=$(today)
    if [ "$myDay" = "$day" ]; then
        return 0
    else
        day=$myDay 
        return 1
    fi
}

# Idle check
isPlexIdle()
{
    local myUpdateTime=$(plexUpdateTime)
    if [ -z "$myUpdateTime" ] || \
       [ "$myUpdateTime" = "$updateTime" ]; then
        return 0
    else
        updateTime=$myUpdateTime
        return 1
    fi
}

# Housekeeping check
isPlexHousekeeping()
{
    local myUserAction=$(plexUserAction)
    if [ -z "$myUserAction" ] || \
       [ "$myUserAction" = "$userAction" ]; then
        return 0
    else
        userAction=$myUserAction
        return 1
    fi
}

# Wait until user has finished using Plex
waitForUser()
{
    initPlexState
    while true; do
        echo "$(timestamp) Caffeinating..." >> "$caffLog"

        sleep 120

        if isPlexIdle;         then break; fi
        if isPlexHousekeeping; then break; fi
    done
}

# Check Plex and caffeinate if needed
initDay
initPlexState
while true; do
    sleep 30

    # Rotate logs
    if ! isSameDay; then mv "$caffLog" "$caffLog".1 2>/dev/null; fi

    # Check Plex
    if isPlexIdle; then
        echo "$(timestamp) Plex is idle" >> "$caffLog"
    elif isPlexHousekeeping; then
        echo "$(timestamp) Plex is running background tasks" >> "$caffLog"

    # Caffeinate
    else
        echo "$(timestamp) Caffeinate" >> "$caffLog"
        waitForUser &
        caffeinate -is -w $! 2>/dev/null
        echo "$(timestamp) Caffeinated" >> "$caffLog"

        initPlexState
    fi
done
  1. In the TextEdit menu bar, click File > Save, then File > Close

  2. Go back to the Terminal window, and copy-paste the following (and hit return):

launchctl unload ~/Library/LaunchAgents/PlexCaffeinate.plist && sleep 3
launchctl load ~/Library/LaunchAgents/PlexCaffeinate.plist

That’s it - the new script is now being used, and you can safely quit Terminal.

1 Like

@Parnty thanks for the great script! After setting it up last night and testing it, it seems to work great, however I noticed that Plex may have actually implemented their own process to prevent sleep.

My desktop has Plex server on it, and when I open up plex and start a stream from my laptop web browser I get these two PreventUserIdleSystemSleep processes:

pid 651(Plex Media Server): [0x0000d552000128c2] 00:02:41 PreventUserIdleSystemSleep named: "PreventUserIdleDisplaySleep"
pid 20418(caffeinate): [0x0000d3c30001274c] 00:09:39 PreventUserIdleSystemSleep named: "caffeinate command-line tool"

The second one is from the caffeinate process running in your script, but the first one comes from Plex Media Server. Oddly, it is a PreventUserIdleSystemSleep process but it is named PreventUserIdleDisplaySleep? Have you noticed this before?

Both processes go away when I close the tab running plex on my laptop. So I’m wondering, is your script necessary anymore? Thanks!

@djcoma Interesting - I see the same thing on my system. I’d never noticed that before, but I hadn’t really been looking for it, so I’m not sure if it’s a new thing or not.

In any case, I just tried disabling my script on my Plex server, and then accessing Plex as I usually do via the Plex app on my Samsung TV. As before, I’m getting freezes and network errors while browsing my library, so I think my script is still needed.

But I’m hoping that someday the (fantastic) Plex development team will do a proper fix of this issue once and for all! Let’s not forget, Plex is free software, so we’ve got to be pretty grateful to these guys. Apart from this minor issue, Plex works amazingly well.

@Parnty Thank you for your script! I have set it up yesterday and tried to test it, but for some reason it does not seem to work for me.
I opened up Console and it is spammed with following messages every 10 seconds.
16.01.2018 16:21:15,480 com.apple.xpc.launchd[1]: (PlexCaffeinate[904]) Service exited with abnormal code: 126
16.01.2018 16:21:15,480 com.apple.xpc.launchd[1]: (PlexCaffeinate) Service only ran for 0 seconds. Pushing respawn out by 10 seconds.
I am running El Capitan on Mac Mini. I’m not sure what additional information may be relevant in this case but (or course) I can provide additional details.
Any help would be greatly appreciated.

@nakiin Can you do the following and post back the results:


  1. From the Dock, click Launchpad > Other > Terminal

  2. In the Terminal window that pops up, enter the following and hit return:

~/Library/Scripts/PlexCaffeinate.sh
  1. If successful, this should appear to do nothing, as it is now running in a loop. Open another Terminal window by clicking Shell > New Window > New Window in the menu bar, then in the window that pops up, enter the following and hit return:
tail -10f ~/Library/Logs/"Plex Media Server/Plex Caffeinate.log"
  1. Do you now see Plex is idle or Plex is running background tasks messages appearing in this window?

When you’re done, enter <ctrl+c> in both Terminal windows, and then quit Terminal.

@Parnty I tried to run the script and immediately got an error:
-bash: /Users/andrzejkrzyzanowski/Library/Scripts/PlexCaffeinate.sh: /bin/bash^M: bad interpreter: No such file or directory

I’m running a Polish version of El Capitan - could it have something to do with localization settings?

I think you need to remove the ^M character after #!/bin/bash in your PlexCaffeinate.sh script

Well, there weren’t any additional characters… At least not that I could see.
Anyway I deleted this part and entered it manually. Now when I run the script I get this:
: command not foundanowski/Library/Scripts/PlexCaffeinate.sh: line 5:
: command not foundanowski/Library/Scripts/PlexCaffeinate.sh: line 9:
: invalid signal specificationrary/Scripts/PlexCaffeinate.sh: line 11: trap: EXIT
: command not foundanowski/Library/Scripts/PlexCaffeinate.sh: line 12:
'Users/andrzejkrzyzanowski/Library/Scripts/PlexCaffeinate.sh: line 27: syntax error near unexpected token </code> <code>'Users/andrzejkrzyzanowski/Library/Scripts/PlexCaffeinate.sh: line 27:isSameDay()

I have no idea what’s going on… I think I’ll rewrite it all by hand. Maybe there are more weird artefacts…

Got it!
I’m running my Mac Mini headless and use TeamViewer to control it. Apparently when I copied the script from my Windows laptop via TeamViewer it added these artefacts. Probably different coding.
I copy&pasted the script again from within and now it works!
Thank you very much for your help :smile:

@nakiin Great! Yes, I thought it might be a copy-paste problem…

I think Plex server on Mac might be using the wrong sleep assertion. See this thread for more info…

@bg3 Thanks a lot for this. I read your posts, and I think you might be right.

As you point out, it looks like Plex is currently using assertion kIOPMAssertionTypePreventUserIdleSystemSleep, which doesn’t seem to be having the desired effect of preventing sleep while using Plex.

You suggested that the Plex devs should use kIOPMAssertionTypePreventSystemSleep instead, which sounds like a good idea. There’s also kIOPMAssertionTypeNoIdleSleep, which might also work.

It’s great that you’ve done some investigating! Hopefully it’ll help the devs to do a proper fix.


The "NetworkClientActive” assertion might also be the right one here, since that’s what iTunes streaming uses, but I’m not sure if that’s a documented call or something just Apple uses.

@Parnty said:

As you point out, it looks like Plex is currently using assertion kIOPMAssertionTypePreventUserIdleSystemSleep, which doesn’t seem to be having the desired effect of preventing sleep while using Plex.

You suggested that the Plex devs should use kIOPMAssertionTypePreventSystemSleep instead, which sounds like a good idea. There’s also kIOPMAssertionTypeNoIdleSleep, which might also work.

It’s great that you’ve done some investigating! Hopefully it’ll help the devs to do a proper fix.

Pulling up this thread as I am experiencing the same problem with PMS on my Mac mini and I could not find a more recent discussion on this topic.
Has anybody from Dev ever responded to this matter?

@“Andreas B.” I’m not aware of any Devs picking this up. @bg3 raised the issue on his thread above, but it’s not clear if anyone’s doing anything about it. In the meantime, I’m making do with my script, which works ok.

1 Like

$0.99 App Wimoweh is on the Apple App Store.
It does the job but not as elegantly as your script, but I haven’t been able to get your script working on Mac OS 10.13.6 High Sierra.