Work/Hardware & home

PatioFan HomeKit bridge

PatioFan puts two patio ceiling fans and their lights into the Home app on an iPhone, with no hub and no cloud. The remotes that came with the fans still work.

Private buildESP32HomeKit

PatioFan bridge, signal path Signal path: command out, remote in Home app iPhone ESP32 DevKitC HomeSpan 2.1 sketch 1.2.0 WL102-341 transmitter Fan AL84 fan + light WL101-341 receiver Handheld remote HAP over Wi-Fi speed %, light GPIO 26 RMT pulses 433.92 MHz OOK 8 copies HAP over Wi-Fi state update GPIO 27 edge IRQ 433.92 MHz OOK remote repeats Speeds 1 to 6 from 17, 33, 50, 67, 83, 100 %. The bridge is deaf for 300 ms after it sends. Fan 1 is left, fan 2 is right. Each fan answers its own remote ID; the bridge clones both. One frame: 32 bits, MSB first, then a trailing 0 pulse remote ID, 16 bits button, 8 bits F + ctr check check = XOR of 7 nibbles, XOR 0xA 1: 750 µs high, 250 µs low 0: 250 µs high, 750 µs low Gap 8000 µs between copies. Counter +1 per press, wraps 7 to 0. PatioFan bridge plate 1 of 3 not to scale Built on the Beach
The ESP32 replays the remote's own 433.92 MHz frames, so the fan cannot tell the bridge from the handheld.
PatioFan bridge, board and wiring Board and wiring, 4:1 on a 2.54 mm grid Wi-Fi antenna ESP32 DevKitC 30-pin, USB-C USB-C faces the cable slot D26 D27 GND 3V3 2.54 mm WL102-341 TX WL101-341 RX - + DAT EN VIN DATA DATA GND OUT pad ANT pad 17.5 mm 22.5 mm 10.5 mm 31.5 mm 3V3 GND D26 (GPIO 26) to WL102 DAT D27 (GPIO 27) to WL101 DATA Module pin ESP32 WL102 DAT D26 WL102 + 3V3 WL102 - GND WL102 EN open WL102 OUT antenna WL101 DATA D27 WL101 VIN 3V3 WL101 GND GND WL101 ANT antenna Both radios on 3V3; rated 2.0 to 3.6 V. Never VIN or 5V. Radio lines stay off strapping pins 0, 2, 12 and 15. Spring antennas a few cm apart, away from the Wi-Fi antenna. Status LED: GPIO 2. BOOT button: GPIO 0. PatioFan bridge plate 2 of 3 4:1 Built on the Beach
Both radio modules hang off the ESP32's 3.3 V rail; data goes out on GPIO 26 and comes in on GPIO 27.
PatioFan bridge, enclosure section Enclosure, section A-A through the cable slot, 2:1 101.8 mm 10.0 mm 30.4 mm 32.8 mm 19.7 mm 7.5 mm drain hole Ø 2.0 mm, lowest corner 1 2 4 5 7 3 6 C Detail C, lid lip, 5:1 lid 2.4 mm lip 1.6 mm, 4.0 mm deep gap 0.3 mm to the wall wall 2.4 mm corner boss, M3 x 10 screw Part Qty Note 1 Base 1 PETG or ASA 2 Lid 1 inner lip 3 Grommet 1 TPU, cable 4.2 mm 4 Lid screw 4 M3 x 10, self-tap 5 Adapter screw 4 M3 x 6, self-tap 6 Wall tab 2 16x10x4, hole 4.5 7 Terminal adapter 1 66 x 63 mm 8 Silica gel pack 1 swap each spring 0.2 mm layers, 4 walls, 25 % infill. Walls 2.4 mm. No supports. Outside 122.8 x 101.8 x 30.4 mm. Inside 118 x 97 x 28 mm. Hang slot down, antennas up. PatioFan bridge plate 3 of 3 2:1 Built on the Beach
The box hangs with the cable slot down, so water drips off the cable and the drain hole sits at the lowest corner.

Drag to pan the drawing.

What it does

Each fan shows up in Home as a fan and a light, so Siri and the family's automations treat them like any other. Slide the fan to a speed and it snaps to one of the six the fan actually has. Dim the light and the box works the remote's button for you, press by press.

One small box does all of it. It speaks the same radio language as the handheld remotes, and it listens too, so when someone grabs the real remote the Home app updates to match. The case is 3D printed, and a guide and a short video show how to build one.

Hard problem we solved

A radio remote that refuses to be copied

The usual trick for a cheap radio remote is to record a press and play it back. These remotes ignore that. Each press differs a little from the last, so a recording does nothing, and the fans just sit there.

So we decoded the protocol from captures. Each frame holds a remote ID, a button code, a rolling counter, and a check nibble, and the check turned out to be an XOR of the nibbles before it. With that worked out, the firmware builds every press fresh and keeps its own counter per fan. An ESP32 sends the frames through a cheap 433 MHz transmitter on one pin, and HomeSpan makes the board a native HomeKit accessory over Wi-Fi. A matching receiver on another pin hears the handheld remotes, so when someone presses one the bridge resyncs its counter and updates the tile.

The light is the crude part. The remote has one toggle button and sends nothing back, so the bridge tracks state to know which way to switch, and brightness means driving the light to full and stepping down by a counted number of presses, 500 ms apart. After a power cut a tile can drift from the real light. The README says so and gives the reset step.

Apple HomeiPhone, Siri, scenesESP32 bridgeHomeSpan firmware433 MHz sendersends built frames433 MHz listenerhears real remotesTwo ceiling fansfan and light eachHandheld remotesrolling counter

Where it stands

Built and working on the bench with all four tiles tested, with the outdoor mount and a range test from the patio still to come.

ShulClimate

Schedules a synagogue's air conditioning, and fails safe to ON so it is never off on Shabbos.

Next in Hardware & home