The Problem: Rack Heat Is Not Optional #
Every homelab eventually runs into it—heat.
As I continued building out my rack, adding compute, storage, and networking gear, one thing became clear:
Airflow wasn’t keeping up.
At first, I did what most people would do—look for off-the-shelf solutions.
⸻
The “Easy” Option That Wasn’t Enough #
I looked at solutions like:
- AC Infinity Cloudplate T1 (1U)
- AC Infinity Cloudplate T7 (2U)
- A few other rack-mounted fan systems
They are solid products, no question. But the more I looked at them, the more I realized something:
They solve airflow… but not observability.
What I wanted was:
- Fan RPM monitoring
- Temperature and humidity metrics
- Power consumption tracking
- Remote control of fan speeds
- Integration into my existing Grafana LGTM stack
At that point, the decision made itself:
If I’m going to spend that money, I might as well build exactly what I want.
⸻
The Approach: “Lazy IT Done Right” #
This entire project aligns with how I approach infrastructure now:
Simple, clean systems that are fully observable and repeatable.
Everything I build now fits into:
- Infrastructure as Code (#IaC)
- Observability-first design (#LGTM)
- Automation with Ansible
- Custom tooling in Go
This project was just extending that philosophy into the physical layer.
⸻
The Build: Hardware Components
Here’s what I used:
- 4 × Noctua NF-R8 Redux 1800 PWM fans (~$13.95 each)
- 2U vented rack blank panel (~$19.99)
- SilverStone 8-port PWM fan hub (~$19.69)
- 12V → 5V micro USB buck converter (~$7.99)
- Molex to SATA power adapters (~$7.99)
- Raspberry Pi Zero 2 WH (~$34.39)
The goal was simple:
Build a quiet, efficient airflow system—but make it fully observable.
⸻
The Late-Night Reality Check 😅 #
This is where the “real engineering” part kicked in.
At one point, I spent way too long troubleshooting why I wasn’t getting any RPM readings from the fan tach signal.
I added a pull-up resistor. Double-checked GPIO. Reviewed the code.
Nothing.
Then came the moment…
The fan wasn’t plugged into the tach-enabled port on the hub.
Classic.
That was one of those “egg on my face” moments—but also a reminder:
Always verify the physical layer before blaming the software.
⸻
The Electronics: Bringing It All Together #
Once everything was wired correctly:
- PWM control (GPIO18)
- Tach feedback (GPIO23)
- DHT temperature/humidity sensor
- Shared ground across all components
Everything clicked into place.
Fan control worked. RPM readings showed up. Temperature and humidity started flowing.
⸻
The Software: Go + Observability #
This is where things got interesting.
I built a custom Go exporter:
👉 https://github.com/mikeosude/fan-tasmota-exporter
It handles:
- Fan PWM control
- Tach-based RPM calculation
- DHT sensor readings
- Tasmota (Sonoff S31) power metrics
- Prometheus /metrics endpoint
From there:
Go Exporter → Grafana Alloy → Mimir → GrafanaNow everything shows up in Grafana:
- Fan RPM
- Temperature
- Humidity
- Voltage
- Current
- Power
- Energy usage
Exactly what I wanted.
⸻
The Result: Full Rack-Level Visibility #
This is where it all came together.
Instead of just “fans spinning,” I now have:
- Real-time RPM visibility
- Environmental monitoring
- Power consumption tracking
- Historical metrics
- Alerting potential
All integrated into the same observability platform I use for everything else.
⸻
Lessons Learned #
A few key takeaways:
1. Hardware matters more than you think #
Most issues were not software—they were wiring and assumptions.
2. Fan hubs are not transparent #
Only one tach signal is exposed. That matters.
3. DHT sensors are not production-grade #
Good for validation, not long-term reliability.
4. Observability should include the physical layer #
Fans, power, environment—everything should be measurable.
⸻
What’s Next #
This is just version 1.
Next steps:
- Replace DHT with BME280/SHT31
- Add automated fan curves based on temperature
- Build alerting around RPM and power anomalies
- Expand to other racks/devices
⸻
Closing Thoughts #
What started as a simple cooling problem turned into something much bigger:
A fully observable, controllable physical infrastructure component.
And that’s really the direction everything is heading:
From software… to systems… to the physical layer itself.
⸻
Full breakdown and configs are available here:
👉 https://github.com/mikeosude/fan-tasmota-exporter
⸻
#LongLiveOpenSource
:::