adjustor 3.5.3__tar.gz → 3.6.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. {adjustor-3.5.3/src/adjustor.egg-info → adjustor-3.6.0}/PKG-INFO +1 -1
  2. {adjustor-3.5.3 → adjustor-3.6.0}/pyproject.toml +1 -1
  3. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/const.py +32 -0
  4. adjustor-3.6.0/src/adjustor/core/fan/__init__.py +1 -0
  5. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/fan/alg.py +2 -3
  6. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/fan/core.py +45 -6
  7. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/asus/__init__.py +4 -1
  8. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/general/__init__.py +3 -3
  9. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/lenovo/__init__.py +11 -1
  10. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/lenovo/settings.yml +6 -0
  11. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/smu/__init__.py +123 -5
  12. adjustor-3.6.0/src/adjustor/drivers/smu/qam.yml +80 -0
  13. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/events.py +1 -0
  14. {adjustor-3.5.3 → adjustor-3.6.0/src/adjustor.egg-info}/PKG-INFO +1 -1
  15. adjustor-3.5.3/src/adjustor/drivers/__init__.py +0 -0
  16. adjustor-3.5.3/src/adjustor/drivers/smu/qam.yml +0 -21
  17. {adjustor-3.5.3 → adjustor-3.6.0}/LICENSE +0 -0
  18. {adjustor-3.5.3 → adjustor-3.6.0}/MANIFEST.in +0 -0
  19. {adjustor-3.5.3 → adjustor-3.6.0}/readme.md +0 -0
  20. {adjustor-3.5.3 → adjustor-3.6.0}/setup.cfg +0 -0
  21. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/__init__.py +0 -0
  22. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/__main__.py +0 -0
  23. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/__init__.py +0 -0
  24. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/acpi.py +0 -0
  25. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/alib.py +0 -0
  26. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/fan/__main__.py +0 -0
  27. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/fan/utils.py +0 -0
  28. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/lenovo.py +0 -0
  29. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/core/platform.py +0 -0
  30. {adjustor-3.5.3/src/adjustor/core/fan → adjustor-3.6.0/src/adjustor/drivers}/__init__.py +0 -0
  31. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/amd/__init__.py +0 -0
  32. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/amd/power-profiles-daemon.dbus.xml.in +0 -0
  33. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/amd/ppd.py +0 -0
  34. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/amd/settings.yml +0 -0
  35. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/asus/settings.yml +0 -0
  36. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/general/settings.yml +0 -0
  37. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/drivers/smu/smu.yml +0 -0
  38. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/fuse/__init__.py +0 -0
  39. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/fuse/driver.py +0 -0
  40. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/fuse/gpu.py +0 -0
  41. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/fuse/utils.py +0 -0
  42. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/hhd.py +0 -0
  43. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/i18n.py +0 -0
  44. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor/settings.yml +0 -0
  45. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor.egg-info/SOURCES.txt +0 -0
  46. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor.egg-info/dependency_links.txt +0 -0
  47. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor.egg-info/entry_points.txt +0 -0
  48. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor.egg-info/requires.txt +0 -0
  49. {adjustor-3.5.3 → adjustor-3.6.0}/src/adjustor.egg-info/top_level.txt +0 -0
  50. {adjustor-3.5.3 → adjustor-3.6.0}/usr/share/dbus-1/system.d/hhd-net.hadess.PowerProfiles.conf +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: adjustor
3
- Version: 3.5.3
3
+ Version: 3.6.0
4
4
  Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
5
5
  Author-email: Kapenekakis Antheas <pypi@antheas.dev>
6
6
  Project-URL: Homepage, https://github.com/hhd-dev/adjustor
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "adjustor"
3
- version = "3.5.3"
3
+ version = "3.6.0"
4
4
  authors = [
5
5
  { name="Kapenekakis Antheas", email="pypi@antheas.dev" },
6
6
  ]
@@ -1,5 +1,33 @@
1
+ from typing import TypedDict
2
+
1
3
  from .alib import A, D, DeviceParams, AlibParams
2
4
 
5
+
6
+ class DevicePreset(TypedDict):
7
+ tdp_limit: int
8
+ slow_limit: int
9
+ fast_limit: int
10
+ slow_time: int
11
+ stapm_time: int
12
+ temp_target: int
13
+ fan_curve: dict[int, float] | None
14
+
15
+
16
+ class DevideProfile(TypedDict):
17
+ quiet: DevicePreset
18
+ balanced: DevicePreset
19
+ performance: DevicePreset
20
+ # Turbo is custom with max tdp values
21
+ turbo: DevicePreset
22
+
23
+ platform_profile_map: dict[str, int]
24
+ ppd_balanced_min: int
25
+ ppd_performance_min: int
26
+
27
+ alib: dict[str, AlibParams]
28
+ dev: dict[str, DeviceParams]
29
+
30
+
3
31
  PLATFORM_PROFILE_MAP = [
4
32
  ("low-power", 0),
5
33
  ("quiet", 0),
@@ -29,6 +57,7 @@ ALIB_PARAMS_5040: dict[str, AlibParams] = ALIB_PARAMS
29
57
  ALIB_PARAMS_7040: dict[str, AlibParams] = ALIB_PARAMS
30
58
  ALIB_PARAMS_6040: dict[str, AlibParams] = ALIB_PARAMS
31
59
  ALIB_PARAMS_8040: dict[str, AlibParams] = ALIB_PARAMS
60
+ ALIB_PARAMS_HX370: dict[str, AlibParams] = ALIB_PARAMS
32
61
 
33
62
  DEV_PARAMS_30W: dict[str, DeviceParams] = {
34
63
  "stapm_limit": D(0, 4, 15, 30, 40),
@@ -69,12 +98,14 @@ DEV_PARAMS_5000: dict[str, DeviceParams] = DEV_PARAMS_25W
69
98
  DEV_PARAMS_6000: dict[str, DeviceParams] = DEV_PARAMS_30W
70
99
  DEV_PARAMS_7040: dict[str, DeviceParams] = DEV_PARAMS_30W
71
100
  DEV_PARAMS_8040: dict[str, DeviceParams] = DEV_PARAMS_30W
101
+ DEV_PARAMS_HX370: dict[str, DeviceParams] = DEV_PARAMS_30W
72
102
  DEV_PARAMS_LEGO = DEV_PARAMS_30W
73
103
 
74
104
  DEV_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams], bool]] = {
75
105
  "NEO-01": (DEV_PARAMS_28W, ALIB_PARAMS_7040, False),
76
106
  "V3": (DEV_PARAMS_28W, ALIB_PARAMS_8040, False),
77
107
  "83E1": (DEV_PARAMS_LEGO, ALIB_PARAMS_7040, False),
108
+ "ONEXPLAYER F1Pro": (DEV_PARAMS_HX370, ALIB_PARAMS_HX370, False),
78
109
  }
79
110
 
80
111
  CPU_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams]]] = {
@@ -88,4 +119,5 @@ CPU_DATA: dict[str, tuple[dict[str, DeviceParams], dict[str, AlibParams]]] = {
88
119
  "AMD Ryzen 7 7840U": (DEV_PARAMS_7040, ALIB_PARAMS_7040),
89
120
  "AMD Ryzen 7 8840U": (DEV_PARAMS_8040, ALIB_PARAMS_8040),
90
121
  # AMD Athlon Silver 3050e (Win600, will it support tdp?)
122
+ "AMD Ryzen AI 9 HX 370": (DEV_PARAMS_HX370, ALIB_PARAMS_HX370),
91
123
  }
@@ -0,0 +1 @@
1
+ from .core import get_fan_info, fan_worker
@@ -34,7 +34,6 @@ UPDATE_FREQUENCY = 5
34
34
  UPDATE_T = 1 / UPDATE_FREQUENCY
35
35
  SETPOINT_UPDATE_FREQUENCY = 1
36
36
  SETPOINT_UPDATE_T = 1 / SETPOINT_UPDATE_FREQUENCY
37
- HYSTERESIS_RATIO = 0.25
38
37
 
39
38
 
40
39
  def _calculate_jerk(speed_span, decel_ratio, freq, time):
@@ -133,12 +132,12 @@ def update_setpoint(temp: float, curr: int, fan_curve: dict[int, float]):
133
132
  # Add some hysterisis to avoid dithering
134
133
  if idx > 0:
135
134
  prev = targets[idx - 1]
136
- if temp < prev + (curr - prev) * HYSTERESIS_RATIO:
135
+ if temp < prev:
137
136
  return prev
138
137
 
139
138
  if idx < len(targets) - 1:
140
139
  next = targets[idx + 1]
141
- if temp > next - (next - curr) * HYSTERESIS_RATIO:
140
+ if temp > next:
142
141
  return next
143
142
 
144
143
  return curr
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import time
3
3
  from typing import TypedDict
4
+ from threading import Lock, Event
4
5
 
5
6
  from .alg import (
6
7
  SETPOINT_UPDATE_T,
@@ -40,10 +41,12 @@ class FanState(TypedDict):
40
41
  v_curr: float
41
42
  v_target: float
42
43
  v_target_pwm: int
44
+ t_target: int
43
45
  v_rpm: list[int]
44
46
  t_junction: float
45
47
  t_edge: float
46
48
  fan_data: FanData
49
+ in_setpoint: bool
47
50
 
48
51
 
49
52
  def get_fan_info() -> FanInfo | None:
@@ -131,11 +134,37 @@ def update_fan_speed(
131
134
  "v_rpm": fan_speeds,
132
135
  "t_junction": t_junction,
133
136
  "t_edge": t_edge,
137
+ "t_target": data["t_target"],
134
138
  "fan_data": data,
139
+ "in_setpoint": in_setpoint,
135
140
  },
136
141
  )
137
142
 
138
143
 
144
+ def fan_worker(
145
+ info: FanInfo,
146
+ should_exit: Event,
147
+ lock: Lock,
148
+ fan_curve: dict[int, float],
149
+ state: FanState,
150
+ junction: Event,
151
+ ):
152
+ try:
153
+ set_fans_to_pwm(True, info)
154
+ while not should_exit.is_set():
155
+ with lock:
156
+ state_tmp = state or None # First time state will be empty
157
+ in_setpoint, state_tmp = update_fan_speed(
158
+ state_tmp, info, fan_curve, junction.is_set()
159
+ )
160
+ state.update(state_tmp)
161
+ time.sleep(SETPOINT_UPDATE_T if in_setpoint else UPDATE_T)
162
+ except Exception as e:
163
+ logger.error(f"Fan worker failed:\n{e}")
164
+ finally:
165
+ set_fans_to_pwm(False, info)
166
+
167
+
139
168
  def fan_pwm_tester(normal_curve: bool = True, observe_only: bool = False):
140
169
  fan_info = get_fan_info()
141
170
  if fan_info is None:
@@ -181,12 +210,22 @@ def fan_pwm_tester(normal_curve: bool = True, observe_only: bool = False):
181
210
 
182
211
  state = None
183
212
  for i in range(10000000):
184
- in_setpoint, state = update_fan_speed(state, fan_info, fan_curve, False, observe_only=observe_only)
185
-
186
- print(f"\n> {i:05d}: {'in setpoint' if in_setpoint else 'updating'}{' (observe)' if observe_only else ''}")
187
- print(f" Junction: {state['t_junction']:.2f}C, Edge: {state['t_edge']:.2f}C")
188
- print(f" Current: {state['v_curr']*100:.1f}%, Target: {state['v_target']*100:.1f}%")
189
- print(f" Fan speeds: {' '.join(map(lambda rpm: f"{rpm:4d}rpm/{MAX_FAN}rpm ({100*rpm/MAX_FAN:.1f}%)", state['v_rpm']))}")
213
+ in_setpoint, state = update_fan_speed(
214
+ state, fan_info, fan_curve, False, observe_only=observe_only
215
+ )
216
+
217
+ print(
218
+ f"\n> {i:05d}: {'in setpoint' if in_setpoint else 'updating'}{' (observe)' if observe_only else ''}"
219
+ )
220
+ print(
221
+ f" Junction: {state['t_junction']:.2f}C, Edge: {state['t_edge']:.2f}C"
222
+ )
223
+ print(
224
+ f" Current: {state['v_curr']*100:.1f}%, Target: {state['v_target']*100:.1f}%"
225
+ )
226
+ print(
227
+ f" Fan speeds: {' '.join(map(lambda rpm: f"{rpm:4d}rpm/{MAX_FAN}rpm ({100*rpm/MAX_FAN:.1f}%)", state['v_rpm']))}"
228
+ )
190
229
  time.sleep(SETPOINT_UPDATE_T if in_setpoint else UPDATE_T)
191
230
  except KeyboardInterrupt:
192
231
  print("Exiting fan test.")
@@ -225,7 +225,7 @@ class AsusDriverPlugin(HHDPlugin):
225
225
  lim != self.old_conf["charge_limit"].to(str)
226
226
  ):
227
227
  self.queue_charge_limit = curr + APPLY_DELAY
228
-
228
+
229
229
  if self.queue_charge_limit and self.queue_charge_limit < curr:
230
230
  self.queue_charge_limit = None
231
231
  match lim:
@@ -281,6 +281,9 @@ class AsusDriverPlugin(HHDPlugin):
281
281
  self.sys_tdp = False
282
282
  tdp_reset = True
283
283
 
284
+ if mode is not None and self.startup:
285
+ tdp_reset = True
286
+
284
287
  # Handle EPP for presets
285
288
  if tdp_reset and mode != "custom":
286
289
  match mode:
@@ -64,7 +64,7 @@ class GeneralPowerPlugin(HHDPlugin):
64
64
  logger.info("Unmasking TuneD in the case it was masked.")
65
65
  os.system('systemctl unmask tuned')
66
66
  subprocess.run(
67
- [tuned],
67
+ [tuned,'active'],
68
68
  check=True,
69
69
  stdin=subprocess.DEVNULL,
70
70
  stdout=subprocess.DEVNULL,
@@ -75,7 +75,7 @@ class GeneralPowerPlugin(HHDPlugin):
75
75
  logger.warning(f"tuned-adm returned with error:\n{e}")
76
76
 
77
77
 
78
- if not self.ppd_supported:
78
+ if not self.ppd_supported and not self.tuned_supported:
79
79
  del sets["children"]["profile"]
80
80
 
81
81
  # SchedExt
@@ -188,7 +188,7 @@ class GeneralPowerPlugin(HHDPlugin):
188
188
  conf["tdp.general.profile"] = self.target
189
189
  except Exception as e:
190
190
  self.tuned_supported = False
191
- logger.warning(f"powerprofilectl returned with error:\n{e}")
191
+ logger.warning(f"tuned-adm returned with error:\n{e}")
192
192
  self.tuned_supported = False
193
193
 
194
194
  # Handle sched
@@ -44,6 +44,7 @@ class LenovoDriverPlugin(HHDPlugin):
44
44
  self.old_conf = None
45
45
  self.sys_tdp = False
46
46
  self.fan_curve_set = False
47
+ self.notify_tdp = False
47
48
 
48
49
  bios_version = get_bios_version()
49
50
  logger.info(f"Lenovo BIOS version: {bios_version}")
@@ -326,6 +327,12 @@ class LenovoDriverPlugin(HHDPlugin):
326
327
  # Save current config
327
328
  self.old_conf = conf["tdp.lenovo"]
328
329
 
330
+ if self.notify_tdp:
331
+ self.notify_tdp = False
332
+ print(new_mode)
333
+ if conf.get("tdp.lenovo.tdp_rgb", False):
334
+ self.emit({"type": "special", "event": f"tdp_cycle_{new_mode}"}) # type: ignore
335
+
329
336
  if self.startup:
330
337
  self.startup = False
331
338
 
@@ -333,7 +340,7 @@ class LenovoDriverPlugin(HHDPlugin):
333
340
  for ev in events:
334
341
  if ev["type"] == "tdp":
335
342
  self.new_tdp = ev["tdp"]
336
- self.sys_tdp = ev['tdp'] is not None
343
+ self.sys_tdp = ev["tdp"] is not None
337
344
  if ev["type"] == "ppd":
338
345
  match ev["status"]:
339
346
  case "power":
@@ -342,6 +349,9 @@ class LenovoDriverPlugin(HHDPlugin):
342
349
  self.new_mode = "balanced"
343
350
  case "performance":
344
351
  self.new_mode = "performance"
352
+ print(ev)
353
+ if ev["type"] == "acpi" and ev.get("event", None) == "tdp":
354
+ self.notify_tdp = True
345
355
 
346
356
  def close(self):
347
357
  pass
@@ -143,6 +143,12 @@ children:
143
143
  hint: >-
144
144
  Reset to the original fan curve provided by Lenovo in BIOS V28.
145
145
 
146
+ tdp_rgb:
147
+ type: bool
148
+ title: Show TDP changes with RGB
149
+ tags: [non-essential]
150
+ default: False
151
+
146
152
  charge_limit:
147
153
  tags: [advanced]
148
154
  type: bool
@@ -1,11 +1,13 @@
1
1
  import logging
2
2
  import time
3
+ from threading import Event as TEvent, Lock, Thread
3
4
  from typing import Sequence
4
5
 
5
6
  from hhd.plugins import Context, Event, HHDPlugin, load_relative_yaml
6
7
  from hhd.plugins.conf import Config
7
8
 
8
9
  from adjustor.core.alib import AlibParams, DeviceParams, alib
10
+ from adjustor.core.fan import fan_worker, get_fan_info
9
11
  from adjustor.core.platform import get_platform_choices, set_platform_profile
10
12
  from adjustor.i18n import _
11
13
 
@@ -15,6 +17,27 @@ PP_DELAY = 0.2
15
17
  APPLY_DELAY = 1
16
18
  SLEEP_DELAY = 4
17
19
 
20
+ DEFAULT_EDGE = {
21
+ 40: 25,
22
+ 45: 25,
23
+ 50: 40,
24
+ 55: 45,
25
+ 60: 50,
26
+ 65: 55,
27
+ 70: 70,
28
+ 80: 85,
29
+ 90: 100,
30
+ }
31
+ DEFAULT_TCTL = {
32
+ 40: 40,
33
+ 50: 45,
34
+ 60: 50,
35
+ 70: 80,
36
+ 80: 90,
37
+ 90: 100,
38
+ 100: 100,
39
+ }
40
+
18
41
 
19
42
  class SmuQamPlugin(HHDPlugin):
20
43
 
@@ -44,6 +67,14 @@ class SmuQamPlugin(HHDPlugin):
44
67
  self.is_set = False
45
68
  self.lims = self.dev.get("skin_limit", self.dev.get("stapm_limit", None))
46
69
 
70
+ self.fan_info = None
71
+ self.fan_t = None
72
+ self.fan_should_exit = TEvent()
73
+ self.fan_junction = TEvent()
74
+ self.fan_lock = Lock()
75
+ self.fan_curve = {}
76
+ self.fan_state = {}
77
+
47
78
  # Workaround for debugging on the legion go
48
79
  # Avoids sending SMU commands that will conflict with Lenovo TDP on
49
80
  # startup
@@ -87,6 +118,33 @@ class SmuQamPlugin(HHDPlugin):
87
118
  {"min": dmin, "max": dmax, "default": default}
88
119
  )
89
120
 
121
+ if not self.fan_info:
122
+ del out["tdp"]["qam"]["children"]["fan"]
123
+ else:
124
+ base = out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_edge"][
125
+ "children"
126
+ ]["st40"]
127
+ reset = out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_edge"][
128
+ "children"
129
+ ].pop("reset")
130
+ for k, v in DEFAULT_EDGE.items():
131
+ out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_edge"][
132
+ "children"
133
+ ][f"st{k}"] = {**base, "title": f"{k}C", "default": v}
134
+ out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_edge"]["children"][
135
+ "reset"
136
+ ] = reset
137
+ reset = out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_junction"][
138
+ "children"
139
+ ].pop("reset")
140
+ for k, v in DEFAULT_TCTL.items():
141
+ out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_junction"][
142
+ "children"
143
+ ][f"st{k}"] = {**base, "title": f"{k}C", "default": v}
144
+ out["tdp"]["qam"]["children"]["fan"]["modes"]["manual_junction"][
145
+ "children"
146
+ ]["reset"] = reset
147
+
90
148
  return out
91
149
 
92
150
  def open(
@@ -95,6 +153,7 @@ class SmuQamPlugin(HHDPlugin):
95
153
  context: Context,
96
154
  ):
97
155
  self.emit = emit
156
+ self.fan_info = get_fan_info()
98
157
 
99
158
  def update(self, conf: Config):
100
159
  self.enabled = conf["hhd.settings.tdp_enable"].to(bool)
@@ -191,12 +250,65 @@ class SmuQamPlugin(HHDPlugin):
191
250
  self.old_tdp = new_tdp
192
251
  self.old_boost = new_boost
193
252
 
253
+ if self.fan_info:
254
+ mode = conf["tdp.qam.fan.mode"].to(str)
255
+ if mode != "disabled":
256
+ with self.fan_lock:
257
+ if conf[f"tdp.qam.fan.{mode}.reset"].to(bool):
258
+ conf[f"tdp.qam.fan.{mode}.reset"] = False
259
+ curve = DEFAULT_EDGE if "edge" in mode else DEFAULT_TCTL
260
+ for k, v in curve.items():
261
+ if f"tdp.qam.fan.{mode}.st{k}" in conf:
262
+ conf[f"tdp.qam.fan.{mode}.st{k}"] = v
263
+
264
+ for k, v in conf[f"tdp.qam.fan.{mode}"].to(dict).items():
265
+ if not k.startswith("st"):
266
+ continue
267
+ self.fan_curve[int(k[2:])] = v / 100
268
+ if self.fan_state:
269
+ s = self.fan_state
270
+ fan_speed = (
271
+ f"{s['v_curr']*100:.1f}% @ {s['t_target']}C"
272
+ if s["in_setpoint"]
273
+ else f"{s['v_curr']*100:.1f}% → {s['v_target']*100:.1f}%"
274
+ )
275
+ conf[f"tdp.qam.fan.{mode}.info"] = (
276
+ f"{fan_speed} ({', '.join(map(str, s['v_rpm']))} RPM)\n"
277
+ + f"Tctl: {s['t_junction']:.2f}C, "
278
+ + f"Edge: {s['t_edge']:.2f}C\n"
279
+ )
280
+ if "junction" in mode:
281
+ self.fan_junction.set()
282
+ else:
283
+ self.fan_junction.clear()
284
+
285
+ if not self.fan_t:
286
+ self.fan_should_exit.clear()
287
+ self.fan_t = Thread(
288
+ target=fan_worker,
289
+ args=(
290
+ self.fan_info,
291
+ self.fan_should_exit,
292
+ self.fan_lock,
293
+ self.fan_curve,
294
+ self.fan_state,
295
+ self.fan_junction,
296
+ ),
297
+ )
298
+ self.fan_t.start()
299
+ else:
300
+ if self.fan_t:
301
+ self.fan_should_exit.set()
302
+ self.fan_t.join()
303
+ self.fan_t = None
304
+ self.fan_state = {}
305
+
194
306
  def notify(self, events: Sequence[Event]):
195
307
  for ev in events:
196
308
  if ev["type"] == "tdp":
197
309
  self.sys_tdp = True
198
310
  self.new_tdp = ev["tdp"]
199
- self.sys_tdp = ev['tdp'] is not None
311
+ self.sys_tdp = ev["tdp"] is not None
200
312
 
201
313
  if ev["type"] == "ppd":
202
314
  # TODO: Make tunable per device
@@ -207,13 +319,19 @@ class SmuQamPlugin(HHDPlugin):
207
319
  self.new_tdp = 15
208
320
  case "performance":
209
321
  self.new_tdp = 25
210
-
211
- if ev['type'] == 'special' and ev.get('event', None) == "wakeup":
212
- logger.info(f"Waking up from sleep, resetting TDP after {SLEEP_DELAY} seconds.")
322
+
323
+ if ev["type"] == "special" and ev.get("event", None) == "wakeup":
324
+ logger.info(
325
+ f"Waking up from sleep, resetting TDP after {SLEEP_DELAY} seconds."
326
+ )
213
327
  self.queued = time.time() + SLEEP_DELAY
214
328
 
215
329
  def close(self):
216
- pass
330
+ if self.fan_t:
331
+ self.fan_should_exit.set()
332
+ self.fan_t.join()
333
+ self.fan_t = None
334
+ self.fan_state = {}
217
335
 
218
336
 
219
337
  class SmuDriverPlugin(HHDPlugin):
@@ -0,0 +1,80 @@
1
+ title: TDP Settings
2
+ type: container
3
+ tags: [ hide-title ]
4
+ children:
5
+ tdp:
6
+ title: TDP
7
+ hint: >-
8
+ Controls all Ryzen SMU settings through preset curves.
9
+ type: int
10
+ step: 1
11
+ unit: W
12
+
13
+ boost:
14
+ title: TDP Boost
15
+ type: bool
16
+ default: True
17
+
18
+ sys_tdp:
19
+ type: display
20
+ title: " "
21
+ tags: []
22
+
23
+ fan:
24
+ type: mode
25
+ title: Custom Fan Curve
26
+ hint: >-
27
+ Allows you to set a custom fan curve and to choose the temperature
28
+ probe (Edge or Junction). Junction is the peak temperature of the
29
+ chip: responds faster and prevents throttling. Edge is the temperature
30
+ of the chip: responds slower and prevents overheating.
31
+
32
+ default: disabled
33
+ modes:
34
+ disabled:
35
+ type: container
36
+ title: Disabled
37
+
38
+ manual_edge:
39
+ type: container
40
+ title: Manual (Edge, Smooth)
41
+ tags: [ non-essential ]
42
+ children:
43
+
44
+ info:
45
+ title: ""
46
+ type: display
47
+
48
+ st40: &speed_template
49
+ hint: Sets the speed at the named temperature.
50
+ tags: [slim]
51
+ type: int
52
+ min: 0
53
+ max: 100
54
+ step: 2
55
+ unit: "%"
56
+ title: 40C
57
+ default: 25
58
+
59
+ reset:
60
+ type: action
61
+ title: Reset to Default
62
+
63
+ manual_junction:
64
+ type: container
65
+ title: Manual (Tctl, Fast)
66
+ tags: [ non-essential ]
67
+ children:
68
+
69
+ info:
70
+ title: ""
71
+ type: display
72
+
73
+ st40:
74
+ <<: *speed_template
75
+ title: 40C
76
+ default: 40
77
+
78
+ reset:
79
+ type: action
80
+ title: Reset to Default
@@ -15,6 +15,7 @@ EVENT_MATCHES: Sequence[tuple[dict[str, Any], str]] = [
15
15
  ({"device_class": b"button/power"}, "powerbutton"),
16
16
  # Legion GO TDP event
17
17
  ({"bus_id": b"D320289E-8FEA-"}, "tdp"),
18
+ ({"device_class": b"wmi", "bus_id": b"PNP0C14:01"}, "tdp"), # Legion go
18
19
  # GPD Force hibernate thermal event
19
20
  # , 'type': 0xf100, 'data': 0x0100 ignore these attrs for now...
20
21
  ({"device_class": b"thermal_zone", "bus_id": b"LNXTHERM:00"}, "hibernate-thermal"),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: adjustor
3
- Version: 3.5.3
3
+ Version: 3.6.0
4
4
  Summary: Adjustor, a userspace program for managing the TDP of handheld devices.
5
5
  Author-email: Kapenekakis Antheas <pypi@antheas.dev>
6
6
  Project-URL: Homepage, https://github.com/hhd-dev/adjustor
File without changes
@@ -1,21 +0,0 @@
1
- title: TDP Settings
2
- type: container
3
- tags: [ hide-title ]
4
- children:
5
- tdp:
6
- title: TDP
7
- hint: >-
8
- Controls all Ryzen SMU settings through preset curves.
9
- type: int
10
- step: 1
11
- unit: W
12
-
13
- boost:
14
- title: TDP Boost
15
- type: bool
16
- default: True
17
-
18
- sys_tdp:
19
- type: display
20
- title: " "
21
- tags: []
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes