From 08ecda72eeb3e8d60d7005243abbf8e69513672b Mon Sep 17 00:00:00 2001 From: Michael Bradley Date: Sat, 29 Mar 2025 17:08:16 -0400 Subject: [PATCH] Optimize Python sunset script --- scripts/sunset.py | 91 ++++++++++++++---------------------------- systemd/sunset.service | 2 +- 2 files changed, 30 insertions(+), 63 deletions(-) mode change 100644 => 100755 scripts/sunset.py diff --git a/scripts/sunset.py b/scripts/sunset.py old mode 100644 new mode 100755 index 26e72d3..ce0426d --- a/scripts/sunset.py +++ b/scripts/sunset.py @@ -5,84 +5,51 @@ from os import environ from socket import AF_UNIX, SOCK_STREAM, socket -def find_hyprsunset_socket() -> str: - """Gets the socket file location""" - xdg_runtime_directory = environ["XDG_RUNTIME_DIR"] - hyprland_instance_signature = environ["HYPRLAND_INSTANCE_SIGNATURE"] - return f"{xdg_runtime_directory}/hypr/{hyprland_instance_signature}/.hyprsunset.sock" +type Range = tuple[float, float] -def apply_temperature(temperature: float) -> None: - """Uses IPC to tell Hyprsunset to update the monitor temperature""" - hyprsunset = socket(AF_UNIX, SOCK_STREAM) - hyprsunset.connect(find_hyprsunset_socket()) - message = f"temperature {temperature:.0f}".encode() - sent = 0 - while sent < len(message): - sent += hyprsunset.send(message[sent:]) - - -type Range[T] = tuple[T, T] -type LerpRange = Range[float] -type HourRange = Range[int] -type ElapsedRange = Range[float] -type TemperatureRange = Range[float] - - -def lerped_amount(x: float, edges: LerpRange) -> float: +def lerped_amount(x: float, edges: Range) -> float: """How far `x` is between `values`""" return (x - edges[0]) / (edges[1] - edges[0]) -def smoothstep(x: float, edges: LerpRange) -> float: +def smoothstep(x: float, edges: Range) -> float: """Smoothly interpolates between the `edges` based on `x`""" # Technically I should bounds check but whatever return (x * x * (3.0 - 2.0 * x)) * (edges[1] - edges[0]) + edges[0] -def calculate_temperature(elapsed: float, sunrise: ElapsedRange, sunset: ElapsedRange, temperature: TemperatureRange) -> float: - """Determines which temperature to set the monitors to""" - if elapsed <= sunrise[0]: - return temperature[0] - elif elapsed < sunrise[1]: - return smoothstep(lerped_amount(elapsed, sunrise), temperature) - elif elapsed <= sunset[0]: - return temperature[1] - elif elapsed < sunset[1]: - return smoothstep(lerped_amount(elapsed, sunrise), temperature[::-1]) - else: - return temperature[0] - - def day_elapsed(hours: int = 0, minutes: int = 0, seconds: int = 0) -> float: """Converts (H, M, S) into [0, 1] representing how far through the day it is""" - TOTAL_SECONDS = 24 * 60 * 60 - elapsed = (((hours * 60) + minutes) * 60) + seconds - return elapsed / TOTAL_SECONDS + return ((((hours * 60) + minutes) * 60) + seconds) / 86400 -def current_elapsed() -> float: - """Time through the day represented in [0, 1]""" - current = datetime.now() - return day_elapsed(current.hour, current.minute, current.second) - - -def to_elapsed(hours: HourRange) -> ElapsedRange: - """Converts a range of hours into a range representing how far through the day is is""" - return day_elapsed(hours[0]), day_elapsed(hours[1]) - - -def main(sunrise: HourRange, sunset: HourRange, temperature: TemperatureRange) -> None: +def main(sunrise: Range, sunset: Range, temp_range: Range) -> None: """Adjusts the monitor temperature based on the current time""" - apply_temperature( - calculate_temperature( - current_elapsed(), - to_elapsed(sunrise), - to_elapsed(sunset), - temperature - ) - ) + now = datetime.now() + elapsed = day_elapsed(now.hour, now.minute, now.second) + + if elapsed <= sunrise[0]: + temperature = temp_range[0] + elif elapsed < sunrise[1]: + temperature = smoothstep(lerped_amount(elapsed, sunrise), temp_range) + elif elapsed <= sunset[0]: + temperature = temp_range[1] + elif elapsed < sunset[1]: + temperature = smoothstep(lerped_amount(elapsed, sunset), (temp_range[1], temp_range[0])) + else: + temperature = temp_range[0] + + hyprsunset = socket(AF_UNIX, SOCK_STREAM) + # In theory I should use $XDG_RUNTIME_DIR, but for me it's always `/run/user/1000/` + hyprsunset.connect(f"/run/user/1000/hypr/{environ["HYPRLAND_INSTANCE_SIGNATURE"]}/.hyprsunset.sock") + # In theory the message might not send in one go, but in practice it does do I won't bother handling it + _ = hyprsunset.send(f"temperature {temperature:.1f}".encode()) if __name__ == "__main__": - main((5, 7), (21, 23), (2500.0, 6000.0)) + main( + (day_elapsed(5), day_elapsed(7)), + (day_elapsed(21), day_elapsed(23)), + (2500.0, 6000.0) + ) diff --git a/systemd/sunset.service b/systemd/sunset.service index c6d5b2f..30686f3 100644 --- a/systemd/sunset.service +++ b/systemd/sunset.service @@ -3,4 +3,4 @@ Description=Sets the monitor temperature based on the time of day [Service] Type=oneshot -ExecStart=/home/mbradley/scripts/sunset.py +ExecStart=/bin/env python -O /home/mbradley/scripts/sunset.py