Skip to content

Instantly share code, notes, and snippets.

@Coltonton
Forked from stefaang/wdhws.sh
Last active March 27, 2024 17:24
Show Gist options
  • Save Coltonton/4eccdb487bfee23c71fa826664586a08 to your computer and use it in GitHub Desktop.
Save Coltonton/4eccdb487bfee23c71fa826664586a08 to your computer and use it in GitHub Desktop.
Hardware control script for PR4100
#!/bin/bash
#
# Main Control script for Free/TrueNAS CORE & SCALE on Western Digital PR2100?/PR4100
# Based off wdhws v1.0 by TFL (stefaang)
# #
# PLEASE SEE: https://github.com/Coltonton/WD-PR4100-FreeNAS-Control #
# #
# wdpreinit V1.1 by Coltonton
# - Fixed Some Typos/Cleaned up while I was here
# - Added Support For TrueNAS Scale as well as TrueNAS CORE
# - More Comments = More Better
#
# BSD 3 LICENSE (inherited from TFL)
# Thanks unix stackexchange question 231975 & github user @stefaang
############### COMMAND LIST ###############
# THING COMMAND USE
# FAN FAN=64 Enter Hex value 01-64 (1-100%) Use at your own risk, only you can prevent forest fires
# USB/Power LED LED=13 (See LED Guide)
# PowerLED-Pulse PLS=01 00-off 01-on (cant change color? is always blue?)
# PowerLED-Blink BLK=01 (See LED Guide)
# LCDBacklight BKL=64 Enter Hex value 00-64 (0-100%)
#
#
# To complete?
################ LED GUIDE #################
#XX-usb/pwr
#00-off/off 01-off/blue 02-off/red 03-off/purple 04-off/green 05-off/teal 06-off/yellow 07-off/White
#08-red/off 09-red/blue 0A-red/red 0B-red/purple 0C-red/green 0D-red/teal 0E-red/yellow 0F-red/White
#10-blue/off 11-blue/blue 12-blue/red 13-blue/purple 14-blue/green 15-blue/teal 16-blue/yellow 17-blue/White
#18-purple/off 19-purple/blue 1A-purple/red 1B-purple/purple 1C-purple/green 1D-purple/teal 1E-purple/yellow 1F-purple/White
###########################################################################
############################# VARS ####################################
###########################################################################
minfanspeed=30 # Minimum fan speed in percent
maxcputemp=80 # Maximum CPU temp before going full beans
opptemp=35 # Optimal (desired) temp (commie C degrees not freedom F :( )
tty=/dev/ttyS2 # Used to init variable, gets changed based on kernal in get_i2c_TTY()
###########################################################################
############################# FUNCS ###################################
###########################################################################
get_i2c_TTY(){
getVer=$(uname -s) # Get Linux Kernal (Linux vs FreeBSD for TrueNas Scal/Core)
if [ $getVer == 'FreeBSD' ] # If FreeBSD Free/TrueNAS Core
then
echo Found FreeBSD
tty=/dev/cuau3 # FreeBSD uses /dev/cuau3 for i2C coms
elif [ $getVer == 'Linux' ] # If Linux Free/TrueNAS Scale
then
echo Found Linux
tty=/dev/ttyS2 # Linux uses much cooler (telatype) /dev/ttyS2 for i2C coms
else # Just in case to catch wrong systems
echo ERROR: Detected Kernal Type Does Not Match Any Supported By This Program
echo Or there was an error
exit
fi
}
setup_tty() {
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/ada0 | grep Temperature_Celsius | awk '{print $10}'
}
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
}
show_welcome() {
# set welcome message
# maximum "xxx xxx xxx xxx "
send "LN1= FreeNAS "
send "LN2= Running "
}
led(){
#echo "PowerMode:$1 - PowerColor:$2 - UsbMode:$3 - UsbColor$4"
if [ "$1" == SOLID ]; then
send BLK=00
send PLS=00
if [ "$2" == BLU ]; then
send LED=01
elif [ "$2" == RED ]; then
send LED=02
elif [ "$2" == PUR ]; then
send LED=03
elif [ "$2" == GRE ]; then
send LED=04
elif [ "$2" == TEA ]; then
send LED=05
elif [ "$2" == YLW ]; then
send LED=06
elif [ "$2" == WHT ]; then
send LED=07
fi
fi
if [ "$1" == FLASH ]; then
send LED=00
send PLS=00
if [ "$2" == BLU ]; then
send BLK=01
elif [ "$2" == RED ]; then
send BLK=02
elif [ "$2" == PUR ]; then
send BLK=03
elif [ "$2" == GRE ]; then
send BLK=04
elif [ "$2" == TEA ]; then
send BLK=05
elif [ "$2" == YLW ]; then
send BLK=06
elif [ "$2" == WHT ]; then
send BLK=07
fi
fi
if [ "$1" == PULSE ]; then
send PLS=01
send LED=00
send BLK=00
fi
}
show_ip() {
send "LN1=Interface re$1"
ip=$(ifconfig re$1 | grep inet | awk '{printf $2}')
send "LN2=$ip"
}
monitor() {
lvl="COOL"
cpumaxtmp=0
minfanspeed=30 #Percent
maxcputemp=80
opptemp=35
# 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!"
led FLASH RED
fi
fi
# check pmc
tmp=$((0x$(get_pmc TMP)))
if [ "$tmp" -gt 64 ]; then
pmclvl="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
# max-opperating=a fullfan-minfan=b b/a= fan percent per degree
# check cpu #max 80 #opp 35 1.5% for every degree above 30% 80-35=45 100-30=70 70/45=1.5
for i in $(seq $(get_ncpu)); do
tmp=$(get_coretemp $((i-1)))
echo "cpu $i is $tmp"
if [ "$tmp" -gt 80 ]; then
echo "CPU $i temperature is $tmp"
lvl="HOT"
fi
if [ $tmp -gt $cpumaxtmp ]; then
cpumaxtmp=$tmp
fi
done
echo "CPU max temp is $cpumaxtmp"
newtmp=$(($cpumaxtmp-$opptemp))
setspeed=$(($newtmp*2+$minfanspeed-5))
echo "speed should be: $setspeed%"
if [ $setspeed -lt $minfanspeed ]; then
setspeed=$minfanspeed
echo "Fan speed below minimum, bumping to $minfanspeed%..."
fi
# check ram
for i in 0 1; do
tmp=$(get_ramtemp $i)
echo "ram$i temp is $tmp"
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=64
led FLASH RED
fi
else
send FAN=$setspeed
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
}
init() {
get_i2c_TTY
setup_tty
setup_i2c
echo "Getting system status and firmware!"
send VER
send CFG
send STA
led SOLID BLU
show_welcome
}
###########################################################################
############################# MAIN ####################################
###########################################################################
init
while true; do
# adjust fan speed every 30 seconds
monitor
# check for button presses
for i in $(seq 10); do
sleep 1
check_btn_pressed
done
done
@superdupe
Copy link

Hello, I have been using the original script for several years on my PR4100 with TrueNAS Core. I just updated to Scale and realized the original script doesn't work any longer. I found your fork and wondering how it might work? Also, I see you have three scripts. How do you use them? Do you run them all? In any order? What do the other scripts do? Sorry to bug... Thank you!

@Coltonton
Copy link
Author

Hello, I have been using the original script for several years on my PR4100 with TrueNAS Core. I just updated to Scale and realized the original script doesn't work any longer. I found your fork and wondering how it might work? Also, I see you have three scripts. How do you use them? Do you run them all? In any order? What do the other scripts do? Sorry to bug... Thank you!

This is nothing more then a fancier version of stefaangs program if that did not work for you this will not. His does have a known issue in the comments about the SMART commands changing a bit causing failure to get the drive temperatures. This does fix that if that’s the reason it won’t run.

As far as the 3 programs go they are for pre-init, post-init, and shutdown. Allowing a little bit more flexibility for crazy people like me who want to see some sort of confirmation that “Hey I got your shutdown button press, I’m going to shutdown” or “Hey FreeNAS is booting (preinit) but not started yet” making potential troubleshooting easier. Pre-Init and Shutdown are currently just one run programs to set the LCD message and LED state. (Flashing yellow?). While the post-init script loops and runs forever. I also added a sudo fan controller outside of the orginal “is something “hot”? Okay fans go full speed!” To actually have a fan profile. To prevent as I noticed little bit of fan for a bit OMG ITS A HURRICANE oh im okay go slow Tornado sirens blaring oh im okay now. While being annoying it is not healthy to thermo cycle things like that. Ideally you want to maintain a temperature. For something probably on 24/7 365 10years that very much can reduce lifespan.

Stefaang and unfortunately others did not write anything out in ‘basic English’ as is common. I very much do not like having no proper documentation; unfortunately that’s the sad reality we live in and I’ve also aimed to provide some more in basic English instead of basically all I found was “here’s the list of commands, no I won’t tell you what they are” as someone did in the one forum. There’s quite an amount of control one can have that’s been previously hidden. I do thank him for his work but it’s time an OCD engineer takes the reins; best part about ‘open source’ people can build and improve!

I have had plans to extend this out and build a full on device interface more like the stock firmware. Certainly it’s not something someone should regularly be using, but it’s really nice and I don’t have a life so 🤷🏼‍♂️ why not. I simply don’t like to just make things work; in my line of work that’s quite undesirable, but I’ve always been that way also.

@superdupe
Copy link

Awesome! Thank you for the reply... :) I'll try your scripts and see how they work... I assumed the reason (I'm not a programmer sorry) the old one didn't was it was written for FreeBSD vs Linux that Scale runs. Is that how it works or is this language generic between both operating systems? Thanks again... :)

@Coltonton
Copy link
Author

Awesome! Thank you for the reply... :) I'll try your scripts and see how they work... I assumed the reason (I'm not a programmer sorry) the old one didn't was it was written for FreeBSD vs Linux that Scale runs. Is that how it works or is this language generic between both operating systems? Thanks again... :)

That’s where it gets tricky. The ‘language’ is only a simple shell program which anything Linux ‘should’ recognize. The problem comes in the system calls, modules and such that some likely vary from system to system.

Just download like the wdpreinit.sh and try that one. I would expect that one to possibly work as all it does is communicate over i2C to the front panel to set the display and LED. The big test is wdhws.sh (postinit) that actually has all the system calls to get temps and stuff. You may need to chmod +x filename.sh and then run with ./filename.sh (may need sudo?)

@superdupe
Copy link

Hey just a followup. I played around with your scripts a bit, referring to some other documents where folks have run Debian on a PR4100... I changed the tty to dev/ttyS2 from the original /dev/cuau3 in the FreeBSD script and it worked! Thanks again for putting this together!

@Coltonton
Copy link
Author

Hey just a followup. I played around with your scripts a bit, referring to some other documents where folks have run Debian on a PR4100... I changed the tty to dev/ttyS2 from the original /dev/cuau3 in the FreeBSD script and it worked! Thanks again for putting this together!

👍🏼 Thanks for the info, I’ll take a look at cleaning this all up a smidge along with seeing what kinda checks I can do to make this multi compliant. I did find THIS which appears like it should be what I need and then set the i2C device accordingly based on system. Had to do something like this before for a python program to get the proper serial device between windows/linux :) if that’s all we need to do then perfect!

@Coltonton
Copy link
Author

Fixed some typos, removed my stuff, and updated file names

@superdupe
Copy link

Ok cool. I’ll try the new versions when I get back home. I think I caught from your comments earlier, your version keeps the fans running a bit more? To keep the temps constant? I ran it without drives and the fans were basically off, but when I put the drives back in, the fans have been running pretty good. Not full throttle but decent… Do you run TrueNAS?

@Coltonton
Copy link
Author

Ok cool. I’ll try the new versions when I get back home. I think I caught from your comments earlier, your version keeps the fans running a bit more? To keep the temps constant? I ran it without drives and the fans were basically off, but when I put the drives back in, the fans have been running pretty good. Not full throttle but decent… Do you run TrueNAS?

I have t done the multi version update yet. The orginal program for this only has like low and high settings for the fans. My PR4100 would like to go between the two quite annoyingly. My version actually has a profile that the warmer it gets the faster they run not just low/high (actually no? Reviewing the code up I don’t seem to have that fan profile published… weird.. I’ll have to do all of that much later. I’m at work lol.)

@superdupe
Copy link

Awesome. Looking forward to the work you have and will be doing!

@Coltonton
Copy link
Author

Awesome. Looking forward to the work you have and will be doing!

Could I possibly get you to run uname -a in the terminal this just gets the “Unix Name” and system information it should print a string like Linux Ash 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux and reply with the results. The second thing (in this example ASH) is your devices host-name I do ask you redact it with like XXX just to be extra extra safe. Learn more about this

@superdupe
Copy link

superdupe commented Mar 21, 2024

Absolutely... Here it is. I just switched from TrueNAS Core to TrueNAS Scale and this is the current release. Its based on Debian.

Linux XXX 6.1.74-production+truenas #2 SMP PREEMPT_DYNAMIC Wed Feb 21 20:30:38 UTC 2024 x86_64 GNU/Linux

@nestandi
Copy link

Hey everyone - also in the same boat with a scale on my pr4100. Great system, but without proper support-toolset it's difficult...
Thank you for your effort Coltonton and for your hint with ttyS2 superdupe!

After playing around with the scripts, I see that the temps are not getting right (i suppose because of another naming scheme of hard drives on scale) not the buttons... I'll try to play around a bit more, maybe I find some way to get this information from the system :)

@Coltonton
Copy link
Author

Hey everyone - also in the same boat with a scale on my pr4100. Great system, but without proper support-toolset it's difficult... Thank you for your effort Coltonton and for your hint with ttyS2 superdupe!

After playing around with the scripts, I see that the temps are not getting right (i suppose because of another naming scheme of hard drives on scale) not the buttons... I'll try to play around a bit more, maybe I find some way to get this information from the system :)

D*mmit. I really didn’t put the right stuff on github did I. Okay so somewhere along the line the SMART utilities changed its output and that’s why the dives temp is like a “)3” or something weird like that. 🙄my actual program with the actual fan profile has a fix le sigh

@nestandi
Copy link

Great news Coltonton - looking forward to your actual program :)

@Coltonton
Copy link
Author

Great news Coltonton - looking forward to your actual program :)

Absolutely... Here it is. I just switched from TrueNAS Core to TrueNAS Scale and this is the current release. Its based on Debian.

To the both of you I’m a dum dum. the real program is HERE on my account 😐 totally forgot about that. That still doesn’t have the i2C check tho(I’ll get it I’ll get it…), but that’s the actual fan control and stuff. If either of you wanna give it a shot. See if there are any other issues you can. Works fine on mine with FreeNAS

execute facepalm.exe

@nestandi
Copy link

nestandi commented Mar 22, 2024

Are you sure it's an updated program - https://github.com/Coltonton/WD-PR4100-FreeNAS-Control/tree/master ?
It seems to me, it's still the same - it's still addressing tty=/dev/cuau3 instead of ttyS2 etc...

Maybe I just don't see the forrest behind of all the trees :)

@Coltonton
Copy link
Author

Are you sure it's an updated program - web ? It seems to me, it's still the same - it's still addressing tty=/dev/cuau3 instead of ttyS2 etc...

Oh it was the right program with better thermal controls :) just not the i2C detection as said. But I think you and @superdupe would be very interested in looking at and trying V1.1 https://github.com/Coltonton/WD-PR4100-FreeNAS-Control/tree/master. ;) It should tm work now works perfectly fine on my (core) unit.

This all of course is still INDEV so I am currently working on some other things now. glad to get SCALE up and running!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment