Skip to content

Instantly share code, notes, and snippets.

@alber70g
Forked from ikus060/smx8fancontrol
Last active November 3, 2023 19:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alber70g/00f2d87c0db78a3c51db28cc670e261a to your computer and use it in GitHub Desktop.
Save alber70g/00f2d87c0db78a3c51db28cc670e261a to your computer and use it in GitHub Desktop.
Python script to edit the X8DTL-iF Registry to control fan speed.

smx8fancontrol on unraid

To change the fan speeds on a SuperMicro X8 board (I have X8DTL-iF) there's a tool smx8fancontrol

Now there's a few deps that are needed and it's a pain to install them on UnRaid. So far this has been my script to get it to run:

# https://www.ikus-soft.com/en/blog/2017-10-01-supermicro-x8-controle-ventilateur/
# install smx8fancontrol on unraid
# install nerd-pack and enable `python3` and `pip`

# install smbus2
pip install smbus2

# get the script
# Optimized version from timemaster67
# See also https://forums.servethehome.com/index.php?threads/supermicro-ipmi-fan-control.12025/#post-167086
sudo wget -O /usr/local/bin/smx8fancontrol \
https://gist.githubusercontent.com/alber70g/00f2d87c0db78a3c51db28cc670e261a/raw/smx8fancontrol

sudo wget -O /usr/local/bin/smx8fancontrolif \
https://gist.githubusercontent.com/alber70g/00f2d87c0db78a3c51db28cc670e261a/raw/smx8fancontrolif

# make it executable
chmod +x /usr/local/bin/smx8fancontrol 

# trigger i2c module
modprobe -r w83795
modprobe i2c-dev

# run it
smx8fancontrol -s

wait 5

# change to smart
smx8fancontrolif -m smart -p 01,05,10,20,40,80 -t 25,30,40,50,60,70 -H 2

wait 5

# set tresholds to not get errors in IPMI
# https://www.truenas.com/community/threads/how-to-change-ipmi-sensor-thresholds-using-ipmitool.53620/page-6
# I have the X8DTL-iF and these are squared. So 10 means 10*10 = 100rpm
ipmitool sensor thresh "FAN 1" lower 10 21 29
wait 2
ipmitool sensor thresh "FAN 2" lower 10 21 29
wait 2
ipmitool sensor thresh "FAN 3" lower 10 21 29
wait 2
ipmitool sensor thresh "FAN 4" lower 10 21 29
wait 2
ipmitool sensor thresh "FAN 1" upper 175 178 181
wait 2
ipmitool sensor thresh "FAN 2" upper 175 178 181
wait 2
ipmitool sensor thresh "FAN 3" upper 175 178 181
wait 2
ipmitool sensor thresh "FAN 4" upper 175 178 181
wait 2

# reset IPMI user ADMIN
#ipmitool -I open user set password 2 ADMIN
#!/usr/bin/env python3
#
# To use to READ the sensors and table
#
#######################
# smx8fancontrol -s
#######################
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import sys
import argparse
from smbus2 import SMBus
from contextlib import contextmanager
#
# All register ceom from
# https://github.com/torvalds/linux/blob/5924bbecd0267d87c24110cbe2041b5075173a25/drivers/hwmon/w83795.c
#
#chip i2c address to use
ADDRESS=0x2f
NUVOTON_VENDOR_ID = 0x5ca3
CHIP_ID = 0x79
W83795_REG_VENDOR_ID = 0X0FD
W83795_REG_CHIP_ID = 0X0FE
#the registery is banked. To access the full data, user must switch the bank, like a page, in this register.
#when this register lower 2 bit are set, the rest of the data change according to it.
#bank0 show sensors related config bank 1 show nothing interesting bank 2 show fan related config. bank 3 show peci related config
W83795_REG_BANKSEL = 0x00
# Fan Control Mode Selection Registers (FCMS)
W83795_REG_FCMS1 = 0x201
W83795_REG_FCMS2 = 0x208
#Temperature to Fan mapping Relationships Register (TFMR)
#W83795_REG_TFMR = lambda index: 0x202 + index
#There is 6 temperature source thus 6 entry, Each entry contains a binary representation of if one of the 8 pwm is linked to that temperature
W83795_REG_TFMR = lambda index: 0x202 + index
#Temperature Source Selection Register (TSS)
#data for pwm1 and 2 are mixed in the first byte, pwm3 and 4, second...
W83795_REG_TSS = lambda index: 0x209 + floor((index/2))
#Default Fan Speed at Power-on (DFSP)
W83795_REG_DFSP = 0x20c
#the range is used to access all element from 0x80 to 0xde without declaring everything.
#temp1 is index 0, thus 0 * 0x10 is 0. we access 0x80 to 0x87 straight.
#temp3 is index 1, thus 1* 0x10 is 0x10, so we access 0x80 + 0x10 = 0x9x to 0x96
W83795_REG_SFIV_TEMP = lambda index: range(0x280 + index * 0x10, 0x280 + index * 0x10 + 6)
W83795_REG_SFIV_DCPWM = lambda index: range(0x288 + index * 0x10, 0x288 + index * 0x10 + 6)
#Fan Output Value (FOV)
W83795_REG_FOV = lambda index: 0x210 + index
#Fan Output Nonstop Value (FONV)
W83795_REG_FONV = lambda index: 0x228 + index
#Fan Output Stop Time (FOST)
W83795_REG_FOST = lambda index: 0x230 + index
#SmartFan Output Step Up Time (SFOSUT)
W83795_REG_SFOSUT = 0x20D
#SmartFan Output Step Down Time (SFOSDT)
W83795_REG_SFOSDT = 0x20E
#Target Temperature of Temperature Inputs (TTTI)
W83795_REG_TTTI = lambda index: 0x260 + index
#Critical Temperature to Full Speed all fan (CTFS)
W83795_REG_CTFS = lambda index: 0x268 + index
#Hystersis of Temperature (HT)
W83795_REG_HT = lambda index: 0x270 + index
#not in use
#Fan Output PWM Frequency Prescalar (FOPFP)
W83795_REG_FOPFP = lambda index: 0x218 + index
@contextmanager
def bank(bus, value):
prev_value = w83795_set_bank(bus, value)
yield
w83795_set_bank(bus, prev_value)
def w83795_set_bank(bus, bank):
assert bank in [0,1,2,3]
# Read current bank value, ignoring reserved bit and high byte access fields.
field = bus.read_byte_data(ADDRESS, W83795_REG_BANKSEL)
cur_bank = field & 0b00000011
# If the bank is already set, nothing to do
if cur_bank == bank:
return cur_bank
# Change the bank, preserving reserved value
bus.write_byte_data(ADDRESS, W83795_REG_BANKSEL, field | bank )
# Return previous bank value
return cur_bank
def w83795_write(bus, reg, value):
"""
Write into the given registry.
"""
with bank(bus, reg >> 8):
return bus.write_byte_data(ADDRESS, reg & 0xff, value & 0xff)
def w83795_read(bus, reg):
"""
Read the given registry.
"""
if hasattr(reg, '__iter__'):
with bank(bus, reg[0] >> 8):
return map(lambda r: bus.read_byte_data(ADDRESS, r & 0xff), reg)
with bank(bus, reg >> 8):
return bus.read_byte_data(ADDRESS, reg & 0xff)
def CheckChipset(bus):
#Check that we are dealing with the W83795 chipset
#set the register to get the high bit value, while keeping the reserved bit and the bank intact
multidata = w83795_read(bus, W83795_REG_BANKSEL)
w83795_write(bus, W83795_REG_BANKSEL, (multidata & 0b01111111) | 0b10000000)
#get the high bit value
vendor = w83795_read(bus, W83795_REG_VENDOR_ID)
#shift vendor part to the left
vendor = vendor << 8
#set the register to get the low bit value, while keeping the reserved bit and the bank intact
w83795_write(bus, W83795_REG_BANKSEL, multidata & 0b01111111)
vendor = vendor | w83795_read(bus, W83795_REG_VENDOR_ID)
chipid = w83795_read(bus, W83795_REG_CHIP_ID)
#debug("vendor %s, chipid %s" % (vendor, chipid))
if vendor != NUVOTON_VENDOR_ID or chipid != CHIP_ID:
print("unexpected vendor %s, chipid %s" % (vendor, chipid))
return False
return True
def ShowInfo(bus):
#get fan configuration
fcms1 = w83795_read(bus, W83795_REG_FCMS1)
fcms2 = w83795_read(bus, W83795_REG_FCMS2) & 0b00111111
#get the Temperature to Fan mapping Relationships Register (TFMR) and keep a cache for multiple reuse
tfmr = []
for t in range(0,6):
tfmr.append(w83795_read(bus, W83795_REG_TFMR(t)))
for f in range(0,6):
#for each controllable pwm
print("Fan%s" % (f+1))
#binary fan value, used for binary and
#shift number binary 00000001 f bytes to the left,
#00000001 shifted 1 time to the left equals 00000010.
fbin = 1 << f
#show the calculated binary number
#print(fbin)
# get the operating mode of the fan (manual, speed cruise, thermal cruise, smart fan)
#Check the mode of the fan by looking at the
#print(fcms1 & fbin)
#print(fcms2 & fbin)
isSpeedCruise = fcms1 & fbin
#wrong wrong wrong. fcms2 affiche les ttemps, pas les fans. !! 8 fans, 6 temp!! il faut checker les temps to fans relationship,
#ensuite checker le mode des temps.
isThermalCruise = not isSpeedCruise and not(fcms2 & fbin)
isSmartFan = not isSpeedCruise and (fcms2 & fbin)
tempToFanMapping = []
#Check if the fan is in manual mode
if (not isSpeedCruise):
#if the fan is marked not in speed cruise but there is no temp relationship to this fan, it's in manual mode
hasAtLeastOneRelationship = False
#there is 6 different temperature
for t in range(0,6):
#check if the current fan (fbin) has a relationship with any of the 6 temperature
if (tfmr[t] & fbin > 0):
hasAtLeastOneRelationship = True
#save the temperature sensor related to this fan
tempToFanMapping.append("Temp %s" % t)
if (not hasAtLeastOneRelationship):
isSmartFan = False
isThermalCruise = False
if isSpeedCruise:
print(" Mode : Speed Cruise mode")
elif isThermalCruise:
print(" Mode : Thermal Cruise mode")
elif isSmartFan:
print(" Mode : Smart Fan mode")
else:
print(" Mode : Manual mode")
pwm = w83795_read(bus, W83795_REG_FOV(f))
print(" Fan Output Value (FOV): %s%%" % round(to_perc(pwm), 2))
if isSmartFan:
print(" Temperature to Fan mapping Relationships Register (TFMR): fan linked to : %s" % ",".join(tempToFanMapping))
#not sure if useful
#print(" Temperature Source Selection Register (TSS)")
#temp = w83795_read(bus, W83795_REG_TSS(f))
print(" Smart Fan Control Table (SFIV)")
temp = w83795_read(bus, W83795_REG_SFIV_TEMP(f))
print(''.join([("%dC" % to_degree(v)).rjust(6) for v in temp]))
dcpwm = w83795_read(bus, W83795_REG_SFIV_DCPWM(f))
print(''.join([("%d%%" % to_perc(v)).rjust(6) for v in dcpwm]))
print('')
if isSpeedCruise or isThermalCruise or isSmartFan :
fonv = w83795_read(bus, W83795_REG_FONV(f))
print(" Fan Output Nonstop Value (FONV): %d%%" % to_perc(fonv))
fost = w83795_read(bus, W83795_REG_FOST(f))
if (fost != 0):
print(" Fan Output Stop Time (FOST):", fost * 0.1, "sec")
else:
print(" Fan Output Stop Time (FOST): never stop")
ctfs = w83795_read(bus, W83795_REG_CTFS(t))
#todo : probably in peci unit
print(" Critical Temperature to Full Speed all fan (CTFS): %d" % (ctfs))
if isThermalCruise or isSmartFan:
#Hystersis of Temperature
ht = w83795_read(bus, W83795_REG_HT(t))
#The critical hystersis might be used to lower a cpu even in manual or speed mode. Documentation is unclear.
ht_critical = ht & 0b11110000
ht_operation = ht & 0b00001111
print(" Hystersis of critical temperature: %dC" % ht_critical)
print(" hystersis of operation temperature: %dC" % ht_operation)
if isThermalCruise :
ttti = w83795_read(bus, W83795_REG_TTTI(f))
#ignore the 8th bit as it's reserved
ttti = ttti & 0b111111
print(" Target Temperature of Temperature Inputs (TTTI):", ttti, "in PECI unit")
print("")
#generic parameters
#Default Fan Speed at Power-on (DFSP)
defpwm = w83795_read(bus, W83795_REG_DFSP)
print("Default Fan Speed at Power-on (DFSP): %d%%" % to_perc(defpwm))
#SmartFan Output Step Up Time (SFOSUT)
stepuptime = w83795_read(bus, W83795_REG_SFOSDT)
print("Fan output step up time: %g sec" % (float(stepuptime) * 0.1))
##SmartFan Output Step Down Time (SFOSDT)
stepdowntime = w83795_read(bus, W83795_REG_SFOSDT)
print("Fan output step down time: %g sec" % (float(stepdowntime) * 0.1))
def to_degree(val, low=0, hi=127):
"""Convert hex value to degree."""
return 127 * val / 255
def to_perc(value):
"""Convert hex value to percentage."""
return value * 100 / 255
def from_perc(value):
"""Convert perc to hex"""
return (int(value * 255 / 100) & 0xff)
def from_degree(value):
#keven
return (int(value * 255 / 127) & 0xff)
def WriteSettings(bus):
# Read arguments
args = sys.argv
pwm_value = None
if len(args)>1:
pwm_value = int(args[1])
# Check if Smarts Fan Control is enabled
fcms1 = w83795_read(bus, W83795_REG_FCMS1)
fcms2 = w83795_read(bus, W83795_REG_FCMS2) & 0xf
#debug("FCMDS1: %s, FCMS2: %s" % (fcms1, fcms2))
if fcms1 !=0 and fcms2 == 0:
print("Smart Fan Control is not enabled")
return
# Extract TEMP with Smart Fan Enabled
temps = [i for i in range(0,6) if fcms2 & (0x1<<i)]
# Set the registry value
if pwm_value:
print("Set minimum PWM to %s%%" % pwm_value)
# Change Smart Fan Control value
for t in temps:
w83795_write(bus, W83795_REG_SFIV_DCPWM(t)[0], from_perc(pwm_value))
# Change Minimum PWM
for f in range(0,6):
w83795_write(bus, W83795_REG_FONV(f), from_perc(pwm_value))
def main():
#Check if we have the right device.
try:
# Open SMBus
try:
bus = SMBus(0)
except:
print("Failed to open i2c bus (/dev/i2d-0). Make sure i2c-dev module is loaded.")
return
booContinue = CheckChipset(bus)
if not booContinue:
#if it's not the correct chipset, stop program
return
#ShowInfo(bus)
parser = argparse.ArgumentParser(description="Utility to show and configure settings of the Nuvoton w83793 chipset")
parser.add_argument("-s", "--show", help="Show current configuration", action="store_true")
parser.add_argument("-f", "--fan", type=int, choices=[1, 2, 3, 4, 5, 6, 7, 8], default = 0, help="Select fan to modify")
parser.add_argument("--sfiv", default=[], nargs = '*', help = "Specify a new set of smartfan values. Specify the temperature then the fan speed for all 6 steps.")
parser.add_argument("--fcms", choices=['manual','thermal cruise','smart fan'])
args = parser.parse_args()
if (args.fan > 0 and args.fcms == "thermal cruise"):
#get fan configuration
fcms1 = w83795_read(bus, W83795_REG_FCMS1)
fcms2 = w83795_read(bus, W83795_REG_FCMS2) & 0b00111111
#binary fan value, used for binary and
#shift number binary 00000001 f bytes to the left,
#00000001 shifted 1 time to the left equals 00000010.
fbin = 1 << args.fan-1
inverse = 0xff - fbin
fcms1 = fcms1 & inverse
print (fcms1)
if (args.fan > 0 and len(args.sfiv) == 12):
print (args.sfiv)
#set to zero based
fan = args.fan-1
temp = []
dcpwm = []
#from 0 to 5, step by 2
for index in range(0,11,2):
#from degree and to degree is weird. from don't work.
temp.append(from_degree(int(args.sfiv[index])))
#from perc does work correclty
dcpwm.append(from_perc(int(args.sfiv[index+1])))
print (temp)
print (dcpwm)
#print(" Smart Fan Control Table (SFIV)")
#temp = w83795_read(bus, W83795_REG_SFIV_TEMP(f))
#print(''.join([("%dC" % to_degree(v)).rjust(6) for v in temp]))
#dcpwm = w83795_read(bus, W83795_REG_SFIV_DCPWM(f))
#print(''.join([("%d%%" % to_perc(v)).rjust(6) for v in dcpwm]))
#print('')
if (args.show):
ShowInfo(bus)
#old stuff from original developper
#for t in range(0,6):
# ctfs = w83795_read(bus, W83795_REG_CTFS(t))
# print("T%sCTFS: %s" % (t, to_degree(ctfs)))
#for f in range(0,6):
# w83795_write(bus, W83795_REG_FONV(f), 50)
#w83795_write(bus, W83795_REG_SFIV_DCPWM(0)[0], 50)
#
#w83795_write(bus, W83795_REG_SFIV_TEMP(0)[0], 85)
#w83795_write(bus, W83795_REG_SFIV_TEMP(1)[0], 85)
finally:
bus.close()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
#
# To use to SET THE VALUES
#
#######################
# smx8fancontrolif -m smart -p 01,05,10,20,40,80 -t 25,30,40,50,60,70 -H 2
#######################
# smx8fancontrolif -m cruise -t 50 -H 5 # cruise
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import sys
import argparse
from smbus2 import SMBus
from contextlib import contextmanager
#
# All register ceom from
# https://github.com/torvalds/linux/blob/5924bbecd0267d87c24110cbe2041b5075173a25/drivers/hwmon/w83795.c
#
#
ADDRESS=0x2f
NUVOTON_VENDOR_ID = 0xa3
CHIP_ID = 0x79
W83795_REG_BANKSEL = 0x00
# Fan Control Mode Selection Registers (FCMS)
W83795_REG_FCMS1 = 0x201
W83795_REG_FCMS2 = 0x208
W83795_REG_TFMR = lambda index: 0x202 + index
W83795_REG_TSS = lambda index: 0x209 + index
W83795_REG_SFIV_TEMP = lambda index: range(0x280 + index * 0x10, 0x280 + index * 0x10 + 7)
W83795_REG_SFIV_DCPWM = lambda index: range(0x288 + index * 0x10, 0x288 + index * 0x10 + 7)
W83795_REG_CTFS = lambda index: 0x268 + index
#Fan Output PWM Frequency Prescalar (FOPFP)
W83795_REG_FOPFP = lambda index: 0x218 + index
#Fan Output Nonstop Value (FONV)
W83795_REG_FONV = lambda index: 0x228 + index
#Hystersis of Temperature (HT)
W83795_REG_HT = lambda index: 0x270 + index
#Target Temperature of Temperature Inputs
W83795_TTTI = lambda index: 0x260 + index
#Read temperature
W83795_REG_VRLSB = 0x3C
W83795_REG_TEMP_READ = [0x21, 0x22, 0x23, 0x24, 0x1f, 0x20]
FANS = range(0,8)
TEMPS = range(0,6)
@contextmanager
def bank(bus, value):
prev_value = w83795_set_bank(bus, value)
yield
w83795_set_bank(bus, prev_value)
def w83795_set_bank(bus, bank):
assert bank in [0,1,2,3]
# Read current bank value
cur_bank = bus.read_byte_data(ADDRESS, W83795_REG_BANKSEL)
# If the bank is already set, nothing to do
if cur_bank == bank:
return cur_bank
# Change the bank
bus.write_byte_data(ADDRESS, W83795_REG_BANKSEL, bank)
# Return previous bank value
return cur_bank
def w83795_write(bus, reg, value):
"""
Write into the given registry.
"""
with bank(bus, reg >> 8):
return bus.write_byte_data(ADDRESS, reg & 0xff, value & 0xff)
def w83795_read(bus, reg):
"""
Read the given registry.
"""
if hasattr(reg, '__iter__'):
with bank(bus, reg[0] >> 8):
return map(lambda r: bus.read_byte_data(ADDRESS, r & 0xff), reg)
with bank(bus, reg >> 8):
return bus.read_byte_data(ADDRESS, reg & 0xff)
def to_degree(val, low=0, hi=127):
"""Convert hex value to degree."""
print("to_degree val", val)
return val
def to_perc(value):
"""Convert hex value to percentage."""
return value * 100 / 255
def from_degree(value):
"""Convert degree to hex"""
value = max(min(int(value) + 1,127),0)
return value
def from_perc(value):
"""Convert perc to hex"""
value = max(min(int(value) + 1,100),0)
return int(value * 255 / 100) & 0xff
def main():
# Read arguments
parser = argparse.ArgumentParser(description='Change SuperMicro X8 Fan Control.')
parser.add_argument('-m', '--mode', type=str, choices=['smart', 'cruise'], help='Set the fan mode: smart or cruise. smart: to use Smart Fan mode. cruise: to use Thermal Cruise mode.')
parser.add_argument('-p', '--pwm', type=str, help='Set Fan Duty (in percentage).')
parser.add_argument('-t', '--temp', type=str, help='Set Temperature (in Celsius) associated to pwm.')
parser.add_argument('-H', '--hystersis', type=int, help='Set Hystersis value in degree (0-15)')
args = parser.parse_args()
# Open SMBus
try:
bus = SMBus(0)
except:
print("Failed to open i2c bus (/dev/i2d-0). Make sure i2c-dev module is loaded.")
return
#Check if we have the right device.
try:
vendor = w83795_read(bus, 0xfd)
chipid = w83795_read(bus, 0xfe)
#debug("vendor %s, chipid %s" % (vendor, chipid))
if vendor != NUVOTON_VENDOR_ID or chipid != CHIP_ID:
print("unexpected vendor %s, chipid %s" % (vendor, chipid))
return
# Check if Smarts Fan Control is enabled
if args.mode == 'smart':
# Check arguments
if not args.pwm or not args.temp:
print('pwm and temp are required')
return
pwm = args.pwm.split(',')
temp = args.temp.split(',')
if len(pwm) != len(temp):
print("pwm and temp must have the same number of values")
return
# Change Smart Fan Control value
for i in range(0,7):
p = pwm[i] if i < len(pwm) else pwm[-1]
tt = temp[i] if i < len(temp) else temp[-1]
print("Set Smart Fan Control %s%% - %sC" % (p, tt))
for t in TEMPS:
w83795_write(bus, W83795_REG_SFIV_DCPWM(t)[i], from_perc(p))
w83795_write(bus, W83795_REG_SFIV_TEMP(t)[i], from_degree(tt)*2)
# Change Minimum PWM
for f in FANS:
w83795_write(bus, W83795_REG_FONV(f), from_perc(pwm[0]))
# Change critical Temp
for t in TEMPS:
w83795_write(bus, W83795_REG_CTFS(t), from_degree(temp[-1]))
# Set Smart Fan Control Mode T6FC - T1FC
w83795_write(bus, W83795_REG_FCMS1, 0x0)
w83795_write(bus, W83795_REG_FCMS2, 0x3f)
elif args.mode == 'cruise':
# Check arguments
if not args.temp:
print('temp is required')
return
temp = int(args.temp)
print("Set Thermal Cruise %sC" % (temp,))
for t in TEMPS:
w83795_write(bus, W83795_TTTI(t), from_degree(temp))
# Change critical Temp
for t in TEMPS:
w83795_write(bus, W83795_REG_CTFS(t), from_degree(80))
# Set Thermal Cruise Mode.
w83795_write(bus, W83795_REG_FCMS1, 0x0)
w83795_write(bus, W83795_REG_FCMS2, 0x0)
# Set hystersis
if args.hystersis:
ht = max(min(args.hystersis,15),0)
print("Set hystersis %sC" % ht)
# Change Smart Fan Control value
for t in range(0,6):
w83795_write(bus, W83795_REG_HT(t), ht)
if args.mode or args.pwm or args.temp or args.hystersis:
return
# Check if Smarts Fan Control is enabled
fcms1 = w83795_read(bus, W83795_REG_FCMS1)
fcms2 = w83795_read(bus, W83795_REG_FCMS2) & 0xff
# Default to show all data.
for t in TEMPS:
print("Temp%s to Fan mapping Relationships (T%sFMR)" % (t+1, t+1))
tfmr = w83795_read(bus, W83795_REG_TFMR(t))
fans= [i+1 for i in FANS if tfmr & (0x1<<i)]
print(' '.join(['Fan%s' % i for i in fans]))
print("Smart Fan Control Table (SFIV)")
temp = w83795_read(bus, W83795_REG_SFIV_TEMP(t))
print(''.join([int("%sC" % to_degree(v)).rjust(6) for v in temp]))
dcpwm = w83795_read(bus, W83795_REG_SFIV_DCPWM(t))
print(''.join([int("%s%%" % to_perc(v)).rjust(6) for v in dcpwm]))
ttti = w83795_read(bus, W83795_TTTI(t))
print("Thermal Cruise (TTTI): %sC" % (ttti,))
ctfs = w83795_read(bus, W83795_REG_CTFS(t))
print("Critical Temperature (T%sCTFS): %sC" % (t, to_degree(ctfs)/2))
ht = w83795_read(bus, W83795_REG_HT(t)) & 0b1111
print("Hysteresis (HT%s): %sC" % (t, ht))
tmp = w83795_read(bus, W83795_REG_TEMP_READ[t])
print("Current Temperature (TEMP%s): %sC" % (t, to_degree(tmp),))
print('---')
for f in FANS:
fonv = w83795_read(bus, W83795_REG_FONV(f))
print("Fan%s Output Nonstop Value (F%sONV): %s%%" % (f+1, f+1, to_perc(fonv)))
#for f in range(0,6):
# w83795_write(bus, W83795_REG_FONV(f), 50)
#w83795_write(bus, W83795_REG_SFIV_DCPWM(0)[0], 50)
#w83795_write(bus, W83795_REG_SFIV_TEMP(0)[0], 85)
#w83795_write(bus, W83795_REG_SFIV_TEMP(1)[0], 85)
finally:
bus.close()
if __name__ == "__main__":
main()
@vc
Copy link

vc commented Dec 9, 2022

Thanks for your fork script. It works fine on my supermicro X8DT3-F. I just wanted to share my success and add my own to the treasury of success.

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