Posts Tagged ‘ComposeUI’
[KotlinConf2024] Compose UI on a Light Switch: KotlinConf2024’s Embedded Adventure
At KotlinConf2024, Jake Wharton, a Kotlin enthusiast, shared his journey of running Compose UI on a smart light switch powered by embedded Linux. Sparked by a friend’s discovery of a backdoor granting root access, Jake transformed a $50 Amazon switch into a custom platform. He navigated challenges from setting up a JVM and Kotlin Native to configuring a graphics stack with Skia and handling touch inputs, culminating in a live demo of a touchable UI controlling the switch’s relay, showcasing Compose UI’s multiplatform potential.
A Side Project Ignited by a Backdoor
Jake’s project began in January 2023 when a friend revealed a smart switch’s ADB server allowed password-free root access, discovered via Home Assistant forums. The Decora-style switch, with a touchscreen, light sensor, and microphone, ran a stripped-down Linux. Jake snipped an extension cord to power it and confirmed root access via ADB, setting the stage for custom software. This accessibility, though later patched by the manufacturer, fueled his ambition to replace the Flutter-based UI with Compose UI, blending curiosity with technical challenge.
Bootstrapping the JVM and Kotlin Native
To run Compose UI, Jake first tested the JVM on the switch’s limited 150MB storage. He pushed a Linux ARM JRE and a Java “Hello World” class, confirming JVM functionality. Next, he compiled a Kotlin Native “Hello World” for Linux ARM, proving Kotlin could run natively. These steps established a foundation, but the switch’s constraints—no compiler, minimal storage—required compiling on a host machine and transferring binaries, a process complicated by the need to match the device’s library versions, like libDRM 2.4.
Wrestling with the Graphics Stack
Rendering Compose UI required a graphics stack, but the switch’s Flutter app used Linux’s Direct Rendering Manager (DRM) with OpenGL ES, not OpenGL. Jake’s initial attempt to use Compose UI Desktop failed due to missing OpenGL and X11 dependencies. He ported C-based DRM code to Kotlin Native, meticulously matching the switch’s libDRM version (2.4.87) by analyzing binaries. This process, spanning months, involved pulling headers and shared objects from the device, ensuring compatibility, and overcoming compilation hurdles, like missing toolchains for Linux ARM.
Skia: Rendering Pixels with Kotlin
To draw pixels, Jake turned to Skia, the graphics library powering Flutter and Android. JetBrains’ Skiko library, binding Skia to Kotlin, lacked Linux ARM support for OpenGL ES. Jake forked Skiko, modifying it to use EGL, and endured weeks of GitHub Actions builds to compile Skia for ARM. He integrated Skiko’s C++ and Kotlin bindings, enabling rendering of basic shapes (e.g., red backgrounds, blue circles). This step, though painful, proved Kotlin Native could handle the switch’s display, setting the stage for Compose UI.
Handling Touch Inputs
Interactivity required processing touchscreen inputs. Jake used Linux’s evtest
to identify the switch’s touchscreen events, capturing X/Y positions and touch states (down/up). He implemented a single-pointer event parser in Kotlin Native, mapping raw events to a data class within the render loop. This avoided multi-touch complexity, as the switch supported only one pointer. By feeding these events to Compose UI, Jake enabled touch interactions, like button ripples, transforming the switch into a responsive interface, despite occasional crashes during live demos.
Bringing Compose UI to Life
Integrating Compose UI was surprisingly straightforward compared to prior challenges. Jake forked JetBrains’ Compose UI repository, adding a Linux ARM target and implementing expect/actual declarations for dependencies like input handling and scrolling. He replaced low-level Skiko calls with Compose UI’s entry point, passing a Skia canvas and touch events. Initial text rendering crashed due to font issues, but a simple button worked, displaying ripples on touch. Jake’s UI, controlling the switch’s relay via a Unix domain socket and Ktor, demonstrated Compose UI’s adaptability, running the same code on desktop for development.
Demo and Future Potential
Jake’s live demo, despite power converter issues, showcased a draggable switch UI toggling a light bulb, built with Compose UI and Kotlin multiplatform. An enclosure housed the switch, highlighting its real-world application. He envisioned future enhancements, like Home Assistant integration or music control, noting the project’s infancy. Community contributions, like his friend Eric’s interactive component, and public forks for Skiko and Ktor, underscore the project’s collaborative spirit. Jake cautioned against internet-connecting the switch due to security concerns, urging manufacturers to simplify hacking for innovation.