jk
Blog

Teaching the PC under my TV when to sleep

The PC under my TV drew 47 W doing nothing. Putting it to sleep was easy. Knowing when sleep was safe, and waking it again, took most of the work.

25 October 20266 min readHomelabPerformance

When I set up a new mini PC under my TV in October, it drew 47 W at the plug while it sat at the login screen doing nothing. In deep sleep the same PC draws 3.4 W. So I wanted it asleep whenever nobody was using it, and awake again the moment somebody wanted it.

Putting it to sleep takes one command. Knowing when that’s safe took most of the work, because “nobody is at the TV” doesn’t mean “nobody is using it”. I also work on this PC from my laptop, sometimes with jobs running overnight. And once it’s asleep, the PC can’t notice the TV coming on or answer a remote desktop connection, so something else has to wake it.

A TV PC that is also a work machine

The PC has an Intel i7-12650H and an Arc A730M graphics chip, and it runs Linux. On the TV it plays video and games, and I drive it with a handheld remote that also works as a mouse. From my laptop I use it as a work machine, over SSH and over remote desktop, which shows its whole screen in a window on the laptop.

Two other devices matter here. The TV reports over the home network whether it’s on. And my home server, a small mini PC that runs my self-hosted apps, never sleeps. It drew 10.7 W when I measured it in January, so the PC under the TV drew more than four times as much doing nothing.

Linux has a few ways to sleep, and on this PC only one of them pays off. Deep sleep keeps only the memory powered and draws 3.4 W. Suspend-to-idle, a lighter mode, drew 41.5 W here, so it isn’t used.

Awake at the login screen47 W
Suspend-to-idle41.5 W
Deep sleep3.4 W
What the PC draws at the plug. Suspend-to-idle saves only 5.5 W, and deep sleep saves almost all of it.

Only one thing decides when it sleeps

Before writing any rules about when to sleep, I had to stop everything else from putting the PC to sleep by its own rules. Three things could: the system’s own idle timer, the desktop’s power settings, and the Sleep key on that handheld remote, which could fire without anyone pressing it. All three are off now. One small service decides when the PC sleeps on its own, and sleeping by hand is still one command.

That service runs on the PC itself, because only the PC can see who is logged in, what’s playing and which programs have asked it to stay awake. The home server’s only job is to wake it.

The rules for “nobody is using it”

With one owner, all the rules live in one place. The PC sleeps once the TV is off and nothing has used it for half an hour, and the service checks several times a minute. Use means someone working on it over SSH or remote desktop, something playing, or the PC doing more than its background chores. A program can also hold a sleep lock, its way of asking the PC to stay awake. A scheduled job that’s running or about to start counts too. An open connection with nothing happening on it doesn’t count, and neither does an app left open on its own.

That leaves one kind of work the rules can’t see: a job that waits quietly, for a reply from the network or for me. To the system, a waiting job and an idle app look the same. For that I added a Keep Awake button to the PC’s desktop, which I see in the remote desktop window on my laptop. Clicking it holds a sleep lock until I click it again or the PC restarts.

The TV goes quiet when it’s off

The TV was the hardest rule to get right. When it goes to standby, it says so once and then stops answering on the network. So silence can mean the TV is off, or that the network has a problem while the TV is on.

The service believes “off” only when the last real answer from the TV was standby. If the TV goes quiet without saying so first, its state is unknown, and unknown keeps the PC awake. Every other check works the same way: if the service can’t tell what the PC is doing, the PC stays awake. Right before it sleeps, the service checks everything once more, and it won’t sleep if the home server that would wake it doesn’t answer.

I first tried a shortcut for the sleep locks. The system’s own sleep command can refuse to sleep while a program holds one. But it also refuses while anyone is logged in, even someone doing nothing, so the service checks the sleep locks itself.

An idle virtual machine kept it awake

Once the rules were running, one thing still kept the PC awake: a Windows virtual machine I keep on it for Windows builds. Even sitting idle, the virtual machine kept the processor busy enough to count as real work, so while it ran, the PC never got its quiet half hour. It now runs only while I use it, and shuts down after the same half hour without a connection.

The home server does the waking

Sleep was only half of it. A sleeping PC also has to wake up when someone wants it, and the obvious ways didn’t work. Turning the TV on didn’t wake it. Pressing the remote’s buttons or moving it didn’t wake it either, whether its USB receiver was in a hub or plugged straight into the PC. Wake-on-LAN did: a small packet sent over the home network to the PC’s network card, which keeps listening while the PC sleeps.

So the home server does it. Every few seconds it asks the TV whether it’s on, and when the TV comes on, it sends the PC a Wake-on-LAN packet. It never decides when the PC sleeps.

Remote desktop needed the same trick. A sleeping PC can’t answer a connection, and the VPN I use to reach it from outside the house sleeps with it. So from outside I connect to the home server instead, which is on the same VPN and never sleeps, and it answers remote desktop connections on the PC’s behalf. When a real remote desktop request arrives, the server wakes the PC, waits for it to come up and passes the connection through unchanged. The encryption, the login and the desktop itself stay on the PC, and the server stores no passwords. Something that only knocks on the port, like a network scan, wakes nothing.

Remote desktop appon my laptop
Home serverwakes the PC for a real request
Wake-on-LAN packet
PC wakes
Connection passed throughlogin stays on the PC
A remote desktop connection to the home server wakes the PC and reaches it unchanged. Only a real remote desktop request wakes it.

It froze once on the way to sleep

Sleep didn’t always go cleanly: on 21 October the PC froze partway into it, and I had to cut the power. The one thing new that day was a text console, the plain text screen Linux shows without a desktop, which a test had switched to that afternoon. Linux keeps that console attached to the HDMI output until the next restart, so for now the PC won’t go to sleep while it’s attached. What actually got stuck I don’t know, because Linux leaves almost no trace from inside a sleep.

What I learned

Automatic sleep needs exactly one owner. The system, the desktop and the handheld remote could each have put this PC to sleep by their own rules. With one service deciding, every reason it stays awake is in one status file and one log.

Anything the PC can’t confirm keeps it awake. The TV goes quiet in standby, so quiet alone never means off. Being wrong this way costs 47 W for a while. Being wrong the other way drops a remote desktop or a running job.

The machine that never sleeps does the waking. Asleep, the PC can’t see the TV come on or hear a remote desktop request. The home server is on anyway, so it watches the TV and answers for remote desktop, and the PC won’t sleep unless the server answers.

Where it stands

The PC now sleeps at 3.4 W when the TV is off and nothing has used it for half an hour. Turning on the TV wakes it, and so does connecting with remote desktop. SSH doesn’t: nothing answers SSH for the sleeping PC, so an SSH connection to it times out.

The freeze from 21 October is still open. To catch it, I’ll have the PC send its kernel messages to the home server over the network as it goes to sleep, so they survive a freeze. Then I’ll switch to the text console on purpose and put the PC to sleep, with someone at home to cut the power if it freezes again.

Read next