Thanks Eric - I think we ended up going down the same rabbit hole. I had previously tried xscreensaver, xfce-screensaver and no screensaver at all with no discernible difference in behavior.
I threw this together earlier today, reformatted the USB drive to ext4, fired up the cooling fan on the drive and started a new backup. It’s been running almost eight hours now without any indication of the disc powering down. I was going to wait until morning to share so as not to jinx it but after your post I thought I should share.
#!/bin/bash
##===================================================================##
# File.......: mksim (mouse keyboard simulator)
# Date.......: May-11-2026
# Description: Utility script to simulate mouse and keyboard activity.
# Considered safe for use to prevent power mangement from
# powering down devices during extended processing (e.g.
# to prevent unmounting USB external drives during
# backup processing). Screen burn is still a problem
# particularly for OLED displays so extended use is
# discouraged since this will defeat screen savers and
# other power management services.
##===================================================================##
set +x
# default delay is 30 seconds
delay=30
# check for a cmdline delay override
if [ $# -eq 1 ]; then
if [[ "${1}" =~ ^[0-9]+$ ]]; then
delay=${1}
fi
fi
if ! type -P xdotool &> /dev/null; then
printf "\nRun \"sudo apt install xdotool\" to use this utility\n\n"
exit 1
fi
# Get the display geometry
read width height <<< $(xdotool getdisplaygeometry 2>/dev/null)
if [[ -z "$width" || -z "$height" ]]; then
printf "\nFailed to get display geometry - aborting!\n\n"
exit 1
fi
# log some startup messages
printf "\nStarting at: `date '+%Y/%d/%m %H:%M:%S'`\n"
printf "Display geometry is width:$width height:$height\n"
printf "Using loop delay $delay\n"
printf "Infinite loop - press <CTL+C> to terminate\n\n"
# initialize some variables
x=0
y=0
xincr=$(($width / 20))
yincr=$(($height / 20))
# main loop
while [ 1 ]
do
# simulate a mouse move
xdotool mousemove $x $y
# increment the mouse coordinates
(( x += $xincr ))
(( y += $yincr ))
# if coordinates get outside the display reset to the origin
[[ $x -gt $width ]] && x=0
[[ $y -gt $height ]] && y=0
# simulate a key press for the left shift key - should be a noop
# this seems to be more reliable than the mouse move for preventing idle detection
# the mouse movements provide a nice visual confirmation everything's working
xdotool key Shift_L
# pause
sleep $delay
done