Turning the printer on and off automatically #automation
The second idea I had for the usb relays I bought was to turn my printer on and off automatically, as is is located in a place where access to the power button means getting on the floor and twisting underneath a desk. Also the has printer lights that are annoying, even when it goes into "hibernation" mode, so I want it turned off when not in use.
I have an access point which has a usb port, and since the access point is always on and it is in the vicinity of the printer, it's a good candidate for controlling the relay.
I connected the usb-cable to the access point and installed the crelay package, which supports my usb controlled relay, and then I connected the power cable to the printer. The access point runs OpenWrt so packages like this are readily available.
So now I can turn the printer on by ssh'ing to the access point and
running the command crelay 1 ON
. Turning it off is similarly simple. I
copied the contents of /root/.ssh/id_rsa.pub
on my computer to
/etc/dropbear/authorized_keys
on the access point to allow
non-interactive ssh access.
On my computer, I'm using CUPS for printing;
after a bit of searching I found and installed the
Tea4CUPS
package, and added these two
lines to /etc/cups/tea4cups.conf
:
prehook_power : ssh accesspoint.koldfront.dk crelay 1 ON
posthook_power : echo /usr/local/bin/printer_off "$TEAPRINTERNAME" | at now + 5 minutes
and preprended tea4cups:
to the DeviceURI
in /etc/cups/printers.conf
.
The prehook runs when a new print jobs enters the queue, and turns the printer on (if the printer is already on, there is no change).
The posthook runs every time a print job finishes, so what I have it do
is to run a little script 5 minutes later. The script checks if the
print queue is empty and if it is, it turns the printer off. If it
isn't, it uses at(1)
to run itself after 5 more minutes, and so on,
until the print queue finally is empty. This is the script:
#!/bin/sh
# printer_off - Turn printer off if queue is empty. If not, try again
# in 5 minutes.
if lpq -P "$1" | grep -q 'no entries'; then
ssh accesspoint.koldfront.dk crelay 1 OFF
else
echo "$*" | at now + 5 minues
fi
What I like about this hook solution is that the printer is turned on when a job is created, and there is no polling/busy looping to detect jobs appearing in the print queue.
Recently an article on this subject caught my eye: "Home Assistant Printer Power Management". It might be interesting to contrast the two solutions.
What I didn't do: run things in docker containers, run a message queue,
run a script that calls lpq
every minute. Not to mention setting up
HomeAssistant.
My script is 10 lines + 3 config lines for the hooks, compared to 104 lines of script + 25 lines of YAML.
If you are already running HomeAssistant, it might be nicer to integrate the printer into it. But also a lot more complicated, it seems.
Thanks for your blog post. The at command in the posthook is important. I spawned a background child job, but the posthook was active until the child process ended, which was not what I wanted. With the at it works well.
I am wondering though if your solution has a race condition:
Assume you have the printer_off script run by the posthook finding out that the print queue is empty.
Not a new job could come in and the prehook for the new job powers on the printer.
Now the printer power off in the posthook gets executed (the print queue was checked before the new job came in).
and then called this script with a file lock in the prehook:
and the posthook:
(using your nice at solution :-))
Thanks for your post again Rainer
- Rainer Dorsch 🕤︎ - 2021-10-20
Rainer Dorsch writes:
You're absolutely right, it does.
In this case I prefer to skip the complexity associated with trying to mitigate the tiny race condition.
Some other computer could also try to use the printer, which wouldn't even make the printer turn on - so this solution isn't comprehensive, but for my use it is sufficient.
Thanks for your comment, I'm happy my post was useful!
- Adam Sjøgren 🕙︎ - 2021-10-20