Presto Music System Display/Controller

I finished my project to turn my Presto into a controller and display for my home Lyrion Music System setup. The full code and documentation can be found here.

https://github.com/goodeb/LMS_controller

In addition to creating a micropython friendly library for interacting with the LMS server, I created a timer library that may be useful for people creating other projects. Timers trigger functions when they expire. They can be set up and started from any part of the code. I used them here to dim the screen at night and brighten it in the morning, to return to the now playing screen after a period of inaction, to update the clock, to update the now playing screen, and more. That library can be found here. GitHub - goodeb/micropytimer: Micropython friendly library to create timers that trigger functions

4 Likes

Nice stuff, thanks for sharing. I really appreciate the good documentation. I know myself how tedious this is: the project is finished and running, and the documentation is just holding you up from the next project.

Additional bonus points for pointing me towards LMS 🙂️👍️🎶️ Never heard of it but it seems worth exploring.

One note regarding your timer-library though: you should read about MicroPython’s async-ibrary. With async, your implementation can be very much simplified. No need to run check_timers() anymore. You just async-sleep for the given time and then the async-task executes the callback.

In one of the other threads here, @SirFico posted a link to a tutorial for async. It is really worth it.

Thanks. Glad you liked the project. LMS should be more widely known as an open source success story. About 20 years ago when I was deciding what to buy for a home music system, I picked Slim Devices exactly because they had open sourced their software and protocols from the start, so I knew no matter what happened with the company, my hardware would keep working. And that’s exactly how it worked out. Logitech bought them, and then shut them down, but despite this the support and variety of hardware available is better today than it’s ever been.

I looked into async, and while that tutorial is quite good, I decided it didn’t quite do what I wanted or at least not as easily. The best case to explain this is the button inaction. When you press a button it starts a 5 second timer to go back to the default screen. Async could set a task to do this easily. But what if you press multiple buttons? I don’t want it to go back 5 seconds after the first button press, just the last. With async, each button press would have to be able to access the task created by previous button, which keep in mind are each implemented in separate functions to keep the setup modular and easier to change. Then it would have to cancel that task and start a new one. With my timers, you just have to call one function start_timer(), and it handles it by setting a new expiration. Timers also make it easier to set an action at a fixed clock time, like dimming the screen at 10 PM. There’s also more flexibility in where in the code base the call back functions come from, and they can be used to set really long time checks without having to incorporate a second package like sched. This is how I handled waiting for the end of daylight savings time.

Well, all of these problems can be handled elegantly with async processing. E.g. I would implement the button task as a sort of generator that puts button events in a queue. This will fully isolate the button-task. Events are then processed from the main task. Note that this is exactly what is happening in professional grade UI systems. Or you could work with async-events to synchronize with or trigger other tasks, without knowing any implementation details of them. And waiting in an async task for a fixed clock time is also trivial.

But in the end async is a (software) tool and not the only way to implement a solution. And as with every tool you need experience to use it in the right way. And there will of course be situations where this is the wrong tool.