Custom Conky displays through Lua and C++
Working on Pioneer again recently inspired me to rewrite much of the code that controls the Brewserver, the Raspberry Pi that controls the fermentation chamber that I use to brew beer.
It was previously all written in Python, because that was quick and easy, but it ended up being terribly interdependent (the thermostat service couldn’t start until after the database was up and running…) and it really just needed to be torn apart and redone from scratch.
So I did, but this time I wrote much of it in C++. While I do think that was a better choice, that had the unfortunate consequence of breaking the web based interface, still in Python, so I now had no easy way of monitoring what was going on. And, rewriting that would be just as time consuming, if not more, than what I had just done.
I have a monitor connected to the RPi and I noticed while setting up Conky that it is now Lua based and can pull in data from custom Lua scripts. And, from working with Pioneer’s ‘new’ PiGui, I knew that moving data between C(++) and Lua wasn’t too difficult either, so I thought Conky would make for a decent solution, at least until I got around to rewriting the web interface.
Development Environment
The first thing to do was getting the proper development packages. The current version of Raspberry Pi OS, Buster, has multiple versions of Lua available:
To make things worse, changes between 5.1 and 5.2 require breaking changes to code on the C side of things. To keep things simple and to ensure it would be compatible, I used the same version of Lua that Conky was built against:
So, Lua 5.1 it is: sudo apt install liblua5.1-0-dev
On the C side
When I rewrote everything in C++, I was somewhat ambitious and thought that I would eventually have multiple executables that do different things, but all needing access to the same data, so I built the bulk of the code into a shared library, libbrewserver.so.
Luckily this made accessing things from Lua even easier, I just needed to write a few functions to export the data I wanted out and I could then load my library as a Lua module:
It’s not pretty, the exception should be handled better, but it’s quick and it will work for now.
CMake
I had also used rewriting the brewserver as an opportunity to learn how to use CMake. But, now I have to get it to link my library against Lua as well. This was surprisingly straight forward once I found the appropriate options.
First, tell CMake I want Lua 5.1:
Then, if Lua is found, include the new file and appropriate compiler flags:
This way the library will still build if the Lua dependency isn’t met, it just won’t have the new Lua export functions included.
Conky and Lua
Finally, libbrewserver.so can now be loaded as a Lua module, and data can be pulled by calling one of the functions like sensor_temp_f
, but I still have to tell Conky how to do that.
Conky has a variable called lua
that will run the specified Lua function, with supplied parameters and then display the returned value. However, this won’t handle loading my module and Conky prepends ‘conky_’ to the function names, so I need a Lua script to load my module and wrap the functions. I also do a bit of formatting on the output too.
So now conky_sensor_temp_f
will call brewserver.SensorTempF
and format the returned value and the return that back to Conky.
Now I have to tell Conky to load the Lua script:
And finally use the lua functions:
Done? Not Quite
The last thing to do is tell Lua where to find libbrewserver.so. If I try to run my new configuration with Conky, I get an error:
I can do that with an environment variable, LUA_CPATH
. Note: it’s CPATH not PATH since this is a shared library, not a lua file:
Also important to note: it’s not just a folder but a pattern, in this case anything begining with ‘lib’ and has the extension ‘.so’. Because of that, it needs to be in quotes and use a real path (~ for home won’t work). Also, the final ‘;’ at the end causes Lua to still search for other modules using the default paths in addtion to this new one.