diff --git a/scripts/sunset.py b/scripts/sunset.py deleted file mode 100755 index ce0426d..0000000 --- a/scripts/sunset.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/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 - - -type Range = tuple[float, 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: 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 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""" - return ((((hours * 60) + minutes) * 60) + seconds) / 86400 - - -def main(sunrise: Range, sunset: Range, temp_range: Range) -> None: - """Adjusts the monitor temperature based on the current time""" - 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( - (day_elapsed(5), day_elapsed(7)), - (day_elapsed(21), day_elapsed(23)), - (2500.0, 6000.0) - ) diff --git a/scripts/sunset.sh b/scripts/sunset.sh new file mode 100755 index 0000000..fb25f57 --- /dev/null +++ b/scripts/sunset.sh @@ -0,0 +1,65 @@ +#!/bin/env sh + +SUNRISE_START="$((5 * 60 * 60))" # When to start turning up temperature +SUNRISE_END="$((7 * 60 * 60))" # When to reach max temperature + +SUNSET_START="$((21 * 60 * 60))" # When to start turning down temperature +SUNSET_END="$((23 * 60 * 60))" # When to reach min temperature + +DAY_TEMP="6000" # Display temperature (K) to use in full daylight +NIGHT_TEMP="2400" # Display temperature (K) to use at night + +CURRENT="$(((($(date '+%-H') * 60) + $(date '+%-M')) * 60 + $(date '+%-S')))" # Time in seconds since start of day + +# Performs a calculation using an argument containing an input string +calc() { + echo "scale=4; $1" | bc +} + +# Evaluates a boolean expression on an argument containing an input string +bool() { + echo "scale=1; $1" | bc +} + +# GLSL Smoothstep, takes a single number as an argument +smoothstep() { + if [ "$(bool "$1 <= 0")" = "1" ]; then + echo 0 + elif [ "$(bool "$1 >= 1")" = "1" ]; then + echo 1 + else + calc "$1 * $1 * (3 - 2 * $1)" + fi +} + +# Interpolates between the 4th and 5th arguments based on the value of the 2nd in relation to the 1st and 3rd +interpolate() { + LOWER_IN="$1" + VALUE="$2" + UPPER_IN="$3" + LOWER_OUT="$4" + UPPER_OUT="$5" + + if [ "$((VALUE <= LOWER_IN))" = "1" ]; then + echo "$LOWER_OUT" + elif [ "$((VALUE < UPPER_IN))" = "1" ]; then + calc "$LOWER_OUT + (($UPPER_OUT - $LOWER_OUT) * $(smoothstep "$(calc "($VALUE - $LOWER_IN) / ($UPPER_IN - $LOWER_IN)")"))" + else + echo "$UPPER_OUT" + fi +} + +if [ "$((CURRENT <= SUNRISE_START))" = "1" ]; then + TEMP="$NIGHT_TEMP" +elif [ "$((CURRENT < SUNRISE_END))" = "1" ]; then + TEMP="$(interpolate "$SUNRISE_START" "$CURRENT" "$SUNRISE_END" "$NIGHT_TEMP" "$DAY_TEMP")" +elif [ "$((CURRENT <= SUNSET_START))" = "1" ]; then + TEMP="$DAY_TEMP" +elif [ "$((CURRENT < SUNSET_END))" = "1" ]; then + TEMP="$(interpolate "$SUNSET_START" "$CURRENT" "$SUNSET_END" "$DAY_TEMP" "$NIGHT_TEMP")" +else + TEMP="$NIGHT_TEMP" +fi + +# TODO: Figure out a nice way to wait until Hyprland has properly started up before running this +hyprctl hyprsunset temperature "$TEMP" diff --git a/systemd/sunset.service b/systemd/sunset.service index 30686f3..4fa5f55 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=/bin/env python -O /home/mbradley/scripts/sunset.py +ExecStart=/home/mbradley/scripts/sunset.sh diff --git a/systemd/sunset.timer b/systemd/sunset.timer index bc257aa..ac60c6b 100644 --- a/systemd/sunset.timer +++ b/systemd/sunset.timer @@ -4,7 +4,7 @@ After=graphical-session.target After=hyprsunset.service [Timer] -OnCalendar=*:0/5 +OnCalendar=*-*-* *:*:00 Persistent=true AccuracySec=5s