Skip to content

Commit

Permalink
Winpower
Browse files Browse the repository at this point in the history
  • Loading branch information
Axorax committed Oct 18, 2024
0 parents commit be9150f
Show file tree
Hide file tree
Showing 15 changed files with 1,894 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
env/
__pycache__/
*-report.html
*.spec
*.txt
dist/
build/
Output/
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<p align="center">
<img src="./icon.svg" width="100" height="100"/>
</p>

<h3 align="center">Winpower</h3>

<p align="center">Improved power settings for Windows</p>

## 💻 Preview

<p align="center">
<img src="./preview.png"/>
</p>

## ✨ Features

- Add custom sleep and screen shutdown times.
- Write custom scripts.
- Execute scripts, shutdown, restart and lock commands after specified time.
- Generate reports.
- Manage changed settings to cancel or apply them.

---

<p align="center"><a href="https://www.patreon.com/axorax">Support me on Patreon</a> — <a href="https://github.com/axorax/socials">Check out my socials</a></p>
13 changes: 13 additions & 0 deletions build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@echo off

pyinstaller ^
--name="Winpower" ^
--onefile ^
--strip ^
--clean ^
--paths=env/Lib/site-packages ^
--add-data="env/Lib/site-packages/sv_ttk;sv_ttk" ^
--add-data="icon.ico;." ^
--noconsole ^
--icon=icon.png ^
main.py
15 changes: 15 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import subprocess

subprocess.run([
"pyinstaller",
"--name=Winpower",
"--onefile",
"--strip",
"--clean",
"--paths=env/Lib/site-packages",
"--add-data=env/Lib/site-packages/sv_ttk:sv_ttk",
"--add-data=icon.ico:.",
"--noconsole",
"--icon=icon.png",
"main.py"
])
13 changes: 13 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

pyinstaller \
--name="Winpower" \
--onefile \
--strip \
--clean \
--paths=env/Lib/site-packages \
--add-data="env/Lib/site-packages/sv_ttk:sv_ttk" \
--add-data="icon.ico:." \
--noconsole \
--icon=icon.png \
main.py
233 changes: 233 additions & 0 deletions core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import os
import re
import ctypes
import subprocess

power_schemes = {
"Best power efficiency": "a1841308-3541-4fab-bc81-f71556f20b4a",
"Balanced": "381b4222-f694-41f0-9685-ff5bb260df2e",
"Best performance": "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c",
}

CREATE_NO_WINDOW = 0x08000000


def get_power_mode():
try:
output = subprocess.check_output(
["powercfg", "/getactivescheme"],
encoding="utf-8",
creationflags=CREATE_NO_WINDOW,
)
for mode, guid in power_schemes.items():
if guid in output:
return mode
return "Unknown"
except subprocess.CalledProcessError:
return "Unknown"


def set_power_mode(mode):
if mode in power_schemes:
try:
subprocess.check_call(
["powercfg", "/setactive", power_schemes[mode]],
creationflags=CREATE_NO_WINDOW,
)
return f"Power mode set to {mode}"
except subprocess.CalledProcessError:
return "Failed to set power mode"
return "Invalid mode"


def get_powercfg_value(subgroup_guid, setting_guid):
command = ["powercfg", "/query", "SCHEME_CURRENT", subgroup_guid, setting_guid]
result = subprocess.run(
command, capture_output=True, text=True, creationflags=CREATE_NO_WINDOW
)
output = result.stdout
match_ac = re.search(r"Current AC Power Setting Index:\s+0x([0-9a-fA-F]+)", output)
match_dc = re.search(r"Current DC Power Setting Index:\s+0x([0-9a-fA-F]+)", output)
ac_value = int(match_ac.group(1), 16) if match_ac else None
dc_value = int(match_dc.group(1), 16) if match_dc else None
return ac_value, dc_value


def set_powercfg_value(subgroup_guid, setting_guid, seconds, power_source):
command = []
if power_source == "AC":
command = [
"powercfg",
"/setacvalueindex",
"SCHEME_CURRENT",
subgroup_guid,
setting_guid,
str(seconds),
]
elif power_source == "DC":
command = [
"powercfg",
"/setdcvalueindex",
"SCHEME_CURRENT",
subgroup_guid,
setting_guid,
str(seconds),
]

subprocess.run(command, creationflags=CREATE_NO_WINDOW)
subprocess.run(
["powercfg", "/setactive", "SCHEME_CURRENT"], creationflags=CREATE_NO_WINDOW
)


def set_screen_timeout(seconds, power_source):
set_powercfg_value("SUB_VIDEO", "VIDEOIDLE", seconds, power_source)


def set_sleep_timeout(seconds, power_source):
set_powercfg_value("SUB_SLEEP", "STANDBYIDLE", seconds, power_source)


def reset_timeouts():
set_screen_timeout(600, "AC")
set_sleep_timeout(1200, "AC")
set_screen_timeout(600, "DC")
set_sleep_timeout(1200, "DC")


def get_timeouts():
def pretty(value):
if value is None:
return "Never (Couldn't fetch)"
rounded_value = round(value / 60, 1)
return "Never" if rounded_value == 0 else f"{rounded_value}m"

sleep = get_powercfg_value("SUB_SLEEP", "STANDBYIDLE")
screen = get_powercfg_value("SUB_VIDEO", "VIDEOIDLE")

return {
"screen_ac": pretty(screen[0]),
"screen_dc": pretty(screen[1]),
"sleep_ac": pretty(sleep[0]),
"sleep_dc": pretty(sleep[1]),
}


def enable_hibernation():
try:
subprocess.check_call(
["powercfg", "/hibernate", "on"], creationflags=CREATE_NO_WINDOW
)
return "Hibernation enabled"
except subprocess.CalledProcessError:
return "Failed to enable hibernation"


def disable_hibernation():
try:
subprocess.check_call(
["powercfg", "/hibernate", "off"], creationflags=CREATE_NO_WINDOW
)
return "Hibernation disabled"
except subprocess.CalledProcessError:
return "Failed to disable hibernation"


def get_hibernation():
try:
output = subprocess.check_output(
["powercfg", "/a"],
encoding="utf-8",
errors="ignore",
creationflags=CREATE_NO_WINDOW,
)
return (
"Hibernate" in output and "Hibernation has not been enabled." not in output
)
except subprocess.CalledProcessError:
return False


def generate_battery_report():
try:
subprocess.check_call(
["powercfg", "/batteryreport"], creationflags=CREATE_NO_WINDOW
)
return True
except subprocess.CalledProcessError:
return False


def generate_sleepstudy_report():
try:
subprocess.check_call(
["powercfg", "/sleepstudy"], creationflags=CREATE_NO_WINDOW
)
return True
except subprocess.CalledProcessError:
return False


def get_brightness():
try:
cmd = [
"powershell",
"-Command",
"(Get-WmiObject -Namespace root/wmi -Class WmiMonitorBrightness).CurrentBrightness",
]
result = subprocess.run(
cmd, capture_output=True, text=True, creationflags=CREATE_NO_WINDOW
)

if result.returncode != 0:
raise Exception(result.stderr.strip())

brightness = int(result.stdout.strip())
return brightness

except Exception as e:
return None


def set_brightness(brightness_value):
try:
if brightness_value < 0 or brightness_value > 100:
raise ValueError("Brightness value must be between 0 and 100")

cmd = [
"powershell",
"-Command",
f"(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,{brightness_value})",
]
result = subprocess.run(
cmd, capture_output=True, text=True, creationflags=CREATE_NO_WINDOW
)

if result.returncode != 0:
raise Exception(result.stderr.strip())

except Exception as e:
pass


def set_mouse_speed(speed):
ctypes.windll.user32.SystemParametersInfoA(113, 0, speed, 0)


def get_mouse_speed():
speed = ctypes.c_int()
ctypes.windll.user32.SystemParametersInfoA(112, 0, ctypes.byref(speed), 0)

return speed.value


def lock_device():
ctypes.windll.user32.LockWorkStation()


def restart_device():
os.system("shutdown /r /t 0")


def shutdown_device():
os.system("shutdown /s /t 0")
21 changes: 21 additions & 0 deletions format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import subprocess
import sys


def format():
try:
import black

installed = True
except ImportError:
installed = False

if not installed:
subprocess.check_call([sys.executable, "-m", "pip", "install", "black"])

subprocess.check_call([sys.executable, "-m", "black", "core.py"])
subprocess.check_call([sys.executable, "-m", "black", "main.py"])


if __name__ == "__main__":
format()
Binary file added icon.ico
Binary file not shown.
Binary file added icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit be9150f

Please sign in to comment.