Skip to content

Commit 446d23c

Browse files
author
Mariya
authored
feat(applications): add support for power-profiles-daemon/tuned as a power management daemon (#4015)
* fix(profiles): install power-profiles-daemon by default in the desktop profile * fix: only install power-profiles-daemon if a battery is detected * chore: clean up has_battery method * fix: make power management daemon a configurable application * fix: make linter happy after merge * fix: fix merge issues * fix: give has_battery a return type to make linter happy * chore: add locale msgids for power management related strings * fix: changes requested in review * fix: cache has_battery result * fix: changes requested in review * fix: just return none directly * fix: add selected power management daemon to applications menu preview
1 parent 83c9bf0 commit 446d23c

File tree

7 files changed

+145
-1
lines changed

7 files changed

+145
-1
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from typing import TYPE_CHECKING
2+
3+
from archinstall.lib.models.application import PowerManagement, PowerManagementConfiguration
4+
from archinstall.lib.output import debug
5+
6+
if TYPE_CHECKING:
7+
from archinstall.lib.installer import Installer
8+
9+
10+
class PowerManagementApp:
11+
@property
12+
def ppd_packages(self) -> list[str]:
13+
return [
14+
'power-profiles-daemon',
15+
]
16+
17+
@property
18+
def tuned_packages(self) -> list[str]:
19+
return [
20+
'tuned',
21+
'tuned-ppd',
22+
]
23+
24+
def install(
25+
self,
26+
install_session: 'Installer',
27+
power_management_config: PowerManagementConfiguration,
28+
) -> None:
29+
debug(f'Installing power management daemon: {power_management_config.power_management.value}')
30+
31+
match power_management_config.power_management:
32+
case PowerManagement.POWER_PROFILES_DAEMON:
33+
install_session.add_additional_packages(self.ppd_packages)
34+
case PowerManagement.TUNED:
35+
install_session.add_additional_packages(self.tuned_packages)

archinstall/lib/applications/application_handler.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from archinstall.applications.audio import AudioApp
44
from archinstall.applications.bluetooth import BluetoothApp
5+
from archinstall.applications.power_management import PowerManagementApp
56
from archinstall.applications.print_service import PrintServiceApp
67
from archinstall.lib.models import Audio
78
from archinstall.lib.models.application import ApplicationConfiguration
@@ -26,6 +27,12 @@ def install_applications(self, install_session: 'Installer', app_config: Applica
2627
users,
2728
)
2829

30+
if app_config.power_management_config:
31+
PowerManagementApp().install(
32+
install_session,
33+
app_config.power_management_config,
34+
)
35+
2936
if app_config.print_service_config and app_config.print_service_config.enabled:
3037
PrintServiceApp().install(install_session)
3138

archinstall/lib/applications/application_menu.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
from typing import override
22

3+
from archinstall.lib.hardware import SysInfo
34
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
4-
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration
5+
from archinstall.lib.models.application import (
6+
ApplicationConfiguration,
7+
Audio,
8+
AudioConfiguration,
9+
BluetoothConfiguration,
10+
PowerManagement,
11+
PowerManagementConfiguration,
12+
PrintServiceConfiguration,
13+
)
514
from archinstall.lib.translationhandler import tr
615
from archinstall.tui.curses_menu import SelectMenu
716
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
@@ -54,8 +63,21 @@ def _define_menu_options(self) -> list[MenuItem]:
5463
preview_action=self._prev_print_service,
5564
key='print_service_config',
5665
),
66+
MenuItem(
67+
text=tr('Power management'),
68+
action=select_power_management,
69+
preview_action=self._prev_power_management,
70+
enabled=SysInfo.has_battery(),
71+
key='power_management_config',
72+
),
5773
]
5874

75+
def _prev_power_management(self, item: MenuItem) -> str | None:
76+
if item.value is not None:
77+
config: PowerManagementConfiguration = item.value
78+
return f'{tr("Power management")}: {config.power_management.value}'
79+
return None
80+
5981
def _prev_bluetooth(self, item: MenuItem) -> str | None:
6082
if item.value is not None:
6183
bluetooth_config: BluetoothConfiguration = item.value
@@ -81,6 +103,29 @@ def _prev_print_service(self, item: MenuItem) -> str | None:
81103
return None
82104

83105

106+
def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None:
107+
group = MenuItemGroup.from_enum(PowerManagement)
108+
109+
if preset:
110+
group.set_focus_by_value(preset.power_management)
111+
112+
result = SelectMenu[PowerManagement](
113+
group,
114+
allow_skip=True,
115+
alignment=Alignment.CENTER,
116+
allow_reset=True,
117+
frame=FrameProperties.min(tr('Power management')),
118+
).run()
119+
120+
match result.type_:
121+
case ResultType.Skip:
122+
return preset
123+
case ResultType.Selection:
124+
return PowerManagementConfiguration(power_management=result.get_value())
125+
case ResultType.Reset:
126+
return None
127+
128+
84129
def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
85130
group = MenuItemGroup.yes_no()
86131
group.focus_item = MenuItem.no()

archinstall/lib/global_menu.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,11 @@ def _prev_applications(self, item: MenuItem) -> str | None:
336336
output += tr('Enabled') if app_config.print_service_config.enabled else tr('Disabled')
337337
output += '\n'
338338

339+
if app_config.power_management_config:
340+
power_management_config = app_config.power_management_config
341+
output += f'{tr("Power management")}: {power_management_config.power_management.value}'
342+
output += '\n'
343+
339344
return output
340345

341346
return None

archinstall/lib/hardware.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ class _SysInfo:
143143
def __init__(self) -> None:
144144
pass
145145

146+
@cached_property
147+
def has_battery(self) -> bool:
148+
for type_path in Path('/sys/class/power_supply/').glob('*/type'):
149+
try:
150+
with open(type_path) as f:
151+
if f.read().strip() == 'Battery':
152+
return True
153+
except OSError:
154+
continue
155+
156+
return False
157+
146158
@cached_property
147159
def cpu_info(self) -> dict[str, str]:
148160
"""
@@ -210,6 +222,10 @@ def graphics_devices(self) -> dict[str, str]:
210222

211223

212224
class SysInfo:
225+
@staticmethod
226+
def has_battery() -> bool:
227+
return _sys_info.has_battery
228+
213229
@staticmethod
214230
def has_wifi() -> bool:
215231
ifaces = list(list_interfaces().values())

archinstall/lib/models/application.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
from typing import Any, NotRequired, TypedDict
44

55

6+
class PowerManagement(StrEnum):
7+
POWER_PROFILES_DAEMON = 'power-profiles-daemon'
8+
TUNED = 'tuned'
9+
10+
11+
class PowerManagementConfigSerialization(TypedDict):
12+
power_management: str
13+
14+
615
class BluetoothConfigSerialization(TypedDict):
716
enabled: bool
817

@@ -32,6 +41,7 @@ class ZramAlgorithm(StrEnum):
3241
class ApplicationSerialization(TypedDict):
3342
bluetooth_config: NotRequired[BluetoothConfigSerialization]
3443
audio_config: NotRequired[AudioConfigSerialization]
44+
power_management_config: NotRequired[PowerManagementConfigSerialization]
3545
print_service_config: NotRequired[PrintServiceConfigSerialization]
3646

3747

@@ -63,6 +73,22 @@ def parse_arg(arg: dict[str, Any]) -> 'BluetoothConfiguration':
6373
return BluetoothConfiguration(arg['enabled'])
6474

6575

76+
@dataclass
77+
class PowerManagementConfiguration:
78+
power_management: PowerManagement
79+
80+
def json(self) -> PowerManagementConfigSerialization:
81+
return {
82+
'power_management': self.power_management.value,
83+
}
84+
85+
@staticmethod
86+
def parse_arg(arg: dict[str, Any]) -> 'PowerManagementConfiguration':
87+
return PowerManagementConfiguration(
88+
PowerManagement(arg['power_management']),
89+
)
90+
91+
6692
@dataclass
6793
class PrintServiceConfiguration:
6894
enabled: bool
@@ -94,6 +120,7 @@ def parse_arg(arg: bool | dict[str, Any]) -> 'ZramConfiguration':
94120
class ApplicationConfiguration:
95121
bluetooth_config: BluetoothConfiguration | None = None
96122
audio_config: AudioConfiguration | None = None
123+
power_management_config: PowerManagementConfiguration | None = None
97124
print_service_config: PrintServiceConfiguration | None = None
98125

99126
@staticmethod
@@ -113,6 +140,9 @@ def parse_arg(
113140
if args and (audio_config := args.get('audio_config')) is not None:
114141
app_config.audio_config = AudioConfiguration.parse_arg(audio_config)
115142

143+
if args and (power_management_config := args.get('power_management_config')) is not None:
144+
app_config.power_management_config = PowerManagementConfiguration.parse_arg(power_management_config)
145+
116146
if args and (print_service_config := args.get('print_service_config')) is not None:
117147
app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config)
118148

@@ -127,6 +157,9 @@ def json(self) -> ApplicationSerialization:
127157
if self.audio_config:
128158
config['audio_config'] = self.audio_config.json()
129159

160+
if self.power_management_config:
161+
config['power_management_config'] = self.power_management_config.json()
162+
130163
if self.print_service_config:
131164
config['print_service_config'] = self.print_service_config.json()
132165

archinstall/locales/base.pot

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,9 @@ msgstr ""
17881788
msgid "Would you like to configure the print service?"
17891789
msgstr ""
17901790

1791+
msgid "Power management"
1792+
msgstr ""
1793+
17911794
msgid "Authentication"
17921795
msgstr ""
17931796

0 commit comments

Comments
 (0)