{"id":17026302,"url":"https://github.com/st3v3nmw/pi-cyclone","last_synced_at":"2026-02-16T10:11:07.999Z","repository":{"id":217108480,"uuid":"743101554","full_name":"st3v3nmw/pi-cyclone","owner":"st3v3nmw","description":"A script to control the active cooler fan on a Raspberry Pi 5","archived":false,"fork":false,"pushed_at":"2024-02-17T12:46:36.000Z","size":13,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-06T06:23:52.369Z","etag":null,"topics":["raspberry-pi","raspberry-pi-5","raspberry-pi-fan","raspberry-pi-script"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/st3v3nmw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-14T10:38:38.000Z","updated_at":"2024-11-26T00:27:03.000Z","dependencies_parsed_at":"2024-01-14T16:39:21.688Z","dependency_job_id":"c41ed711-92a2-498a-bb70-4da650e4b724","html_url":"https://github.com/st3v3nmw/pi-cyclone","commit_stats":null,"previous_names":["st3v3nmw/pi-cyclone"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st3v3nmw%2Fpi-cyclone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st3v3nmw%2Fpi-cyclone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st3v3nmw%2Fpi-cyclone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/st3v3nmw%2Fpi-cyclone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/st3v3nmw","download_url":"https://codeload.github.com/st3v3nmw/pi-cyclone/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246399798,"owners_count":20770908,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["raspberry-pi","raspberry-pi-5","raspberry-pi-fan","raspberry-pi-script"],"created_at":"2024-10-14T07:31:39.860Z","updated_at":"2025-10-04T12:59:08.664Z","avatar_url":"https://github.com/st3v3nmw.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pi Cyclone\n\nThis is a script to control the active cooler fan on a Raspberry Pi 5.\n\nAt the time of writing, I'm running Ubuntu Server 23.10 and there have been\nissues integrating with the fan:\n\n1. [Fan speed control not working on Pi 5 under Ubuntu 23.10](https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/2041741) - Fixed\n2. [Fan toggles on/off repeatedly](https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/2044341) - Fixed\n\nThe 2nd issue means that hysteresis is not working and the fan keeps going on and off at around 50°C. With a 5°C hysteresis,\nthe fan is turned on at 50°C, it runs until the Pi cools down to 45°C. Without hysteresis, the fan turns off immediately\nthe temperature goes below 50°C. A few seconds later, the Pi heats up a little and the fan turns on again... You get the idea.\n\nHere are the results while my Pi 5 4GB is idle-ish (running home assistant on Docker Swarm, connected to the official active cooler fan and a 256GB SSD through a USB3.0 to SATA interface):\n\n|                | Min (°C) | Mean (°C) | Max (°C) |\n| :------------- | -------: | --------: | -------: |\n| No  hysteresis |     48.0 |      49.4 |     50.7 |\n| 5°C hysteresis |     44.1 |      47.2 |     50.1 |\n\n## Setup\n\n_(most of these actions require root access)_\n\nInstall `pinctrl` from [here](https://github.com/raspberrypi/utils) if you don't have it already:\n\n```console\n$ sudo apt-get update \u0026\u0026 sudo apt-get install build-essential cmake\n$ git clone https://github.com/raspberrypi/utils.git\n$ cd utils/pinctrl\n$ cmake .\n$ make\n$ sudo make install\n```\n\n## Install\n\nCopy the `cyclone.py` script in this repository to your Raspberry Pi. You can use the secure copy protocol (scp) if you're doing this via SSH.\n\nMake it executable:\n\n```console\n$ sudo chmod +x cyclone.py\n```\n\nCreate a service template (change the path to point to where you've stored the `cyclone.py` script):\n\n```\n[Unit]\nDescription = Pi Cyclone\n\n[Service]\nType = simple\nExecStart = python3 /home/stephen/cyclone.py\nUser = root\nGroup = root\nRestart = on-failure\nSyslogIdentifier = pi-cyclone\nRestartSec = 5\nTimeoutStartSec = infinity\n\n[Install]\nWantedBy = multi-user.target\n```\n\nSave the file as `pi-cyclone.service` and place the file in your daemon service folder (usually `/etc/systemd/system/`).\n\nEnable the service to start on boot and start it:\n\n```console\n$ sudo systemctl enable pi-cyclone\nCreated symlink /etc/systemd/system/multi-user.target.wants/pi-cyclone.service → /etc/systemd/system/pi-cyclone.service.\n$ sudo systemctl daemon-reload\n$ sudo systemctl start pi-cyclone\n```\n\nTo check that the script is running, run:\n\n```console\n$ sudo systemctl status pi-cyclone\n● pi-cyclone.service - Pi Cyclone\n     Loaded: loaded (/etc/systemd/system/pi-cyclone.service; enabled; preset: enabled)\n     Active: active (running) since Sun 2024-01-14 13:18:24 EAT; 1min 30s ago\n   Main PID: 40454 (python3)\n      Tasks: 1 (limit: 4592)\n     Memory: 6.2M\n        CPU: 104ms\n     CGroup: /system.slice/pi-cyclone.service\n             └─40454 python3 /home/stephen/cyclone.py\n\nJan 14 13:18:24 luna systemd[1]: Started pi-cyclone.service - Pi Cyclone.\nJan 14 13:18:24 luna pi-cyclone[40454]: 2024-01-14 13:18:24 INFO: Temperature = 51.6°C, current speed = 0%, new speed = 30%\n```\n\nHere are some logs after running `stress --cpu 4` and letting the Pi cool down:\n\n```console\n$ cat /var/log/pi-cyclone.log\n2024-01-14 13:18:24 INFO: Temperature = 51.6°C, current speed = 0%, new speed = 30%\n2024-01-14 13:21:40 INFO: Temperature = 44.4°C, current speed = 30%, new speed = 0%\n2024-01-14 13:24:05 INFO: Temperature = 53.8°C, current speed = 0%, new speed = 30%\n2024-01-14 13:24:35 INFO: Temperature = 60.4°C, current speed = 30%, new speed = 50%\n2024-01-14 13:24:50 INFO: Temperature = 52.7°C, current speed = 50%, new speed = 30%\n2024-01-14 13:28:05 INFO: Temperature = 44.4°C, current speed = 30%, new speed = 0%\n```\n\nYou can check the CPU temperature yourself by running:\n\n```console\n$ vcgencmd measure_temp\ntemp=46.6'C\n```\n\nTo customize the setting while running the script, use the following options:\n\n```console\n$ /home/stephen/cyclone.py --help\nusage: cyclone.py [-h] [--low_speed_temp LOW_SPEED_TEMP] [--med_speed_temp MED_SPEED_TEMP] [--high_speed_temp HIGH_SPEED_TEMP] [--full_speed_temp FULL_SPEED_TEMP] [--hysteresis HYSTERESIS]\n\noptions:\n  -h, --help            show this help message and exit\n  --low_speed_temp LOW_SPEED_TEMP\n                        Low fan speed temperature threshold (°C)\n  --med_speed_temp MED_SPEED_TEMP\n                        Medium fan speed temperature threshold (°C)\n  --high_speed_temp HIGH_SPEED_TEMP\n                        High fan speed temperature threshold (°C)\n  --full_speed_temp FULL_SPEED_TEMP\n                        Full fan speed temperature threshold (°C)\n  --hysteresis HYSTERESIS\n                        Hysteresis (°C)\n```\n\n### Details\n\nThe script will run the following during operation (not necessarily in order):\n\nUnload the `pwm_fan` driver:\n\n```console\n$ sudo rmmod pwm_fan\n```\n\nYou can then export and activate the pwm channel:\n\n```console\n$ pinctrl FAN_PWM\n45: a0    pd | hi // FAN_PWM/GPIO45 = PWM1_CHAN3\n$ cd /sys/class/pwm/pwmchip0\n$ echo 3 \u003e export\n```\n\nYou should now see `/sys/class/pwm/pwmchip0/pwm3`:\n\n```console\n$ cd /sys/class/pwm/pwmchip0/pwm3 \u0026\u0026 ls\ncapture  duty_cycle  enable  period  polarity  power  uevent\n```\n\nFinally, you need to enable the channel:\n\n```console\n$ echo 1 \u003e enable\n```\n\nWe're now be able to control the fan speed by updating the `duty_cycle`:\n\n```console\n$ echo 10000 \u003e duty_cycle\n```\n\nThe maximum `duty_cycle` is:\n\n```console\n$ cat period\n41566\n```\n\nCredits to [this StackExchange answer](https://raspberrypi.stackexchange.com/a/145563) for the setup instructions.\n\n## Uninstall\n\nStop \u0026 disable the service:\n\n```console\n$ sudo systemctl disable pi-cyclone\n$ sudo systemctl stop pi-cyclone\n```\n\nClean up the files:\n\n```console\n$ sudo rm /etc/systemd/system/pi-cyclone.service\n$ rm /home/stephen/cyclone.py\n```\n\nDisable the pwm channel:\n\n```console\n$ cd /sys/class/pwm/pwmchip0/pwm3\n$ echo 0 \u003e enable\n```\n\nLoad the `pwm_fan` driver:\n\n```console\n$ sudo modprobe pwm_fan\n```\n\nRestart!\n\n## Resources\n\n- [Cooling Raspberry Pi 5](https://www.raspberrypi.com/documentation/computers/raspberry-pi-5.html#cooling-raspberry-pi-5)\n- [Heating and cooling Raspberry Pi 5](https://www.raspberrypi.com/news/heating-and-cooling-raspberry-pi-5/)\n- [Disable automatic fan speed control of the Raspberry Pi 5 to control it manually](https://raspberrypi.stackexchange.com/questions/145514/disable-automatic-fan-speed-control-of-the-raspberry-pi-5-to-control-it-manually)\n- [Manual fancontrol on Raspberry Pi 5 for Ubuntu 23.10 64bit](https://gist.github.com/s-geissler/89d2dbe8ee75e67aaadf5c870cf9291e)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fst3v3nmw%2Fpi-cyclone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fst3v3nmw%2Fpi-cyclone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fst3v3nmw%2Fpi-cyclone/lists"}