diff options
| author | Aryadev Chavali <aryadev@aryadevchavali.com> | 2025-11-03 01:27:34 +0000 |
|---|---|---|
| committer | Aryadev Chavali <aryadev@aryadevchavali.com> | 2025-11-03 01:29:48 +0000 |
| commit | 0ebaa99bea6975fcb010ea0a3f7932b0afb56ea2 (patch) | |
| tree | 4e07d4a3ef47b33cc58332f024b31bd02671723d | |
| download | uni-sync-temp-timer-0ebaa99bea6975fcb010ea0a3f7932b0afb56ea2.tar.gz uni-sync-temp-timer-0ebaa99bea6975fcb010ea0a3f7932b0afb56ea2.tar.bz2 uni-sync-temp-timer-0ebaa99bea6975fcb010ea0a3f7932b0afb56ea2.zip | |
v1.0.0: Basics
| -rw-r--r-- | README.txt | 14 | ||||
| -rw-r--r-- | curves.json | 40 | ||||
| -rwxr-xr-x | main.py | 109 |
3 files changed, 163 insertions, 0 deletions
diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..601940f --- /dev/null +++ b/README.txt @@ -0,0 +1,14 @@ +/******************************************************/ +/* _ _ _ _ */ +/* | | (_) __ _ _ __ | | (_) */ +/* | | | |/ _` | '_ \| | | | */ +/* | |___| | (_| | | | | |___| | */ +/* |_____|_|\__,_|_| |_|_____|_| */ +/* _____ ____ _ _ */ +/* | ___|_ _ _ __ / ___|___ _ __ | |_ _ __ ___ | | */ +/* | |_ / _` | '_ \| | / _ \| '_ \| __| '__/ _ \| | */ +/* | _| (_| | | | | |__| (_) | | | | |_| | | (_) | | */ +/* |_| \__,_|_| |_|\____\___/|_| |_|\__|_| \___/|_| */ +/******************************************************/ + +A script that uses unisync to set fan speeds based on a temperature curve. diff --git a/curves.json b/curves.json new file mode 100644 index 0000000..46b5f56 --- /dev/null +++ b/curves.json @@ -0,0 +1,40 @@ +[ + { + "sensor": "Sensor 2", + "channel": 0, + "curve": [ + {"temp": 25, "speed": 10}, + {"temp": 40, "speed": 30}, + {"temp": 50, "speed": 100} + ] + }, + { + "sensor": "Sensor 2", + "channel": 1, + "curve": [ + {"temp": 25, "speed": 10}, + {"temp": 40, "speed": 30}, + {"temp": 50, "speed": 100} + ] + }, + { + "sensor": "Tctl", + "channel": 2, + "curve": [ + {"temp": 35, "speed": 10}, + {"temp": 45, "speed": 35}, + {"temp": 50, "speed": 45}, + {"temp": 60, "speed": 99}, + {"temp": 75, "speed": 100} + ] + }, + { + "sensor": "Tctl", + "channel": 3, + "curve": [ + {"temp": 0, "speed": 100}, + {"temp": 50, "speed": 100}, + {"temp": 100, "speed": 100} + ] + } +] @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +from dataclasses import dataclass +from typing import List, Dict +from math import floor +from subprocess import run, PIPE +from re import sub +from json import load, dump + +UNI_SYNC_FILEPATH = "/etc/uni-sync/uni-sync.json" +PROFILE_FILEPATH = "/etc/lian-li-fancontrol/curves.json" + +def get_temps(): + return run(["sensors"], capture_output=True, text=True) \ + .stdout \ + .strip() \ + .split("\n")\ + +@dataclass +class TempCurve: + sensor: str + channel: int + points: [(float, int)] + + def __init__(self, sensor: str, channel: int, points: [(float, int)]): + assert(len(points) >= 3) + assert(all(map(lambda p : p[0] >= 0 and p[0] <= 100, points))) + assert(all(map(lambda p : p[1] >= 0 and p[1] <= 100, points))) + assert(channel >= 0) + self.sensor = sensor + self.channel = channel + self.points = list(sorted(points, key = lambda x: x[0])) + if self.points[0][0] > 0: + self.points = [(0, self.points[0][1])] + points + if self.points[-1][0] < 100: + self.points.append((100, self.points[-1][1])) + + @property + def current_temp(self) -> float: + temp = "" + for line in get_temps(): + if line.startswith(self.sensor): + temp = line + break + temp = sub(f"{self.sensor}:.*?\\+", "", temp) + temp = sub("°C.*", "", temp) + return float(temp) + + @property + def current_speed(self) -> int: + return self.speed(self.current_temp) + + def speed(self, temp: float) -> int: + # get upper and lower bounds + lower = 0 + for (index, (temp_point, speed)) in enumerate(self.points): + if temp_point == temp: + return speed + elif temp_point > temp: + lower = index - 1 + break + + if lower == len(self.points) - 1: + return self.points[lower][1] + + (low_temp, low_speed) = self.points[lower] + (high_temp, high_speed) = self.points[lower + 1] + + return floor(low_speed + (((temp - low_temp) / (high_temp - low_temp)) * (high_speed - low_speed))) + +def read_curves(path: str) -> [TempCurve]: + curves = [] + with open(path, "r") as fp: + json = load(fp) + for obj in json: + curves.append(TempCurve(obj["sensor"], obj["channel"], + [(i["temp"], i["speed"]) + for i in obj["curve"]])) + + return curves + +def compile_unisync(curves: [TempCurve]): + # Setup the version of curves we want + indexed_curves = dict() + for curve in curves: + indexed_curves[curve.channel] = curve.current_speed + + compiled_curves = [] + for i in range(len(curves)): + compiled_curves.append({"mode": "Manual", "speed": indexed_curves[i]}) + + # parse the current unisync + current_config = None + with open(UNI_SYNC_FILEPATH, "r") as fp: + current_config = load(fp) + current_config["configs"][0]["channels"] = compiled_curves + return current_config + +def run_unisync(): + return run(["uni-sync"]) + +if __name__ == '__main__': + curves = read_curves(PROFILE_FILEPATH) + for curve in curves: + print(f"Channel [{curve.channel}]: Sensor={curve.sensor} => Speed={curve.current_speed} based on {curve.current_temp}") + new_config = compile_unisync(curves) + with open(UNI_SYNC_FILEPATH, "w") as fp: + dump(new_config, fp) + run_unisync() |
