Skip to content

Instantly share code, notes, and snippets.

@stefaang stefaang/wdhws.sh

Last active Jun 9, 2020
Embed
What would you like to do?
Hardware control script for PR2100/PR4100
#!/bin/bash
#
# Post-init script for FreeNAS on Western Digital PR2100/PR4100
# wdhws v1.0 by TFL
#
# BSD 3 LICENSE
#
# thanks unix stackexchange question 231975
setup_tty() {
tty=/dev/cuau3
exec 4<$tty 5>$tty
}
setup_i2c() {
# load kernel modules required for the temperature sensor on the RAM modules
kldload -n iicbus smbus smb ichsmb
}
send() {
setup_tty
# send a command to the PMC module and echo the answer
echo -ne "$1\r" >&5
read ans <&4
if [ "$ans" = "ALERT" ]; then
echo -ne ALERT >&2
exit 2
else
# keep this for debugging failing commands
if [ "$ans" = "ERR" ] || [ -z "$ans" ]; then
echo "CMD $1 gives ERR at $2" >&2
send_empty
ans=$(send "$1" $(($2 + 1)))
#exit 1
fi
fi
# only echo the result for retries ($2 not empty)
if [ ! -z $2 ]; then
echo "CMD $1 gives '$ans' at $2" >&2
fi
echo $ans
send_empty
# deconstruct tty file pointers, otherwise this script breaks on sleep
exec 4<&- 5>&-
}
send_empty() {
# send a empty command to clear the output
echo -ne "\r" >&5
read ignore <&4
}
get_ncpu() {
# get the number of CPUs
sysctl -n hw.ncpu
}
get_coretemp() {
# get the CPU temperature and strip of the Celsius
sysctl -n dev.cpu.$1.temperature | cut -d'.' -f1
}
get_disktemp() {
# get the disk $i temperature only if it is spinning
smartctl -n standby -A /dev/ada$1 | grep Temperature_Celsius | awk '{print $NF}'
}
get_ramtemp() {
# get the memory temperature from the I2C sensor
smbmsg -s 0x98 -c 0x0$1 -i 1 -F %d
}
get_pmc() {
# get a value from the PMC
# e.g. TMP returns TMP=25 --> 25
send $1 | cut -d'=' -f2
}
init() {
setup_tty
setup_i2c
echo "get system status and firmware"
send VER
send CFG
send STA
show_welcome
stop_powerled
}
show_welcome() {
# set welcome message
# maximum "xxx xxx xxx xxx "
send "LN1= FreeNAS "
send "LN2= go go go go go "
}
stop_powerled() {
# stop blinking power LED
send PLS=00
send LED=00 # set to 01 to enable it
send BLK=00
}
show_ip() {
send "LN1=Interface re$1"
ip=$(ifconfig re$1 | grep inet | awk '{printf $2}')
send "LN2=$ip"
}
monitor() {
lvl="COOL"
# check RPM (fan may get stuck) and convert hex to dec
fan=$(get_pmc FAN)
rpm=$((0x$(get_pmc RPM)))
echo "Got rpm $rpm"
if [ "$rpm" != ERR ]; then
if [ "$rpm" -lt 400 ]; then
echo "WARNING: low RPM - $rpm - clean dust!"
fi
fi
# check pmc
tmp=$((0x$(get_pmc TMP)))
if [ "$tmp" -gt 64 ]; then
lvl="HOT"
fi
# check disks [adjust this for PR2100!!]
for i in 0 1 2 3 ; do
tmp=$(get_disktemp $i)
echo "disk $i is $tmp"
if [ ! -z $tmp ] && [ "$tmp" -gt 40 ]; then
echo "Disk $i temperature is $tmp"
lvl="HOT"
fi
done
# check cpu
for i in $(seq $(get_ncpu)); do
tmp=$(get_coretemp $((i-1)))
echo "cpu $i is $tmp"
if [ "$tmp" -gt 50 ]; then
echo "CPU $i temperature is $tmp"
lvl="HOT"
fi
done
# check ram
for i in 0 1; do
tmp=$(get_ramtemp $i)
echo "ram temp is $tmp for $i"
if [ "$tmp" -gt 40 ]; then
echo "RAM $i temperature is $tmp"
lvl="HOT"
fi
done
echo "Temperature LVL is $lvl"
if [ "$lvl" == HOT ] ; then
if [ "$fan" != 40 ]; then
send FAN=40
fi
else
if [ "$fan" != 20 ]; then
send FAN=20
fi
fi
}
check_btn_pressed() {
btn=$(get_pmc ISR)
#echo "Btn is .$btn."
case $btn in
20*)
echo "Button up pressed!"
menu=$(( ($menu + 1) % 3 ))
;;
40*)
echo "Button down pressed!"
menu=$(( ($menu + 2) % 3 ))
;;
*)
return
esac
case "$menu" in
0)
show_welcome
;;
1)
show_ip 0
;;
2)
show_ip 1
;;
# if you add menu items here, update mod 3 uses above
esac
}
# initial setup
init
while true; do
# adjust fan speed every 30 seconds
monitor
# check for button presses
for i in $(seq 30); do
sleep 1
check_btn_pressed
done
done
@yuanjs

This comment has been minimized.

Copy link

yuanjs commented Aug 21, 2018

I try this script. after a while, it pop up a error:
./hardwarectl.sh: line 126: 2a: value too great for base (error token is "2a")

@ihongyi

This comment has been minimized.

Copy link

ihongyi commented Aug 24, 2018

Can this script be used for dsm 6.1.7?

@stefaang

This comment has been minimized.

Copy link
Owner Author

stefaang commented Sep 24, 2018

I try this script. after a while, it pop up a error:
./hardwarectl.sh: line 126: 2a: value too great for base (error token is "2a")

The value needs hex2decimal conversion.
Sorry for the late reply, I didn't get a notification of the warning.

use for dsm 6.1.7
I think you'll need another tty port, but yes.

@ihongyi

This comment has been minimized.

Copy link

ihongyi commented Sep 25, 2018

hello stefaang
Can you elaborate? Or is there a guide? Sorry, I don't have experience in this area.

@tstyopin

This comment has been minimized.

Copy link

tstyopin commented Mar 5, 2020

Hi, Stefaang!
Thank you very much for script, it does a great job!
Something changed in smartctl command, and get_disktemp gives something like 24/55 (it is minimum and maximum lifetime temperature)
I changed script line 65 a little and it worked well by now:
smartctl -n standby -A /dev/ada$1 | grep Temperature_Celsius | cut -d'/' -f37 | awk '{print $NF}'
I don't have a bash scripting experience at all, please correct if needed.
edit:corrected by forum post

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.