@@ -25,6 +25,7 @@ def __init__(self):
2525
2626 self .hwmon_default_curve = [] # 风扇默认曲线
2727 self .hwmon_curve_paths = [] # 风扇曲线写入路径
28+ self .fixed_temps = [] # 固定温度点 (firmware-imposed, e.g. [10,20,...,100])
2829
2930 self .hwmon_black_list = [] # 风扇hwmon黑名单
3031 self .hwmon_black_list_rules = [] # 风扇hwmon黑名单规则
@@ -167,6 +168,15 @@ def __parse_fan_configuration_HWMON(self, name_path_map):
167168 }
168169 )
169170
171+ # Parse fixed_temps from config
172+ fixed_temps_conf = (
173+ fan_pwm_write ["fixed_temps" ]
174+ if "fixed_temps" in fan_pwm_write
175+ and isinstance (fan_pwm_write ["fixed_temps" ], list )
176+ else []
177+ )
178+ fc .fixed_temps = fixed_temps_conf
179+
170180 if fc .hwmon_mode == 0 :
171181 fc .hwmon_pwm_path = (
172182 name_path_map [hwmon_name ]
@@ -185,44 +195,59 @@ def __parse_fan_configuration_HWMON(self, name_path_map):
185195 curve_temp_path = (
186196 curve_path ["temp_write" ]
187197 if curve_path is not None and "temp_write" in curve_path
198+ and isinstance (curve_path ["temp_write" ], list )
188199 else []
189200 )
190201 curve_pwm_path = (
191202 curve_path ["pwm_write" ]
192203 if curve_path is not None and "pwm_write" in curve_path
193204 else []
194205 )
195- for i in range (min (len (curve_temp_path ), len (curve_pwm_path ))):
196- point_info = {
197- "pwm_write" : name_path_map [hwmon_name ]
198- + "/"
199- + curve_pwm_path [i ],
200- "temp_write" : name_path_map [hwmon_name ]
201- + "/"
202- + curve_temp_path [i ],
203- }
204- if os .path .exists (
205- point_info ["pwm_write" ]
206- ) and os .path .exists (point_info ["temp_write" ]):
207- fc .hwmon_curve_paths .append (point_info )
208-
209- # 读取风扇转速的路径
210- fan_pwm_input = hwmon_config ["pwm_input" ]
211- fan_hwmon_label_input = (
212- fan_pwm_input ["hwmon_label" ]
213- if "hwmon_label" in fan_pwm_input
214- else hwmon_name
215- )
216- fc .hwmon_input_path = (
217- name_path_map [fan_hwmon_label_input ]
218- + "/"
219- + fan_pwm_input ["pwm_read_path" ]
220- )
221- fc .fan_value_max = (
222- fan_pwm_input ["pwm_read_max" ]
223- if "pwm_read_max" in fan_pwm_input
224- else 0
225- )
206+ point_count = (
207+ len (curve_pwm_path ) if not curve_temp_path
208+ else min (len (curve_temp_path ), len (curve_pwm_path ))
209+ )
210+ for i in range (point_count ):
211+ pwm_full_path = (
212+ name_path_map [hwmon_name ] + "/" + curve_pwm_path [i ]
213+ )
214+ temp_full_path = (
215+ name_path_map [hwmon_name ] + "/" + curve_temp_path [i ]
216+ if i < len (curve_temp_path )
217+ else None
218+ )
219+ if not os .path .exists (pwm_full_path ):
220+ continue
221+ if temp_full_path is not None and not os .path .exists (temp_full_path ):
222+ continue
223+ fc .hwmon_curve_paths .append ({
224+ "pwm_write" : pwm_full_path ,
225+ "temp_write" : temp_full_path ,
226+ })
227+
228+ # 读取风扇转速的路径 (optional)
229+ fan_pwm_input = hwmon_config .get ("pwm_input" )
230+ if fan_pwm_input :
231+ fan_hwmon_label_input = (
232+ fan_pwm_input ["hwmon_label" ]
233+ if "hwmon_label" in fan_pwm_input
234+ else hwmon_name
235+ )
236+ fc .hwmon_input_path = (
237+ name_path_map [fan_hwmon_label_input ]
238+ + "/"
239+ + fan_pwm_input ["pwm_read_path" ]
240+ if "pwm_read_path" in fan_pwm_input
241+ else None
242+ )
243+ fc .fan_value_max = (
244+ fan_pwm_input ["pwm_read_max" ]
245+ if "pwm_read_max" in fan_pwm_input
246+ else 0
247+ )
248+ else :
249+ fc .hwmon_input_path = None
250+ fc .fan_value_max = 0
226251 max_value_from_settings = self .fansSettings .getSetting (
227252 f"fan{ len (self .fan_config_list )} _max"
228253 )
@@ -527,10 +552,9 @@ def get_fanRPM(self, index: int):
527552 def __get_fanRPM_HWMON (self , fc : FanConfig ):
528553 try :
529554 hwmon_input_path = fc .hwmon_input_path
555+ if hwmon_input_path is None :
556+ return 0
530557 fanRPM = int (open (hwmon_input_path ).read ().strip ())
531- # logger.debug(
532- # f"使用hwmon数据 当前机型:{PRODUCT_NAME} hwmon地址:{hwmon_input_path} 风扇转速:{fanRPM}"
533- # )
534558 return fanRPM
535559 except Exception :
536560 logger .error ("使用hwmon获取风扇转速异常:" , exc_info = True )
@@ -750,10 +774,11 @@ def __set_fanAuto_HWMON(self, fc: FanConfig, value: bool):
750774 fanWriteValue = hwmon_default_curve [index ]["pwm_value" ]
751775 pwm_path = point ["pwm_write" ]
752776 open (pwm_path , "w" ).write (str (fanWriteValue ))
753- # 写入温度
754- temp = hwmon_default_curve [index ]["temp_value" ]
777+ # 写入温度 (skip if read-only / None)
755778 temp_path = point ["temp_write" ]
756- open (temp_path , "w" ).write (str (temp ))
779+ if temp_path is not None :
780+ temp = hwmon_default_curve [index ]["temp_value" ]
781+ open (temp_path , "w" ).write (str (temp ))
757782 logger .debug (
758783 f"写入hwmon数据 写入hwmon转速地址:{ pwm_path } 风扇转速写入值:{ fanWriteValue } 温度地址:{ temp_path } 温度大小:{ temp } "
759784 )
@@ -885,10 +910,11 @@ def __set_fanPercent_HWMON(self, fc: FanConfig, value: int):
885910 # 写入转速
886911 pwm_path = point ["pwm_write" ]
887912 open (pwm_path , "w" ).write (str (fanWriteValue ))
888- # 写入温度
913+ # 写入温度 (skip if read-only / None)
889914 temp = temp + addTemp
890915 temp_path = point ["temp_write" ]
891- open (temp_path , "w" ).write (str (temp ))
916+ if temp_path is not None :
917+ open (temp_path , "w" ).write (str (temp ))
892918 logger .debug (
893919 f"写入hwmon数据 写入hwmon转速地址:{ pwm_path } 风扇转速百分比{ value } 风扇最大值{ rpm_write_max } 风扇转速写入值:{ fanWriteValue } 温度地址:{ temp_path } 温度大小:{ temp } "
894920 )
@@ -946,6 +972,33 @@ def __set_fanPercent_ECIO(self, fc: FanConfig, value: int):
946972 logger .error ("使用ECIO写入风扇转速异常:" , exc_info = True )
947973 return False
948974
975+ def _interpolate_to_fixed_temps (
976+ self , temp_list : List [int ], pwm_list : List [int ], fixed_temps : List [int ]
977+ ):
978+ """Interpolate user curve points to match fixed temperature points."""
979+ if not temp_list or not pwm_list :
980+ return list (fixed_temps ), [0 ] * len (fixed_temps )
981+
982+ points = sorted (zip (temp_list , pwm_list ), key = lambda p : p [0 ])
983+ result_pwm = []
984+ for target_temp in fixed_temps :
985+ if target_temp <= points [0 ][0 ]:
986+ result_pwm .append (points [0 ][1 ])
987+ elif target_temp >= points [- 1 ][0 ]:
988+ result_pwm .append (points [- 1 ][1 ])
989+ else :
990+ for i in range (len (points ) - 1 ):
991+ if points [i ][0 ] <= target_temp <= points [i + 1 ][0 ]:
992+ t0 , p0 = points [i ]
993+ t1 , p1 = points [i + 1 ]
994+ if t1 == t0 :
995+ result_pwm .append (p0 )
996+ else :
997+ ratio = (target_temp - t0 ) / (t1 - t0 )
998+ result_pwm .append (int (p0 + ratio * (p1 - p0 )))
999+ break
1000+ return list (fixed_temps ), result_pwm
1001+
9491002 def set_fanCurve (self , index : int , temp_list : List [int ], pwm_list : List [int ]):
9501003 try :
9511004 logger .info (f"[FanDebug] set_fanCurve fan[{ index } ] temps={ temp_list } pwms={ pwm_list } " )
@@ -958,6 +1011,14 @@ def set_fanCurve(self, index: int, temp_list: List[int], pwm_list: List[int]):
9581011 fc = self .fan_config_list [index ]
9591012 hwmon_mode = fc .hwmon_mode
9601013
1014+ if fc .fixed_temps :
1015+ temp_list , pwm_list = self ._interpolate_to_fixed_temps (
1016+ temp_list , pwm_list , fc .fixed_temps
1017+ )
1018+ logger .info (
1019+ f"[FanDebug] interpolated to fixed_temps: temps={ temp_list } pwms={ pwm_list } "
1020+ )
1021+
9611022 if hwmon_mode == 2 and fc .is_found_hwmon :
9621023 if fc .hwmon_enable_path :
9631024 try :
@@ -989,15 +1050,17 @@ def __set_fanCurve_HWMON(
9891050 enable_path = fc .hwmon_enable_path
9901051
9911052 if mode == 2 :
992- for i in range (min (len (temp_list ), len (pwm_list ))):
1053+ for i in range (min (len (temp_list ), len (pwm_list ), len ( hwmon_curve_paths ) )):
9931054 pwm_path = hwmon_curve_paths [i ]["pwm_write" ]
9941055 temp_path = hwmon_curve_paths [i ]["temp_write" ]
9951056 fanWritePwmValue = max (
9961057 min (int (pwm_list [i ] / 100 * rpm_write_max ), rpm_write_max ), 0
9971058 )
998- fanWriteTempValue = max (min (int (temp_list [i ]), rpm_write_max ), 0 )
9991059 open (pwm_path , "w" ).write (str (fanWritePwmValue ))
1000- open (temp_path , "w" ).write (str (fanWriteTempValue ))
1060+ fanWriteTempValue = None
1061+ if temp_path is not None :
1062+ fanWriteTempValue = max (min (int (temp_list [i ]), rpm_write_max ), 0 )
1063+ open (temp_path , "w" ).write (str (fanWriteTempValue ))
10011064 logger .debug (
10021065 f"hwmon写入数据, pwm_path:{ pwm_path } , pwm_value:{ fanWritePwmValue } ; temp_path:{ temp_path } , temp_value:{ fanWriteTempValue } "
10031066 )
@@ -1097,6 +1160,7 @@ def get_fanConfigList(self):
10971160 "fan_hwmon_mode" : fan_hwmon_mode ,
10981161 "fan_default_curve" : fan_default_curve ,
10991162 "fan_pwm_write_max" : fan_pwm_write_max ,
1163+ "fan_fixed_temps" : config .fixed_temps ,
11001164 }
11011165 )
11021166 return config_list
0 commit comments