I have already modified my Spin_down script to control the LEDs to show me the drive status.
The inner ring shows me the countdown percentage. and the outer ring shows me the drive spin down/up status.
My code is kind of a hack of kyyhkynen's spin down script, but it works quite nicely. I've also modified the script to change the spin down time based on drive temperature (as my drive has a tendancy to overheat).
Here's my hacked script - I've documented most of t to help me keep track of what I've done:
#!/bin/bash
#
# smart_spindown
#
# Copyright (C) 2003 by Bart Samwel
#
# You may do with this file (and parts thereof) whatever you want, as long
# as my copyright notice is retained.
#
# Extended by joerk at gentoo-wiki.com
# Modified to fit WD MyBook World external hard drives by kyyhkynen at gmail.com
#
###################################################################
#
# Configuration
#
# Disk(s) to monitor.
# If you have only one disk, leave DISK2 empty
DISK1=sda
DISK2=
# The base "no reads" wait time (in seconds). This is multiplied by
# the backoff factor to determine the real "no reads" wait time.
WAITTIME=300
#Time for when Drive is overheating
OVERHEATWAITTIME=60
# The maximum "no reads" wait time (in seconds).
# This also limits the backoff factor: the backoff factor cannot increase
# above a value that makes the "no reads" wait time larger than MAXWAIT.
# Default is 1200 seconds.
MAXWAIT=1200
# Time (in seconds) between polls to see if the disk is active again.
# Default is 30 seconds.
POLLTIME=30
# Output levels. Level 2 is verbose, level 1 is normal output.
# Enable all levels you would like to see.
OUTLEVEL1=true
OUTLEVEL2=false
# Decide which output to use. Useful if run in daemon mode
# echo or logger
# output1 is logged to normal, output2 to debug syslog
# Is PID of this shell logged?
#OUTPUT1=echo
#OUTPUT2=echo
OUTPUTTAG="$(basename -- $0)[$$]"
OUTPUT1="logger -t $OUTPUTTAG -p user.notice --"
OUTPUT2="logger -t $OUTPUTTAG -p user.debug --"
# LED pointers FUEL_GAUGE is the inner ring, and POWER is the outer
FUEL_GAUGE="/sys/class/leds/wdc-leds:fuel-gauge/brightness"
POWER="/sys/class/leds/wdc-leds:power/brightness"
PERCENT=0;
#
# End of configuration. You shouldn't have to change lines below this :)
#
#########################################################################
# Device name(s) for the disk(s).
DEVNAME1=/dev/$DISK1
[ "$DISK2" ] && DEVNAME2=/dev/$DISK2
[ -z "$DISK2" ] && DEVNAME2=
# Stats file: the file used to monitor the disk's read activity.
# The first entry in this stats file must represent the read activity.
STATSFILE1=/sys/block/$DISK1/stat
STATSFILE2=/sys/block/$DISK2/stat
# Multiplication factor for the backoff after a spinup, in percentages.
# Default is 300 = factor 3.
BACKOFF_INCREASE_PCT=200
# Multiplication factor for the backoff at every poll that shows that
# the disk is spun down. This determines how fast the backoff value
# decreases.
BACKOFF_DECREASE_PCT=98
# Enable this if you don't use laptop_mode. This will make the script
# sync before spinning down the disc. To make this work, you must
# ensure that:
# 1. /proc/sys/vm/dirty_expire_centisecs is set to a high value. You can
# use 60000 for 10 minutes.
# 2. /proc/sys/vm/dirty_writeback_centisecs is set to the same value.
# 3. Your ext3 filesystems are mounted with "commit=n", where n is the
# number of seconds between commit. Use 600 for 10 minutes.
NO_LAPTOP_MODE=true
#
# Let's go!
#
# Number of poll times that the disc was found to be spun down.
POLLSSPUNDOWN=0
# Number of spindowns performed
SPINDOWNS=0
# Number of times (*100) the WAITTIME of no-reads required before spindown
BACKOFF_FACTOR=100
# Stats: Total time the disk has been up.
UPTIME=0
# Total duration of last spun-down period.
LASTDOWNTIME=-1
# Total duration of the last spun-up period.
LASTUPTIME=0
# Duration of the last poll. Always equal to POLLTIME except the first
# time around.
LASTPOLLTIME=0
# Make sure the stuff we use is in the cache. I've seen it happen
# that the script spun the disk down, and then "sleep" wasn't in
# the cache and the disk spun right up again. :)
true
false
sleep 1
# Log the end of script execution
trap "$OUTPUT1 'Exiting.'" EXIT
#Set Power Led to ON
echo 255 > $POWER
if [ "$DISK2" ] ; then
$OUTLEVEL1 && ${OUTPUT1} "Monitoring spindown opportunities for disks $DISK1 and $DISK2." ;
else
$OUTLEVEL1 && ${OUTPUT1} "Monituring spindown opportunities for disk $DISK1." ;
fi ;
if ($OUTLEVEL1) ; then
hdparm -C $DEVNAME1 $DEVNAME2 |grep active >/dev/null
if [ "$?" == "0" ] ; then
[ "$DISK2" ] && ${OUTPUT1} "A drive is currently spun up." ;
[ -z "$DISK2" ] && ${OUTPUT1} "The drive is currently spun up." ;
# Drive is Up, Use 100% of fuel gauge
PERCENT=100 ;
echo 255 > $POWER
else
[ "$DISK2" ] && ${OUTPUT1} "Both drives are currently spun down." ;
[ -z "$DISK2" ] && ${OUTPUT1} "The drive is currently spun down." ;
# Drive is Down, Use 0% of fuel gauge
PERCENT=0 ;
echo 0 > $POWER
fi ;
fi
# Get Drive Temperature
TEMPERATURE=`/usr/sbin/smartctl -d ata -A /dev/sda |grep 194 |awk '{ print $10; }'` ;
while [[ /sbin/true ]]; do
hdparm -C $DEVNAME1 $DEVNAME2 |grep active >/dev/null
if [ "$?" == "0" ] ; then
THISWAIT=$(($WAITTIME*$BACKOFF_FACTOR/100)) ;
# Drive is Up, Use 100% of fuel gauge, Turn on POWER LED
PERCENT=100 ;
echo 255 > $POWER
#Backup RamDisk - Remove if you do not use the Ramdisk
/etc/init.d/S13ramdisk backup
if [[ $THISWAIT -gt $MAXWAIT ]] ; then
THISWAIT=$MAXWAIT ;
fi ;
# Increase the backoff irrespective of whether we failed
# or not. The backoff should drop again by the lack of
# spinups afterwards.
BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_INCREASE_PCT/100)) ;
if [[ $(($BACKOFF_FACTOR*$WAITTIME/100)) -gt $MAXWAIT ]] ; then
BACKOFF_FACTOR=$(($MAXWAIT*100/$WAITTIME)) ;
fi ;
UPTIME=$(($UPTIME+$LASTPOLLTIME)) ;
LASTUPTIME=$(($LASTUPTIME+$LASTPOLLTIME)) ;
if [ "$LASTDOWNTIME" -ge "0" ] ; then
$OUTLEVEL1 && ${OUTPUT1} "A drive spun up after $LASTDOWNTIME seconds. Total time up/down: $UPTIME/$(($POLLSSPUNDOWN*$POLLTIME)) (avg sleep time $(($POLLSSPUNDOWN*$POLLTIME/$SPINDOWNS)))" ;
fi
PREVIOUS_READS_DISK1=-1 ;
PREVIOUS_READS_DISK2=-1 ;
NEXT_READS_DISK1=-1 ;
NEXT_READS_DISK2=-1 ;
NUM_EQUALS=0 ;
# Value to prevent writing to Log too often
LAST_TEMP_WRITE=0 ;
$OUTLEVEL2 && ${OUTPUT2} "Waiting for $THISWAIT seconds of read inactivity..." ;
PREVIOUS_READS_DISK1=`cat $STATSFILE1 |awk '{ print $1; }'` ;
[ "$DISK2" ] && PREVIOUS_READS_DISK2=`cat $STATSFILE2 |awk '{ print $1; }'` ;
while [[ $(($NUM_EQUALS*5)) -lt $THISWAIT ]]; do
# Get Drive Temperature
TEMPERATURE=`/usr/sbin/smartctl -d ata -A /dev/sda |grep 194 |awk '{ print $10; }'` ;
if [ "$NUM_EQUALS" -ge "$LAST_TEMP_WRITE" ] ; then
$OUTLEVEL1 && ${OUTPUT1} "Current Drive Temperature: $TEMPERATURE Degrees." ;
LAST_TEMP_WRITE=$(($NUM_EQUALS+5)) ;
fi ;
# If Temp too High - reduce sleep time.
if [ "$TEMPERATURE" -ge "50" ] ; then
$OUTLEVEL2 && ${OUTPUT2} "Drive is OverHeating. Lowering Sleep Timeout" ;
THISWAIT=$OVERHEATWAITTIME ;
fi ;
sleep 5 ;
UPTIME=$(($UPTIME+5)) ;
LASTUPTIME=$(($LASTUPTIME+5)) ;
NEXT_READS_DISK1=`cat $STATSFILE1 |awk '{ print $1; }'` ;
[ "$DISK2" ] && NEXT_READS_DISK2=`cat $STATSFILE2 |awk '{ print $1; }'` ;
if [[ $PREVIOUS_READS_DISK1 -ne $NEXT_READS_DISK1 ]] ; then
NUM_EQUALS=0 ;
PREVIOUS_READS_DISK1=$NEXT_READS_DISK1 ;
$OUTLEVEL2 && ${OUTPUT2} "$DISK1 read, restarting..." ;
else
if [ "$DISK2" -a $PREVIOUS_READS_DISK2 -ne $NEXT_READS_DISK2 ] ; then
NUM_EQUALS=0 ;
PREVIOUS_READS_DISK2=$NEXT_READS_DISK2 ;
$OUTLEVEL2 && ${OUTPUT2} "$DISK2 read, restarting..." ;
else
NUM_EQUALS=$(($NUM_EQUALS+1)) ;
$OUTLEVEL2 && ${OUTPUT2} "Seconds of quiet: $(($NUM_EQUALS*5))" ;
fi
fi
# Set Fuel Gauge to show Sleep timer
PERCENT=$(((100-(($NUM_EQUALS*5)*100)/$THISWAIT)));
echo $PERCENT > $FUEL_GAUGE ;
$OUTLEVEL2 && ${OUTPUT2} "Fuel Gauge at: $PERCENT %" ;
done
# We've just had $THISWAIT seconds of read inactivity. Writes can be
# cached, reads always spin up the disk; the inactivity indicates
# that we're ready to go to sleep. Laptop mode will have synced all
# writes for us after the last read, so we don't have to explicitly
# sync.
if ( $NO_LAPTOP_MODE ) ; then
sync ;
fi ;
hdparm -q -y $DEVNAME1 $DEVNAME2 ;
SPINDOWNS=$(($SPINDOWNS+1)) ;
$OUTLEVEL1 && ${OUTPUT1} "Drive(s) spun down after $LASTUPTIME seconds (with $THISWAIT seconds of inactivity), total spin down count: ${SPINDOWNS}." ;
LASTUPTIME=0 ;
LASTDOWNTIME=0 ;
# Turn Off Power LED
echo 0 > $POWER ;
else
# Check Drive Temperature
TEMPERATURE=`/usr/sbin/smartctl -d ata -A /dev/sda |grep 194 |awk '{ print $10; }'` ;
$OUTLEVEL1 && ${OUTPUT1} "Current Drive Temperature: $TEMPERATURE Degrees." ;
POLLSSPUNDOWN=$(($POLLSSPUNDOWN+1)) ;
if [[ $SPINDOWNS -eq 0 ]] ; then
SPINDOWNS=1 ;
fi
LASTDOWNTIME=$(($LASTDOWNTIME+$LASTPOLLTIME)) ;
BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_DECREASE_PCT/100)) ;
if [ $BACKOFF_FACTOR -lt 100 ] ; then
BACKOFF_FACTOR=100 ;
fi
fi ;
if ( $OUTLEVEL2 ) ; then
${OUTPUT2} "spindowns: $SPINDOWNS, time up/down: $UPTIME/$(($POLLSSPUNDOWN*$POLLTIME)), backoff $BACKOFF_FACTOR, down for $LASTDOWNTIME (avg $(($POLLSSPUNDOWN*$POLLTIME/$SPINDOWNS)))." ;
fi ;
sleep $POLLTIME ;
LASTPOLLTIME=$POLLTIME ;
done