Skip to content

Commit 020b474

Browse files
authored
Merge pull request #104 from mengmeet/go_fans
2 parents 0588efc + f0c6522 commit 020b474

9 files changed

Lines changed: 279 additions & 83 deletions

File tree

py_modules/fan.py

Lines changed: 106 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
hwmon_name: legion_wmi_fan
2+
3+
fans:
4+
- fan_name: Fan
5+
pwm_mode: 2
6+
7+
pwm_enable:
8+
manual_value: 1
9+
auto_value: 2
10+
pwm_enable_path: pwm1_enable
11+
12+
pwm_write:
13+
pwm_write_max:
14+
default: 255
15+
fixed_temps: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
16+
curve_path:
17+
temp_write: []
18+
pwm_write:
19+
- pwm1_auto_point1_pwm
20+
- pwm1_auto_point2_pwm
21+
- pwm1_auto_point3_pwm
22+
- pwm1_auto_point4_pwm
23+
- pwm1_auto_point5_pwm
24+
- pwm1_auto_point6_pwm
25+
- pwm1_auto_point7_pwm
26+
- pwm1_auto_point8_pwm
27+
- pwm1_auto_point9_pwm
28+
- pwm1_auto_point10_pwm
29+
default_curve:
30+
temp:
31+
- 10
32+
- 20
33+
- 30
34+
- 40
35+
- 50
36+
- 60
37+
- 70
38+
- 80
39+
- 90
40+
- 100
41+
pwm:
42+
- 112
43+
- 122
44+
- 140
45+
- 153
46+
- 181
47+
- 201
48+
- 222
49+
- 222
50+
- 255
51+
- 255
52+
53+
temp_mode: 0

py_modules/fan_config/schema/hwmon.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
"description": "读取数值最大值"
113113
}
114114
},
115-
"required": ["pwm_read_path", "pwm_read_max"]
115+
"required": []
116116
},
117117
"PWMWrite": {
118118
"title": "PWMWrite",
@@ -138,6 +138,13 @@
138138
"curve_path": {
139139
"$ref": "#/definitions/PWMWriteCurvePath",
140140
"description": "曲线路径"
141+
},
142+
"fixed_temps": {
143+
"type": "array",
144+
"items": {
145+
"type": "number"
146+
},
147+
"description": "固定温度点列表(固件限制温度不可更改时使用, 如 [10,20,...,100])"
141148
}
142149
},
143150
"required": []
@@ -181,7 +188,7 @@
181188
"items": {
182189
"type": "string"
183190
},
184-
"description": "温度路径数组"
191+
"description": "温度路径数组(可为空数组, 表示温度只读)"
185192
},
186193
"pwm_write": {
187194
"type": "array",
@@ -191,7 +198,7 @@
191198
"description": "PWM路径数组"
192199
}
193200
},
194-
"required": ["temp_write", "pwm_write"]
201+
"required": ["pwm_write"]
195202
},
196203
"BlackListRule": {
197204
"title": "BlackListRule",

0 commit comments

Comments
 (0)