It might be worth looking at the decompiled app code some more and seeing if it contains any clues as to the type of command you may have sent, just in case it happens to be some command used for updating the firmware or something. It probably isn't, but you never know.
That said, I suspect you're right and the order of operations was probably something like this, assuming the light controller uses a microprocessor:
1. Controller receives valid command to switch to light pattern 12.
2. Light pattern 12 is saved as user's preference (so it can be restored on power-on).
3. Controller attempts to find light pattern 12 and hits a bounds overflow in the pattern lookup table.
4. There's probably no error checking for this because this "can't happen"[0], so it tries to use the data it finds, which is garbage.
(The next steps depend on how the lookup table is formed, but for the sake of example, let's say the lookup table is an array of pointers to callback routines for each pattern.)
5. The controller remembers whatever garbage it found, treating it as a pointer.
6. The next time the controller wants to update the lights, it tries to call this garbage pointer (which is possibly just a null pointer).
7. Microprocessor tries to execute code there, but whatever it finds causes it instead to infinitely loop.
8. Dimming LEDs typically require a PWM signal, which they're no longer getting, so they go dark.
9. It's dead, Jim.
When you switch off and on again, the process restarts at step 3.
In other words, there may be a possibility for unbricking if you can factory reset, or find out how it stored your light pattern. (Though the latter will probably require at least opening it up and hoping you find a JTAG header, and a lot of patience and Zen. Don't do things willy-nilly!)
In any case, that's my best guess as to what happened here, based purely on the story and without any knowledge of the architecture or home integration ecosystem. If you attempt to fix it, good luck!
[0] http://www.catb.org/jargon/html/C/can-t-happen.html