The AC Infinity Controller 69 is a grow tent fan with Bluetooth. The Bluetooth range is 30 feet. My couch is 35 feet away.
This five-foot gap escalated into: decompiling an Android APK, reverse-engineering a proprietary BLE protocol with a non-standard CRC16 checksum, publishing a Python library to PyPI, and building a full AWS serverless platform with WebSocket, DynamoDB, and five Lambda functions.
All because I didn't want to get up.
Phase 1: Decompiling the Android App
There's no public API for this fan. No protocol documentation. No open-source library. Just an Android app that talks to the device via Bluetooth Low Energy.
So we decompiled it. JADX on the APK, extracting the full Java source. Inside com.eternal.base.protocol, 972 lines of ProtocolResolution.java, the entire BLE protocol:
[Byte 0-1] Header: [0xA5, 0x00]
[Byte 2-3] Length of payload
[Byte 4-5] Sequence number
[Byte 6-7] CRC16 of bytes 0-5
[Byte 9] Command type (0x01=query, 0x03=set)
The checksum was a custom CRC16, not the standard CCITT. Use a standard CRC16 library and your checksums don't match. The device silently ignores every command. No error. No response. Just nothing. You sit there wondering if the fan is broken while the fan sits there wondering why you're sending it gibberish.
Getting the Python translation right required sending actual commands to the physical device and checking whether it responded. Claude could translate the Java to Python, but only a real fan could tell us if the checksum was correct.
Phase 2: Publishing to PyPI
Published to PyPI as ac-infinity-ble, version 0.4.3. With GitHub Actions CI/CD and semantic versioning. For a fan controller.
The library supports device types A through G with automatic detection from BLE advertisements. Temperature and humidity come from broadcast packets, transmitted as integers in hundredths (2350 = 23.50°C).
I have a published package on PyPI and it controls a single fan. The ratio of infrastructure to purpose is staggering.
Phase 3: Where It Got Out of Hand
The library worked perfectly, within 30 feet. Which was the original problem.
So we built a cloud bridge. Mac Mini near the fan runs the BLE library, maintains a WebSocket connection to AWS. Phone connects from anywhere. Commands flow phone → AWS → Mac → BLE → fan. State flows back.
For a fan. Five Lambda functions. A DynamoDB table. A WebSocket API Gateway. For adjusting fan speed from the couch. A reasonable person would have moved the couch.
The Delegation Shift
During Phase 1, I was reviewing every line. "Show me the protocol class." "What's this CRC function doing?" "Translate this to Python." Classic Level 2, in the loop on every detail.
During Phase 3, I said:
"You are the fullstack architect. Execute Phase 1 of the cloud bridge."
And Claude built the entire SST infrastructure (five Lambdas, DynamoDB table design, WebSocket routing, Python client) while I went to make coffee. I reviewed the architecture and the deployed result. Not the individual lines.
The prompt changed from "write this function" to "build this system." The review changed from "is this line correct" to "does this architecture make sense."
That's the L2→L3 shift. It happened in one project, somewhere between decompiling an APK and deploying a serverless WebSocket bridge for a fan.
Scope Creep as Learning
The trajectory:
- "Control my fan from the couch" (~10 minutes)
- "Decompile the Android app" (~2 hours)
- "Build a Python library" (~4 hours)
- "Publish it to PyPI" (~1 hour)
- "Build a serverless cloud bridge" (~6 hours)
Each step was deliberate. When AI makes the marginal cost of a feature approach the cost of typing a prompt, scope creep stops being a bug. It becomes the mechanism through which you learn.
I learned BLE protocols, CRC algorithms, APK decompilation, PyPI publishing, WebSocket architecture, and serverless IoT design, all from a project that started because my couch was five feet too far from my fan.