[
  {
    "path": "README.md",
    "content": "# PowerEdge-shutup\n<details>\n<summary>\n<b>[ Changelog ] </b>\n</summary>\n<p>\n\n- 2023 XX XX | >Since last year my R720's motherboard has been dying. Not sure if I'll get around to do finish the full 2.0 rework of this script since I won't really use it, but who knows, could gamble of me getting incredibly bored at some point.\n- 2022 07 11 | >minor update: Swapping CPU IDs fixing single CPU detection failure.\n- 2022 05 13 | >minor update: Adding custom failsafe value. Work In Progress branch for upcoming R5. \n- 2022 03 04 | >R4 patch1 : Adding new CPU Data source option, minor log corrections.\n- 2022 03 03 | >R4 Deltacheck CPU mode, DeltaA/E with Ambient check, failsafes, infinite CPU count.\n- 2022 02 27 | >minor update: adding IPMI-fail fail-safe.\n- 2022 02 27 | >R3 Auto CPUn/Ambient mode switching, logging, auto hexadecimal conversion, and more.\n- 2022 02 01 | >minor update: beginner friendly guide for beginner friendly Unraid and minor edits.\n- 2021 11 10 | >/!\\ r2f : fixing a small, but quite critical fluke.\n- 2021 08 19 | >R2 update: now takes in account intake and exhaust temperatures!\n- 2021 04-08 | > various shit edits\n- 2021 04 14 | >R1 initial dump from my running environment & comments\n</p>\n</details>\n\n## Requirements\n- iDrac Entreprise (afaik it won't work with express)\n- [IPMItool](https://github.com/ipmitool/ipmitool)\n- G11*, G12, G13/G14** Dell Poweredge server\n\n*See also [me/PowerEdge-IPMItools](https://github.com/White-Raven/PowerEdge-IPMItools) for more applications and resources.*\n\n## What about it\nDoes what it says, depending on your environmental constraints, it might let you make your servers whisper-quiet, which \n- for an office or small business, might let you have a functionnal and capable server room without ACTUALLY having to have a proper server room with space and soundproofing,\n- and for a small home setup or homelab might be a life and sleep saver\n\n\nIt's the \"raw script\" that can be almost used as is in a cron job, you're obviously free to use it and modify it.\n\nI'ld just appreciate that if you itterate on it or send it somewhere, you could else reference the source or commit it here under a new file name*, or fork it.\n(*to keep the original as-is, as an example of lazyness)\n\nAs of what you can do with these great little commands... well..\n\nYou can run them as a cron job, or create a loop, but point is, lets you set your fan speed to bare minimum RPM depending of how warm or cool is your room and how hard you hit your servers.\n\n\n\n## What if Linux hangs, and my server stops adjusting its fan speed?\n\nFor the sake of simplicity in this repo, I won't dive into the whole mess of scripts in own setup, BUT\nbut the script actually doesn't run on the server itself but on a Pi2 of which the sole purpose is to manage IPMI enabled machines' cooling, be a server to distribute UPS data/status, and answer pings.\n\n- If the Pi hangs, when the server pings it, it won't get an answer, and the server will switch itself on auto fan mode, which is BIOS/Firmware managed.\nThe server can also change its curve when running some tasks/loads, in fact it goes through NetCat to tell the pie \"now I need that\" and the pie switches to an other set of fan curve for that server.\n\n- If the server hangs... well it hanged, no biggie, the Pi keeps its cooling managed, since the IPMI would still pull accurate temps readings and would still answer the phone when the Pi tells it to do some stuff.\nSo yeah, bit more convoluted but it allows the servers to not be needing to be stable indefinitely to not risk to catch fire.\n\nI simply haven't included all that because it's a lot more cumbersome and needs to be kinda adapted to each setup and set of needs, and I'm clearly not going to do that.\n\n\n----------------\n*_G11 seem to lack CPU temps in the data you can pull and rely on. Beware of the comments about it in the script, look for Delta A/E mode and Ambient mode._\n\n**_I was told it is also working on iDrac8 (G13) and iDrac9 (G14), but that beyond iDrac update 3.30.30.30 for G13 and 3.34.34.34 for G14, Dell has modified/removed the ability to control the fans via IMPI._\n"
  },
  {
    "path": "fancontrol.sh",
    "content": "#!/bin/bash\n\n#WIP - sum\n#>Present data sources:\n#-IPMI CPU\n#-IPMI Ambient/INLET\n#-IPMI EXHAUST\n#-lm-sensors CPU (doable through SSH with a passwordless secure auth)\n#Todo\n#-Add select drive temps (using smartctl or other)\n\n#>Present modes:\n#-'default' - CPU temps (average/highest governor) + AE modifier + CPU temp delta safeguard for average temp governor\n#-'ambient-default' - DELTA AE, drives fan speed from calculation using the delta of temperature between inlet and exhaust and uses it instead of CPU temps, \n#  then + AE modifiers as in default mode. Is the default fall back method for missing CPU temp data.\n#-'ambient-legacy' - ignores CPU temps and curves, drives fan speed from AE temps only following ambient specific curve, crude fall back method.\n#Todo\n#- create additional parameters for drive temps, seperated in two famillies (either for front and back, or for HDD and SSD... or maybe 3 famillies/groups), \n#  with each a 3 step curve of modifiers.\n#- turn the bottom mess into a single dynamic function that each mode can call to do the job to facilitate adding new modes/profiles\n#- ?rewrite to use arrays instead of variables to store fan curves, and possibly from CPU temp data too?\n#- add alternative failsafe - 100% instead of auto\n\n\n#the IP address of iDrac\nIPMIHOST=192.168.0.42\n\n#iDrac user\nIPMIUSER=root\n\n#iDrac password (calvin is the default password)\nIPMIPW=calvin\n\n#YOUR IPMI ENCRYPTION KEY - a big string of zeros is the default, and by default isn't mandatory to be specified.\n#You can modify it, for example in idrac7's webinterface under iDRAC Settings>Network , in the IPMI Settings section.\nIPMIEK=0000000000000000000000000000000000000000\n\n#Side note: you shouldn't ever store credentials in a script. Period. Here it's an example. \n#I suggest you give a look at tools like https://github.com/plyint/encpass.sh \n\n#Failsafe mode\n#(Possible values being a number between 80 and 100, or \"auto\")\nE_value=\"auto\"\n\n#IPMI IDs\n#/!\\ IMPORTANT - the \"0Eh\"(CPU0),\"0Fh\"(CPU1), \"04h\"(inlet) and \"01h\"(exhaust) values are the proper ones for MY R720, maybe not for your server. \n#To check your values, use the \"temppull.sh\" script.\nCPUID0=0Eh\nCPUID1=0Fh\nCPUID2=\"0#h\"\nCPUID3=\"0#h\"\n#Yes, there are 4 CPU servers in the poweredge line. I don't have one, so I left 0#h values for these. As said above, modify accordingly.\nAMBIENT_ID=04h\nEXHAUST_ID=01h\n#-------------------------------------------------\n#For G11 servers and some other unlucky ones:\n#I was made aware that people on iDrac6, notably the R610, reported only having access to ambient temperature, and not CPU temps neither exhaust temps.\n#Keep in mind though that this method is way less indicative of CPU temps. \n#If your load isn't consistent enough to properly profile your server, it might lead to overheating.\n#In that case, you will have to do with only Ambient temp to define your fan speed, or rely on other sources for CPU temps.\n#-------------------------------------------------\n\n#Non-IPMI data source for CPU:\nNICPU_toggle=false\n#Command, or you way to pull data per device (here, using coretemp driver's coretemp-isa-#### )\nNICPUdatadump_command=(sensors -A)\n#Top level Device scan\nNICPUdatadump_device=\"coretemp-isa-\"\n#Top level device count of numbers. For example coretemp-isa-0000 and coretemp-isa-0001 on a R720, coretemp-isa-#### would be 4.\nNICPUdatadump_device_num=4\n#\"Core #\" label for grep\nNICPUdatadump_core=Core\n#Where to cut in the line\nNICPUdatadump_cut=\"-c16-18\"\n#Temperature offset : Some drivers report higher or lower temps than real world. Your offset must be an integer (ex: 0, -5, 12)\nNICPUdatadump_offset=0\n#IPMI data can be still used for Ambient and Exhaust data, but if you want to ignore pulling IPMI data all together, you can toggle it to false.\nIPMIDATA_toggle=true\n\n#Logtype:\n#0 = Only Alerts\n#1 = Fan speed output + alerts\n#2 = Simple text + fanspeed output + alerts\n#3 = Table + fanspeed output + alerts\nLogtype=2\n\n#There you basically define your fan curve. For each fan step temperature (in °C) you define which fan speed it uses when it's equal or under this temp.\n#For example: until it reaches step0 at 30°C, it runs at 2% fan speed, if it's above 30°C and under 35°C, it will run at 6% fan speed, ect\n#Fan speed values are to be set as for each step in the FST# value, in % between 0 and 100.\nTEMP_STEP0=30\nFST0=2\nTEMP_STEP1=35\nFST1=6\nTEMP_STEP2=40\nFST2=8\nTEMP_STEP3=50\nFST3=10\nTEMP_STEP4=60\nFST4=12\nTEMP_STEP5=75\nFST5=20\n#CPU fan governor type - keep in mind, with IPMI it's CPUs, not cores.\n#0 = uses average CPU temperature accross CPUs\n#1 = uses highest CPU temperature\nTEMPgov=0\n#Maximum allowed delta in TEMPgov0. If exceeded, switches profile to highest value.\nCPUdelta=15\n\n#These values are used as steps for the intake temps.\n#If Ambient temp is within range of $AMBTEMP_STEP#, it inflates the CPUs' temp average by AMBTEMP_STEP#_MOD when checked against TEMP_STEP#s.\n#If Ambient temp is above $AMBTEMP_MAX, which is step 4, a temp modifier of 69 should be well enough to make the script select auto-fan mode.\n#AMBTEMP_STEPX_noCPU_Fanspeed : Some servers don't report their CPU temps. In that case Fan speed can only be adjusted using Ambient temperature.\n#In case of lack of CPU temps in IPMI, Fan speed values are to be defined here as for each step in the AMBTEMP_noCPU_FS_STEP# value, in % between 0 and 100.\n\nAMBTEMP_STEP0=20\nAMBTEMP_MOD_STEP0=0\nAMBTEMP_noCPU_FS_STEP0=8\n\nAMBTEMP_STEP1=21\nAMBTEMP_MOD_STEP1=10\nAMBTEMP_noCPU_FS_STEP1=15\n\nAMBTEMP_STEP2=24\nAMBTEMP_MOD_STEP2=15\nAMBTEMP_noCPU_FS_STEP2=20\n\nAMBTEMP_STEP3=26\nAMBTEMP_MOD_STEP3=20\nAMBTEMP_noCPU_FS_STEP3=30\n\nMAX_MOD=69\n\n#If your exhaust temp is reaching 65°C, you've been cooking your server. It needs the woosh.\nEXHTEMP_MAX=65\n\n#Ambient fan mode - Delta mode\n# => Fall back method when no CPU readings are available.\n#Delta mode uses the temperature difference (delta) between intake (ambient) and exhaust to control fan-speed.\n#To set the Deltatemp and fan speeds for each, use the parameters for the CPU fan mode profile.\n#By default, for safety, the temperature is divided by 3, so for the default first step, 30°C of CPU temp, the delta value is 10°C.\n#To modify the ratio, modify the value DeltaR. Default is 3, no ratio is 1.\nAMBDeltaMode=true\nDeltaR=3\n#If in delta mode, ambient temp would warrant an higher fan speed according to the ambient profile, it will use ambient profile's\n#recommendation as to protect your hardware from running with a low delta but with an overall too high temperature.\n#If you lack Exhaust temps, there is a fallback method to solely ambient.\n#If you lack Intake temps, the fall back method swaps Exhaust to intake temps, you need to modify Ambient temp stepping,\n#because the values are too low, even if they are safe, since fans would run higher than you might want in that case.\n#If you lack both readings, it falls back to auto-fan mode.\n\n#Log loop debug - true or false, logging of loops for debugging script\nLogloop=false\n\n#Looplog prefix\nl=\"Loop -\"\n\n#IPMI Commands to set fan speeds.\n# \"ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x01 0x01\" gives back to the server the right to automate fan speed\n# \"ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x01 0x00\" stops the server from adjusting fanspeed by itself, no matter the temp\n# \"ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x02 0xff 0x\"hex value 00-64\" lets you define fan speed\n\n#Extra Curves and data sources\n\n#Hexadecimal conversion and IPMI command into a function \nipmifanctl=(ipmitool -I lanplus -H \"$IPMIHOST\" -U \"$IPMIUSER\" -P \"$IPMIPW\" -y \"$IPMIEK\" raw 0x30 0x30)\nfunction setfanspeed () { \n    TEMP_Check=$1\n    TEMP_STEP=$2\n    FS=$3\n    if [[ $FS == \"auto\" ]]; then\n        if [ \"$Logtype\" != 0 ] && [ \"$4\" -eq 0 ]; then\n                echo \"> $TEMP_Check °C is higher or equal to $TEMP_STEP °C. Switching to automatic fan control\"\n        fi\n        [ \"$4\" -eq 1 ] && echo \"> ERROR : Keeping fans on auto as safety measure\"\n        \"${ipmifanctl[@]}\" 0x01 0x01\n        exit $4\n    else\n        if [[ $FS -gt \"100\" ]]; then\n            FS=100\n        fi\n        HEX_value=$(printf '%#04x' \"$FS\")\n        if [ \"$4\" -eq 1 ]; then\n            echo \"> ERROR : Keeping fans on high profile ($3 %) as safety measure\"\n        elif [ \"$Logtype\" != 0 ]; then\n            echo \"> $TEMP_Check °C is lower or equal to $TEMP_STEP °C. Switching to manual $FS % control\"\n        fi\n        \"${ipmifanctl[@]}\" 0x01 0x00\n        \"${ipmifanctl[@]}\" 0x02 0xff \"$HEX_value\"\n        exit $4\n     fi\n}\n#Failsafe = Parameter check\nre='^[0-9]+$'\nren='^[+-]?[0-9]+?$'\nif [ \"$Logloop\" != false ] && [ \"$Logloop\" != true ]; then\n        echo \"Logloop parameter invalid, must be true or false!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [ \"$AMBDeltaMode\" != false ] && [ \"$AMBDeltaMode\" != true ]; then\n        echo \"AMBDeltaMode parameter invalid, must be true or false!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$DeltaR\" =~ $ren ]]; then\n        if [ \"$DeltaR\" -le \"0\" ]; then\n                echo \"DeltaR parameter invalid, must be greater than 0!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"DeltaR parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$CPUdelta\" =~ $ren ]]; then\n        if [ \"$CPUdelta\" -le \"0\" ]; then\n                echo \"CPUdelta parameter invalid, must be greater than 0!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"CPUdelta parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [ \"$TEMPgov\" != 1 ] && [ \"$TEMPgov\" != 0 ]; then\n        echo \"TEMPgov parameter invalid, can only be 0 or 1!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$Logtype\" =~ $ren ]]; then\n        if [ \"$Logtype\" -lt 0 ] || [ \"$Logtype\" -gt 3 ]; then\n                echo \"Logtype parameter invalid, must be in 0-3 range!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"Logtype parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$EXHTEMP_MAX\" =~ $ren ]]; then\n        if [ \"$EXHTEMP_MAX\" -lt 0 ]; then\n                echo \"EXHTEMP_MAX parameter invalid, can't be negative!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"EXHTEMP_MAX parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ $MAX_MOD =~ $ren ]]; then\n        if [ \"$MAX_MOD\" -lt 0 ]; then\n                echo \"MAX_MOD parameter invalid, can't be negative!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"MAX_MOD parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$E_value\" =~ $ren ]]; then\n        if [ \"$E_value\" -lt 80 ]; then\n                echo \"E_value parameter invalid, can't be negative or lower than 80\"\n                E_value=\"auto\"\n        fi\n        if [ \"$E_value\" -gt 100 ]; then\n                echo \"E_value parameter invalid, can't be greater than 100\"\n                E_value=\"auto\"\n        fi\nelif [ \"$E_value\" != \"auto\" ]; then\n        echo \"E_value parameter invalid, not a number!\"\n        E_value=\"auto\"\nfi\n#Counting CPU Fan speed steps and setting max value\nif $Logloop ; then\n        echo \"$l New loop => Counting CPU Fan speed steps and setting max value\"\nfi\nfor ((i=0; i>=0 ; i++))\ndo\n        inloopstep=\"TEMP_STEP$i\"\n        inloopspeed=\"FST$i\"\n        if [[ ! -z \"${!inloopspeed}\" ]] && [[ ! -z \"${!inloopstep}\" ]]; then\n                if $Logloop ; then\n                        echo \"$l CPU Temperature step n°$i = ${!inloopstep}°C\"\n                        echo \"$l Fan speed step n°$i = ${!inloopspeed}%\"\n                fi\n                if ! [[ \"${!inloopstep}\" =~ $ren ]]; then\n                        echo \"Butterfinger failsafe: CPU Temperature step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopspeed}\" =~ $ren ]]; then\n                        if [[ \"${!inloopspeed}\" -lt 0 ]]; then\n                                echo \"Butterfinger failsafe: Fan speed step n°$i is negative!\"\n                                setfanspeed XX XX \"$E_value\" 1\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Fan speed step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n        else\n                inloopmaxstep=\"TEMP_STEP$((i-1))\"\n        if [ $((i-1)) -le 0 ]; then\n                        echo \"Butterfinger failsafe: no CPU stepping found!!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                MAXTEMP=\"${!inloopmaxstep}\"\n                TEMP_STEP_COUNT=$i\n                if $Logloop ; then\n                        echo \"$l CPU temperature step count = $i\"\n                        echo \"$l CPU max temperature to auto mode = $MAXTEMP°C\"\n                        echo \"$l CPU Temp Steps counting = stop\"\n                fi\n                break\n        fi\ndone\n#Counting Ambiant Fan speed and MOD steps and setting max value\nif $Logloop ; then\n        echo \"$l New loop => Counting Ambiant Fan speed and MOD steps and setting max value\"\nfi\nfor ((i=0; i>=0 ; i++))\ndo\n        inloopstep=\"AMBTEMP_STEP$i\"\n        inloopspeed=\"AMBTEMP_noCPU_FS_STEP$i\"\n        inloopmod=\"AMBTEMP_MOD_STEP$i\"\n        if [[ ! -z \"${!inloopspeed}\" ]] && [[ ! -z \"${!inloopmod}\" ]] && [[ ! -z \"${!inloopstep}\" ]]; then\n                if $Logloop ; then\n                        echo \"$l Ambient temperature step n°$i = ${!inloopstep}°C\"\n                        echo \"$l Ambient modifier for CPU temp step n°$i = ${!inloopmod}°C\"\n                        echo \"$l Ambient NO CPU fan speed step n°$i = ${!inloopspeed}%\"\n                fi\n                if ! [[ \"${!inloopstep}\" =~ $ren ]]; then\n                        echo \"Butterfinger failsafe: Ambient temperature step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopmod}\" =~ $ren ]]; then\n                        if [[ \"${!inloopmod}\" -lt 0 ]]; then\n                                echo \"Beware: Ambient modifier for CPU temp step n°$i is negative!\"\n                                echo \"Proceeding...\"\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Ambient modifier for CPU temp step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopspeed}\" =~ $ren ]]; then\n                        if [[ \"${!inloopspeed}\" -lt 0 ]]; then\n                                echo \"Butterfinger failsafe: Ambient NO CPU fan speed step n°$i is negative!\"\n                                setfanspeed XX XX \"$E_value\" 1\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Ambient NO CPU fan speed step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n        else\n                inloopmaxstep=\"AMBTEMP_STEP$((i-1))\"\n        if [ $((i-1)) -le 0 ]; then\n                        echo \"Butterfinger failsafe: no Ambient stepping found!!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                AMBTEMP_MAX=\"${!inloopmaxstep}\"\n                AMB_STEP_COUNT=$i\n                if $Logloop ; then\n                        echo \"$l Ambient temperature step count = $i\"\n                        echo \"$l Ambient max temperature to max mod = $AMBTEMP_MAX°C\"\n                        echo \"$l CPU Ambiant Steps counting = stop\"\n                fi\n                break\n        fi\ndone\n#Pulling temperature data from IPMI\nif $IPMIDATA_toggle ; then\n    IPMIPULLDATA=$(ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK sdr type temperature)\n    DATADUMP=$(echo \"$IPMIPULLDATA\")\n    if [ -z \"$DATADUMP\" ]; then\n        echo \"No data was pulled from IPMI\"\n        setfanspeed XX XX \"$E_value\" 1\n    else\n        AUTOEM=false\n    fi\nelse\n    if $NICPU_toggle ; then\n        AUTOEM=false\n    else\n        echo \"Both IPMI data and Non-IPMI-CPU data are toggled off\"\n        setfanspeed XX XX \"$E_value\" 1\n    fi\nfi\n#Parsing CPU Temp data into values to be later checked in count, continuity and value validity.\nif $NICPU_toggle ; then\n    echo \"Non-IPMI data source. An error can be thrown without incidence.\"\n    if $Logloop ; then\n        echo \"$l New loop => Pulling data dynamically from Non-IPMI source\"\n    fi\n    for ((j=0; j>=0 ; j++))\n    do\n        [ -z \"$socketcount\" ] && socketcount=0\n        datadump=$(\"$NICPUdatadump_command\" \"$NICPUdatadump_device$(printf \"%0\"$NICPUdatadump_device_num\"d\" \"$socketcount\")\")\n        if [[ ! -z $datadump ]]; then\n            if $Logloop ; then\n                echo \"$l Detected CPU socket $socketcount !!\"\n                echo \"$l New loop => Parsing CPU Core data\"\n            fi\n            socketcount=$((socketcount+1))\n            for ((i=0; i>=0 ; i++))\n            do\n                [ -z \"$corecount\" ] && corecount=0\n                Corecountloop_data=$( echo \"$datadump\" | grep -A 0 \"$NICPUdatadump_core $i\"| cut \"$NICPUdatadump_cut\")\n                if [[ ! -z $Corecountloop_data ]]; then\n                    declare CPUTEMP$corecount=\"$((Corecountloop_data+NICPUdatadump_offset))\"\n                    if $Logloop ; then\n                        echo \"$l Defining CPUTEMP$corecount with value : $((CPUTEMP$corecount))\"\n                    fi\n                    corecount=$((corecount+1))\n                else\n                    if $Logloop ; then\n                        echo \"$l CPU Core data parsing on CPU Socket $((socketcount-1)) = stop\"\n                    fi\n                    break\n                fi\n            done\n        else\n            echo \"Non-IPMI detection : done.\"\n            if $Logloop ; then\n                echo \"$l Result : $corecount Total CPU temperature sources added.\"\n                echo \"$l CPU Data parsing from Non-IPMI source = stop\"\n            fi\n            break\n        fi\n    done\nelse\n    CPUTEMP0=$(echo \"$DATADUMP\" |grep \"$CPUID0\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP1=$(echo \"$DATADUMP\" |grep \"$CPUID1\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP2=$(echo \"$DATADUMP\" |grep \"$CPUID2\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP3=$(echo \"$DATADUMP\" |grep \"$CPUID3\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nfi\n#CPU counting\nif [ -z \"$CPUTEMP0\" ]; then\n        CPUcount=0\nelse\n        if [[ ! -z \"$CPUTEMP0\" ]]; then #Infinite CPU number adding, if you pull individual CPU cores from lm-sensors or something\n                for ((i=0; i>=0 ; i++))\n                    do\n                        CPUcountloop=\"CPUTEMP$i\"\n                        if [[ ! -z \"${!CPUcountloop}\" ]]; then\n                                if $Logloop ; then\n                                        echo \"$l CPU detection = CPU$i detected / Value = ${!CPUcountloop}\"\n                                fi\n                                if ! [[ \"${!CPUcountloop}\" =~ $re ]] ; then\n                                   echo \"!!error: Reading is not a number or negative!!\"\n                                   echo \"Falling back to ambient mode...\"\n                                   CPUcount=0\n                                   break\n                                fi\n                                currcputemp=\"${!CPUcountloop}\"\n                                CPUcount=$((i+1))\n                                TEMPadd=$((TEMPadd+currcputemp))\n                        else\n                                if [[ $((CPUcount % 2)) -eq 0 ]] || [[ $CPUcount -eq 1 ]]; then\n                                        if $Logloop ; then\n                                                if [ \"$CPUcount\" -eq \"1\" ]; then\n                                                        echo \"$l CPU count : $CPUcount CPU detected!\"\n                                                else\n                                                        echo \"$l CPU count is even : $CPUcount CPU detected!\"\n                                                fi\n                                                echo \"$l CPU counting = stop\"\n                                        fi\n                                        CPUn=$((TEMPadd/CPUcount))\n                                        break\n                                else\n                                        CPUcount=0\n                                        echo \"CPU count is odd, please check your configuration\";\n                                        echo \"Falling back to ambient mode...\"\n                                        break\n                                fi\n                        fi\n                done\n\n        fi\nfi\n#CPU Find lowest and highest CPU temps\nif [ \"$CPUcount\" -gt 1 ]; then\n        if $Logloop ; then\n                echo \"$l New loop => Finding highest and lowest CPU temps\"\n        fi\n        for ((i=0; i<CPUcount; i++)) #General solution to finding the highest number with a shitty shell loop\n            do if [[ $i -le $CPUcount ]]; then\n                CPUtemploop=\"CPUTEMP$i\"\n                if $Logloop ; then\n                        echo \"$l Checking for CPU$i = ${!CPUtemploop}°C\"\n                fi\n                if [ \"$i\" -eq 0 ]; then\n                      CPUh=${!CPUtemploop}\n                      CPUl=${!CPUtemploop}\n                else\n                    if [ ${!CPUtemploop} -gt $CPUh ]; then\n                        if $Logloop ; then\n                                echo \"$l New high! CPU$i = ${!CPUtemploop}°C\"\n                        fi\n                        CPUh=${!CPUtemploop}\n                    fi\n                    if [ ${!CPUtemploop} -lt $CPUl ]; then\n                        if $Logloop ; then\n                                echo \"$l New low! CPU$i = ${!CPUtemploop}°C\"\n                        fi\n                        CPUl=${!CPUtemploop}\n                    fi\n                fi\n            fi\n        done\n    if $Logloop ; then\n        echo \"$l Lowest = $CPUl°C\"\n        echo \"$l Highest = $CPUh°C\"\n        echo \"$l CPU Find highest = stop\"\n    fi\nfi\nif [ $TEMPgov -eq 1 ] || [ $((CPUh-CPUl)) -gt $CPUdelta ]; then\n        echo \"!! CPU DELTA Exceeded !!\"\n        echo \"Lowest : $CPUl°C\"\n        echo \"Highest: $CPUh°C\"\n        echo \"Delta Max: $CPUdelta °C\"\n        echo \"Switching CPU profile...\"\n        CPUdeltatest=1\n        CPUn=$CPUh\nfi\n#Ambient temperature modifier when CPU temps are available.\nAMBTEMP=$(echo \"$DATADUMP\" |grep \"$AMBIENT_ID\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nif [ $CPUcount != 0 ]; then\n        if [[ ! -z \"$AMBTEMP\" ]]; then\n                if $Logloop ; then\n                        echo \"$l New loop => Ambient temperature modifier\"\n                fi\n                if [ \"$AMBTEMP\" -ge $AMBTEMP_MAX ]; then\n                        echo \"Intake temp is very high!! : $AMBTEMP °C!\"\n                        TEMPMOD=$MAX_MOD\n                else\n                        for ((i=0; i<AMB_STEP_COUNT; i++))\n                        do\n                                AMBTEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                if $Logloop ; then\n                                        echo \"$l Checking for Ambient temperature($AMBTEMP) =< Ambient temperature step n°$i(${!AMBTEMP_STEPloop})\"\n                                fi\n                                if [ \"$AMBTEMP\" -le \"${!AMBTEMP_STEPloop}\" ]; then\n                                        AMBTEMP_MOD_STEPloop=\"AMBTEMP_MOD_STEP$i\"\n                                        TEMPMOD=\"${!AMBTEMP_MOD_STEPloop}\"\n                                        if $Logloop ; then\n                                                echo \"$l Result Checking for Ambient temperature($AMBTEMP) is =< Ambient temperature step n°$i(${!AMBTEMP_STEPloop})\"\n                                                echo \"$l Ambient temperature modifier for CPU fans speed set to +${!AMBTEMP_MOD_STEPloop}°C\"\n                                                echo \"$l Ambient temperature Modifier check - Stop\"\n                                        fi\n                                        break\n                                fi\n                        done\n                fi\n    fi\nfi\n#Exhaust temperature modifier when CPU temps are available and Checks for Delta Mode and Ambient mode\nEXHTEMP=$(echo \"$DATADUMP\" |grep \"$EXHAUST_ID\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nif [ $CPUcount != 0 ]; then\n        if [[ ! -z \"$EXHTEMP\" ]]; then\n                if [ \"$EXHTEMP\" -ge $EXHTEMP_MAX ]; then\n                        echo \"Exhaust temp is critical!! : $EXHTEMP °C!\"\n                        TEMPMOD=$MAX_MOD\n                fi\n        fi\nelse\n        if $AMBDeltaMode ; then\n                if [[ -z \"$EXHTEMP\" ]] && [[ ! -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING EXHAUST READING\"\n                        echo \"FALL BACK TO DEFAULT AMBIENT MODE\"\n                        AMBDeltaMode=false\n                        EMAMBmode=false\n                elif [[ ! -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING AMBIENT READING\"\n                        echo \"FALL BACK TO EMERGENCY AMBIENT MODE\"\n                        echo \"!!EMERGENCY MODE => USING AMBIANT PROFILE WITH EXHAUST TEMP!!\"\n                        AMBDeltaMode=false\n                        EMAMBmode=true\n                elif [[ -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING AMBIENT READING\"\n                        echo \"DELTA MODE ERROR => MISSING EXHAUST READING\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AMBDeltaMode=false\n                        AUTOEM=true\n                elif [[ -z \"$DeltaR\" ]] || [[ \"$DeltaR\" -le 0 ]]; then\n                        echo \"DELTA MODE ERROR => DELTA RATIO INVALID\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AMBDeltaMode=false\n                        AUTOEM=true\n                fi\n        else\n                if [[ ! -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"!!MISSING AMBIENT READING!!\"\n                        echo \"FALL BACK TO EMERGENCY AMBIENT MODE\"\n                        echo \"!!EMERGENCY MODE => USING AMBIANT PROFILE WITH EXHAUST TEMP!!\"\n                        EMAMBmode=true\n                elif [[ -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"NO TEMPERATURE READINGS\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AUTOEM=true\n                else\n                        EMAMBmode=false\n                        if [[ ! -z \"$EXHTEMP\" ]]; then\n                                if [ \"$EXHTEMP\" -ge $EXHTEMP_MAX ]; then\n                                        echo \"Exhaust temp is critical!! : $EXHTEMP °C!\"\n                                        TEMPMOD=$MAX_MOD\n                                fi\n                        fi\n                fi\n        fi\nfi\n#vTemp\nif [ -z \"$TEMPMOD\" ]; then\n    TEMPMOD=0\nfi\nif [ $CPUcount != 0 ]; then\n        vTEMP=$((CPUn+TEMPMOD))\nelse\n        if [[ ! -z \"$EXHTEMP\" ]] && [[ ! -z \"$AMBTEMP\" ]]; then\n                if $AMBDeltaMode ; then\n                        if [ \"$AMBTEMP\" -ge \"$EXHTEMP\" ]; then\n                                echo \"!! Intake = $AMBTEMP°C / Exhaust = $EXHTEMP°C !!\"\n                                echo \"?Insufficient or reverse airflow?\"\n                                echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                                AUTOEM=true\n                        else\n                                vTEMP=$((EXHTEMP-AMBTEMP))\n                        fi\n                else\n                        if $EMAMBmode ; then\n                                vTEMP=$EXHTEMP\n                        else\n                                vTEMP=$((AMBTEMP+TEMPMOD))\n                        fi\n                fi\n        else\n                if $EMAMBmode ; then\n                        vTEMP=$EXHTEMP\n                else\n                        vTEMP=$((AMBTEMP+TEMPMOD))\n                fi\n        fi\nfi\n#Emergency mode trigger\nif $AUTOEM ; then\n        setfanspeed XX XX \"$E_value\" 1\nfi\n#Logtype logic\nif [ $Logtype -eq 2 ]; then\n        for ((i=0; i<CPUcount; i++))\n         do if [[ $i -le $CPUcount ]]; then\n                CPUtemploopecho=\"CPUTEMP$i\"\n                 echo \"CPU$i = ${!CPUtemploopecho} °C\"\n            fi\n         done\n        [ \"$CPUcount\" -eq 0 ] && echo \"No CPU sensors = Ambient Mode\"\n        [ \"$TEMPgov\" -eq 0 ] && [ \"$CPUcount\" -gt 1 ] && echo \"$CPUcount CPU average = $CPUn °C\"\n        [ \"$TEMPgov\" -eq 1 ] && [ \"$CPUcount\" -gt 1 ] && echo \"$CPUcount CPU highest = $CPUn °C\"\n        [[ ! -z \"$AMBTEMP\" ]] && echo \"Ambient = $AMBTEMP °C\" \n        [[ ! -z \"$EXHTEMP\" ]] && echo \"Exhaust = $EXHTEMP °C\"\n        [[ \"$CPUcount\" != 0 ]] && [[ \"$TEMPMOD\" != 0 ]] && echo \"TEMPMOD = +$TEMPMOD °C\"\n        if [ \"$CPUcount\" -ge 1 ]; then \n                [ -z \"$CPUdeltatest\" ] && echo \"CPUdelta = $CPUdelta °C\" || echo \"CPUdelta EX! = $CPUdelta °C\"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                echo  \"vTEMP = $vTEMP °C\" \n        else\n                if $AMBDeltaMode ; then\n                        echo \"Delta Ratio = : $DeltaR \"\n                        echo \"Delta A/E = $vTEMP °C\"\n                else\n                        echo \"Virtual Temp = +$vTEMP °C\"\n                fi\n        fi\nfi\nif [ $Logtype -eq 3 ]; then\n        (\n         printf 'SOURCE\\tFETCH\\tTEMPERATURE\\n' \n         for ((i=0; i<CPUcount; i++))\n         do if [[ $i -le $CPUcount ]]; then\n                CPUtemploopecho=\"CPUTEMP$i\"\n                 printf '%s\\t%4s\\t%12s\\n' \"CPU$i\" \"OK\" \"${!CPUtemploopecho} °C\"\n            fi\n         done\n        [ \"$CPUcount\" -eq 0 ] && printf '%s\\t%4s\\t%12s\\n' \"CPU\" \"NO\" \"Ambient Mode\"\n        [ \"$TEMPgov\" -eq 0 ] && [ \"$CPUcount\" -gt 1 ] && printf '%s\\t%4s\\t%12s\\n' \"$CPUcount CPU average\" \"OK\" \"$CPUn °C\"\n        [ \"$TEMPgov\" -eq 1 ] && [ \"$CPUcount\" -gt 1 ] && printf '%s\\t%4s\\t%12s\\n' \"$CPUcount CPU highest\" \"OK\" \"$CPUn °C\"\n        [[ ! -z \"$AMBTEMP\" ]] && printf '%s\\t%4s\\t%12s\\n' \"Ambient\" \"OK\" \"$AMBTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"Ambient\" \"NO\" \"NaN \" \n        [[ ! -z \"$EXHTEMP\" ]] && printf '%s\\t%4s\\t%12s\\n' \"Exhaust\" \"OK\" \"$EXHTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"Exhaust\" \"NO\" \"NaN \" \n        if [ \"$CPUcount\" -ge 1 ]; then \n                [ -z \"$CPUdeltatest\" ] && printf '%s\\t%4s\\t%12s\\n' \"CPUdelta\" \"OK\" \"$CPUdelta °C\" || printf '%s\\t%4s\\t%12s\\n' \"CPUdelta\" \"EX\" \"$CPUdelta °C\"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                [[ \"$TEMPMOD\" != 0 ]] && printf '%s\\t%4s\\t%12s\\n' \"TEMPMOD\" \"OK\" \"+$TEMPMOD °C\" || printf '%s\\t%4s\\t%12s\\n' \"TEMPMOD\" \"NO\" \"NaN \"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                [[ \"$vTEMP\" != \"$CPUn\" ]] && printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"OK\" \"$vTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"EQ\" \"$vTEMP °C\" \n        else\n                if $AMBDeltaMode ; then\n                        printf '%s\\t%4s\\t%12s\\n' \"Delta Ratio\" \"OK\" \":$DeltaR \"\n                        printf '%s\\t%4s\\t%12s\\n' \"Delta A/E\" \"OK\" \"+$vTEMP °C\"\n                else\n                        printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"OK\" \"$vTEMP °C\"\n                fi\n        fi\n        ) | column -t -s $'\\t'\nfi\n#Logtype logic end.\n\n#Temp comparisons\nif [ $CPUcount -eq 0 ]; then\n        if $AMBDeltaMode ; then\n                echo \"!! A/E DELTA TEMPERATURE MODE !!\"\n                if [ $vTEMP -ge $((MAXTEMP / DeltaR)) ]; then\n                        echo \"!! A/E DELTA : Delta check = Temperature Critical trigger!!\"\n                        setfanspeed \"$DeltaR x $vTEMP\" $MAXTEMP \"$E_value\" 0\n                else\n                        if $Logloop ; then\n                                echo \"$l New loop => Defining fan speeds according to Delta A/E to CPU temp steps : $DeltaR\"\n                        fi\n                        for ((i=0; i<TEMP_STEP_COUNT; i++))\n                        do\n                                TEMP_STEPloop=\"TEMP_STEP$i\"\n                                TEMP_STEPloop=\"${!TEMP_STEPloop}\"\n                                FSTloop=\"FST$i\"\n                                if $Logloop ; then\n                                        echo \"$l Test vTEMP(=EXHTEMP-AMBTEMP)($EXHTEMP-$AMBTEMP=$vTEMP) =< TEMP_STEP$i($TEMP_STEPloop) by ratio $DeltaR\"\n                                fi\n                                if [ $vTEMP -le \"$((TEMP_STEPloop / DeltaR))\" ]; then\n                                        if $Logloop ; then\n                                                echo \"$l Test vTEMP(=EXHTEMP-AMBTEMP)($EXHTEMP-$AMBTEMP=$vTEMP) is =< TEMP_STEP$i($TEMP_STEPloop) by ratio $DeltaR\"\n                                                echo \"$l Buffering command #setfanspeed $DeltaR x $vTEMP°C $TEMP_STEPloop°C ${!FSTloop}%\"\n                                                echo \"$l CPU temperature Fan Speed control - Stop\"\n                                        fi\n                                        DAEloop_arg1=\"$DeltaR x $vTEMP\"\n                                        DAEloop_arg2=$TEMP_STEPloop\n                                        DAEloop_arg3=\"${!FSTloop}\"\n                                        break\n                                fi\n                        done\n                        if [ \"$AMBTEMP\" -ge $AMBTEMP_MAX ]; then\n                                echo \"!! A/E DELTA : Ambient check = Temperature Critical trigger!!\"\n                                setfanspeed \"$AMBTEMP\" $AMBTEMP_MAX \"$E_value\" 0\n                        else        \n                                if $Logloop ; then\n                                        echo \"$l New loop => Checking fan speeds according to values provided by Ambient temp steps\"\n                                fi\n                                for ((i=0; i<AMB_STEP_COUNT; i++))\n                                do \n                                        TEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                        FSTloop=\"AMBTEMP_noCPU_FS_STEP$i\"\n                                        if $Logloop ; then\n                                                echo \"$l Test AMBTEMP($AMBTEMP) =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                        fi\n                                        if [ \"$AMBTEMP\" -le \"${!TEMP_STEPloop}\" ]; then\n                                                if $Logloop ; then\n                                                        echo \"$l Result AMBTEMP($AMBTEMP) is =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                                        echo \"$l Buffering #setfanspeed $AMBTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                                        echo \"$l Ambient temperature Fan Speed control - Stop\"\n                                                fi\n                                                AMBloop_arg1=$AMBTEMP\n                                                AMBloop_arg2=\"${!TEMP_STEPloop}\"\n                                                AMBloop_arg3=\"${!FSTloop}\"\n                                                break\n                                        fi\n                                done\n                        fi\n                        if [ $AMBloop_arg3 -gt $DAEloop_arg3 ]; then\n                                echo \"Ambient temp fan step : $AMBloop_arg3 %\"\n                                echo \"Delta A/E fan step : $DAEloop_arg3 %\"\n                                echo \"Ambient temperature ($AMBloop_arg1°C) requires higher cooling than Delta A/E profile.\"\n                                setfanspeed \"$AMBloop_arg1\" \"$AMBloop_arg2\" \"$AMBloop_arg3\" 0\n                                if $Logloop ; then\n                                        echo \"$l Result Compare: Ambient profile selected\"\n                                fi\n                        else\n                                if $Logloop ; then\n                                        echo \"$l Result Compare: Delta A/E profile selected\"\n                                fi\n                                setfanspeed \"$DAEloop_arg1\" \"$DAEloop_arg2\" \"$DAEloop_arg3\" 0\n                        fi\n                fi\n        else\n                echo \"!! AMBIANT TEMPERATURE MODE !!\"\n                if [ $vTEMP -ge $AMBTEMP_MAX ]; then\n                        echo \"!! Ambient check = Temperature Critical trigger !!\"\n                        setfanspeed $vTEMP $AMBTEMP_MAX \"$E_value\" 0\n                else        \n                        if $Logloop ; then\n                                echo \"$l New loop => Defining fan speeds according to values provided by Ambiant temp steps\"\n                        fi\n                        for ((i=0; i<AMB_STEP_COUNT; i++))\n                        do \n                                TEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                FSTloop=\"AMBTEMP_noCPU_FS_STEP$i\"\n                                if $Logloop ; then\n                                        echo \"$l Test vTEMP($vTEMP) =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                fi\n                                if [ $vTEMP -le \"${!TEMP_STEPloop}\" ]; then\n                                        if $Logloop ; then\n                                                echo \"$l Result vTEMP($vTEMP) is =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                                echo \"$l sending command #setfanspeed $vTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                                echo \"$l Ambient temperature Fan Speed control - Stop\"\n                                        fi\n                                        setfanspeed $vTEMP \"${!TEMP_STEPloop}\" \"${!FSTloop}\" 0\n                                        break\n                                fi\n                        done\n                fi\n        fi\nelse\n        if [ $vTEMP -ge $MAXTEMP ]; then\n                setfanspeed \"$vTEMP\" $MAXTEMP \"$E_value\" 0\n                echo \"!! CPU MODE : Temperature Critical trigger!!\"\n        else\n                if $Logloop ; then\n                        echo \"$l New loop => Defining fan speeds according to values provided by CPU temp steps\"\n                fi\n                for ((i=0; i<TEMP_STEP_COUNT; i++))\n                do\n                        TEMP_STEPloop=\"TEMP_STEP$i\"\n                        FSTloop=\"FST$i\"\n                        if $Logloop ; then\n                                echo \"$l Test vTEMP(=CPUn+TEMPMOD)($CPUn+$TEMPMOD=$vTEMP) =< TEMP_STEP$i(${!TEMP_STEPloop})\"\n                        fi\n                        if [ $vTEMP -le \"${!TEMP_STEPloop}\" ]; then\n                                if $Logloop ; then\n                                        echo \"$l Result TEMP(=CPUn+TEMPMOD)($CPUn+$TEMPMOD=$vTEMP) is =< TEMP_STEP$i(${!TEMP_STEPloop})\"\n                                        echo \"$l Sending command #setfanspeed $vTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                        echo \"$l CPU temperature Fan Speed control - Stop\"\n                                fi\n                                setfanspeed $vTEMP \"${!TEMP_STEPloop}\" \"${!FSTloop}\" 0\n                                break\n                        fi\n                done\n        fi\nfi"
  },
  {
    "path": "guide/unraid.md",
    "content": "# PowerEdge-shutup on Unraid\n\nHow to get it up and running easily on Unraid.\n\n## Requirements\n- iDrac Entreprise (afaik it won't work with express)\n- [IPMItool](https://github.com/ipmitool/ipmitool)\n- G11*, G12 or G13** Dell Poweredge server\n- Unraid duh\n\n*See also [me/PowerEdge-IPMItools](https://github.com/White-Raven/PowerEdge-IPMItools) for more applications and resources.*\n\n## Cron Jobs and Unraid\n\nLet's start with that. Cron jobs are just a linux way to tell your computer \"Run this at this interval\". \n\"This\" being any kind of simple single command to a slew of cascading scripts spanning thousands of lines of code.\n\nUnraid makes it easy to create and manage cron jobs. No need to fiddle with the CLI, making it very userfriendly for beginners.\n\nThis script basically is a basic \"enter credential, ip and ready to run\" with cron jobs already, so if we even have a GUI for it it's perfect.\n\nYou can install the User Scripts plugin by Andrew Zawadzki in the Community Applications.\n\nIf you are on an Unraid version older than 6.10, and you don't have the Community App 'store' installed, head to your plugins, \"Install Plugin\" tab, and paste in:\n```\nhttps://raw.githubusercontent.com/Squidly271/community.applications/master/plugins/community.applications.plg\n```\n\nIf you are on Unraid 6.10 or newer, the Community App section should still appear whether or not you have it installed. Head up to there and click on the install button.\n\n## Add new Cron Jobs in Unraid\n\nOnce User Scripts in installed, head to your \"Setting\" section in Unraid's webui. You should find User Scripts under the USER UTILITIES sub section.\n\nAdding in a new script then is as simple as clicking the \"Add New Script\" button, name it (keep it clean with A-Z 0-9, don't splurge in symbols).\n\nYou should see your new script in the list. Click on the inline Cog left to its name, and in the pop-up, \"Edit Script\".\n\nYou're now presented to a text area in which you can paste in and edit your script, which for this guide would be the [fancontrol.sh](https://github.com/White-Raven/PowerEdge-shutup/blob/main/fancontrol.sh) script I provide.\n\nRemmember, you need to punch in your own informations, from the IP of your dedicated iDrac nic, to the login and password, eventually the IPMI ids corresponding to your hardware.\n\nYou can also obviously adjust the fan curves, for both CPU driven control or Ambient driven control. Note the Ambient/Inlet temp is also used in CPU temp driven mode, as a modifier.\n\n<details>\n<summary>\n<b>Also available here. Check link before for commented version with detailed info!</b>\n</summary>\n<p>\n\n```bash\n#!/bin/bash\n#the IP address of iDrac\nIPMIHOST=192.168.0.42\n\n#iDrac user\nIPMIUSER=root\n\n#iDrac password (calvin is the default password)\nIPMIPW=calvin\n\n#YOUR IPMI ENCRYPTION KEY \nIPMIEK=0000000000000000000000000000000000000000\n\n#Side note: you shouldn't ever store credentials in a script. Period. Here it's an example. \n#I suggest you give a look at tools like https://github.com/plyint/encpass.sh \n\n#Failsafe mode\n#(Possible values being a number between 80 and 100, or \"auto\")\nE_value=\"auto\"\n\n#IPMI IDs\nCPUID0=0Eh\nCPUID1=0Fh\nCPUID2=\"0#h\"\nCPUID3=\"0#h\"\nAMBIENT_ID=04h\nEXHAUST_ID=01h\n\n#Non-IPMI data source for CPU:\nNICPU_toggle=false\nNICPUdatadump_command=(sensors -A)\nNICPUdatadump_device=\"coretemp-isa-\"\nNICPUdatadump_device_num=4\nNICPUdatadump_core=Core\nNICPUdatadump_cut=\"-c16-18\"\nNICPUdatadump_offset=0\nIPMIDATA_toggle=true\n\n#Logtype:\n#0 = Only Alerts\n#1 = Fan speed output + alerts\n#2 = Simple text + fanspeed output + alerts\n#3 = Table + fanspeed output + alerts\nLogtype=2\n\n#There you basically define your fan curve.\nTEMP_STEP0=30\nFST0=2\nTEMP_STEP1=35\nFST1=6\nTEMP_STEP2=40\nFST2=8\nTEMP_STEP3=50\nFST3=10\nTEMP_STEP4=60\nFST4=12\nTEMP_STEP5=75\nFST5=20\n#CPU fan governor type\nTEMPgov=0\nCPUdelta=15\n\n#These values are used as steps for the intake temps.\n\nAMBTEMP_STEP0=20\nAMBTEMP_MOD_STEP0=0\nAMBTEMP_noCPU_FS_STEP0=8\n\nAMBTEMP_STEP1=21\nAMBTEMP_MOD_STEP1=10\nAMBTEMP_noCPU_FS_STEP1=15\n\nAMBTEMP_STEP2=24\nAMBTEMP_MOD_STEP2=15\nAMBTEMP_noCPU_FS_STEP2=20\n\nAMBTEMP_STEP3=26\nAMBTEMP_MOD_STEP3=20\nAMBTEMP_noCPU_FS_STEP3=30\n\nMAX_MOD=69\n\nEXHTEMP_MAX=65\n\n#Ambient fan mode - Delta mode\nAMBDeltaMode=true\nDeltaR=3\n\n#Log loop debug - true or false, logging of loops for debugging script\nLogloop=false\n\n#Looplog prefix\nl=\"Loop -\"\n\n#Hexadecimal conversion and IPMI command into a function \nipmifanctl=(ipmitool -I lanplus -H \"$IPMIHOST\" -U \"$IPMIUSER\" -P \"$IPMIPW\" -y \"$IPMIEK\" raw 0x30 0x30)\nfunction setfanspeed () { \n    TEMP_Check=$1\n    TEMP_STEP=$2\n    FS=$3\n    if [[ $FS == \"auto\" ]]; then\n        if [ \"$Logtype\" != 0 ] && [ \"$4\" -eq 0 ]; then\n                echo \"> $TEMP_Check °C is higher or equal to $TEMP_STEP °C. Switching to automatic fan control\"\n        fi\n        [ \"$4\" -eq 1 ] && echo \"> ERROR : Keeping fans on auto as safety measure\"\n        \"${ipmifanctl[@]}\" 0x01 0x01\n        exit $4\n    else\n        if [[ $FS -gt \"100\" ]]; then\n            FS=100\n        fi\n        HEX_value=$(printf '%#04x' \"$FS\")\n        if [ \"$4\" -eq 1 ]; then\n            echo \"> ERROR : Keeping fans on high profile ($3 %) as safety measure\"\n        elif [ \"$Logtype\" != 0 ]; then\n            echo \"> $TEMP_Check °C is lower or equal to $TEMP_STEP °C. Switching to manual $FS % control\"\n        fi\n        \"${ipmifanctl[@]}\" 0x01 0x00\n        \"${ipmifanctl[@]}\" 0x02 0xff \"$HEX_value\"\n        exit $4\n     fi\n}\n#Failsafe = Parameter check\nre='^[0-9]+$'\nren='^[+-]?[0-9]+?$'\nif [ \"$Logloop\" != false ] && [ \"$Logloop\" != true ]; then\n        echo \"Logloop parameter invalid, must be true or false!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [ \"$AMBDeltaMode\" != false ] && [ \"$AMBDeltaMode\" != true ]; then\n        echo \"AMBDeltaMode parameter invalid, must be true or false!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$DeltaR\" =~ $ren ]]; then\n        if [ \"$DeltaR\" -le \"0\" ]; then\n                echo \"DeltaR parameter invalid, must be greater than 0!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"DeltaR parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$CPUdelta\" =~ $ren ]]; then\n        if [ \"$CPUdelta\" -le \"0\" ]; then\n                echo \"CPUdelta parameter invalid, must be greater than 0!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"CPUdelta parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [ \"$TEMPgov\" != 1 ] && [ \"$TEMPgov\" != 0 ]; then\n        echo \"TEMPgov parameter invalid, can only be 0 or 1!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$Logtype\" =~ $ren ]]; then\n        if [ \"$Logtype\" -lt 0 ] || [ \"$Logtype\" -gt 3 ]; then\n                echo \"Logtype parameter invalid, must be in 0-3 range!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"Logtype parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$EXHTEMP_MAX\" =~ $ren ]]; then\n        if [ \"$EXHTEMP_MAX\" -lt 0 ]; then\n                echo \"EXHTEMP_MAX parameter invalid, can't be negative!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"EXHTEMP_MAX parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ $MAX_MOD =~ $ren ]]; then\n        if [ \"$MAX_MOD\" -lt 0 ]; then\n                echo \"MAX_MOD parameter invalid, can't be negative!\"\n                setfanspeed XX XX \"$E_value\" 1\n        fi\nelse\n        echo \"MAX_MOD parameter invalid, not a number!\"\n        setfanspeed XX XX \"$E_value\" 1\nfi\nif [[ \"$E_value\" =~ $ren ]]; then\n        if [ \"$E_value\" -lt 80 ]; then\n                echo \"E_value parameter invalid, can't be negative or lower than 80\"\n                E_value=\"auto\"\n        fi\n        if [ \"$E_value\" -gt 100 ]; then\n                echo \"E_value parameter invalid, can't be greater than 100\"\n                E_value=\"auto\"\n        fi\nelif [ \"$E_value\" != \"auto\" ]; then\n        echo \"E_value parameter invalid, not a number!\"\n        E_value=\"auto\"\nfi\n#Counting CPU Fan speed steps and setting max value\nif $Logloop ; then\n        echo \"$l New loop => Counting CPU Fan speed steps and setting max value\"\nfi\nfor ((i=0; i>=0 ; i++))\ndo\n        inloopstep=\"TEMP_STEP$i\"\n        inloopspeed=\"FST$i\"\n        if [[ ! -z \"${!inloopspeed}\" ]] && [[ ! -z \"${!inloopstep}\" ]]; then\n                if $Logloop ; then\n                        echo \"$l CPU Temperature step n°$i = ${!inloopstep}°C\"\n                        echo \"$l Fan speed step n°$i = ${!inloopspeed}%\"\n                fi\n                if ! [[ \"${!inloopstep}\" =~ $ren ]]; then\n                        echo \"Butterfinger failsafe: CPU Temperature step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopspeed}\" =~ $ren ]]; then\n                        if [[ \"${!inloopspeed}\" -lt 0 ]]; then\n                                echo \"Butterfinger failsafe: Fan speed step n°$i is negative!\"\n                                setfanspeed XX XX \"$E_value\" 1\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Fan speed step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n        else\n                inloopmaxstep=\"TEMP_STEP$((i-1))\"\n        if [ $((i-1)) -le 0 ]; then\n                        echo \"Butterfinger failsafe: no CPU stepping found!!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                MAXTEMP=\"${!inloopmaxstep}\"\n                TEMP_STEP_COUNT=$i\n                if $Logloop ; then\n                        echo \"$l CPU temperature step count = $i\"\n                        echo \"$l CPU max temperature to auto mode = $MAXTEMP°C\"\n                        echo \"$l CPU Temp Steps counting = stop\"\n                fi\n                break\n        fi\ndone\n#Counting Ambiant Fan speed and MOD steps and setting max value\nif $Logloop ; then\n        echo \"$l New loop => Counting Ambiant Fan speed and MOD steps and setting max value\"\nfi\nfor ((i=0; i>=0 ; i++))\ndo\n        inloopstep=\"AMBTEMP_STEP$i\"\n        inloopspeed=\"AMBTEMP_noCPU_FS_STEP$i\"\n        inloopmod=\"AMBTEMP_MOD_STEP$i\"\n        if [[ ! -z \"${!inloopspeed}\" ]] && [[ ! -z \"${!inloopmod}\" ]] && [[ ! -z \"${!inloopstep}\" ]]; then\n                if $Logloop ; then\n                        echo \"$l Ambient temperature step n°$i = ${!inloopstep}°C\"\n                        echo \"$l Ambient modifier for CPU temp step n°$i = ${!inloopmod}°C\"\n                        echo \"$l Ambient NO CPU fan speed step n°$i = ${!inloopspeed}%\"\n                fi\n                if ! [[ \"${!inloopstep}\" =~ $ren ]]; then\n                        echo \"Butterfinger failsafe: Ambient temperature step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopmod}\" =~ $ren ]]; then\n                        if [[ \"${!inloopmod}\" -lt 0 ]]; then\n                                echo \"Beware: Ambient modifier for CPU temp step n°$i is negative!\"\n                                echo \"Proceeding...\"\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Ambient modifier for CPU temp step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                if [[ \"${!inloopspeed}\" =~ $ren ]]; then\n                        if [[ \"${!inloopspeed}\" -lt 0 ]]; then\n                                echo \"Butterfinger failsafe: Ambient NO CPU fan speed step n°$i is negative!\"\n                                setfanspeed XX XX \"$E_value\" 1\n                        fi\n\n                else\n                        echo \"Butterfinger failsafe: Ambient NO CPU fan speed step n°$i isn't a number!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n        else\n                inloopmaxstep=\"AMBTEMP_STEP$((i-1))\"\n        if [ $((i-1)) -le 0 ]; then\n                        echo \"Butterfinger failsafe: no Ambient stepping found!!\"\n                        setfanspeed XX XX \"$E_value\" 1\n                fi\n                AMBTEMP_MAX=\"${!inloopmaxstep}\"\n                AMB_STEP_COUNT=$i\n                if $Logloop ; then\n                        echo \"$l Ambient temperature step count = $i\"\n                        echo \"$l Ambient max temperature to max mod = $AMBTEMP_MAX°C\"\n                        echo \"$l CPU Ambiant Steps counting = stop\"\n                fi\n                break\n        fi\ndone\n#Pulling temperature data from IPMI\nif $IPMIDATA_toggle ; then\n    IPMIPULLDATA=$(ipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK sdr type temperature)\n    DATADUMP=$(echo \"$IPMIPULLDATA\")\n    if [ -z \"$DATADUMP\" ]; then\n        echo \"No data was pulled from IPMI\"\n        setfanspeed XX XX \"$E_value\" 1\n    else\n        AUTOEM=false\n    fi\nelse\n    if $NICPU_toggle ; then\n        AUTOEM=false\n    else\n        echo \"Both IPMI data and Non-IPMI-CPU data are toggled off\"\n        setfanspeed XX XX \"$E_value\" 1\n    fi\nfi\n#Parsing CPU Temp data into values to be later checked in count, continuity and value validity.\nif $NICPU_toggle ; then\n    echo \"Non-IPMI data source. An error can be thrown without incidence.\"\n    if $Logloop ; then\n        echo \"$l New loop => Pulling data dynamically from Non-IPMI source\"\n    fi\n    for ((j=0; j>=0 ; j++))\n    do\n        [ -z \"$socketcount\" ] && socketcount=0\n        datadump=$(\"$NICPUdatadump_command\" \"$NICPUdatadump_device$(printf \"%0\"$NICPUdatadump_device_num\"d\" \"$socketcount\")\")\n        if [[ ! -z $datadump ]]; then\n            if $Logloop ; then\n                echo \"$l Detected CPU socket $socketcount !!\"\n                echo \"$l New loop => Parsing CPU Core data\"\n            fi\n            socketcount=$((socketcount+1))\n            for ((i=0; i>=0 ; i++))\n            do\n                [ -z \"$corecount\" ] && corecount=0\n                Corecountloop_data=$( echo \"$datadump\" | grep -A 0 \"$NICPUdatadump_core $i\"| cut \"$NICPUdatadump_cut\")\n                if [[ ! -z $Corecountloop_data ]]; then\n                    declare CPUTEMP$corecount=\"$((Corecountloop_data+NICPUdatadump_offset))\"\n                    if $Logloop ; then\n                        echo \"$l Defining CPUTEMP$corecount with value : $((CPUTEMP$corecount))\"\n                    fi\n                    corecount=$((corecount+1))\n                else\n                    if $Logloop ; then\n                        echo \"$l CPU Core data parsing on CPU Socket $((socketcount-1)) = stop\"\n                    fi\n                    break\n                fi\n            done\n        else\n            echo \"Non-IPMI detection : done.\"\n            if $Logloop ; then\n                echo \"$l Result : $corecount Total CPU temperature sources added.\"\n                echo \"$l CPU Data parsing from Non-IPMI source = stop\"\n            fi\n            break\n        fi\n    done\nelse\n    CPUTEMP0=$(echo \"$DATADUMP\" |grep \"$CPUID0\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP1=$(echo \"$DATADUMP\" |grep \"$CPUID1\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP2=$(echo \"$DATADUMP\" |grep \"$CPUID2\" |grep degrees |grep -Po '\\d{2}' | tail -1)\n    CPUTEMP3=$(echo \"$DATADUMP\" |grep \"$CPUID3\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nfi\n#CPU counting\nif [ -z \"$CPUTEMP0\" ]; then\n        CPUcount=0\nelse\n        if [[ ! -z \"$CPUTEMP0\" ]]; then #Infinite CPU number adding, if you pull individual CPU cores from lm-sensors or something\n                for ((i=0; i>=0 ; i++))\n                    do\n                        CPUcountloop=\"CPUTEMP$i\"\n                        if [[ ! -z \"${!CPUcountloop}\" ]]; then\n                                if $Logloop ; then\n                                        echo \"$l CPU detection = CPU$i detected / Value = ${!CPUcountloop}\"\n                                fi\n                                if ! [[ \"${!CPUcountloop}\" =~ $re ]] ; then\n                                   echo \"!!error: Reading is not a number or negative!!\"\n                                   echo \"Falling back to ambient mode...\"\n                                   CPUcount=0\n                                   break\n                                fi\n                                currcputemp=\"${!CPUcountloop}\"\n                                CPUcount=$((i+1))\n                                TEMPadd=$((TEMPadd+currcputemp))\n                        else\n                                if [[ $((CPUcount % 2)) -eq 0 ]] || [[ $CPUcount -eq 1 ]]; then\n                                        if $Logloop ; then\n                                                if [ \"$CPUcount\" -eq \"1\" ]; then\n                                                        echo \"$l CPU count : $CPUcount CPU detected!\"\n                                                else\n                                                        echo \"$l CPU count is even : $CPUcount CPU detected!\"\n                                                fi\n                                                echo \"$l CPU counting = stop\"\n                                        fi\n                                        CPUn=$((TEMPadd/CPUcount))\n                                        break\n                                else\n                                        CPUcount=0\n                                        echo \"CPU count is odd, please check your configuration\";\n                                        echo \"Falling back to ambient mode...\"\n                                        break\n                                fi\n                        fi\n                done\n\n        fi\nfi\n#CPU Find lowest and highest CPU temps\nif [ \"$CPUcount\" -gt 1 ]; then\n        if $Logloop ; then\n                echo \"$l New loop => Finding highest and lowest CPU temps\"\n        fi\n        for ((i=0; i<CPUcount; i++)) #General solution to finding the highest number with a shitty shell loop\n            do if [[ $i -le $CPUcount ]]; then\n                CPUtemploop=\"CPUTEMP$i\"\n                if $Logloop ; then\n                        echo \"$l Checking for CPU$i = ${!CPUtemploop}°C\"\n                fi\n                if [ \"$i\" -eq 0 ]; then\n                      CPUh=${!CPUtemploop}\n                      CPUl=${!CPUtemploop}\n                else\n                    if [ ${!CPUtemploop} -gt $CPUh ]; then\n                        if $Logloop ; then\n                                echo \"$l New high! CPU$i = ${!CPUtemploop}°C\"\n                        fi\n                        CPUh=${!CPUtemploop}\n                    fi\n                    if [ ${!CPUtemploop} -lt $CPUl ]; then\n                        if $Logloop ; then\n                                echo \"$l New low! CPU$i = ${!CPUtemploop}°C\"\n                        fi\n                        CPUl=${!CPUtemploop}\n                    fi\n                fi\n            fi\n        done\n    if $Logloop ; then\n        echo \"$l Lowest = $CPUl°C\"\n        echo \"$l Highest = $CPUh°C\"\n        echo \"$l CPU Find highest = stop\"\n    fi\nfi\nif [ $TEMPgov -eq 1 ] || [ $((CPUh-CPUl)) -gt $CPUdelta ]; then\n        echo \"!! CPU DELTA Exceeded !!\"\n        echo \"Lowest : $CPUl°C\"\n        echo \"Highest: $CPUh°C\"\n        echo \"Delta Max: $CPUdelta °C\"\n        echo \"Switching CPU profile...\"\n        CPUdeltatest=1\n        CPUn=$CPUh\nfi\n#Ambient temperature modifier when CPU temps are available.\nAMBTEMP=$(echo \"$DATADUMP\" |grep \"$AMBIENT_ID\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nif [ $CPUcount != 0 ]; then\n        if [[ ! -z \"$AMBTEMP\" ]]; then\n                if $Logloop ; then\n                        echo \"$l New loop => Ambient temperature modifier\"\n                fi\n                if [ \"$AMBTEMP\" -ge $AMBTEMP_MAX ]; then\n                        echo \"Intake temp is very high!! : $AMBTEMP °C!\"\n                        TEMPMOD=$MAX_MOD\n                else\n                        for ((i=0; i<AMB_STEP_COUNT; i++))\n                        do\n                                AMBTEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                if $Logloop ; then\n                                        echo \"$l Checking for Ambient temperature($AMBTEMP) =< Ambient temperature step n°$i(${!AMBTEMP_STEPloop})\"\n                                fi\n                                if [ \"$AMBTEMP\" -le \"${!AMBTEMP_STEPloop}\" ]; then\n                                        AMBTEMP_MOD_STEPloop=\"AMBTEMP_MOD_STEP$i\"\n                                        TEMPMOD=\"${!AMBTEMP_MOD_STEPloop}\"\n                                        if $Logloop ; then\n                                                echo \"$l Result Checking for Ambient temperature($AMBTEMP) is =< Ambient temperature step n°$i(${!AMBTEMP_STEPloop})\"\n                                                echo \"$l Ambient temperature modifier for CPU fans speed set to +${!AMBTEMP_MOD_STEPloop}°C\"\n                                                echo \"$l Ambient temperature Modifier check - Stop\"\n                                        fi\n                                        break\n                                fi\n                        done\n                fi\n    fi\nfi\n#Exhaust temperature modifier when CPU temps are available and Checks for Delta Mode and Ambient mode\nEXHTEMP=$(echo \"$DATADUMP\" |grep \"$EXHAUST_ID\" |grep degrees |grep -Po '\\d{2}' | tail -1)\nif [ $CPUcount != 0 ]; then\n        if [[ ! -z \"$EXHTEMP\" ]]; then\n                if [ \"$EXHTEMP\" -ge $EXHTEMP_MAX ]; then\n                        echo \"Exhaust temp is critical!! : $EXHTEMP °C!\"\n                        TEMPMOD=$MAX_MOD\n                fi\n        fi\nelse\n        if $AMBDeltaMode ; then\n                if [[ -z \"$EXHTEMP\" ]] && [[ ! -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING EXHAUST READING\"\n                        echo \"FALL BACK TO DEFAULT AMBIENT MODE\"\n                        AMBDeltaMode=false\n                        EMAMBmode=false\n                elif [[ ! -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING AMBIENT READING\"\n                        echo \"FALL BACK TO EMERGENCY AMBIENT MODE\"\n                        echo \"!!EMERGENCY MODE => USING AMBIANT PROFILE WITH EXHAUST TEMP!!\"\n                        AMBDeltaMode=false\n                        EMAMBmode=true\n                elif [[ -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"DELTA MODE ERROR => MISSING AMBIENT READING\"\n                        echo \"DELTA MODE ERROR => MISSING EXHAUST READING\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AMBDeltaMode=false\n                        AUTOEM=true\n                elif [[ -z \"$DeltaR\" ]] || [[ \"$DeltaR\" -le 0 ]]; then\n                        echo \"DELTA MODE ERROR => DELTA RATIO INVALID\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AMBDeltaMode=false\n                        AUTOEM=true\n                fi\n        else\n                if [[ ! -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"!!MISSING AMBIENT READING!!\"\n                        echo \"FALL BACK TO EMERGENCY AMBIENT MODE\"\n                        echo \"!!EMERGENCY MODE => USING AMBIANT PROFILE WITH EXHAUST TEMP!!\"\n                        EMAMBmode=true\n                elif [[ -z \"$EXHTEMP\" ]] && [[ -z \"$AMBTEMP\" ]]; then\n                        echo \"NO TEMPERATURE READINGS\"\n                        echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                        AUTOEM=true\n                else\n                        EMAMBmode=false\n                        if [[ ! -z \"$EXHTEMP\" ]]; then\n                                if [ \"$EXHTEMP\" -ge $EXHTEMP_MAX ]; then\n                                        echo \"Exhaust temp is critical!! : $EXHTEMP °C!\"\n                                        TEMPMOD=$MAX_MOD\n                                fi\n                        fi\n                fi\n        fi\nfi\n#vTemp\nif [ -z \"$TEMPMOD\" ]; then\n    TEMPMOD=0\nfi\nif [ $CPUcount != 0 ]; then\n        vTEMP=$((CPUn+TEMPMOD))\nelse\n        if [[ ! -z \"$EXHTEMP\" ]] && [[ ! -z \"$AMBTEMP\" ]]; then\n                if $AMBDeltaMode ; then\n                        if [ \"$AMBTEMP\" -ge \"$EXHTEMP\" ]; then\n                                echo \"!! Intake = $AMBTEMP°C / Exhaust = $EXHTEMP°C !!\"\n                                echo \"?Insufficient or reverse airflow?\"\n                                echo \"!!EMERGENCY MODE => FALL BACK TO AUTO FAN PROFILE!!\"\n                                AUTOEM=true\n                        else\n                                vTEMP=$((EXHTEMP-AMBTEMP))\n                        fi\n                else\n                        if $EMAMBmode ; then\n                                vTEMP=$EXHTEMP\n                        else\n                                vTEMP=$((AMBTEMP+TEMPMOD))\n                        fi\n                fi\n        else\n                if $EMAMBmode ; then\n                        vTEMP=$EXHTEMP\n                else\n                        vTEMP=$((AMBTEMP+TEMPMOD))\n                fi\n        fi\nfi\n#Emergency mode trigger\nif $AUTOEM ; then\n        setfanspeed XX XX \"$E_value\" 1\nfi\n#Logtype logic\nif [ $Logtype -eq 2 ]; then\n        for ((i=0; i<CPUcount; i++))\n         do if [[ $i -le $CPUcount ]]; then\n                CPUtemploopecho=\"CPUTEMP$i\"\n                 echo \"CPU$i = ${!CPUtemploopecho} °C\"\n            fi\n         done\n        [ \"$CPUcount\" -eq 0 ] && echo \"No CPU sensors = Ambient Mode\"\n        [ \"$TEMPgov\" -eq 0 ] && [ \"$CPUcount\" -gt 1 ] && echo \"$CPUcount CPU average = $CPUn °C\"\n        [ \"$TEMPgov\" -eq 1 ] && [ \"$CPUcount\" -gt 1 ] && echo \"$CPUcount CPU highest = $CPUn °C\"\n        [[ ! -z \"$AMBTEMP\" ]] && echo \"Ambient = $AMBTEMP °C\" \n        [[ ! -z \"$EXHTEMP\" ]] && echo \"Exhaust = $EXHTEMP °C\"\n        [[ \"$CPUcount\" != 0 ]] && [[ \"$TEMPMOD\" != 0 ]] && echo \"TEMPMOD = +$TEMPMOD °C\"\n        if [ \"$CPUcount\" -ge 1 ]; then \n                [ -z \"$CPUdeltatest\" ] && echo \"CPUdelta = $CPUdelta °C\" || echo \"CPUdelta EX! = $CPUdelta °C\"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                echo  \"vTEMP = $vTEMP °C\" \n        else\n                if $AMBDeltaMode ; then\n                        echo \"Delta Ratio = : $DeltaR \"\n                        echo \"Delta A/E = $vTEMP °C\"\n                else\n                        echo \"Virtual Temp = +$vTEMP °C\"\n                fi\n        fi\nfi\nif [ $Logtype -eq 3 ]; then\n        (\n         printf 'SOURCE\\tFETCH\\tTEMPERATURE\\n' \n         for ((i=0; i<CPUcount; i++))\n         do if [[ $i -le $CPUcount ]]; then\n                CPUtemploopecho=\"CPUTEMP$i\"\n                 printf '%s\\t%4s\\t%12s\\n' \"CPU$i\" \"OK\" \"${!CPUtemploopecho} °C\"\n            fi\n         done\n        [ \"$CPUcount\" -eq 0 ] && printf '%s\\t%4s\\t%12s\\n' \"CPU\" \"NO\" \"Ambient Mode\"\n        [ \"$TEMPgov\" -eq 0 ] && [ \"$CPUcount\" -gt 1 ] && printf '%s\\t%4s\\t%12s\\n' \"$CPUcount CPU average\" \"OK\" \"$CPUn °C\"\n        [ \"$TEMPgov\" -eq 1 ] && [ \"$CPUcount\" -gt 1 ] && printf '%s\\t%4s\\t%12s\\n' \"$CPUcount CPU highest\" \"OK\" \"$CPUn °C\"\n        [[ ! -z \"$AMBTEMP\" ]] && printf '%s\\t%4s\\t%12s\\n' \"Ambient\" \"OK\" \"$AMBTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"Ambient\" \"NO\" \"NaN \" \n        [[ ! -z \"$EXHTEMP\" ]] && printf '%s\\t%4s\\t%12s\\n' \"Exhaust\" \"OK\" \"$EXHTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"Exhaust\" \"NO\" \"NaN \" \n        if [ \"$CPUcount\" -ge 1 ]; then \n                [ -z \"$CPUdeltatest\" ] && printf '%s\\t%4s\\t%12s\\n' \"CPUdelta\" \"OK\" \"$CPUdelta °C\" || printf '%s\\t%4s\\t%12s\\n' \"CPUdelta\" \"EX\" \"$CPUdelta °C\"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                [[ \"$TEMPMOD\" != 0 ]] && printf '%s\\t%4s\\t%12s\\n' \"TEMPMOD\" \"OK\" \"+$TEMPMOD °C\" || printf '%s\\t%4s\\t%12s\\n' \"TEMPMOD\" \"NO\" \"NaN \"\n        fi\n        if [ \"$CPUcount\" != 0 ]; then\n                [[ \"$vTEMP\" != \"$CPUn\" ]] && printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"OK\" \"$vTEMP °C\" || printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"EQ\" \"$vTEMP °C\" \n        else\n                if $AMBDeltaMode ; then\n                        printf '%s\\t%4s\\t%12s\\n' \"Delta Ratio\" \"OK\" \":$DeltaR \"\n                        printf '%s\\t%4s\\t%12s\\n' \"Delta A/E\" \"OK\" \"+$vTEMP °C\"\n                else\n                        printf '%s\\t%4s\\t%12s\\n' \"vTEMP\" \"OK\" \"$vTEMP °C\"\n                fi\n        fi\n        ) | column -t -s $'\\t'\nfi\n#Logtype logic end.\n\n#Temp comparisons\nif [ $CPUcount -eq 0 ]; then\n        if $AMBDeltaMode ; then\n                echo \"!! A/E DELTA TEMPERATURE MODE !!\"\n                if [ $vTEMP -ge $((MAXTEMP / DeltaR)) ]; then\n                        echo \"!! A/E DELTA : Delta check = Temperature Critical trigger!!\"\n                        setfanspeed \"$DeltaR x $vTEMP\" $MAXTEMP \"$E_value\" 0\n                else\n                        if $Logloop ; then\n                                echo \"$l New loop => Defining fan speeds according to Delta A/E to CPU temp steps : $DeltaR\"\n                        fi\n                        for ((i=0; i<TEMP_STEP_COUNT; i++))\n                        do\n                                TEMP_STEPloop=\"TEMP_STEP$i\"\n                                TEMP_STEPloop=\"${!TEMP_STEPloop}\"\n                                FSTloop=\"FST$i\"\n                                if $Logloop ; then\n                                        echo \"$l Test vTEMP(=EXHTEMP-AMBTEMP)($EXHTEMP-$AMBTEMP=$vTEMP) =< TEMP_STEP$i($TEMP_STEPloop) by ratio $DeltaR\"\n                                fi\n                                if [ $vTEMP -le \"$((TEMP_STEPloop / DeltaR))\" ]; then\n                                        if $Logloop ; then\n                                                echo \"$l Test vTEMP(=EXHTEMP-AMBTEMP)($EXHTEMP-$AMBTEMP=$vTEMP) is =< TEMP_STEP$i($TEMP_STEPloop) by ratio $DeltaR\"\n                                                echo \"$l Buffering command #setfanspeed $DeltaR x $vTEMP°C $TEMP_STEPloop°C ${!FSTloop}%\"\n                                                echo \"$l CPU temperature Fan Speed control - Stop\"\n                                        fi\n                                        DAEloop_arg1=\"$DeltaR x $vTEMP\"\n                                        DAEloop_arg2=$TEMP_STEPloop\n                                        DAEloop_arg3=\"${!FSTloop}\"\n                                        break\n                                fi\n                        done\n                        if [ \"$AMBTEMP\" -ge $AMBTEMP_MAX ]; then\n                                echo \"!! A/E DELTA : Ambient check = Temperature Critical trigger!!\"\n                                setfanspeed \"$AMBTEMP\" $AMBTEMP_MAX \"$E_value\" 0\n                        else        \n                                if $Logloop ; then\n                                        echo \"$l New loop => Checking fan speeds according to values provided by Ambient temp steps\"\n                                fi\n                                for ((i=0; i<AMB_STEP_COUNT; i++))\n                                do \n                                        TEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                        FSTloop=\"AMBTEMP_noCPU_FS_STEP$i\"\n                                        if $Logloop ; then\n                                                echo \"$l Test AMBTEMP($AMBTEMP) =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                        fi\n                                        if [ \"$AMBTEMP\" -le \"${!TEMP_STEPloop}\" ]; then\n                                                if $Logloop ; then\n                                                        echo \"$l Result AMBTEMP($AMBTEMP) is =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                                        echo \"$l Buffering #setfanspeed $AMBTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                                        echo \"$l Ambient temperature Fan Speed control - Stop\"\n                                                fi\n                                                AMBloop_arg1=$AMBTEMP\n                                                AMBloop_arg2=\"${!TEMP_STEPloop}\"\n                                                AMBloop_arg3=\"${!FSTloop}\"\n                                                break\n                                        fi\n                                done\n                        fi\n                        if [ $AMBloop_arg3 -gt $DAEloop_arg3 ]; then\n                                echo \"Ambient temp fan step : $AMBloop_arg3 %\"\n                                echo \"Delta A/E fan step : $DAEloop_arg3 %\"\n                                echo \"Ambient temperature ($AMBloop_arg1°C) requires higher cooling than Delta A/E profile.\"\n                                setfanspeed \"$AMBloop_arg1\" \"$AMBloop_arg2\" \"$AMBloop_arg3\" 0\n                                if $Logloop ; then\n                                        echo \"$l Result Compare: Ambient profile selected\"\n                                fi\n                        else\n                                if $Logloop ; then\n                                        echo \"$l Result Compare: Delta A/E profile selected\"\n                                fi\n                                setfanspeed \"$DAEloop_arg1\" \"$DAEloop_arg2\" \"$DAEloop_arg3\" 0\n                        fi\n                fi\n        else\n                echo \"!! AMBIANT TEMPERATURE MODE !!\"\n                if [ $vTEMP -ge $AMBTEMP_MAX ]; then\n                        echo \"!! Ambient check = Temperature Critical trigger !!\"\n                        setfanspeed $vTEMP $AMBTEMP_MAX \"$E_value\" 0\n                else        \n                        if $Logloop ; then\n                                echo \"$l New loop => Defining fan speeds according to values provided by Ambiant temp steps\"\n                        fi\n                        for ((i=0; i<AMB_STEP_COUNT; i++))\n                        do \n                                TEMP_STEPloop=\"AMBTEMP_STEP$i\"\n                                FSTloop=\"AMBTEMP_noCPU_FS_STEP$i\"\n                                if $Logloop ; then\n                                        echo \"$l Test vTEMP($vTEMP) =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                fi\n                                if [ $vTEMP -le \"${!TEMP_STEPloop}\" ]; then\n                                        if $Logloop ; then\n                                                echo \"$l Result vTEMP($vTEMP) is =< AMBTEMP_STEP$i(${!TEMP_STEPloop})\"\n                                                echo \"$l sending command #setfanspeed $vTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                                echo \"$l Ambient temperature Fan Speed control - Stop\"\n                                        fi\n                                        setfanspeed $vTEMP \"${!TEMP_STEPloop}\" \"${!FSTloop}\" 0\n                                        break\n                                fi\n                        done\n                fi\n        fi\nelse\n        if [ $vTEMP -ge $MAXTEMP ]; then\n                setfanspeed \"$vTEMP\" $MAXTEMP \"$E_value\" 0\n                echo \"!! CPU MODE : Temperature Critical trigger!!\"\n        else\n                if $Logloop ; then\n                        echo \"$l New loop => Defining fan speeds according to values provided by CPU temp steps\"\n                fi\n                for ((i=0; i<TEMP_STEP_COUNT; i++))\n                do\n                        TEMP_STEPloop=\"TEMP_STEP$i\"\n                        FSTloop=\"FST$i\"\n                        if $Logloop ; then\n                                echo \"$l Test vTEMP(=CPUn+TEMPMOD)($CPUn+$TEMPMOD=$vTEMP) =< TEMP_STEP$i(${!TEMP_STEPloop})\"\n                        fi\n                        if [ $vTEMP -le \"${!TEMP_STEPloop}\" ]; then\n                                if $Logloop ; then\n                                        echo \"$l Result TEMP(=CPUn+TEMPMOD)($CPUn+$TEMPMOD=$vTEMP) is =< TEMP_STEP$i(${!TEMP_STEPloop})\"\n                                        echo \"$l Sending command #setfanspeed $vTEMP°C ${!TEMP_STEPloop}°C ${!FSTloop}%\"\n                                        echo \"$l CPU temperature Fan Speed control - Stop\"\n                                fi\n                                setfanspeed $vTEMP \"${!TEMP_STEPloop}\" \"${!FSTloop}\" 0\n                                break\n                        fi\n                done\n        fi\nfi\n```\n\n</p>\n</details>\n\n## Cron job yet?\n\nGood, you added your script. Still, at this moment, it doesn't run by itself.\n\nIt's normal, for now it's just a script on a file, with no wit to it, it's not YET a cron job. You now have to give it a schedule (if you so desire).\n\nUnraid makes it easy again.\nClick on the droplist that should be showing \"Schedule Disabled\" as its selected option.\nYou should find a pre-made array of ready to go schedules as follow:\n\nSchedule Disabled|\n------------ |\nScheduled Hourly |\nScheduled Weekly |\nScheduled Monthly |\nAt Startup of Array | \nAt Stopping of Array |\nAt First Array Start Only |\n**Custom** |\n\nThe ones linked to array events execute on the array's \"active time\", aka after the array started, and before it shuts down, keep that in mind.\n\n**But** that's not what we want for a script managing cooling. Polling data and adjusting fan speed must be on a schedule way tighter than hourly, so we will use the **Custom** option.\n\nSelection the \"Custom\" option will pop a little text box to the right of the droplist, of which the formatting is important and follow standard cron job format.\n\nCron expressions speak in minutes, hours, day of the month, month, day of the week and year.\n\nBefore going more in depth, let's cut to the chase, if you want your script to run every minute, punch in: ```* * * * *```\n\n**Keep in mind** that as stated before user scripts only run on Array uptime, meaning that setting up a script that puts back fan control on auto when you shut down the array is more than advised.\n\nTo do so, create a separate script, scheduled on \"At stopping of Array\", punching in your own infos and credentials, that goes as follow:\n```bash\n#!/bin/bash\nIPMIHOST=192.168.0.42\n#iDrac user\nIPMIUSER=root\n#iDrac password (calvin is the default password)\nIPMIPW=calvin\n#YOUR IPMI ENCRYPTION KEY - a big string of zeros is the default, and by default isn't mandatory to be specified.\n#You can modify it, for example in idrac7's webinterface under iDRAC Settings>Network , in the IPMI Settings section.\nIPMIEK=0000000000000000000000000000000000000000\n\n#The command will just put fans back to auto.\nipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK raw 0x30 0x30 0x01 0x01\n```\nWith that, you're more or less set for the fan control.\n\n\n## More cron\nWell, you can do a lot with cron expressions, that's the gist of it.\n\n<details>\n<summary>\n<b>Everything you need should be here</b>\n</summary>\n<p>\n\nInstead of boring you with text, here's the alphabet of them:\n\nField Name |\tMandatory |\tAllowed Values |\tAllowed Special Characters |\n------ | ------- | ------- | ------- |\nMinutes |\tYES |\t0 - 59 |\t, - \\* / |\nHours |\tYES |\t0 - 23 |\t, - \\* / |\nDay of month |\tYES |\t1 - 31 |\t, - \\* ? / L W |\nMonth |\tYES |\t1 - 12 (representing Jan - Dec), JAN - DEC (case-insensitive), JANUARY - DECEMBER (case-insensitive) |\t, - \\* / |\nDay of week |\tYES |\t0 - 6, 7 (representing Sun - Sat and Sun again), SUN - SAT (case-insensitive), SUNDAY - SATURDAY (case-insensitive) |\t, - \\* ? / L # |\nYear |\tNO |\tempty or 1970-2099 |\t, - \\* / |\n\nAnd here a cheatsheet, you'll probably find what you're looking for in it, or be able to make it from it.\n \nCron Expression\texamples | Meaning |\n--------- | --------- |\n\\* \\* \\* \\* \\* 2022 |\tExecute a cron job every minute during the year 2022 |\n\\* \\* \\* \\* \\* |\tExecute a cron job every minute |\n\\*/5 \\* \\* \\* \\* |\tExecute a cron job every 5 minutes |\n0 \\* \\* \\* \\* |\tExecute a cron job every hour |\n0 12 \\* \\* \\* |\tFire at 12:00 PM (noon) every day |\n15 10 \\* \\* \\* |\tFire at 10:15 AM every day |\n15 10 \\* \\* ? |\tFire at 10:15 AM every day |\n15 10 \\* \\* \\* 2022-2024 |\tFire at 10:15 AM every day during the years 2022, 2023 and 2024 |\n\\* 14 \\* \\* \\* |\tFire every minute starting at 2:00 PM and ending at 2:59 PM, every day |\n0/5 14,18 \\* \\* \\* |\tFire every 5 minutes starting at 2:00 PM and ending at 2:55 PM, AND fire every 5 minutes starting at 6:00 PM and ending at 6:55 PM, every day |\n0-5 14 \\* \\* \\* |\tFire every minute starting at 2:00 PM and ending at 2:05 PM, every day |\n10,44 14 \\* 3 3 |\tFire at 2:10 PM and at 2:44 PM every Wednesday in the month of March. |\n15 10 \\* \\* 1-5 |\tFire at 10:15 AM every Monday, Tuesday, Wednesday, Thursday and Friday |\n15 10 15 \\* \\* |\tFire at 10:15 AM on the 15th day of every month |\n15 10 L \\* \\* |\tFire at 10:15 AM on the last day of every month |\n15 10 \\* \\* 5L |\tFire at 10:15 AM on the last Friday of every month |\n15 10 \\* \\* 5#3 |\tFire at 10:15 AM on the third Friday of every month |\n0 12 1/5 \\* \\* |\tFire at 12:00 PM (noon) every 5 days every month, starting on the first day of the month. |\n11 11 11 11 \\* |\tFire every November 11th at 11:11 AM. |\n11 11 11 11 \\* 2022\t| Fire at 11:11 AM on November 11th in the year 2022. |\n0 0 \\* \\* 3 |\tFire at midnight of each Wednesday. |\n0 0 1,2 \\* \\* |\tFire at midnight of 1st, 2nd day of each month |\n0 0 1,2 \\* 3 |\tFire at midnight of 1st, 2nd day of each month, and each Wednesday. |\n\n</p>\n</details>\n"
  },
  {
    "path": "temppull.sh",
    "content": "#!/bin/bash\n#the IP address of your target iDrac\nIPMIHOST=192.168.0.42\n\n#iDrac user\nIPMIUSER=root\n\n#iDrac password (calvin is the default password)\nIPMIPW=calvin\n\n#YOUR IPMI ENCRYPTION KEY\nIPMIEK=0000000000000000000000000000000000000000\n\n#Side note: you shouldn't ever store credentials in a script. Period. Here it's an example. \n#I suggest you give a look at tools like https://github.com/plyint/encpass.sh \n\nipmitool -I lanplus -H $IPMIHOST -U $IPMIUSER -P $IPMIPW -y $IPMIEK sdr type temperature\n\n# Should return something like that:\n#Inlet Temp | 04h | ok | 7.1 | 19 degrees C\n#Exhaust Temp | 01h | ok | 7.1 | 36 degrees C\n#Temp | 0Eh | ok | 3.1 | 41 degrees C\n#Temp | 0Fh | ok | 3.2 | 40 degrees C\n\n#It lets you know the \"id\" to grep for in the fancontrol.sh script.\n"
  }
]