LED Matrix framework tool - FLEM

Hey folks,

Just recently got my LED Matrices and got them installed. I wanted to display a fair amount of information on my matrix. I started with a static program that was drawing information, and then I wanted something that was a bit more flexible and configurable. I’ve been writing this tool (very much to be considered an alpha product) to do exactly that.

As it says on the readme, it’s a configuration based, async renderer that works with independent modules. I’m not finished creating all the modules that I want, but it’s in a place where it’s working “well enough” that I feel like I can share.

The configuration reloads automatically (i.e., if you change your config, the matrix updates with the new config), and each module can have its own refresh rate (i.e., if you want your CPU module to refresh every .5 seconds, that doesn’t make the clock refresh every half second)

The modules next on my list are:

  1. RAM Module
    
  2. CPU Temp Module
    
  3. GPU Temp Module
    
  4. Weather Module
    
  5. Battery Module
    

If you have any modules that you’d like to see, let me know, and I’ll see about adding it to my roadmap. The code is reasonably easy to work on, so if you have your own idea and don’t mind getting in the code, you can pretty easily implement your own things.

I’ve seen some pretty neat libraries on the forum that are doing similar things, but I wanted to share this with the community. If you have any suggestions or feedback, I’d love to hear it!

8 Likes

Hi!
This looks like a great project to me, although I cannot use it because I have no LED matrix.
But I am curious how it will go.
Looking at the current modules and the goal (having as much information as possible and use the space as best as possible): It could be an advantage to display the usage as a progress bar instead of a number. In its most minimalistic version, you could display e.g. the CPU usage in one line, compared to now, where you need 6 rows to display the full number. But maybe you had this idea already and there are reasons not to implement it that way.

For the clock there was a KDE widget coming into my mind which shows the current time using binary numbers. Could also be interesting due to the pixelized nature of the panel :slight_smile:

2 Likes

Hey thanks for checking it out! I did just add “scenes” so that the modules can rotate on intervals. I don’t have enough modules to really rotate things right now, but it’s a foundational update that’ll allow me to change the layouts on the fly from the config.

Love the ideas. I’ve added those to the roadmap, and I’ll probably make those modules today. I spent most the night last night fighting Python’s build and packaging. I’m not a Python developer, so it’s been a bit of a learning experience.

2 Likes

My deepest sympathy for the struggle with the dependencies and pypi. I also had that pain a few times :joy:
When you found a setup that works it is okay, but the path to that point seems to always be covered with stones.
As it might help you, here is a repo with a relatively lightweight setup.py and a corresponding gitlab-ci.yml that contains the step for releasing it to pypi. You could use it as a reference, although the most recent way would probably be to use a pyproject.toml

2 Likes

Oh lawd, I tell you what. I think I figured it out late last night. It was a PYTHONPATH thing. I’m using the toml file and Flit because I apparently love pain. Flit is supposed to be simple, so we’ll see how it goes.

I work with gitlab at my day job, but I’m hoping I can just find an easy, reliable method with GitHub actions. Fingers crossed that I’ll get that done and a bit more tonight. Going to work up some of those modules as well and simplify some of my chunkier code. I’ve got my “pip” (not python pip, like, small indicator pip - seen on the clock and ram modules) code in two places now, and I need to consolidate that into a single method that’ll work across the board.

Figure I’ll make the bar graphs for ram, temp, cpu, and gpu work with the same “pip” functionality. Thinking about a two “pixel” high bar that moves top->bottom->increment column->top->bottom, etc… that gives me 68 pips, so I can have a fairly dynamic graph. We’ll see how it turns out

1 Like

Well, at least the pain has a cute logo. Didn’t know about Flit yet, thank you for the pointer :slight_smile:
I’ll keep my fingers crossed too that the build stuff works soonish and you can focus on the tinkering. I can imagine it is fun to see the LED’s getting alive.

1 Like

Well, I’ve got it working, but I actually switched out for hatch, and it was a lot smoother. Still took some reworking. I restructured the whole project, cleaned up a bunch of stuff, Added logging, more error handling, and! Bar graphs for CPU and GPU. They look pretty cool. Going to circle back a little bit later tonight to work something up on the RAM module. I’m trying to figure out how I can display that with some indicator of what it is. RAM is surprisingly hard to write in a 9 pixel width, and I haven’t been able to figure out how to display any sort of header that makes sense

Anyway, if anyone is brave enough to try this out, you can actually install it via pip now

pip install flem-tool
flem

I’ve still got some messing around to do with the pip package. I want it to create a ~/.flem/ directory on installation, and I haven’t even started looking into that. I also need to implement the option to run it as a daemon so it doesn’t hog a terminal while it’s running. I also, also need to configure an option to write logs out to the ~/.flem/ directory for troubleshooting.

That user directory is going to be where the config is stored. It ships with a config, but I don’t really like the idea of making people mess around inside their python folders. This is also where any user made modules will eventually go, but I’m still quite a ways from allowing custom code outside of the project. Got a lot of security considerations and API documentation before I can make that a reality.

Anyway, good update from the last couple working sessions. Hopefully more to come soon

2 Likes

That looks really cool :slight_smile:
Btw are you sure that you need the latest Python version for the flem tool? You might simplify the onboarding for people when you use an older version, as older distributions might not ship the latest Python version by default

1 Like

Thanks! I just pushed a pretty big update, and I’m considering this officially a beta product

Also, good question and great suggestion. In the latest push, I lowered the minimum version to 3.9. As of now, I’m testing on 3.13, and that’s why I had it set to being required. It’s the only version that I know will work.

After this update, I’m going to switch gears a bit more into testing and optimization. I’m hoping that I can test this across multiple distros (and Windows) and versions of Python, build an automated test suite (possibly an integration suite with a mocked serial device), and start profiling the code to find any potential hotspots or bottlenecks.

I’m about to start a move (new place to live yay!), so I’m going to be focused on that and getting settled for the next couple weeks. I’ll still have some late night sessions to put in some good updates.

A gif of the updates:

Updates:

  1. Officially moved the version to 0.1.0 - Considering this a beta, as it’s not that well tested or optimized (yet)
  2. Weather Module - See the details! This one is a bit unique, and it’s using the other module that I finished up for this update as a submodule. The…
  3. Animator Module - See the details! I can’t believe I didn’t start with this. It’s a really simple concept, but it’s super powerful. It allows arbitrary scenes to be drawn and animated by providing an array (see the weather animations for examples). It can be used with an external file that holds the animation data or the animation can be put directly into the config. It can draw everything from complex, full-panel animations to simple, static 3x3 drawings. Each frame specifies its own duration, so you can easily make whatever you can imagine. Still works with scenes, so you can rotate your animations.
  4. I fixed a nasty threading bug that had been lurking for a while. After fixing that, everything is working much, much better than it was previously. I imagine that it would have resulted in some really poor performance and memory leaks if I hadn’t caught it when I did.

That’s about it. I’m really happy with where it’s at right now. I think the underlying framework is pretty rock solid, and I’m mostly focusing on features and modules. I still have quite a few things on my TODO list that’ll make me revisit the core framework, but I think I can mostly leave it alone for a little while (until bug reports come in).

Anyway, thanks for checking it out!

2 Likes

This is awesome! Great work.

1 Like

Just released v0.2.0. I added the battery module and fixed a bug with the pips on the bar graphs. They were always showing one more pip than they should have been.

The battery module has three different states:

Critical - A configurable lower threshold to blink the battery pips to indicate a low battery state

Charging - Shows the current charge pips as well as an animation of the battery filling. Once the battery is filled, the animation stops for 2 seconds and shows the current charge

Discharging - The last battery pip (indicating current charge) blinks to show that the battery is discharging

You can also specify whether or not you want to show the numeric percentage below the battery or not. If you don’t show the percentage, this is a nice, compact little module - 4x9. Super easy to fit into almost any scene

I think this officially completes all the modules I wanted to have out of the box. Still open to creating other modules, but I’m pretty satisfied with the current crop. If anyone else has any suggestions, let me know. I can spin up modules pretty quickly, assuming the information is easily available. I’ll probably circle back here and there to add a fun module (or animation… was thinking that a “Portal” animation would be kinda fun to include with the tool), but I’m switching my focus to some other areas of the tool now. Probably going to tinker on trigger configs when I find the time.

I also got a basic test suite added. Most the tests are AI generated, so they’re mediocre at best. Still a lot of edge cases to cover, but it’s a decent framework, and I actually caught some bugs while I was running the suite. All in all, good changes. I’ve also got the tests running in github, so I’ll know a bit better if I break something with a commit.

Battery Module in action:

I’m back with another update. Nothing super exciting this time. I had a couple false starts on the package release, but I’ve settled on version 0.3.3.

Two real updates with this release:

  1. Added a CLI to manage FLEM a little bit more sanely
  2. Added the ability to run FLEM as a service.

The CLI is still a bit of a work in progress, but I have most of the things that I wanted in there. The main thing that I want to add is the ability to edit the config through the CLI. Basically a wizard that would allow you to add modules to the config without manually messing around with JSON. I thought it might be a nice option for folks who aren’t used to messing around in configs. CLI Docs

It would also dovetail nicely on another idea I’ve been thinking about which is a GUI for managing FLEM. Thinking about making it in QT, Electron, or Avalonia (a .net project). It’s pretty far down the list right now, but making a CLI wizard would get the flow hammered out. That’d just leave me with making the actual UI and implement the wizard from the CLI

And finally, running FLEM as a service. This is something I’ve wanted since the early days, but I’ve never done anything with Linux services before. It was a bit of a learning curve, and I struggled early on with some really cryptic bugs. Eventually, I borrowed some code from another project and made it my own.

It’s working! It’s nice to not have to have FLEM running in a terminal and spitting out logs constantly. It also starts with the system when it’s running as a service, and it resumes from sleeping nicely. There’s still an option to run it standalone through the CLI, but I figured that most people would only use that for debugging.

Run as a service

flem service install
flem service start

Run in the terminal

flem run

Either way, it’s a good update, and it was a nice change of pace during these busy days. I’m probably going to take a few days off after this and focus on my move and trying to get some sleep.

My next piece of work is probably going to be trying to bundle my custom version of NVTOP with FLEM since I’m not seeing a lot of movement on my PR. I haven’t quite decided how I’m going to do it yet, but I’ll probably implement it as another CLI command (flem install-gpu-support or something like that). I’ll probably end up just uploading the artifact on my fork of the project and have FLEM go out and download it to the .flem directory.

I’d like people to be able to use the GPU module without having to go through the pain of building the custom version, so that’s definitely going to make it in soon.

That’s about it. I also restructured my docs a little bit because the main readme was getting a little bit bloated. I created docs for the modules, docs for the CLI, and kept most the more generic information in the main readme.

Hope everyone has a great weekend!

This looks like a great project! I’ll check it out next time I switch back to the white matrix modules.

2 Likes

Awesome. Appreciate you checking it out. Would love to get some feedback when you get around to trying it.

I’ve been on a bit more extended hiatus than I had originally planned, but I did want to check back in and give a brief update.

I don’t have any code or feature updates, sadly, but there should be some more coming soon (fingers crossed). I’m finished with the move and I’m slowly unpacking and organizing to try to get everything settled. My office is a wreck, and there’s a lot to do in there before it’ll be the code haven I want it to be.

Then I got COVID in the middle of the move and I’m recovering from that now.

As far as FLEM updates: I’ve settled on what I’m going to tackle next. As I said in my last update, it’s pretty stable right now, and I feel that it’s in a pretty good place from a core functionality standpoint. I’ve been running it with the service pretty non-stop, and I’ve only seen one instance where there was a bug (matrix stopped updating and went to sleep). I didn’t have time to diagnose, and I foolishly didn’t have the file logging enabled. I’m going to enable that so I can do some diagnosis if it happens again.

  1. I’m going to add some extra configuration options that are primarily going to take the place of the command line arguments. When it’s running as a service, the arguments can be specified (as a part of the command that the service runs), but it requires you to modify the service unit file. I don’t want to have to do that, so I’m going to add a few more top level fields to the configuration to specify log level, writing to log file, etc…

  2. The first task should be a pretty quick chore. Once that’s done, I’m going to start working on user created modules. I think this makes the most sense since it’ll add to the flexibility of the tool. I was originally going to work on trigger events, but I think that’s a narrower use case. This also gives me the excuse to really clean up my API and write the documentation that I need. As a part of this, I’ll probably also set up readthedocs as I’m updating my documentation.

Essentially, the plan for user created modules is to add another directory in the .flem directory where users can add their .py files. Once they’re added there, FLEM will be able to search that directory similarly to what it does now for the dynamic loading of modules.

The idea is that anyone can now add and share modules with the community without having to do a PR to the main project. There’s a couple hurdles there that I’m still debating how to handle.

  1. Configuration

I’ve got the base configuration set up so that it’s extensible (via the arguments property), so it’s definitely possible to add additional configuration options to a user created module. The pattern I’ve established with the pre built modules is “typed” configurations. I’ve done this just so I can verify the configuration at run time and have better checking of the configuration of the modules. I’m not sure how I want to (or if I want to) handle this for user created modules. I’ll do some more noodling around this and hopefully come up with a plan

  1. Security

Obviously, any time you have code that’s being contributed from the internet, there’s a risk of bad actors and malicious code. I don’t believe that within this community and for something this niche, there’s going to be sufficient motivation for any bad actors to make a bad module. However, it’s a non-zero chance, so it’s something I want to consider. If you’re writing your own module, obviously, you trust it, but if you snag someone else’s module, you can’t inherently trust what it’s doing unless you read the code.

I’ve been thinking about doing some sort of static analysis at a minimum just to look for any potentially risky operations, but I don’t know if the juice is worth the squeeze at this stage in the development cycle. It is on my mind, though, and if this starts taking off, I’ll definitely revisit this topic.

One final update (and I’m going to add this to the readme just as soon as I’m feeling less sick) is that NVTOP has merged my PR, and there’s a new version you can install if you’re interested in using the GPU Modules. Check out the release! Release Release 3.2.0 · Syllo/nvtop · GitHub

It’s pretty exciting because there’s now a way for folks to install this and have the full functionality out of the box.

Anyway, that’s the update. Not a huge update, but the project is still alive, and I’m still thinking about it a lot. Hopefully I’ll be back to pushing regular updates sometime next week.

Have a great week and stay healthy out there

2 Likes