Erik Rospo Erik Rospo

Kontrol

Kontrol is a status dashboard that I built to monitor stats and visualize data from my computer. It is a web-based application that provides real-time information about various aspects of my system, such as CPU usage, memory usage, media playback status, and more.

Links:

Keeping the Kindle alive

Kontrol started out as TabletControl, a very simple and limited dashboard that I built to display some basic information about my computer. It was built on an old Kindle Fire that I’d jailbroken. The tablet was incredibly old and ran Android 5.1 with 1 GB of RAM, so I had to be very careful with performance and resource usage. TabletControl was a great learning experience, but it was limited in terms of functionality and design.

The 1GB of RAM constraint was brutal. You may think that any reasonable web application can’t take up more than 1GB of RAM, but you’d be surprised. Modern web applications can easily consume hundreds of megabytes of RAM, especially if they use a lot of JavaScript and have complex visualizations. Admittedly, I wasn’t the most careful with performance when I first started building TabletControl, and it quickly became apparent that I needed to optimize the application to run smoothly on the limited hardware. This involved a lot of trial and error, as well as learning about performance optimization techniques for web applications.

In the end, though, it was untenable to maintain TabletControl. At one point, I had a thread on my desktop server that was entirely dedicated to just keeping TabletControl alive, as it would OOM about every 24 hours or so. It would first try to POST a restart signal to the TabletControl server process. If that didn’t work, it would attempt to restart the server process via SSH. If that didn’t work, it would attempt to start the SSH server via ADB. If that didn’t work, it would give up and wait for manual intervention. It was a pretty ridiculous setup, but it was necessary to keep TabletControl running on such limited hardware. It didn’t end up working very reliably, and I had to intervene manually quite often to restart the server process or the SSH server.

Giving it a better home

Eventually, I decided to move the dashboard over to a Raspberry Pi and a Waveshare 7” touchscreen. This allowed me to build a much more robust and feature-rich dashboard, which I renamed to Kontrol. The Raspberry Pi has much more powerful hardware than the old Kindle Fire, so I was able to add a lot more functionality and visualizations without worrying about performance issues. Kontrol is now a much more reliable and enjoyable dashboard to use, and it has become an essential part of my setup for monitoring my computer’s stats and media playback status.

What’s going on behind the widgets?

So, with that bit of background out of the way, let’s dive into some of the technical details of how Kontrol works and how I built it.

Many of the widgets are fairly self-explanatory. The time and date bits are fairly straightforward. Similarly, the ping widget is simply measuring latency between a few devices. Room temperature is measured using a temperature and pressure sensor that I have connected to the Raspberry Pi.

Following the music

Now, for the more interesting bits. The media playback status widget is built around the DBUS MPRIS2 specification, which is a standard interface for controlling media players on Linux. Originally, the webui polled it, but I found it more efficient to use websockets to push updates. The media player sends updates about the current playback status, track information, and other relevant data to the webui in real-time. This allows the media playback status widget to display accurate and up-to-date information about what’s currently playing on my computer.

Finding the right lyrics and album art

The lyrics widget is reasonably similar, it uses the same DBUS MPRIS2 interface to get updates about the currently playing track, and then it uses the LRCLib API to fetch the lyrics for the currently playing track. The lyrics are then displayed in the widget, and they update in real-time as the track changes. One of the tricky things about this is the fact that the listed artist, album, and track info isn’t always accurate or consistent. So instead of just plugging all the information we have directly into LRCLib, I try to clean up and find all possible permutations of the artist, album, and track info to increase the chances of finding a match for the lyrics. This involves things like removing any text in parentheses or brackets, removing any featuring artists from the artist name, and trying different combinations of the artist and track name.

For album art, MPRIS does provide a URL for the album art, but it’s not always reliable or consistent across different media players. So instead, I use the MusicBrainz API to fetch the album art based on the artist and album information. This allows me to get more accurate and consistent album art for the currently playing track.

Keeping an eye on the machine

As for the system stats widgets, I use a combination of different tools and libraries to fetch the relevant information. For CPU and memory usage, I use the psutil library in Python, which provides an easy way to access system information. Memory info is from /proc/meminfo. For GPU usage, I use the nvidia-smi command-line tool, which is specific to NVIDIA GPUs. The desktop server periodically fetches and manages the data, and then generates graphs with matplotlib to visualize the CPU, memory, and GPU usage over time. The WebUI then fetches the generated graphs and displays them in the respective widgets.

Similarly, the room temp and pressure widgets use the temperature and pressure sensor that I have connected to the Raspberry Pi. The desktop server periodically reads the data from the sensor and updates the widgets in the WebUI with the latest temperature and pressure readings.

Making the spectrum move

The spectrum widgets are built using Cava, which is a console-based audio spectrum analyzer for Linux. Cava reads audio data from the system’s audio output and generates a visual representation of the audio spectrum. I configured Cava to output the spectrum data in a format that can be easily consumed by the WebUI, and then I built custom widgets to display the spectrum data in real-time using WebSockets to push updates from the desktop server to the WebUI.