SALIOT — Driving Gallery Lighting Without the Vendor App
Reverse engineering the motorised SALIOT spotlights so ~160 fixtures can be driven from code instead of one at a time from a tablet app.
Role: Analysis and implementation
About the project
The motorised SALIOT spotlights in the exhibition halls can only be operated from the vendor’s app, one fixture at a time, by hand. With around 160 fixtures, anything that has to happen across many of them at once is not possible that way — and there is no documented protocol and no API to automate against.
The goal was to drive the fixtures from code. The only starting point was the Android app.
Approach
- Take the APK apart — pulled the app from an APK mirror and opened it with apktool + jadx.
- Identify the stack — the package tree contained
com/csr/mesh: the fixtures speak CSRmesh, Qualcomm/CSR’s Bluetooth mesh stack, which has prior work to build on. - Recover the crypto — reconstructed key derivation, nonce and frame format from the obfuscated classes and verified them byte-for-byte against the app.
- Translate to Python — payload, encryption, framing and CSRmesh’s best-effort transmit as a compact Python implementation.
- Debug by instrumentation — when writes were silently ignored, built a capture rig: a Frida gadget inside the app (an old Android phone, no root) to see what the app actually does differently at the GATT layer.
Result
Full local control of the fixtures from Python. The real bug turned out to be two swapped GATT control points on older fixtures — a week down the wrong path, a two-line fix.
The full technical story — protocol, code, the traps — is in the blog post.