From e154348dd7a0114ab69dad5252db7af34ed37f6c Mon Sep 17 00:00:00 2001 From: Olli Graf Date: Wed, 1 Apr 2026 10:47:17 +0200 Subject: [PATCH] first commit --- fanctrl.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 12 +++++++ uv.lock | 84 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 fanctrl.py create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/fanctrl.py b/fanctrl.py new file mode 100644 index 0000000..8c487d3 --- /dev/null +++ b/fanctrl.py @@ -0,0 +1,94 @@ +import RPi.GPIO as GPIO +import signal +import sys +from gpiozero import CPUTemperature +import time +from pathlib import Path +import configparser + + + +# initializing GPIO, setting mode to BOARD. +# Default pin of fan is physical pin 8, GPIO14 +Fan = 8 +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BOARD) +GPIO.setup(Fan, GPIO.OUT) + +def handle_exit(signum, frame): + print(f"Signal {signum} received, setting fan to 100%") + p.ChangeDutyCycle(100) + time.sleep(0.5) # waiting to ensure that PWM is set + p.stop() + GPIO.cleanup() + sys.exit(0) + +#initialize GPIO +p = GPIO.PWM(Fan, 50) +p.start(0) + +signal.signal(signal.SIGTERM, handle_exit) +signal.signal(signal.SIGINT, handle_exit) # optional (Ctrl+C) + +def read_config(): + confparser = configparser.ConfigParser() + f = Path("/boot/config.txt") + if f.is_file(): + confparser.read('/boot/config.txt') + else: + f = Path('/boot/firmware/config.txt') + if f.is_file(): + confparser.read('/boot/firmware/config.txt') + + + return confparser +confparser = read_config() + +def parse_config(): + confparser = read_config() + stages= [] + + stage0_temp = float(confparser['fan']['fan_temp0_temp']) + stage0_speed = float(confparser['fan']['fan_temp0_speed']) + stage1_temp = float(confparser['fan']['fan_temp1_temp']) + stage1_speed = float(confparser['fan']['fan_temp1_speed']) + stage2_temp = float(confparser['fan']['fan_temp2_temp']) + stage2_speed = float(confparser['fan']['fan_temp2_speed']) + + stages.append({'temp': stage0_temp,'speed': stage0_speed}) + stages.append({'temp': stage1_temp,'speed': stage1_speed}) + stages.append({'temp': stage2_temp,'speed': stage2_speed}) + return stages + +stages = parse_config() +print(f'stages={stages}') +try: + stage= oldstage = 0 + print(f'stage={stage}') + while True: + cpu = CPUTemperature() + temperature = cpu.temperature + + #print(f'temperature={temperature}/{temp}') + + if temperature < stages[0]['temp']: + stage = 0 + elif temperature > stages[1]['temp'] and temperature < stages[2]['temp']: + stage = 1 + elif temperature > stages[2]['temp']: + stage = 2 + + if stage != oldstage: + oldstage = stage + print(f'stage={stage},temperature={temperature}°C') + p.ChangeDutyCycle(stages[stage]['speed']) + + time.sleep(0.2) +except KeyboardInterrupt: + pass +finally: +# ensure on exit that fan runs full speed + p.ChangeDutyCycle(100) + p.stop() + GPIO.cleanup() + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2d3697e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,12 @@ +[project] +name = "fancontrol" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "gpio>=1.0.1", + "gpiozero>=2.0.1", + "lgpio>=0.2.2.0", + "rpi-gpio>=0.7.1", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..46aaafc --- /dev/null +++ b/uv.lock @@ -0,0 +1,84 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "colorzero" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/688824a06e8c4d04c7d2fd2af2d8da27bed51af20ee5f094154e1d680334/colorzero-2.0.tar.gz", hash = "sha256:e7d5a5c26cd0dc37b164ebefc609f388de24f8593b659191e12d85f8f9d5eb58", size = 25382, upload-time = "2021-03-15T23:42:23.261Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/a6/ddd0f130e44a7593ac6c55aa93f6e256d2270fd88e9d1b64ab7f22ab8fde/colorzero-2.0-py2.py3-none-any.whl", hash = "sha256:0e60d743a6b8071498a56465f7719c96a5e92928f858bab1be2a0d606c9aa0f8", size = 26573, upload-time = "2021-03-15T23:42:21.757Z" }, +] + +[[package]] +name = "fancontrol" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "gpio" }, + { name = "gpiozero" }, + { name = "lgpio" }, + { name = "rpi-gpio" }, +] + +[package.metadata] +requires-dist = [ + { name = "gpio", specifier = ">=1.0.1" }, + { name = "gpiozero", specifier = ">=2.0.1" }, + { name = "lgpio", specifier = ">=0.2.2.0" }, + { name = "rpi-gpio", specifier = ">=0.7.1" }, +] + +[[package]] +name = "gpio" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/21/1655623a323191d7c01ee05ac23b75ad98ed8e2b889eba6febd166ca2cb2/gpio-1.0.1.tar.gz", hash = "sha256:2deb1dcd8be1b11e61ffe8701cbb32f3a354902467f16a55fd2d7724e5a3d631", size = 5281, upload-time = "2025-07-14T16:08:22.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/7e/9d81b4012363b68ee88aeff04f8c44cc9dc1c1d307356eb06cf3b745a826/gpio-1.0.1-py3-none-any.whl", hash = "sha256:56e75e24d569048add247085936fc8f8c12324265d78b21293f9fa7e9c199610", size = 5354, upload-time = "2025-07-14T16:08:21.125Z" }, +] + +[[package]] +name = "gpiozero" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorzero" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/334b8db8a981eca9a0fb1e7e48e1997a5eaa8f40bb31c504299dcca0e6ff/gpiozero-2.0.1.tar.gz", hash = "sha256:d4ea1952689ec7e331f9d4ebc9adb15f1d01c2c9dcfabb72e752c9869ab7e97e", size = 136176, upload-time = "2024-02-15T11:07:02.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/eb/6518a1b00488d48995034226846653c382d676cf5f04be62b3c3fae2c6a1/gpiozero-2.0.1-py3-none-any.whl", hash = "sha256:8f621de357171d574c0b7ea0e358cb66e560818a47b0eeedf41ce1cdbd20c70b", size = 150818, upload-time = "2024-02-15T11:07:00.451Z" }, +] + +[[package]] +name = "lgpio" +version = "0.2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/33/26ec2e8049eaa2f077bf23a12dc61ca559fbfa7bea0516bf263d657ae275/lgpio-0.2.2.0.tar.gz", hash = "sha256:11372e653b200f76a0b3ef8a23a0735c85ec678a9f8550b9893151ed0f863fff", size = 90087, upload-time = "2024-03-29T21:59:55.901Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/4e/5721ae44b29e4fe9175f68c881694e3713066590739a7c87f8cee2835c25/lgpio-0.2.2.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:5b3c403e1fba9c17d178f1bde102726c548fc5c4fc1ccf5ec3e18f3c08e07e04", size = 382992, upload-time = "2024-03-29T22:00:45.039Z" }, + { url = "https://files.pythonhosted.org/packages/88/53/e57a22fe815fc68d0991655c1105b8ed872a68491d32e4e0e7d10ffb5c4d/lgpio-0.2.2.0-cp311-cp311-manylinux_2_34_aarch64.whl", hash = "sha256:a2f71fb95b149d8ac82c7c6bae70f054f6dc42a006ad35c90c7d8e54921fbcf4", size = 364848, upload-time = "2024-04-01T22:49:45.889Z" }, + { url = "https://files.pythonhosted.org/packages/a4/71/11f4e3d76400e4ca43f9f9b014f5a86d9a265340c0bea45cce037277eb34/lgpio-0.2.2.0-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:e9f4f3915abe5ae0ffdb4b96f485076d80a663876d839e2d3fd9218a71b9873e", size = 370183, upload-time = "2024-04-13T14:08:14.139Z" }, + { url = "https://files.pythonhosted.org/packages/fe/73/e56c9afb845df53492d42bdea01df9895272bccfdd5128f34719c3a07990/lgpio-0.2.2.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:6c65ac42e878764d04a71ed12fe6d46089b36e9e8127722bf29bb2e4bc91de22", size = 383956, upload-time = "2024-03-29T22:00:47.315Z" }, + { url = "https://files.pythonhosted.org/packages/3b/1c/becd00f66d2c65feed9a668ff9d91732394cb6baba7bec505d55de0e30c9/lgpio-0.2.2.0-cp312-cp312-manylinux_2_34_aarch64.whl", hash = "sha256:d907db79292c721c605af08187385ddb3b7af09907e1ffca56cf0cd6558ace0a", size = 366058, upload-time = "2024-04-01T22:49:47.615Z" }, + { url = "https://files.pythonhosted.org/packages/4c/7a/e3b4e5225c9792c4092b2cc07504746acbe62d0a8e4cb023bdf65f6430cf/lgpio-0.2.2.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:2aadff092f642fcdada8457c158f87259dfda3a89ec19bae0b99ff22b34aac4b", size = 372103, upload-time = "2024-04-13T14:08:16.351Z" }, +] + +[[package]] +name = "rpi-gpio" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/0f/10b524a12b3445af1c607c27b2f5ed122ef55756e29942900e5c950735f2/RPi.GPIO-0.7.1.tar.gz", hash = "sha256:cd61c4b03c37b62bba4a5acfea9862749c33c618e0295e7e90aa4713fb373b70", size = 29090, upload-time = "2022-02-06T15:15:06.022Z" } + +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +]