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)

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.96.1 -->
<!-- Created with Cambalache 0.96.3 -->
<interface>
<!-- interface-name thermals.ui -->
<!-- interface-description The Thermals page for YAFI -->
@@ -92,6 +92,12 @@
<property name="visible">False</property>
</object>
</child>
<child>
<object class="AdwExpanderRow" id="fan_set_points">
<property name="selectable">False</property>
<property name="title">Fan Set Points</property>
</object>
</child>
<style>
<class name="boxed-list"/>
</style>

View File

@@ -1,9 +1,9 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
<!-- Created with Cambalache 0.96.1 -->
<!-- Created with Cambalache 0.96.3 -->
<cambalache-project version="0.96.0" target_tk="gtk-4.0">
<ui template-class="YafiWindow" filename="yafi.ui" sha256="9d1b2f030e4a816eb0b1aa53ae1d80c5b50a2f4646e32c7a64803eb6f6ed3947"/>
<ui template-class="ThermalsPage" filename="thermals.ui" sha256="e301e65649005315ff60d250b60a47f6250ad6feb27db104051fcf0143cde173"/>
<ui template-class="ThermalsPage" filename="thermals.ui" sha256="89f5b68da04abad587d8b949d18357cd956313680e663b10e5d42697f9bfbf6e"/>
<ui template-class="LedsPage" filename="leds.ui" sha256="abc3ee759974a5c92feb48cc258dbe7271d0402facf71fd5e779f2bb1a277e16"/>
<ui template-class="BatteryLimiterPage" filename="battery-limiter.ui" sha256="b5d41b19cb1fb7ca5b4bcfae43244e54111f5e8d8c51d95448d6a92b5185d2c4"/>
<ui template-class="HardwarePage" filename="hardware.ui" sha256="37ea282198d9f60435f80e4adf8256cd2249e590dcad4b63af634d828673f1bf"/>

Binary file not shown.