Implement fan set points

This commit is contained in:
Stephen Horvath
2025-12-25 19:35:33 +10:00
parent 1fc4b94237
commit 2b50f0816f
6 changed files with 113 additions and 30 deletions

View File

@@ -27,11 +27,17 @@ import cros_ec_python.exceptions as ec_exceptions
class ThermalsPage(Gtk.Box):
__gtype_name__ = 'ThermalsPage'
first_run = True
fan_rpm = Gtk.Template.Child()
fan_mode = Gtk.Template.Child()
fan_set_rpm = Gtk.Template.Child()
fan_set_percent = Gtk.Template.Child()
fan_percent_scale = Gtk.Template.Child()
fan_set_points = Gtk.Template.Child()
set_points = []
ec_set_points_supported = False
ec_set_points = []
temperatures = Gtk.Template.Child()
temp_items = []
@@ -40,10 +46,40 @@ class ThermalsPage(Gtk.Box):
super().__init__(**kwargs)
def setup(self, app):
# Temperature sensors
while temp_child := self.temperatures.get_last_child():
self.temperatures.remove(temp_child)
self.temp_items.clear()
try:
ec_temp_sensors = ec_commands.thermal.get_temp_sensors(app.cros_ec)
except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
# Generate some labels if the command is not supported
ec_temp_sensors = {}
temps = ec_commands.memmap.get_temps(app.cros_ec)
for i, temp in enumerate(temps):
ec_temp_sensors[f"Sensor {i}"] = (temp, None)
else:
raise e
for key, value in ec_temp_sensors.items():
off_row = Adw.ActionRow(title=key, subtitle=f"{value[0]}°C")
off_row.add_css_class("property")
self.temperatures.append(off_row)
self.temp_items.append(off_row)
self._update_thermals(app)
# Don't let the user change the fans if they can't get back to auto
if ec_commands.general.get_cmd_versions(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_AUTO_FAN_CTRL
):
self.ec_set_points_supported = ec_commands.general.check_cmd_version(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_GET_THRESHOLD, 1
) and ec_commands.general.check_cmd_version(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_SET_THRESHOLD, 1
)
def handle_fan_mode(mode):
match mode:
@@ -51,13 +87,18 @@ class ThermalsPage(Gtk.Box):
self.fan_set_rpm.set_visible(False)
self.fan_set_percent.set_visible(False)
ec_commands.thermal.thermal_auto_fan_ctrl(app.cros_ec)
self.fan_set_points.set_visible(self.ec_set_points_supported)
case 1: # Percent
self.fan_set_points.set_visible(False)
self.fan_set_rpm.set_visible(False)
self.fan_set_percent.set_visible(True)
case 2: # RPM
self.fan_set_points.set_visible(False)
self.fan_set_rpm.set_visible(True)
self.fan_set_percent.set_visible(False)
handle_fan_mode(self.fan_mode.get_selected())
self.fan_mode.connect(
"notify::selected",
lambda combo, _: handle_fan_mode(combo.get_selected()),
@@ -81,41 +122,77 @@ class ThermalsPage(Gtk.Box):
):
def handle_fan_rpm(entry):
rpm = int(entry.get_text())
rpm = int(entry.get_value())
ec_commands.pwm.pwm_set_fan_rpm(app.cros_ec, rpm)
self.fan_set_rpm.connect(
"notify::text", lambda entry, _: handle_fan_rpm(entry)
"notify::value", lambda entry, _: handle_fan_rpm(entry)
)
else:
self.fan_set_rpm.set_sensitive(False)
else:
self.fan_mode.set_sensitive(False)
# Temperature sensors
while temp_child := self.temperatures.get_last_child():
self.temperatures.remove(temp_child)
self.temp_items.clear()
# Set points
if self.ec_set_points_supported and self.first_run:
def handle_set_point(entry, key):
index = entry.ec_index
temp = int(entry.get_value())
# Don't allow an off temp higher than max temp and vice versa
match key:
case "temp_fan_off":
if temp > self.ec_set_points[index]["temp_fan_max"]:
entry.set_value(self.ec_set_points[index]["temp_fan_off"])
return
case "temp_fan_max":
if temp < self.ec_set_points[index]["temp_fan_off"]:
entry.set_value(self.ec_set_points[index]["temp_fan_max"])
return
self.ec_set_points[entry.ec_index][key] = temp
ec_commands.thermal.thermal_set_thresholds(
app.cros_ec, index,
self.ec_set_points[index]
)
try:
ec_temp_sensors = ec_commands.thermal.get_temp_sensors(app.cros_ec)
except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
# Generate some labels if the command is not supported
ec_temp_sensors = {}
temps = ec_commands.memmap.get_temps(app.cros_ec)
for i, temp in enumerate(temps):
ec_temp_sensors[f"Sensor {i}"] = (temp, None)
else:
raise e
for i, sensor in enumerate(ec_temp_sensors):
ec_set_point = ec_commands.thermal.thermal_get_thresholds(app.cros_ec, i)
self.ec_set_points.append(ec_set_point)
off_row = Adw.SpinRow(
title=f"Fan On - {sensor}",
subtitle=f"Turn fan on when above temp (°C)",
)
off_row.ec_index = i
# 0K to 65535K for 16bit unsigned range
# Actually the EC takes 32bits, but let's keep it like this for sanity
off_row.set_adjustment(Gtk.Adjustment(
lower=-273,
upper=65_262,
page_increment=10,
step_increment=1,
value=ec_set_point["temp_fan_off"],
))
off_row.connect(
"notify::value", lambda entry, _: handle_set_point(entry, "temp_fan_off")
)
max_row = Adw.SpinRow(
title=f"Fan Max - {sensor}",
subtitle=f"Max fan speed when above temp (°C)",
)
max_row.ec_index = i
max_row.set_adjustment(Gtk.Adjustment(
lower=-273,
upper=65_262,
page_increment=10,
step_increment=1,
value=ec_set_point["temp_fan_max"],
))
max_row.connect(
"notify::value", lambda entry, _: handle_set_point(entry, "temp_fan_max")
)
self.fan_set_points.add_row(off_row)
self.fan_set_points.add_row(max_row)
for key, value in ec_temp_sensors.items():
new_row = Adw.ActionRow(title=key, subtitle=f"{value[0]}°C")
new_row.add_css_class("property")
self.temperatures.append(new_row)
self.temp_items.append(new_row)
self._update_thermals(app)
self.first_run = False
# Schedule _update_thermals to run every second
GLib.timeout_add_seconds(1, self._update_thermals, app)