The humidity in the house could then be measured with a RH sensor and the controller could then send cool signal to add some water to the pads if RH dropped below a certain point. This keeps the humidity way down while only increasing temp by 1-2 degrees. So much more comfortable as i can now keep the RH in the 50-60% range base on outside conditions.
I recently picked the project back up and with newer Claude models i have been making significant progress. For one, the code to determine when to 'cool' is getting better at managing as outside conditions change - temp/RH etc outside impacts cooler performance. Second, I can now start to fully replace the remote so the code manages via feedback loop. the remote has a keep alive sync signal that i was able to figure out that prevented me from using just the eps32. if the remote was off, the controller would turn on the cooler fine but if i didnt send a keep alive, the cooler eventually shuts off.
I have also added a RX module that allows me to now listen for the remote signal and shut off controller when i turn off via remote. eg turn on cooler via remote and controller can be turned on/off to work its magic.
Ultimate goal is to maintain the RH in house all day while outside conditions vary - morning, afternoon, evening and storms etc and then turn off at night once certain conditions are met. My wifes request is to have it turn off at bedtime so she can fall asleep, then turn back on after about 1 hour - so a timer is future feature.
The one thing I have learned is RF is hard but satisfying to figure out - I would have never attempted learning this w/o Claude. I also have a meter reader esp32 i am still working to debug and feel confident i can figure it out.
Anyway i was going to post my favourite tool in this space https://github.com/jopohl/urh universal radio hacker just makes the process trivial, but i see the repo is marked archived now. Either way, the software is excellent.
A major difference is that I relied on a flipper zero I had to do the 433 MHz capture instead of an RTL-SDR (I have one too, but have not needed it yet).
For reference, the transceiver is the one that came with this product: https://www.athom.tech/blank-1/8ch-inching-self-lock-relay-f... (which I already use for controlling a heater). Weirdly, it is not listed in the official esphome config (possibly because RF is a recent addition to esphome). My next step is to test it on another esp board & compare timings with what esphome generates.
I should start doing write-ups too. I came across quite a few interesting sources during this mini project (2-3 hours max).
I also really like automatically adjusting the brightness/color temperature of all our lights during the day.
It’s by no means necessary, but I don’t want to go back now.
Another use-case I have for this is in a house where the mezzanine gets much warmer than below when heating during winter: detect this with a couple of temperature sensors and turn the fan on when needed.
2026.06.24 · 8 min read
When we moved into our current place, we knew pretty quickly we'd want to change our bedroom ceiling fan. That thing easily covered a quarter of our ceiling, wobbled like crazy, and I could not figure out what any of the three (!) pull chains did. It had to go.
After some searching, this fan (the CLF513S) from Dreo seemed like a good option. It's reasonably priced, looks quite nice, and most importantly, it's a normal size.
I've been on a smart home kick over the past few years, with Home Assistant as my core platform, so I wanted to be able to add the new fan to my setup. Unfortunately, Dreo's smart home integration is cloud-only out of the box. They do get bonus points, though, for maintaining an official Home Assistant integration.
I really try to avoid cloud-based smart home controls whenever possible, for a number of reasons:
The fan was sleek and affordable enough that I held my nose and bought it, with the hope of figuring out local control once I had it installed.
When exploring my options for local control, I found this excellent project by ouaibe on GitHub where they used some very impressive firmware reverse engineering to get ESPHome running on a different Dreo fan.
While I could try to follow in their footsteps and attempt to replicate their methods on my ceiling fan, the prospect of bricking something hard-wired into my ceiling put me off.
The fan's only local control mechanism was its remote, so I wanted to try the "universal remote" path: decode the remote's commands and replay them. Universal remotes are famously reliable products, so clearly I was on the right track.

The remote did not require line of sight, so it was not infrared like a TV remote. Looking up the FCC ID listed on the back confirmed it was an RF transmitter.
To enable local control through Home Assistant, there were three steps I needed to take:
With the approach settled, the first step was understanding what the remote was actually sending.
To decode a (simple) RF control scheme, you need to figure out three things:
Having found the carrier frequency in the manufacturer's FCC documentation (433.92 MHz, a common frequency for remotes), the next step was figuring out the modulation method.
Two common digital modulation methods for remotes are:
It's the same basic idea as AM vs FM radio, but with digital signals instead of analog audio. The FCC documentation says the remote uses FSK, but I wanted to verify the actual signal rather than take that at face value. Often these documents use generic values so they aren't the most reliable source.
I used an RTL-SDR (with gqrx) to capture RF spectrum data while pressing some of the remote buttons. This made it clear that the remote was using ASK (OOK specifically): bursts of high amplitude at the carrier frequency with silence in between. Below is a waterfall plot, rotated sideways, showing the spectrum captured when pressing the Fan On/Off button twice.

Looking at the capture in more detail with the plot below, the signal appeared to use short and long bursts of amplitude, kind of like Morse code's dots and dashes.

Zooming in on one of the button presses, I saw that a specific pattern was being repeated five times in quick succession. The plot below shows one of those repetitions, which I could then decode into logical 1s and 0s. I repeated this process for each button I wanted to replicate (fan on/off, fan speed presets, light on/off, and brightness up/down).

Each command followed the same structure, with a single packet repeated five times with an 8.8 ms gap between repetitions:
For example, the Fan On/Off button's payload was:
0111110010000
As mentioned above, the logical bits were encoded as short OOK pulse patterns, with 1000 representing a logical 0 and 1110 representing a logical 1. Each pulse in those patterns was transmitted for 300 μs, so each logical bit (four pulses) took 1.2 ms to transmit.
That means the Fan On/Off payload above was transmitted as:
1000 1110 1110 1110 1110 1110 1000 1000 1110 1000 1000 1000 1000
All the decoded commands can be found in the project's repo.
To replay these commands, I wired a Xiao ESP32-C6 board to an RFM69HCW 433 MHz RF transceiver. I've been using Seeed Studio's Xiao boards a lot recently; they're absolutely tiny and great for keeping projects compact. The ESP32 is completely covered by the transceiver breakout.

As far as I could tell, the packet structure I had decoded was proprietary and not supported by existing libraries like RadioHead. Rather than asking the radio library to understand the protocol, I used the transceiver in a raw transmit mode and manually toggled its data pin with the pulse timings I had decoded from the original remote.
To replay a command, the microcontroller needs to:
This is where the RTL-SDR earned its keep a second time. Without it, debugging was mostly a matter of flashing firmware, walking into the bedroom, and seeing whether the fan had responded. With the SDR, I could actually compare my generated signal against the original remote capture.
The most annoying issue was timing. The fan was surprisingly picky: a command that looked right in code could still be ignored if the pulse timing or inter-packet gap was slightly off.
The last hurdle was a self-inflicted bug in my radio/SPI handling which caused the ESP32 to drop its Wi-Fi connection. Once that was fixed, and after quite a bit of running between my office and bedroom to test commands, the ESP32 was reliably replaying the same commands as the original remote!
Now that I had the ability to replay the commands I wanted to use, I needed a way to trigger them from Home Assistant. A simple solution was MQTT, a lightweight messaging protocol that is widely used in smart home devices. MQTT works by having devices publish messages to named topics, while other devices subscribe to those topics and react when messages arrive.

I configured the ESP32 to subscribe to a set of MQTT topics, with each topic corresponding to a specific fan or light command. Home Assistant could then publish messages to these topics whenever a user interacted with the fan controls in the dashboard. When the ESP32 receives a message, it replays the appropriate RF command.
Since the fan doesn't send anything back to the transmitter, the ESP32 has no way to tell what the fan is actually doing. To get around this, when the device first powers on, it assumes a default state: light off, medium brightness, and fan off. As it sends commands, it updates this internal state accordingly. The state is saved to persistent storage, so the default state is only needed for the first boot.
Very occasionally the state can go out of sync with the fan, for example if commands are sent while the fan is powered off at the wall. When that happens, I just use the remote to bring the fan back into the state Home Assistant expects.

After printing a little case for the transmitter, including the obligatory accent color for the antenna, it was finally ready to go.
The best sign a project like this has worked is that no one has to think about it anymore. I've had the little transmitter sitting on a shelf in my office for nearly a year now, and my partner and I happily control our fan with Siri every day.
If you're interested in replicating this approach, check out the project's repo.