{"id":18929093,"url":"https://github.com/jwillikers/pwm-fan-controller-micropython","last_synced_at":"2025-10-10T11:04:29.971Z","repository":{"id":104839031,"uuid":"487385334","full_name":"jwillikers/PWM-Fan-Controller-MicroPython","owner":"jwillikers","description":"A simple program for controlling a fan using MicroPython on a microcontroller","archived":false,"fork":false,"pushed_at":"2025-04-03T00:31:57.000Z","size":32261,"stargazers_count":14,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-06T21:52:14.124Z","etag":null,"topics":["fan-control","microcontroller","micropython","nix","pico","pwm","python","raspberry-pi","rp2040"],"latest_commit_sha":null,"homepage":"","language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jwillikers.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.adoc","code_of_conduct":"CODE_OF_CONDUCT.adoc","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-30T21:30:26.000Z","updated_at":"2025-03-17T17:20:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"879aa592-9975-4a8f-974c-1151e4f8baeb","html_url":"https://github.com/jwillikers/PWM-Fan-Controller-MicroPython","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2FPWM-Fan-Controller-MicroPython","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2FPWM-Fan-Controller-MicroPython/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2FPWM-Fan-Controller-MicroPython/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2FPWM-Fan-Controller-MicroPython/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwillikers","download_url":"https://codeload.github.com/jwillikers/PWM-Fan-Controller-MicroPython/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249088868,"owners_count":21210876,"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":["fan-control","microcontroller","micropython","nix","pico","pwm","python","raspberry-pi","rp2040"],"created_at":"2024-11-08T11:29:48.393Z","updated_at":"2025-10-10T11:04:24.951Z","avatar_url":"https://github.com/jwillikers.png","language":"Nix","funding_links":[],"categories":[],"sub_categories":[],"readme":"= PWM Fan Controller MicroPython\nJordan Williams \u003cjordan@jwillikers.com\u003e\n:experimental:\n:icons: font\nifdef::env-github[]\n:tip-caption: :bulb:\n:note-caption: :information_source:\n:important-caption: :heavy_exclamation_mark:\n:caution-caption: :fire:\n:warning-caption: :warning:\nendif::[]\n:Asciidoctor_: https://asciidoctor.org/[Asciidoctor]\n:just: https://github.com/casey/just[just]\n:Linux: https://www.linuxfoundation.org/[Linux]\n:MicroPython: https://micropython.org/[MicroPython]\n:nix: https://nixos.org/[Nix]\n:nix-direnv: https://github.com/nix-community/nix-direnv[nix-direnv]\n:Noctua-NF-P12-redux-1700-PWM-Fan: https://noctua.at/en/nf-p12-redux-1700-pwm[Noctua NF-P12 redux-1700 PWM Fan]\n:pip-tools: https://github.com/jazzband/pip-tools[pip-tools]\n:pre-commit: https://github.com/nix-community/nixpkgs-update[pre-commit]\n:Python: https://www.python.org/[Python]\n:Raspberry-Pi-Pico: https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]\n\nimage:https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json[Ruff, link=https://github.com/astral-sh/ruff]\n\nA simple PWM fan controller for the {Raspberry-Pi-Pico}, written in {MicroPython}.\n\nifdef::env-github[]\n++++\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Raspberry PI Pico PWM Fan Controller Breadboard Top View 1\" src=\"pics/pico-pwm-fan-controller-breadboard-top-1.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Raspberry PI Pico PWM Fan Controller Breadboard Top View 2\" src=\"pics/pico-pwm-fan-controller-breadboard-top-2.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Raspberry PI Pico PWM Fan Controller Breadboard Side View 1\" src=\"pics/pico-pwm-fan-controller-breadboard-side-1.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Raspberry PI Pico PWM Fan Controller Breadboard Side View 2\" src=\"pics/pico-pwm-fan-controller-breadboard-side-2.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Raspberry PI Pico PWM Fan Controller Breadboard Side View 3\" src=\"pics/pico-pwm-fan-controller-breadboard-side-3.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n++++\nendif::[]\n\nifndef::env-github[]\nimage::pics/pico-pwm-fan-controller-breadboard-top-1.jpg[Raspberry PI Pico PWM Fan Controller Breadboard Top View 1, align=center]\nimage::pics/pico-pwm-fan-controller-breadboard-top-2.jpg[Raspberry PI Pico PWM Fan Controller Breadboard Tope View 2, align=center]\nimage::pics/pico-pwm-fan-controller-breadboard-side-1.jpg[Raspberry PI Pico PWM Fan Controller Breadboard Side View 1, align=center]\nimage::pics/pico-pwm-fan-controller-breadboard-side-2.jpg[Raspberry PI Pico PWM Fan Controller Breadboard Side View 2, align=center]\nimage::pics/pico-pwm-fan-controller-breadboard-side-3.jpg[Raspberry PI Pico PWM Fan Controller Breadboard Side View 3, align=center]\nendif::[]\n\n== Hardware\n\nAll the hardware components in my particular build are enumerated here.\n\n.Fan Controller Components\n* https://www.adafruit.com/product/798[12V DC 1000mA (1A) regulated switching power adapter - UL listed]\n* https://www.digikey.com/en/products/detail/onsemi/1N4001RLG/918017[1N4001 Power Blocking Diode]\n* https://www.digikey.com/en/products/detail/molex/0470533000/3262217[4-Pin Male Fan Header]\n* https://www.digikey.com/en/products/detail/texas-instruments/SN74AHCT125N/375798[74AHCT125 - Quad Level-Shifter]\n* https://www.adafruit.com/product/368[Female DC Power adapter - 2.1mm jack to screw terminal block]\n* https://www.adafruit.com/product/64[Half-size breadboard]\n* https://www.adafruit.com/product/1311[Hook-up Wire - 22AWG Solid Core]\n* micro USB Power Supply for the microcontroller\n* {Raspberry-Pi-Pico}\n* https://www.adafruit.com/product/759[Premium Male/Male Jumper Wires - 40 x 3\" (75mm)]\n\nProgramming will require a micro USB cable and a computer.\nIf you don't already have one, you'll probably want a fan, too.\nThis circuit is meant for a 12V fan.\nI use this controller for the {Noctua-NF-P12-redux-1700-PWM-Fan}.\n\n== How it Works\n\nThis is a dead-simple PWM fan controller that simply lowers the speed of the {Noctua-NF-P12-redux-1700-PWM-Fan} to a quiet 40%.\nThe microcontroller simply sets the fan speed and then does nothing.\nThe fan setup might evolve in the future to take into account temperature sensing and dynamic speed adjustment.\n\nThe 3.3V microcontroller used here requires a logic level shifter to boost the PWM signal up to 5V for the fan.\nI use the 74AHCT125 to perform the logic level conversion, using pin #40, `VBUS`, to provide the 5V reference voltage.\n\nThe Raspberry Pi Pico only draws 8.63 mA of power now that the firmware is taking advantage of the light sleep mode.\nIf you're concerned about power usage or type safety, then you might be interested in my Rust-based implementation, https://github.com/jwillikers/PWM-Fan-Controller[PWM Fan Controller].\nThe Rust-based version still sips a bit less power on the Pico, 1.99 mA.\nThis is probably mostly due to the fact that the Rust-based version runs entirely off the low-power Ring Oscillator clock instead of the Crystal Oscillator.\nIf you know any ways to improve the energy usage, feel free to get in touch or contribute!\n\n=== Wiring\n\nThe 74AHCT125 is wired as shown in the \u003c\u003c74AHCT125 Wiring\u003e\u003e table.\nAll pins omitted from the table are connected to ground.\n\n.74AHCT125 Wiring\n[cols=\"1,2,2\"]\n|===\n| 74AHCT125 Pin\n| Signal\n| Connection\n\n| 2\n| 3.3V logic level input\n| Pico pin #20 (GP15)\n\n| 3\n| 5V logic level output\n| 1N4001 to fan header pin #4 (Control)\n\n| 8\n| 5V\n| Pico pin #40 (VBUS)\n|===\n\nThe output signal from the logic level shifter is sent through the 1N4001 power blocking diode to the fan header.\nThe pins on the 4-pin fan header are classified in the \u003c\u003c4-pin Fan Header Pinout\u003e\u003e table.\nThe pins are numbered one through four from left to right with the pins reaching upwards and the overhang positioned between the viewer and the pins.\n\n.4-pin Fan Header Pinout\n[cols=\"1,4\"]\n|===\n| Fan Header Pin\n| Signal\n\n| 1\n| GND\n\n| 2\n| +12VDC\n\n| 3\n| Sense\n\n| 4\n| Control\n|===\n\n== Getting Started\n\nThe instructions here setup the software for the Raspberry Pi Pico.\nIt is assumed that you are on and familiar with Linux and using MicroPython on microcontrollers.\n\n[TIP]\n====\nTo access the serial connection to the Raspberry Pi Pico without requiring superuser privileges, add your user to the `dialout` group.\n\n[,sh]\n----\nsudo usermod --append --groups dialout $USER\n----\n\nNow log out and back in for the change to take effect.\n====\n\n. Install {just} by following the instructions in the https://github.com/casey/just?tab=readme-ov-file#installation[installation section].\n\n. Clone this project's repository.\n+\n[,sh]\n----\ngit clone https://github.com/jwillikers/PWM-Fan-Controller-MicroPython.git\n----\n\n. Change into the project directory.\n+\n[,sh]\n----\ncd PWM-Fan-Controller-MicroPython\n----\n\n. Hold down the button marked _BOOTSEL_ on the board while plugging it in to your computer with a micro USB cable.\n\n. Mount the drive provided by the Pico.\nThe RP2040 may be mounted as a disk on your computer automatically.\nIf not, determine the block device representing the Pico by perusing the block devices available from the `lsblk` command.\nTo mount `/dev/sda1`, as in my case, use the `udisksctl` command like so to mount the block device.\n+\n[,sh]\n----\nudisksctl mount --block-device /dev/sda1\n----\n\n. To download and install MicroPython, run `just install-micropython`.\n+\n[,sh]\n----\njust install-micropython\n----\n\n. Wait for the file to finish copying.\nWhen it is done, a serial console will become available which provides access to the board.\nThis serial port can be found with the `dmesg` command as follows.\n+\n--\n[,sh]\n----\nsudo dmesg | tail\n[  443.276661] usb 1-4.3.2: reset high-speed USB device number 22 using xhci_hcd\n[ 2180.628239] usb 1-3.2: USB disconnect, device number 10\n[ 4242.965271] usb 1-3.1: USB disconnect, device number 6\n[ 4245.247932] usb 1-3.1: new full-speed USB device number 23 using xhci_hcd\n[ 4245.387678] usb 1-3.1: New USB device found, idVendor=2e8a, idProduct=0005, bcdDevice= 1.00\n[ 4245.387681] usb 1-3.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3\n[ 4245.387682] usb 1-3.1: Product: Board in FS mode\n[ 4245.387683] usb 1-3.1: Manufacturer: MicroPython\n[ 4245.387684] usb 1-3.1: SerialNumber: df6050788b1e1c2e\n[ 4245.397678] cdc_acm 1-3.1:1.0: ttyACM0: USB ACM device\n----\n\n`ttyACM0` in the preceding output indicates the device node.\nThis device resides under `/dev` on the filesystem.\nNote the name of the device shown in your output, since it will be used to copy the source code to the microcontroller's on-board filesystem.\n--\n\n. Run `just install` to install the firmware to the Pico.\n+\n--\n[,sh]\n----\njust install\n----\n\n[NOTE]\n====\nIf you previously installed the firmware, you must install the firmware or connect to the board with the `mpremote` command within the first fifteen seconds after plugging in the board.\nThis is because the board will start sleeping in small intervals to reduce power usage.\n====\n--\n\n. Once the previous command finishes, you may unplug the board.\n\n== Development\n\nThe following instructions describe how to set up a local development environment and perform development tasks.\n\n=== Development Environment\n\nIt's possible to use a development environment from {Nix} or from a standard Python virtual environment.\nBoth methods are described in the following sections.\n\n==== Nix\n\nI've added development environment and some helpers using {Nix}.\nHonestly, with {pip-tools} and a hard-coded version of MicroPython, this project is already very reproducible.\nNix doesn't offer much on top of that, except that it manages the version Python which is nice, and builds MicroPython itself.\nThis allows further tweaks to be made to the MicroPython implementation in a reproducible manner.\nAdditionally, it provides better consistency between the development environment and CI.\nI mostly wanted to use this as a learning opportunity, which was well worth the effort.\nCurrently, Nix is just using a virtual environment with the dependencies from the `requirements-dev.txt` file.\n\nThe `nix develop` command can be used to enter or run commands in an environment with all of the necessary dependencies.\nFor convenience, direnv can be used to automatically load this environment when entering the project's directory.\nThe https://marketplace.visualstudio.com/items?itemName=mkhl.direnv[mkhl.direnv VSCode extension] integrates this environment in VSCode for development.\nNix also generates the configuration for {pre-commit}, which automates formatting and various checks when committing changes.\nFollow the instructions here to set up your development environment using Nix.\n\n. Install an implementation of {Nix}, such as https://lix.systems[Lix] used here.\n+\n[,sh]\n----\ncurl -sSf -L https://install.lix.systems/lix | sh -s -- install\n----\n\n. Install direnv for your system according to the https://direnv.net/docs/installation.html[direnv installation instructions].\n+\n[,sh]\n----\nsudo rpm-ostree install direnv\nsudo systemctl reboot\n----\n\n. Integrate direnv with your shell by following the instructions on the https://direnv.net/docs/hook.html[direnv Setup page].\n\n. Permit the direnv configuration for the repository.\n+\n[,sh]\n----\ndirenv allow\n----\n\nThere are a couple of Nix commands available for common tasks.\n\n. Install MicroPython by running the `micropython` app output.\n+\n[,sh]\n----\nnix run .#micropython\n----\n\n. Install the fan controller firmware by running the `pwm-fan-controller` app output.\n+\n[,sh]\n----\nnix run .#pwm-fan-controller\n----\n\n==== Virtual Environment\n\n. Run `just init-dev` to initialize the virtual environment for development.\nThis will install all of the necessary dependencies and the {pre-commit} hooks.\n+\n[,sh]\n----\njust init-dev\n----\n\n=== Develop\n\nThe easiest way to test code on the device is to use mount the repository on the device and execute the code from there.\nThe following code demonstrates how to use the `mpremote` command to do just this.\n\n[,sh]\n----\nmpremote connect mount . exec \"import main\"\n----\n\nIt's also possible to run a repl instead by omitting the second command.\n\n[,sh]\n----\nmpremote connect mount .\n----\n\nFor more information on how to use `mpremote`, check out the https://docs.micropython.org/en/latest/reference/mpremote.html[MicroPython remote control: mpremote] page of the MicroPython documentation.\n\n=== Just\n\nMany of the necessary tasks for development have dedicated just commands.\nHere is the briefest overview.\n\n. For local development, the `just run` command can be used to run commands after mounting the local directory on the device.\nBy default, it it will execute the main.py file, but other commands to `mpremote` can be provided as the first argument.\n+\n[,sh]\n----\njust run\n----\n\n. To update dependencies, run `just update`.\n+\n[,sh]\n----\njust update\n----\n\n. Use `just --list` to list other available tasks.\n+\n[,sh]\n----\njust --list\n----\n\n== Todo\n\n. Use mypy to enforce static typing.\nUnfortunately, mypy is not able to properly load the MicroPython stubs.\nWait until support is better to implement this functionality.\n\n== References\n\n* https://www.ti.com/lit/ds/symlink/sn74ahct125.pdf[SN74AHCT125 Datasheet]\n* https://en.wikipedia.org/wiki/Computer_fan_control#Pulse-width_modulation[Computer Fan Control: Pulse-width modulation]\n* https://docs.micropython.org/en/latest/rp2/quickref.html#pwm-pulse-width-modulation[MicroPython Quick reference for the RP2: PWM (pulse width modulation)]\n* https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf[RP2040 Datasheet]\n* https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#pico-1-family[Raspberry Pi Pico Documentation]\n* https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#pinout-and-design-files-2[Raspberry Pi Pico Pinout]\n\n== Contributing\n\nContributions in the form of issues, feedback, and even pull requests are welcome.\nMake sure to adhere to the project's link:CODE_OF_CONDUCT.adoc[Code of Conduct].\n\n== Open Source Software\n\nThis project is built on the hard work of countless open source contributors.\nSeveral of these projects are enumerated below.\n\n* {Asciidoctor_}\n* {MicroPython}\n* {Linux}\n* {pip-tools}\n* {pre-commit}\n* {Python}\n\n== Code of Conduct\n\nRefer to the project's link:CODE_OF_CONDUCT.adoc[Code of Conduct] for details.\n\n== License\n\nThis repository is licensed under the https://www.gnu.org/licenses/gpl-3.0.html[GPLv3], a copy of which is provided link:LICENSE.adoc[here].\n\n© 2022-2024 Jordan Williams\n\n== Authors\n\nmailto:{email}[{author}]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fpwm-fan-controller-micropython","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwillikers%2Fpwm-fan-controller-micropython","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fpwm-fan-controller-micropython/lists"}