dotfiles/scripts/sunset.py

88 lines
2.8 KiB
Python

#!/bin/env python
"""Sets the monitor temperature based on the current time using Hyprsunset"""
from datetime import datetime
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"
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:
"""How far `x` is between `values`"""
return (x - edges[0]) / (edges[1] - edges[0])
def smoothstep(x: float, edges: LerpRange) -> 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
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:
"""Adjusts the monitor temperature based on the current time"""
apply_temperature(
calculate_temperature(
current_elapsed(),
to_elapsed(sunrise),
to_elapsed(sunset),
temperature
)
)
if __name__ == "__main__":
main((5, 7), (21, 23), (2500.0, 6000.0))