TLDR; I have this "Smart Fan" for staying cool when indoor cycling on my turbo trainer and wanted easy access to it because HomeKit integration is missing. I listened to the communication and re-implemented this in my own iOS and watchOS app. It was a really turbulent project with some challenging parts.
The situation
I bought this fan over a year ago as it seemed to fit my needs perfectly. It can be paired to a heart rate monitor and adjusts fan speed accordingly. On the product page was also the hint that HomeKit compatibility is coming soon. That would mean I can access it without a special app from my phone, watch, or via voice control.
During the last months I had many problems with the connection of my heart rate sensor dropping either the connection to the fan (🥵) or to my phone recording my workout (🤬). No news from the vendor about HomeKit.
Manually accessing the control during a workout is also not perfect because you have to open the Wahoo app, navigate to settings, sensors, select the sensor, wait for it to pair, and lastly switching to the speed control.
The idea
So if I just would know the control commands I could write my own app. I've done a couple of things with Bluetooth Low Energy so that would not be the hard part. The hard part would be listening to the conversation between my phone and the fan and find the essential bits in this noise.
The communication
The first step was to use a BLE scanner app on the phone to see the device's services and characteristics.
Interestingly the fan does not announce any services which leads to a bad assumption in my result. I have to filter for the device name and hope that nobody else will ever build a smart fan called "HEADWIND". In the scanner app I found the service and characteristic uuid I was looking for and saw some values updating over time. But without control commands this was useless. I needed to see them from WAHOO's app by using a BLE sniffer. A sniffer is a third device capturing all network packages from the air.
Unfortunately my Adafruit Bluefruit LE Sniffer does not work anymore because it used some "interesting" USB kernel extensions in the past and I'm not smart enough to update it.
After some research I found out that my shiny new nRF52 DK has already a complete BLE Sniffer application and a Wireshark integration. This is way better because it's a standalone system independent from the traffic on the system bus.
After 30 minutes of flashing and configuring the Wireshark device integration I saw the first (thousands) packages flying around.
I think this task would have been much faster to complete if I only was more fluent in Wireshark's recording and display filter expressions. After some minutes I had captured more than 200k of packages and was only able to reduce them to 21k by filtering for source and destination.
It took some hours but then I finally had what I was looking for. The power-on command. And the command to set the fan speed.
The iOS App
Knowing the details of communication now this was the easy part. Setting up a central manager, looking for devices with the correct name, connecting to them. Thereafter scanning for the service with the control characteristic and sending the power on command. Build & run – and it really powered on. This was a really satisfying moment that lastet for about 2 minutes.
After running the app again I had to admit that this was not really perfect because I ignored the current state of the fan. It took some more hours to understand the received values but now I could send something and see the direct result which was much more convenient than the sniffer-method.
The result was already looking good. But switching apps during a workout ... I don't know. The better solution would be having the control on my wrist. So on to ...
The watchOS App
I could reuse almost all of my code from iOS and reduced the interface to only one element. A slider setting values multiples of 25 was the only thing I needed. The slider can also be controlled via the digital crown which fits a workout situation perfectly.
The most time I spend with this was deploying to the watch. After one year away from developing for watchOS I had almost forgotten all the pain that comes with it. Xcode's "making device ready for development" message brought back those bad memories almost instantly. In most situations you can use a Simulator and reduce the real-device deployments to a bare minimum. When developing with bluetooth that's not working so ... some more hours.
What's left
It still lacks support for voice control but this involves Siri Intents which I only used once a couple of years ago. Something to tackle the next days.
Did I reach my goal?
Yes! Looking back all of this was totally worth it. A weekend project including microcontrollers, Bluetooth LE, a phone and a watch to reach a state where it should have been when I was unboxing the fan. And when I'm doing a project like this again and start sweating, now I can just switch on my fan from my wrist.