

GarageVentilation v1
GarageVentilation is a small DIY project that decides when ventilating a garage will actually help remove moisture.
- Size
- 45 × 55 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 5
- Nets
- 22
- Pads
- 34
- Tracks, vias
- 33, 0
- Routed
- Yes
- KiCad
- KiCad 10.0 (file 20260206)
- Created
- 4 Nov 2026
- Updated
- 4 Nov 2026
Overview
GarageVentilation v1 is an open-source printed circuit board by Joozd, from the Joozd/GarageVentilation repository on GitHub. It is a 2-layer board of 45 × 55 mm with 5 parts on 22 nets, routed with 33 tracks and 0 vias.
It is built around the IRLZ34N. Its parts include 2 connectors, 1 resistor, 1 IC and 1 transistor. It belongs with the ESP32 and RISC-V boards of this library.
Main components
1README
README.mdGarageVentilation
Battery-powered, humidity-aware garage ventilation using an ESP32-C5, Bluetooth sensors and a 5 V fan.
GarageVentilation is a small DIY project that decides when ventilating a garage will actually help remove moisture. Instead of switching a fan on whenever the relative humidity is high, it compares the absolute humidity of the air inside and outside. The fan should run only when the garage is humid enough and the outside air contains sufficiently less water vapor.
The project combines an ESP32-C5, two existing Bluetooth sensors, a MOSFET-switched fan, and a rechargeable battery. It is being developed with PlatformIO and includes a custom PCB designed in KiCad.
Status: work in progress. BLE measurement decoding, ventilation decision logic, fan switching and sleep behavior are being developed and tested. This is a prototype, not a finished commercial device.
How it works
SwitchBot (inside) ── BLE ──┐
│
▼
ESP32-C5
▲
│
RuuviTag (outside) ── BLE ─┘
│
Compare humidity
│
Ventilation worthwhile?
/ \
yes no
│ │
MOSFET → fan Deep sleep
│
Light sleep
│
Measure again- Scan Bluetooth advertisements from the indoor SwitchBot and outdoor RuuviTag.
- Decode temperature and relative humidity from both sensors.
- Calculate absolute humidity in g/m³.
- Start the fan if the indoor relative humidity is high enough and the indoor air contains sufficiently more moisture than the outside air.
- Use different start/continue thresholds (hysteresis) to avoid rapidly switching the fan on and off.
- Sleep between measurements to conserve battery power.
If a measurement cannot be obtained, the controller takes a conservative approach instead of assuming ventilation is useful. While ventilating, the current firmware allows one missed measurement cycle before stopping the fan.
Why absolute humidity?
Relative humidity alone is misleading when temperatures differ. Cold outside air can have a high relative humidity while containing less water vapor than warmer garage air. Once that outside air warms up in the garage, its relative humidity falls.
Comparing absolute humidity gives a better indication of whether exchanging the air will remove moisture. It does not guarantee that every surface will become drier immediately: surface temperature, condensation, airflow and moisture sources still matter.
Current control thresholds
These are experimental firmware settings, not universal recommendations:
| Condition | Start ventilating | Continue ventilating |
|---|---|---|
| Minimum indoor relative humidity | 66% | 64% |
| Minimum indoor–outdoor absolute-humidity difference | 2.0 g/m³ | 1.5 g/m³ |
Both conditions must be satisfied. The lower continuation thresholds provide hysteresis.
Hardware
| Component | Purpose |
|---|---|
| Seeed Studio XIAO ESP32-C5 | Microcontroller and BLE receiver |
| SwitchBot temperature/humidity sensor | Indoor measurement via BLE advertisements |
| RuuviTag | Outdoor temperature/humidity measurement via BLE RAWv2 |
| 5 V Noctua fan | Exhaust air from the garage |
| Logic-level N-channel MOSFET | Switch the fan from an ESP32 GPIO |
| Seeed LiPo Rider Plus | Rechargeable battery power and 5 V boost output |
| Single-cell Li-ion battery pack | Portable power source |
| Custom KiCad PCB | Mount and connect the electronics |
Fan wiring (simplified)
5 V boost output ───────── Fan +
Fan − ─── MOSFET drain
ESP32 GPIO (D2) ────────── MOSFET gate
Ground ─────────────────── MOSFET sourceThe ESP32 and fan power supply must share a common ground. A suitable gate resistor and gate pull-down are part of the MOSFET control circuit. The fan is switched on the low side; it is not powered directly by an ESP32 GPIO.
The ESP32 is powered from the boost converter's 5 V output. Consult the XIAO ESP32-C5 and LiPo Rider Plus documentation before reproducing the power connections, particularly when combining external power and USB.
Battery safety: Use a protected battery pack and a charging/power board appropriate for its chemistry. Check polarity, current limits and mechanical protection before operating unattended.
Firmware architecture
The code is organized so that measurement collection, humidity decisions, hardware switching and sleep management have separate responsibilities.
main.cpp
├── MeasurementsScanner
│ ├── BleScanner (NimBLE + FreeRTOS queue)
│ ├── AdvertisementClassifier
│ ├── RuuviDecoder
│ └── SwitchbotDecoder
├── VentilationController
├── Fan
└── sleep utilitiesMeasurementsScannergathers and decodes the two sensor measurements. It returns either a complete pair or no measurement.BleScannerhandles passive BLE scanning. Incoming advertisements are copied into a bounded FreeRTOS queue and processed by the main application task. Bluetooth is initialized at the start of each scan and deinitialized afterward, so it does not remain active during light sleep.VentilationControllerdecides whether ventilation is worthwhile using measurement data and configurable thresholds; it does not manipulate hardware.Fanowns the output GPIO and controls the MOSFET, including GPIO hold so the output stays high during light sleep.- Sleep utilities put the controller into light sleep while ventilating or deep sleep when ventilation is not needed.
Deep sleep restarts the program on wake-up. Light sleep resumes execution where the program left off.
Building and flashing
The firmware uses C++, the Arduino framework, PlatformIO and NimBLE-Arduino.
- Install Visual Studio Code and the PlatformIO IDE extension.
- Open this repository as a folder in VS Code.
- Connect the XIAO ESP32-C5 over USB.
- In PlatformIO, select the
seeed-xiao-esp32-c5environment and build/upload the firmware. - Open the serial monitor at 115200 baud for diagnostic output.
The project's platformio.ini defines the board, framework and library dependencies. Use the configuration committed with the code rather than copying settings from an older version of this README.
Power-saving approach
The prototype aims for a low average current draw rather than continuously operating the radio and fan:
- Fan off: stop scanning, shut down Bluetooth and enter deep sleep until the next measurement cycle.
- Fan on: keep the MOSFET gate asserted, shut down Bluetooth and use light sleep between measurement cycles.
- After waking: initialize Bluetooth again for the next scan.
A fan duty cycle around 10% is an initial design target, not a measured long-term result. Actual battery life depends on fan runtime, battery capacity, boost-converter losses, measurement frequency and standby current. No runtime guarantee is made yet.
PCB and mechanical design
A custom PCB is designed in KiCad. The intent is to keep the electronics easy to assemble and allow the battery to sit in a separate, mechanically secured holder. The LiPo Rider Plus charging connection should remain accessible.
The repository can contain the PCB sources alongside the firmware, for example:
GarageVentilation/
├── src/
├── include/
├── lib/
├── hardware/
│ └── pcb/
│ ├── *.kicad_pro
│ ├── *.kicad_sch
│ └── *.kicad_pcb
├── platformio.ini
└── README.mdThis layout is illustrative; the actual folder structure may evolve.
Project status / next steps
- Decode RuuviTag BLE RAWv2 measurements
- Decode SwitchBot temperature/humidity advertisements
- Compare inside/outside absolute humidity
- Drive the fan through a MOSFET
- Test GPIO hold across light sleep
- Design an initial PCB in KiCad
- Verify reliable repeated BLE scans across sleep cycles
- Validate long-term power consumption and battery runtime
- Finish mechanical mounting and battery holder
- Test control thresholds against real garage conditions
- Document the finished wiring and add build photos
A note on scope
This is a purpose-built garage ventilator, not a general home automation platform. The design deliberately favors a small, readable firmware structure and a simple hardware interface over unnecessary abstraction.
Built as a practical electronics, embedded C++ and humidity-control learning project.
Parts
5| Qty | Value | Footprint | References |
|---|---|---|---|
| 1 | 1M | Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal | R1 |
| 1 | Fan pin header | Connector:FanPinHeader_1x03_P2.54mm_Vertical | J2 |
| 1 | IRLZ34N | Package_TO_SOT_THT:TO-220-3_Vertical | Q1 |
| 1 | Lipo_Rider_Plus | GarageVentilation:LiPo_Rider_Plus | J1 |
| 1 | XIAO-ESP32-C5-DIP | GarageVentilation:XIAO-ESP32-C5-DIP_mount | U1 |
Questions
How big is the GarageVentilation v1 PCB?
It measures 45 × 55 mm and has 2 copper layers, 1.6 mm thick.
What parts does the GarageVentilation v1 use?
5 parts, built around the IRLZ34N. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
Where can I download the GarageVentilation v1 KiCad files?
From the Joozd/GarageVentilation repository on GitHub, at the commit this page was made from: the board is hardware/GarageVentilation_v1.kicad_pcb and its schematic hardware/GarageVentilation_v1.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the GarageVentilation v1 design in my own project?
Its repository states no licence, so its author keeps all rights: ask Joozd before reusing the design.
Similar boards
- 2 layers100 × 50 mm

- 2 layers224.8 × 60.3 mm

Deurnode nieuw
Hans-Beerman/Deurnode_ESP32-PoE
KiCad design Deurnode for the MakerSpace Leiden, based on the Olimex ESP32-PoE
38 parts4Apache-2.0 - 2 layers111.3 × 68.1 mm

MKS relay v4
3D-Printing-for-Microfluidics/3D_printer_control
2nd generation 3D printer control software
67 parts3GPL-3.0 - 2 layers

Watch cleaner pcb
DavidJ-Saving-Time/watch-cleaner
So this is a very rough draft of code designed to run on an esp32 to control a watch cleaning machine see this YouTube video https://youtu.be/Opr75n8DbYY I'll be adding to this and making it easier for people to use.
16 parts3MIT - 2 layers31.8 × 114.8 mm

3DWelderPCB
destroyer796/3DWelder
An overbuilt 3D pen that will use a chc pro hotend and custom dc extruder powered by a power tool battery
17 parts3MIT - 2 layers83.8 × 50.8 mm

Shunt charge controller
grillbaer/solar-power-supply
Solar power harvesting for micro controller projects with li-Ion battery and highly efficient charge controller
16 parts3MIT - 2 layers80 × 45 mm

WifiOiler01
volw/wifiOiler
Automatic, distance depending chain oiler for motorbikes with track recording (GPS).
15 parts3GPL-3.0 - 2 layers80 × 20 mm

Spider dropper
aidtopia/spider_dropper
Mechanism to "drop" a spider (or other lightweight prop) for Halloween fun
10 parts2