Coverage for linuxpy/thermal.py: 0%
69 statements
« prev ^ index » next coverage.py v7.6.8, created at 2025-05-27 13:54 +0200
« prev ^ index » next coverage.py v7.6.8, created at 2025-05-27 13:54 +0200
1#
2# This file is part of the linuxpy project
3#
4# Copyright (c) 2023 Tiago Coutinho
5# Distributed under the GPLv3 license. See LICENSE for more info.
7"""
8Human friendly interface to linux thermal subsystem.
10The heart of linuxpy thermal library are the [`ThermalZone`][linuxpy.thermal.ThermalZone]
11and [`CoolingDevice`][linuxpy.thermal.CoolingDevice] classes.
13Probably the most common way to create a thermal device is through
14the [`find`][linuxpy.thermal.find] helper:
16```python
17with find(type="x86_pkg_temp") as tz:
18 print(f"X86 temperature: {tz.temperature/1000:6.2f} C")
19```
20"""
22import pathlib
23import time
25from linuxpy.device import device_number
26from linuxpy.sysfs import THERMAL_PATH, Attr, Device, Int, Mode, Str
27from linuxpy.types import Callable, Iterable, Optional, Union
28from linuxpy.util import make_find
31class ThermalZone(Device):
32 """
33 Thermal sensor
35 Attributes:
36 type (str): thermal zone type
37 policy (str): the policy
38 available_policies list[str]: list of available policies
39 temperature (int): current temperature in milli-celsius
40 offset (int): offet in milli-celsius
41 mode (Mode): current mode (enabled/disabled)
42 device_number (int): thermal device number
43 trip_points (list[TripPoint]): list of trip points (new list every time)
44 """
46 type = Str("type")
47 policy = Str("policy")
48 available_policies = Attr("available_policies", str.split)
49 temperature = Int("temp")
50 offset = Int("offset")
51 mode = Attr("mode", Mode)
53 @classmethod
54 def from_id(cls, n):
55 return cls.from_syspath(THERMAL_PATH / f"thermal_zone{n}")
57 @property
58 def trip_points(self):
59 result = []
60 for temp_path in self.syspath.glob("trip_point_*_temp"):
61 type_path = temp_path.with_name(temp_path.name.replace("_temp", "_type"))
62 result.append(TripPoint(temp_path, type_path))
63 return result
65 @property
66 def device_number(self) -> Optional[int]:
67 return device_number(self.syspath)
70class TripPoint:
71 """
72 Trip point associated with the thermal zone
74 Attributes:
75 temperature (int): trip point temperature in milli-celsius
76 type (str): trip point type
77 """
79 def __init__(self, temperature_path, type_path):
80 self.temperature_path = temperature_path
81 self.type_path = type_path
83 @property
84 def temperature(self) -> int:
85 with self.temperature_path.open() as f:
86 return int(f.read())
88 @property
89 def type(self) -> str:
90 with self.type_path.open() as f:
91 return f.read().strip()
94class CoolingDevice(Device):
95 """
96 Cooling device (fan, processor, ...)
98 Attributes:
99 type (str): thermal zone type
100 """
102 type = Str("type")
103 state = Int("cur_state")
104 max_state = Int("max_state")
106 @property
107 def device_number(self) -> Optional[int]:
108 return device_number(self.syspath)
111def iter_thermal_zone_paths() -> Iterable[pathlib.Path]:
112 """Returns an iterator over all thermal zone paths"""
113 yield from THERMAL_PATH.glob("thermal_zone*")
116def iter_thermal_zone_devices() -> Iterable[ThermalZone]:
117 """Returns an iterator over all thermal zone devices"""
118 return (ThermalZone.from_syspath(path) for path in iter_thermal_zone_paths())
121def iter_cooling_device_paths() -> Iterable[pathlib.Path]:
122 """Returns an iterator over all cooling device paths"""
123 yield from THERMAL_PATH.glob("cooling_device*")
126def iter_cooling_devices() -> Iterable[CoolingDevice]:
127 """Returns an iterator over all cooling devices"""
128 return (CoolingDevice.from_syspath(path) for path in iter_cooling_device_paths())
131def iter_devices() -> Iterable[Union[ThermalZone, CoolingDevice]]:
132 """Returns an iterator over all thermal and cooling devices"""
133 yield from iter_thermal_zone_devices()
134 yield from iter_cooling_devices()
137_find = make_find(iter_devices)
140def find(
141 find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs
142) -> Union[Device, Iterable[Device], None]:
143 """
144 If find_all is False:
146 Find a device follwing the criteria matched by custom_match and kwargs.
147 If no device is found matching the criteria it returns None.
148 Default is to return a random first device.
150 If find_all is True:
152 The result is an iterator.
153 Find all devices that match the criteria custom_match and kwargs.
154 If no device is found matching the criteria it returns an empty iterator.
155 Default is to return an iterator over all input devices found on the system.
156 """
157 return _find(find_all, custom_match, **kwargs)
160def main():
161 def acq():
162 for dev in sorted(iter_thermal_zone_devices(), key=lambda dev: dev.type):
163 yield dev, dev.temperature
165 while True:
166 read = acq()
167 print(" | ".join(f"{dev.type} = {temp / 1000:6.2f}" for dev, temp in read), end="\r")
168 time.sleep(0.1)
171if __name__ == "__main__":
172 main()