Pico fan controller
A Raspberry Pi Pico 2 on the Pi 3's USB port controls up to six 4-pin PWM fans: one for the voltage regulator (VR) of each Bitaxe and up to three for the case. On top come a 7.5-inch e-paper with the most important values, four buttons and temperature sensors. If anything fails, the fans run at full speed.
Set up the Raspberry Pi: ready-made image · Breadboard · Display, buttons, sensors · Shopping list · Pico via WLAN ·Deutsch
Pi 3Ready-made image: write it once, done
The release page has BitaxeTuner-Server-<version>-pi-arm64.img.xz: the official Raspberry Pi OS Lite (64-bit) with the BitaxeTuner server pre-installed, the restart function for button 4 and the host name bitaxetuner. Your credentials and miner data are not part of the image; the desktop app puts them on the SD card afterwards.
- Open Raspberry Pi Imager → device “Raspberry Pi 3” → operating system “Use custom” → the .img.xz file → SD card (16 GB or more) → write. The Imager offers no settings for custom images – the app takes care of that in the next step.
- Re-insert the SD card. In the BitaxeTuner app (0.3.1 or later): Mode → Prepare Raspberry Pi → choose the “bootfs” drive, enter the admin password for the server twice, user and password for the Pi (SSH), Wi-Fi name and password (Pi 3: 2.4 GHz only; empty = LAN cable only), tick “Include my data” → “Write setup package to the SD card”. All passwords are stored on the card only as hashes. The app remembers the address and access token.
- Insert the card into the Pi and power it on. The first boot takes 3–5 minutes (expand the file system, create the user, apply the package). Afterwards the Pi deletes the password hash and the data copy from the card.
- In the app: “Test connection” → “Switch only”. Only now does the Pi poll the miners, and the PC stops doing so. The interface is also available in the browser at http://bitaxetuner.local:8484/.
OverviewWho talks to whom
CircuitOne channel (build it the same way six times)
PinoutWhich channel on which pin
| Channel | Suggestion | PWM → R1 | Tach ← fan pin 3 |
|---|---|---|---|
| Ch1 | VR fan miner 1 | GP0 · Pin 1 | GP16 · Pin 21 |
| Ch2 | VR fan miner 2 | GP2 · Pin 4 | GP17 · Pin 22 |
| Ch3 | VR fan miner 3 | GP4 · Pin 6 | GP18 · Pin 24 |
| Ch4 | Case fan 1 | GP6 · Pin 9 | GP19 · Pin 25 |
| Ch5 | Case fan 2 | GP8 · Pin 11 | GP20 · Pin 26 |
| Ch6 | Spare | GP10 · Pin 14 | GP21 · Pin 27 |
| — | 3.3 V for all R3 (soldered version only) | 3V3(OUT) · Pin 36 | |
| — | Ground (with supply −) | GND · pin 38 (or 3, 8, 13, 18, 23, 28, 33) | |
Each PWM pin sits on its own PWM slice of the Pico, so every channel gets a clean 25 kHz. Which channel belongs to which miner is set later in the interface; the table is only the suggested wiring. If you only build Ch1–Ch3 for now, Ch4–Ch6 simply stay empty.
BreadboardBuild without soldering
Everything goes on an 830-point breadboard (columns 1–63, rows a–j). The drawing shows channel Ch1 fully wired; Ch2–Ch6 are built the same way, each six columns further right. On the breadboard R3 is left out: the software switches on the Pico's built-in pull-up for the tach line.
One channel, step by step
B is the channel's first column (Ch1: B = 22, so B+3 = 25). The table below lists B and the Pico holes for each channel.
| # | Part / jumper | from | to |
|---|---|---|---|
| 1 | Fan pin header (4 pins) | a(B) … a(B+3) | a(B) = pin 1 GND (black), a(B+3) = pin 4 PWM (blue) |
| 2 | Jumper fan GND | b(B) | upper blue rail (GND) |
| 3 | Jumper fan +5 V | b(B+1) | upper red rail (+5 V) |
| 4 | Jumper tach | b(B+2) | Pico tach hole (table) |
| 5 | Transistor BC547B, flat side facing you (towards row j) | g(B+3) C · g(B+4) B · g(B+5) E | across the gap: jumper e(B+3) → f(B+3) |
| 6 | R1 1 kΩ (lying flat) | h(B) | h(B+4) |
| 7 | R2 10 kΩ | i(B+4) | lower blue rail (GND) |
| 8 | Jumper emitter | j(B+5) | lower blue rail (GND) |
| 9 | Jumper PWM from the Pico | Pico PWM hole (table) | j(B) |
| Channel | Columns (B) | Pin header | Pico PWM hole | Pico tach hole |
|---|---|---|---|---|
| Ch1 | 22–27 (22) | a22–a25 | j1 · GP0 | a20 · GP16 |
| Ch2 | 28–33 (28) | a28–a31 | j4 · GP2 | a19 · GP17 |
| Ch3 | 34–39 (34) | a34–a37 | j6 · GP4 | a17 · GP18 |
| Ch4 | 40–45 (40) | a40–a43 | j9 · GP6 | a16 · GP19 |
| Ch5 | 46–51 (46) | a46–a49 | j11 · GP8 | a15 · GP20 |
| Ch6 | 52–57 (52) | a52–a55 | j14 · GP10 | a14 · GP21 |
Once for all channels
- Pico GND: jumper a3 → upper blue rail.
- Power via the USB fan adapter on a USB charger (5 V, at least 2 A): two female-male jumpers, socket onto the adapter pins, pin into the board. Pin 2 (+5 V, red/yellow) → upper red rail, pin 1 (GND, black) → upper blue rail. Pins 3 and 4 stay free.
- Ground jumper: upper blue rail → lower blue rail (e.g. at column 62).
- Electrolytic capacitor 470 µF: long leg (+) into the upper red rail, striped leg (−) into the upper blue rail.
ExtensionE-paper, buttons and temperature sensors
Everything hangs on the same Pico and goes onto the same breadboard. The holes below again refer to the Pico in columns 1–20 (pins 1–20: holes i/j, pins 21–40: holes a/b). None of them is used by the fans yet.
| Connection | Pico pin | Breadboard hole | Target |
|---|---|---|---|
| E-paper VCC | VSYS · Pin 39 | b2 | display socket pin 39 |
| E-paper GND | GND | upper blue rail | display socket pin 38 |
| E-paper DIN | GP15 · Pin 20 | i20 | display socket pin 15 |
| E-paper CLK | GP14 · Pin 19 | i19 | display socket pin 14 |
| E-paper CS | GP13 · Pin 17 | i17 | display socket pin 12 |
| E-paper DC | GP12 · Pin 16 | i16 | display socket pin 11 |
| E-paper RST | GP11 · Pin 15 | i15 | display socket pin 16 |
| E-paper BUSY | GP22 · Pin 29 | a12 | display socket pin 17 |
| Button 1 · next screen / acknowledge block found | GP1 · Pin 2 | j2 | tab A; tab B → lower GND rail |
| Button 2 · fans automatic | GP3 · Pin 5 | j5 | as above |
| Button 3 · fans 100 % (hold 5 s: fans off) | GP5 · Pin 7 | j7 | as above |
| Button 4 (red) · restart Pi + Pico, hold 3 s | GP7 · Pin 10 | j10 | as above |
| Sensor bus column 3.3 V | 3V3(OUT) · Pin 36 | a5 | jumper to a60 |
| Sensor bus column data | GP26 · Pin 31 | a10 | jumper to a61 |
| Resistor 4.7 kΩ (only one for all sensors) | e60 – e61 | ||
| Each sensor: red (+3.3 V) | b60 / c60 / d60 | one hole per sensor | |
| Each sensor: yellow (data) | b61 / c61 / d61 | one hole per sensor | |
| Each sensor: black (GND) | upper blue rail |
E-paper 7.5" (red/black/white)
The module is actually designed for plugging the Pico on top. Here the Pico stays on the breadboard, and only eight wires go via male-male jumpers into the module's socket header – each into the hole where the module expects the signal (column “Target”, pin 1 is marked on the module). Do not plug the Pico directly onto the module: the module expects the display on GP8–GP13, but the fans use GP8 and GP10 here – BitaxeTuner drives the display on GP11–GP15 and GP22. The display's ribbon cable goes into the module's flip-lock connector, contacts facing down.
The display refreshes at most every 3 minutes (default 5, optionally not at all at night) and takes about 16 seconds to do so. That protects the panel. On an alert (miner offline, case too warm) it refreshes immediately.
Pages (each can be switched on or off, preview in the browser under Fans & display): overview, daily summary, history, BTC, BCH or both prices, monthly and daily summary with a selectable chart, groups, electricity price traffic light, temperature sensors and a QR code to the web UI. Colours can be inverted (white text on black). The block found screen ends either after a configurable number of hours or – like the warnings – only with button 1.
Program updates: when a new BitaxeTuner version ships a new fan program, the server installs it by itself on the next connection – via USB or over Wi-Fi – and the Pico restarts. Only MicroPython itself is updated by hand (UF2 file, as during the first setup).
Buttons
The push buttons have solder tabs: one alligator clip each on tab A and B, the other ends on the pins of two male-male jumpers that go into the board. Direction doesn't matter. The Pico has built-in pull-ups, no resistors needed; its LED blinks on every press.
Button 1 flips to the next page or acknowledges a special screen (e.g. block found); the display then reacts after about 30 seconds instead of 3 minutes. Button 2 (automatic) cancels “100 %” and “Off”. Button 3 briefly sets the fans to 100 % immediately, even if the server isn't responding right now; holding it for 5 seconds switches the extra fans off (safety rules stay active). Button 4 only reacts after holding it for 3 seconds (LED lights for 1 s); a short press does nothing. Before restarting, the server stops running benchmarks and restores the miner settings. The buttons can be disabled in the settings.
Several temperature sensors (e.g. power supply and miner room)
The 3-wire DS18B20 all hang in parallel on the same three lines: column 60 collects 3.3 V, column 61 the data (both columns are free to the right of Ch6). There is only one 4.7 kΩ resistor, no matter how many sensors. Each sensor has a fixed built-in ID: the server recognises it by that and adds it by itself under “Fans & display → Temperature sensors”, where you give it a name and a warning threshold.
- Which one is which? Warm a sensor in your hand and watch which value rises in the list.
- Red must be connected (no “parasitic” mode over 2 wires).
- Soft stranded wire ends hold poorly in a breadboard: use an alligator clip onto a male-male jumper, or ferrules or Dupont connectors.
- Sensor on a small board with its own resistor (often called a “module”, pins −/+/S): then our 4.7 kΩ is not needed; three such modules are still fine.
- Cables up to about 10 m in total are no problem with 4.7 kΩ.
For each sensor you decide whether it counts for the case fans (measured value “Temperature sensors”, the warmest one applies) and whether it appears on the display. Too warm → push notification and red display line. Sensor missing for more than 2 minutes → notification. If it counts for the case fans, they run at the value for “unknown” (default 100 %) until then.
PowerSupply
5 V fans (recommended)
- 3 × NF-A4x10 5V PWM
- about 0.05 A each
- 2 × case 5V PWM
- about 0.1–0.15 A each
- total
- below 0.5 A
- source
- USB charger 5 V, ≥ 2 A via the USB fan adapter
+5 V to all fan pins 2, ground to the GND rail. An electrolytic capacitor (470 µF) on the 5 V rail smooths voltage spikes at start-up.
12 V case fans (if you have them)
The circuit is the same: the PWM signal doesn't depend on the fan voltage. Pin 2 then gets +12 V from a second power supply whose minus also goes to the common GND rail.
+12 V must never touch the Pico, the Pi or the 5 V line. Separate screw terminals and coloured wires help.
Don't power the fans from the Pi's 5 V pin or the Pico's USB: the Pi 3 has little headroom for that, and fans briefly draw much more current when starting up.
ShoppingWhat you need (no soldering)
| Part | Qty | Purpose | Shop (Germany) | |
|---|---|---|---|---|
| Raspberry Pi Pico 2 H (RP2350, headers already soldered) | 1 | Fan, display and button controller | BerryBase · 6,50 € | required |
| 7.5" e-paper module for Pico, 800 × 480, red/black/white | 1 | Status display | BerryBase · 52,90 € | display |
| Square push button, normally open – 3 × black, 1 × red (restart) | 4 | Next / automatic / 100 % / restart | BerryBase · about €0.80 each | buttons |
| Alligator clip cable set | 1 | Connect buttons without soldering | BerryBase · about €3.90 | buttons |
| Temperature sensor DS18B20, 3-wire (e.g. waterproof, 1 m cable) | 1–3 | Power supply, miner room, … | BerryBase · about €2.70 | sensors |
| Resistor 4.7 kΩ, ¼ W | 1 | Pull-up for the DS18B20 | BerryBase | sensors |
| microSD card 16 GB or more (for the ready-made image) | 1 | Pi 3 | have one? | required |
| Breadboard set 400 & 830 points with 3 × 40 jumper wires (M-M, F-F, M-F) – used: 830 board, male-male and 2 × female-male | 1 | Build | Amazon | required |
| Transistor BC547B (NPN, TO-92) | 6 (+2 spare) | Q1 per channel | BerryBase | required |
| Resistor 1 kΩ, ¼ W | 6 | R1 per channel | BerryBase | required |
| Resistor 10 kΩ, ¼ W | 6 | R2 per channel (no R3 on the breadboard) | BerryBase | required |
| Pin header 1×40, straight – break into 4-pin pieces for the fan connector | 1 | Fan connection | BerryBase | required |
| Jumper wires male-male, strip of 40, 20 cm (only needed for all 6 channels) | 0–1 | extra jumpers | BerryBase | for 6 channels |
| Jumper wire box, 140 pieces in 14 lengths | 1 | short, flat jumpers (emitter, ground, collector) | BerryBase | recommended |
| USB-A to 4-pin fan adapter (pins at the end), check for 5 V first | 1 | Fan power onto the board | have one | required |
| USB charger 5 V, at least 2 A (e.g. an old phone charger) | 1 | Power source for the fans | have one? | required |
| Electrolytic capacitor 470 µF / 25 V | 1 | Buffer on the 5 V rail | BerryBase | recommended |
| USB 2.0 cable A to Micro-B, 0.5 m (data cable) | 1 | Pi 3 ↔ Pico | BerryBase | required |
| Noctua NF-A4x10 5V PWM (40 mm) – or NF-A4x20 5V PWM for more airflow | 3 | VR cooling per miner | Noctua shop, Caseking, Amazon | required |
| Case fan 5V PWM, e.g. Noctua NF-A8 5V PWM or NF-A12x25 5V PWM | 1–2 | Case ventilation | Noctua shop, Caseking, Amazon | optional |
Tools: just side cutters (split the pin header, trim legs) and a multimeter for checking. As of 27 Sep 2026: the 830 breadboard was out of stock at BerryBase, hence the Amazon set. The shops are examples from Germany – any electronics shop with the same parts will do. A power supply module or barrel jack is not needed; the power comes via the USB fan adapter.
AssemblyPutting it together and first test
- MicroPython onto the Pico: hold the BOOTSEL button, plug the Pico into a PC via USB, drag the UF2 file for “Raspberry Pi Pico 2” (RPI_PICO2) from micropython.org/download onto the drive that appears. The server flashes the fan program itself later.
- Populate the breadboard according to the layout – first the Pico, rails and ground jumper, then one channel after the other. Don't connect any fan or power supply yet.
- Check (multimeter, continuity test): no continuity between the red and the blue rail; nothing in column 1 at the top (VBUS); every black fan wire ends up in a(B).
- First the USB charger, then one fan on Ch1: without the Pico it must run at full speed right away. That's the fail-safe, which works here even without software.
- Plug the Pico into the Pi 3 via USB. The server detects it, uploads the fan program and takes over control; the speed appears in the interface.
- Assign the fans (Fans & display) and connect the remaining channels.
- Good to know: from fan program v8 a hardware watchdog supervises the Pico. If its program hangs, it restarts after 8 seconds, and until then the fans run at full speed. If you open the Pico with Thonny or a terminal for tinkering, you will therefore see a restart every few seconds – for tinkering, flash MicroPython again first (BOOTSEL + UF2); the server installs the fan program again afterwards.
From 0.9.7No cable to the server: Pico via WLAN
With a Raspberry Pi Pico 2 WH (with WLAN, headers already soldered) the fan controller and the display no longer have to be connected to the server via USB. There are two variants, which can also be combined:
Fan Pico
Pico 2 WH instead of Pico 2 H on the fan board (or the breadboard) – same form factor, same pins. The fans still get their power from the board's USB-C socket, the Pico gets its own USB power supply on its micro-USB socket.
An e-paper can still hang on the board via cable.
Display Pico
Plug the Pico 2 WH directly onto the Waveshare e-paper module – no wires, no board. Orientation as shown by the Pico outline printed on the module: USB socket towards the “Interface Config” end, i.e. away from the ribbon cable, VBUS on VBUS, GP0 on GP0; with power off. Power via a USB power supply on the Pico.
The program then uses the Waveshare layout (GP8–GP13, BUSY GP13), not the cable layout of the fan board (BUSY GP22). Which layout applies is set by the Pico's role, not by the server setting. On the module: switch “Interface Config” at 0 (4-wire SPI). Without WLAN: “Set up display Pico via USB (no WLAN) …” sets the role directly over the USB cable.
Keys on the module (Pico program 8.2 and later): KEY0 turns the page or acknowledges a special screen (like button 1). KEY1 redraws the current page right away with fresh values; hold it for 3 seconds to trigger the restart (like button 4). The RUN key only restarts the Pico itself.
It shows the display and reports its buttons; it has no fans. For this the program uses the Waveshare pin layout (GP8–GP13).
- Install MicroPython for the W: hold BOOTSEL, connect the Pico to a PC via USB, drag the UF2 file for “Raspberry Pi Pico 2 W” (RPI_PICO2_W) from micropython.org/download onto the drive. The file without “W” has no WLAN.
- Connect the Pico to the server with a USB data cable (Pi or PC running the BitaxeTuner server). If another Pico is already plugged in there, choose the right port in the dialog.
- In the browser open Fans & display and choose “Set up fan Pico for WLAN …” (card Connection) or “Set up display Pico for WLAN …” (card E-paper display, “Display is attached: own display Pico”).
- Enter WLAN name and password (the Pico only supports 2.4 GHz), keep or change the device name. After about 30 seconds BitaxeTuner reports “Set up” and the IP address the Pico got.
- Unplug the Pico from the server and connect it to its own power supply (5 V, 1 A is enough). The server connects by itself within a few seconds; the connection is shown under Connection or “Connected via”.
Security
- During setup every Pico gets its own random key. Both sides prove it when connecting, after that every line is signed and numbered – other devices on the WLAN can neither switch fans nor inject values or replay old commands.
- The WLAN password is stored only on the Pico, not on the server. Whoever gets hold of the Pico can read it, though – so don't leave the Pico lying around openly.
- The fail-safe stays: if the WLAN drops, the fan Pico gets no more commands and sets all fans to 100 % after 5 seconds. Button 3 sets 100 % even without server.
- After 10 minutes without server the e-paper shows “KEINE VERBINDUNG ZUM SERVER” (no connection to server).
If it doesn't work
- “key does not match”
- The Pico was set up again elsewhere or the server was reinstalled → from Pico program 8.5 without USB: hold BOOTSEL on the Pico (display Pico also KEY0) for 3 seconds until the LED blinks fast, then “Fans & display → Picos” → “Pair again” and compare the code with the LED or display. Otherwise set the Pico up for WLAN again via USB.
- “does not answer (WLAN?)”
- Check WLAN name/password, is the 2.4 GHz network on? Look up the Pico's IP in the router and enter it.
- “is set up as display Pico”
- Fan and display Pico swapped → use the other setup button.
- Display stays blank
- Check first: Pico orientation on the module (USB socket away from the ribbon cable, VBUS on VBUS), ribbon cable fully inserted and locked, switch “Interface Config” at 0, role “display” (see above). To check the hardware without a server: open epd_test.py in Thonny and "Run" – after 20–30 s a test picture with a black and a red bar appears; the output says “(BUSY ok)” when the display answers. The program on the Pico stays unchanged.
- Thonny loses the connection
- From Pico program 8 a hardware watchdog restarts the Pico 8 s after the program is stopped. From 8.1: press BOOTSEL within 3 s after plugging in (LED lit) – the program then does not start and Thonny stays connected.
- Back to USB
- Choose “Connection: USB cable on the server” and save; the program keeps working via USB.
SoftwareSettings in BitaxeTuner
VR fan per miner (Ch1–Ch3)
- Manual
- fixed value, e.g. 60 %
- Automatic
- curve by this miner's VR temperature
- Example curve
- up to 50 °C → 25 %, from 70 °C → 100 %, linear in between
- Hysteresis
- 2 °C so the fan doesn't oscillate
- Minimum
- adjustable; below it the fan stays off or runs at minimum
Case fans (Ch4–Ch6)
- Manual
- fixed value for the whole group
- Automatic
- by the highest temperature of all assigned miners
- Measured value
- VR, ASIC or sensor temperature (DS18B20)
- Curve
- own values, separate from the VR fans
- Night mode
- optional maximum at fixed times (quieter)
Always active, cannot be switched off
- Miner offline or its data older than 30 seconds → its fan to 100 %.
- Pico receives no command for 5 seconds (server hangs or restarts) → all fans to 100 %.
- Pico without power or USB unplugged → the circuit itself ensures 100 %.
- Fan should spin but reports 0 rpm → push notification “fan stalled”.
- A temperature sensor above its warning threshold → push notification with its name and a red line on the display; a missing sensor is reported too.
- Even with “Off” (button 3, hold 5 s) the rules above apply: a fan that runs anyway for safety reasons is reported.
- Every change in manual mode and every switch manual ↔ automatic is noted in the miner's log.