esp32 – HomeKit Bathroom Ventilation Controller

When we renovated our bathroom, a new ventilation unit was installed — including a wireless remote control. Sounds convenient. In reality… not so much. The remote was constantly misplaced, forgotten, or — even worse — the battery was empty again. And surprisingly fast. That meant the ventilation was either running unnecessarily or not running when it should. As an embedded engineer, that simply could not stay like that. So I built a proper solution.

The Goal

  • Integrate the bathroom fan into Apple HomeKit
  • Enable fully automatic humidity-based control
  • Keep manual control available
  • Work completely offline
  • Maintain professional HAP compliance
  • Avoid hacking the 230V installation directly

In short: Make the bathroom ventilation intelligent, reliable and autonomous.

First Attempt – RF Sniffing

The ventilation unit uses an RF remote (868 MHz). My first approach was to clone the signal using a: CC1101 868MHz SPI RF module

The idea was simple:

  1. Sniff the transmission
  2. Decode the payload
  3. Replay it from an ESP32

After many evenings of analyzing waveforms, modulation, and packet structure…

It became clear: The protocol is secured / encrypted. Replay attacks were not working. Rolling codes or crypto was involved. That path was closed.

The “Dirty” Hack (That Actually Works)

Since cloning the RF protocol was not feasible, I took a more pragmatic approach. Instead of emulating the radio signal, I simulated the button presses on the original remote. The remote PCB was opened and wired as follows:

  • 3.3V → Powered from ESP32
  • GND → Shared ground
  • Each button line → Connected to ESP32 GPIO
  • ESP32 outputs configured as open-drain
  • A short active-low pulse simulates a button press

So effectively: The ESP32 “presses” the remote buttons electronically. Not pretty. Not elegant. But extremely reliable!

And since the remote already handles pairing and secure communication — we reuse the original certified hardware. Sometimes engineering means shipping, not perfection.

Hardware Architecture

The controller is built around:

The ESP32 runs everything locally. HomeKit is optional for monitoring and manual override. If Wi-Fi fails? It continues working autonomously.

Ventilation Logic (ISO-Style Behavior)

This is not just “if humidity > X then ON”. The logic is designed to behave like professional ventilation controllers.

Fan activates when:

  • Humidity > 65%
  • OR rapid humidity spike detected (shower detection)
  • OR temperature > 26°C (optional boost)

Fan stops only when:

  • Humidity < 60% (hysteresis)
  • AND minimum runtime (15 minutes) passed

This prevents:

  • Rapid toggling
  • Relay chatter
  • Under-ventilation
  • Mold formation

The system also learns baseline humidity when idle.

Fan Speeds

ModeOutput
LOW30%
MID60%
HIGH100%

Speed selection is implemented via active-low GPIO pulses to the remote PCB.

Manual Override

From HomeKit you can:

  • Turn the fan ON / OFF
  • Select speed

When manually controlled:

  • AUTO mode is disabled
  • After 20 minutes, it safely returns to automatic mode

This prevents the “fan left on forever” problem.

Sensor Processing

To avoid noise and unstable readings:

  • EMA smoothing (α = 0.2)
  • Baseline humidity tracking
  • Relative rise detection
  • Delta-based reporting

This allows accurate shower detection without false triggers.

HAP-Safe Notification Strategy

HomeKit is sensitive to excessive updates. To remain stable and production-grade:

  • Temperature notify only if change > 0.2°C
  • Humidity notify only if change > 0.5%
  • Minimum notify interval enforced
  • Event-per-minute limits applied
  • Spike mode allows temporary faster updates

This prevents:

  • TCP congestion
  • iOS throttling
  • OTA instability
  • Random HomeKit disconnects

Professional embedded systems require guardrails.

Lifecycle Manager Integration

Using:

  • esp32-lcm
  • OTA triggers
  • Hardware button management
  • Wi-Fi provisioning
  • Automatic reconnect

Hardware button functions:

ActionResult
Single pressOTA update
Double pressReset HomeKit pairing
Long pressFactory reset

Wiring Overview

  • Identify LED → GPIO 8
  • Hardware button → GPIO 3
  • Fan LOW/MED/HIGH → configurable GPIO
  • I2C SCL → GPIO 7
  • I2C SDA → GPIO 6
  • SHT3X address → 0x44

All fan control GPIOs are configured as open-drain to safely simulate button presses.

Code

Result

After flashing:

  1. Device boots
  2. Wi-Fi connects (or provisioning mode starts)
  3. Sensor initializes
  4. AUTO mode active
  5. Fan responds intelligently to humidity
  6. Manual override works from Home app
  7. OTA updates available

No more forgotten remote. No more empty batteries. No more condensation. Just silent automation!

Why This Matters

Smart home is not about adding apps. It is about:

  • Removing friction
  • Increasing reliability
  • Solving real problems
  • Designing systems that fail gracefully

This controller now runs fully autonomous. Even if:

  • Wi-Fi is down
  • HomeKit is unreachable
  • Internet is offline

The bathroom stays dry.

Engineering Lessons

  • RF protocols are often secured — plan for that.
  • Reusing certified hardware can save enormous time.
  • Stability matters more than feature count.
  • HAP rate limiting is not optional.
  • Sometimes the “dirty” solution is the most robust one.

Conclusion

What started as an annoying remote control issue became a fully autonomous, production-grade bathroom ventilation controller.

Powered by:

  • ESP32-C3
  • HomeKit
  • SHT3X
  • Lifecycle Manager
  • Secure RF remote reuse

Reliable. Autonomous. Professional!

error: Content is protected !!
Scroll to Top