The Flow Card That Was Never Missing
A lighting app that seemed to be failing at runtime, a house-wide migration to replace it, and the malformed API call underneath the whole thing.
Earlier this week I installed Lumina, a third-party adaptive-lighting app for Homey, to replace a pile of hand-rolled flows that adjusted color temperature through the day. Within a night it was fighting my "Evening" scene: lights would snap back to Lumina's daytime curve — dim around 0.6, temp around 0.85 — a few minutes after Evening had set them warm and dim on purpose.
First fix was a 5-second delay before Evening's lighting commands fired, on the theory Lumina was just overwriting a stale write. Didn't hold. Second fix was a 12-second corrective re-assert after the scene ran, forcing the values back a second time. That held better, which told me something useful: this wasn't a one-time race, it was periodic. Lumina recomputes every 300 seconds, and if that tick landed right after Evening flipped a zone off, it would recompute against stale state and shove the day curve back in. It was worse on the Govee bulbs than the local Zigbee ones — cloud round-trip latency gave the recompute more room to land badly. The fix that actually stuck was a new recurring flow, "Evening: Lumina Enforcer," re-asserting the scene's values every 10 minutes for as long as Evening is active. Not elegant, but it's the kind of fix that matches the actual shape of the bug instead of guessing at it.
Then it got worse. Lumina's smart_on action card started failing outright: ManagerFlowLocal.runFlowCardAction → Not Found: FlowCardAction with ID smart_on. I tried the obvious ladder — restart the app, restore its settings, uninstall and reinstall, reboot the whole Homey hub. None of it brought the card back. At that point the working theory was that Lumina 0.6.3 simply wasn't registering its own flow cards with Homey at runtime — a real bug in the app, not in my setup. I drafted a report for the developer, and in parallel migrated the whole house — kitchen, living room, dining room, office, master bathroom — over to a different adaptive lighting app from the maker of a bed-presence sensor I already trusted.
Here's the part I don't love telling but is the actual point of the post: later that same day I caught that the original test calling smart_on was wrong. Homey's API wants a single string identifier — homey:app:com.3cheesehigh.lumina:smart_on — and the test had split it into separate uri and id fields instead. Lumina was never broken. The flow card was there the whole time; the call to it wasn't shaped the way Homey expects. I said as much directly: I need to flag something serious — I made a testing mistake, and Lumina was never actually broken.
So the decision became: put the house back on Lumina, or keep what I'd already migrated to. I kept the migration. Lumina still wins on per-zone customization, and that's a real loss. But the replacement was already fully wired up and covering more of the house than Lumina ever had, and ripping out a working system to reinstate one because a diagnosis turned out to be wrong isn't obviously the better move just because the diagnosis was wrong. That's a product decision, not a technical one, and it's worth being honest that it was made on coverage and momentum rather than on which tool is actually better.
The generalizable part isn't "test your API calls before you trust them," though that's true. It's that a false root cause doesn't announce itself as false. It produces real, reproducible symptoms, survives four different fix attempts, and looks exactly like a vendor bug right up until someone checks the one line of code doing the calling. Any debugging process that ends in "I migrated off the broken thing" should leave room for the possibility that the thing doing the diagnosing was the broken part — because by the time you've built a workaround good enough to ship, you've also built a reason not to look any closer.