Search
99 results for “imrehg”
-
The face when you are (marginally) better at #Python than puzzles, so you write code to solve a puzzle in an adventure game.
Definite spoiler for the magnet puzzle in #Machinarium, after trying fiddling around with it for more than 30 minutes originally.
https://gist.github.com/imrehg/cb8c45aa41c2212737967097cab678d7
And this way, I had 2x the amount of fun... Though makes me worried, years ago I remember finishing this game without any programming, so what did I know then that I no longer do?? #GettingOld
-
Musical Sunday morning: #9m88 - Beyond Mediocrity #Taiwan
https://9m88baba.bandcamp.com/album/beyond-mediocrity
And #Bandcamp is pretty darn good, I think I'm getting near in digital albums to how many physical CD's I've gotten before... https://bandcamp.com/imrehg
-
When parts of a system are strongly interconnected, one can discover latent issues while debugging something completely different. This is what happened with this blog’s caching and integrating with the Fediverse.
Fediverse adventures
I was part of The Great Twitter Exodus of 2022, and like many I’ve landed on Mastodon (hey, hello, https://fosstodon.org/@imrehg). Mastodon and the whole Fediverse and its build around the ActivityPub protocol is technically very interesting and brings back a bit of retro-joy to me (which needs some reflections on why and how is retro joyful, but another time). This current blog is running WordPress, and soon found that there’s a plugin to turn a WordPress blog into a my own ActivityPub node. That seemed some excellent way to connect up tools and make a more inter-connected Internet (besides nerding out, if I’m fully honest).
ActivityPub plugin
It was super easy to set up, and seemed to have worked well: take my author URL, put it your Mastodon instance’s search, and voila, there’s a compatible profile which one can follow and interact with (to an extent, but still):
How does my author profile look when searched on a Mastodon instance, this time on Fosstodon. One can use either the author URL or the shortened address shown under the profile picture to find a person.
It all seemed to have worked, but coming back after a while, but Site Health popped up a critical issue. 🙀
WordPress Site Health highlighting the issue with the author URL.
Digging in into what the endpoint actually returned when setting what response format the client want to accept:
curl --silent -H "Accept: application/activity+json" https://gergely.imreh.net/blog/author/gergely/
I can see that it indeed doesn’t look like a JSON file, instead the cached web content:
Hot on your trail, W3 Total Cache (W3TC)! I use this plugin to make this site (hopefully) more performant, but it’s not looking great in this instance. Fortunately I got some interesting pointers by asking none other the Fediverse about this issue, and got some helpful pointers.
W3 Total Cache
The way I understood how the W3TC plugin and my configuration worked was the following:
The plugin does some internal caching (opcode, objects,…) using PHP, and something I don’t worry about much.
The main performance benefit is coming from generating page caches on disk that can be loaded quicker then regenerating the page.
Routing to those cached files is mostly through my nginx web server’s configuration: the caching plugin creates an nginx configuration file with the relevant logic and redirects, so on the “happy path” when the target page is cached, the request doesn’t even touch WordPress’ backend at all.
Disabling Caching for an Endpoint
Based on the above (especially point 2), my train of thought started at “Can I tell W3TC not to cache that author endpoint if a specific header is received?” Looking at the W3TC FAQs, there’s indeed a way to signal that, by disabling e.g. page caching when the plugin (ActivityPub in this case), by setting this inside the code path of the relevant page:
define('DONOTCACHEPAGE', true);
Looking at the source code of the ActivityPub plugin, I could find where in the data flow one would set this, before the author template is returned. I tried it out and seemed to have worked. I’ve even opened a GitHub issue so that hopefully a fix can be developed for everyone!
Looking further in the code (to do that fix), though, it’s not only the “author” page, but silently also all the posts and the front page has the same issue (of getting cached HTML when asking for JSON). 🙀 If one disables caching on author + blogposts + frontpage, what else of note is left cached? Nothing really. And the plugin owner agrees.
Route Request Based on Headers
Let’s try instead routing the request based on headers: if a compatible “Accept” header is received, bypass the cache, and use what he endpoint returns. Here comes the issue about the 3rd point above: the nginx configuration and its use.
Ideally I would be able to add to the config a tests for this header, a check, roughly along the lines of this in nginx config::
if ( $http_accept = 'application/activity+json' ) {
# switch vars not to cache
}Following the installation steps, when Page Caching is enabled in W3TC generates an extra nginx.conf file that governs what happens. There are a lot of various checks (e.g. do not cache on POST requests, do not rewrite paths if the predicted cache file location is empty….) I’ve been following the generated file, and tried to adjust the caching behaviour. To debug, I turned to adding various headers to the response, as it was easier than messing with the nginx logging rules. For example adding this just before the last rewrite rule kicks in would show the variable’s value that would decide if a rewrite happens:
add_header X-gergely-debug "rewrite-$w3tr_rewrite";
Looking at this, in every situation I was getting “no rewrite to do” outcomes, and it wasn’t in the end too much a surprise, as the logic in that file seems to be flawed: generating on disk file locations from the request incorrectly and thus never finding anything (and/or some of my misconfiguration? But there are definitely things which look plain wrong).
But while the nginx rules shrugged, in the same time my web requests were returning the files from disk! If I rewrote the generated files, I got the modified version back. Then, frustrated, even emptied out nginx.conf to try to “break” caching – and it continued to work! 🙃
So I guess the actual behaviour was different from the above 3. point, and rather:
W3TC generates nginx rules and hope that they work and take load off the WordPress backend
If that doesn’t fly, generate the caches internally in the plugin (of course, have to be able to do that on first requests/preloading anyways)
The plugin still checks internally (in code) whether the cached file exists where it expects one on the disk and loads that, bypassing this above point!
I haven’t verified this yet by looking at the code, but this explains all the behaviour I’ve seen while trying things (serving files that I’ve manually changed and working while having an empty nginx rewrite).
So after all, these checks for the Accept header would need to be both in the nginx config (less important for me as it was already broken), and also in the code of W3TC (which feels currently less tractable).
Current and Future Fixes
What I’ve ended up with is the simple and dumb way for now: disable Page Caching altogether.
For my site and level of traffic that should definitely not be a serious issue, though I did check with a site speed test just in case, and I don’t see much difference for my otherwise semi-broken setup.
Still, it’s definitely a step forward not assuming & hoping things are working (ie. nginx-based chaching) when they are not.
What would be good for the future, though, is a pattern where cache plugins only cache what they can and if not pass it on to the rest of the processing (ie. check if the client “Accept” header is empty or defaults to some browser-y value). I bet this is a naive view, and there are more complications. There likely should be more complications if WordPress is more of a “platform”, given then it will have to support a lot more different use cases and behaviours.
Future Rabbitholes
I’m definitely not alone in this quest, there are others who hit various ActivityPub + caching issues (e.g. using CloudFlare CDN). With More Mastodon usage there might be some more satisfying solutions than “disable most caching”.
I’ve definite learned more about WordPress Plugin internals by looking at the ActivityPub plugin’s repo. I’m sure I could pick up some stuff for the 100 Days to Offload plugin in the future.
During debugging I was also looking at my web server logs which I haven’t done for years, but I know would be a “proper” sysadmin thing to do. There were a lot of interesting queries that I want to follow up on (bots, sites, tools scaraping the blog and interacting with various bits). It’s the Internet, after all, so let’s look at the connections made!
#activitypub #mastodon #w3tc #wordpress-plugin
https://gergely.imreh.net/blog/2023/02/when-wordpress-caching-is-not-what-it-seems/
-
Refreshing Airplane Tracking Software With and Without AI
A bit like last time this post is about a bit of programmer hubris, a bit of AI, a bit of failure… Though I also took away more lessons this time about software engineering, with or without fancy tools. This is about rabbit-holing myself into an old software project that I had very little knowhow to go on…
The story starts with me rediscovering a DVB-T receiver USB stick, that I had for probably close to decade. It’s been “barnacled” by time spent in the Taiwanese climate, so I wasn’t sure if it still works, but it’s such a versatile tool, that it was worth trying to revive it.
When these receivers function, they can receive digital TV (that’s the DVB-T), but also FM radio, DAB, and also they can act as software defined radio (SDR). This last thing makes them able to receive all kinds of transitions that are immediately quite high on the fun level, in particular airplane (ADS-B transmission) and ship (AIS) tracking. Naturally, there are websites to do both if you just want to see it (for example Flightradar24 and MarineTraffic, respectively, are popular aggregators for that data but there are tons), but doing your own data collection opens doors to all kinds of other use cases.
So on I go, trying to find, what software tools people use these days to use these receivers. Mine is a pretty simple one (find out everything about it by following the “RTL-SDR” keywords wherever you like to do that :) and so I remembered there were many tools. However also time passed, I forgot most that I knew, and also there were new projects coming and going.
ADSBox
While I was searching, I found the adsbox project, that was interesting both kinda working straight out of box for me, while it was also last updated some 9 years ago, so it’s an old code base that tickles my “let’s maintain all the things!” drive…
The tool is written mostly in C, while it also hosts its own server for a web interface, for listing flights, and (back in the day) supporting things like Google Maps and Google Earth.
The adsbox plane listing interface.Both the Google Maps and Earth parts seem completely: Maps has changed a lot since, as I also had to update my Taiwan WWII Map Overlays project over time too (the requirement of using API keys to even load the map, changes to the JavaScript API…). Earth I haven’t tried, but I’m thinking that went the way of the dodo on the the desktop?
So in the supur of the this-is-the-weekend-and-I-have-energy-to-code moment, I started to think of the options:
- could fix up the map, either with the Google Maps changes, or bring in some other map?
- the project has barely any readme, and I mainly managed to make it work by looking at old articles from the time when
adsboxwaas new, could fix those up? - during the compilation, loads of warnings happened, that seem to call for some “better quality” coding, let’s fix stuff until
-Werror(making all warnings errors) passes too! This would be a learning experience - I’m sure I can find other tasks to do as well, like an error message here, a strange behaviour there…
Here’s the kicker though: I don’t really know C. I spend most of my time in Python-land, and haven’t done a C project in anger yet. Is it worth trying to dig in, while there are other ADS-B projects that a) work better, b) are in languages that I’m more looking to learn, such as Rust?
There was an additional drive of curiosity, just like in my last post: can I use Large Language Models (LLMs) to complement me on things I lack, such as knowledge of the exact programming language at hand?
With this I thought let’s dig in, and let’s dig into the C code: that seemed immediately tractable, more limited in scope, and thus would help build up (hopefully) some successes and I’ll learn my way around the codebase better.
On the LLM side I have GitHub Copilot – though it seems somewhat crippled in my open source Code Server installation of VS Code, rather than the official VS Code, in particular the context menus and Copilot Chat seems missing, and thus it was only communicating with me through TAB-completions and me adding comments to guide or suggest. That’s not very practical, so didn’t push it too far for the relevant tasks of explanation and exploration of options that I wanted to do.
I also have Claude that I can chat with. If I wasn’t working on my 13 year old Lenovo ThinkPad X201, I’d probably set up Ollama, but that’s just excruciating with even the smallest models on this machine (until I upgrade something newer, or run the questions on my work M1 MacBook). So Claude it is for now.
Hello Fixes
I guess it’s one sign of hubris (or unlimited optimism), to jump into fixing compilation warnings, without knowing anything much of the codebase yet. This started in areas where the airplane tracking interacts with SQLite, for example had warnings about casting pointers to integers of different size while shuffling around SQLite query results:
int * t = (int *) sqlite3_value_int(argv[0]);This was also part of a larger code section (formatting integers into hexadecimal or octal strings, for example for the ICAO codes…), and thus had to play around how much context to give to Claude to actually have something useful.
A segment from a discussion with Claude.A bit of mocking around there seemed to have worked, and while I should have asked more software architecture & best practices questions, probably knew about it enough to be dangerous, and left it as it was so far.
Having said that, after this change it turned out that some part of the interface now displaying stuff differently: the 24-bit ICAO airplane registration codes had useless leading zeros for 8 hex digits, rather than the expected 6 digits – since the fix was done without this context. Here we go, manual adaptation on this regression.
Now there were cases when “sprintf may write a terminating nul past the end of the destination“, as the code seems to have written its data back into the same place as this:
sprintf(data->avr_data, "*%s", data->avr_data + 13);This ended up being again about a much bigger context (interative reading, processing, and passing on of recorded ADS-B packets), where based on the Claude’s suggestions I couldn’t really get to anything useful. The real point was always one step further:
- instead of the line look at the nearby lines
- instead of the near by lines, look at the whole funciton
- instead of the whole function, look at the wider codebase with its configuration
These are of course no-brainers. However Claude with its chat interface cannot really do that, while Copilot without its chat interface also cannot do this digging. Catch-22? Since in the end I admitted myself (for the nth time) that I need to understand the purpose of the code better before “fixing” it. Then due to the lack of comments in the codebase + lack of natural intuition of the built in C functions’ behaviour, I’ve just left them as they were for now, since they do work.
From here I turned to other parts. The webserver was not serving some files with the correct MIME type, due to its hand-rolled file extension extraction (splitting filenames at the first
.rather than the last), this was easy to fix – with a bit of StackOverflow this time, rather than asking Claude.Then there was an issue with the tool apparently not playing back the recorded packet data, which I fixed with a combo of regular ol’ debug printouts, StackOverflow, and just thinking about how it could work (it’s the issue of explicitly filling in daylight saving data in the relevant
tmstruct –tm_isdst– and thus IMHO it’s doing a regular “undefined” behaviour: in this case jumped the first timestamp’s time ahead by an hour, and thus would have needed to wait an hour to pass as the playback (following the real timingof the packets) catch up and start actually replaying. Still weird, why only the first packet’s data was shifted, and could I do a more solid fix than setting it once as the code never seem to overwrite it? These are the questions that are more addressing C-knowledge or potential best practice of the code’s structure overall…Finally I’ve started on replacing Google Maps with OpenFreeMap and got as far as displaying the map (which is the easy step:). The whole replacement would likely be a lot more, also given the amount of barely documented JavaScript code in the project – but hopefully I have more working knowledge of JS than C.
Lessons Learned
First lesson is that I likely have a “saviour complex”, trying to fix up every code I see being imperferct in some way, whether or not I am capable of doing it or not. This is something to meditate further on for sure.
When using LLMs for code work, they are just as useful as another mid-level coder without much context – almost not at all. The context of code is always relevant, so either the LLM would have to get it itself, or the person pairing with the LLM would have to provide it. Thus the work is always there, just not always possible.
It’s very nice that I can do things in programming languages that I don’t really understand, but that’s only the case if I either spend much-much time actually getting to know things so I can start to judge whether the changes even have a chance to be correct or not; or I don’t care whether they are correct or not (but is this really an option?)
Overall the LLMs need the same things as humans to do a good job, and cannot pretend that they really can do work without these (even if they might appear being able to do without these for some time):
- good comment in the code so the intention can be ascertained as well
- tests that show what the correct behaviour should be, and catch regressions or unintentional breakages
- have domain knowledge to form better mental models about what should happen
The first two wasn’t true in this project. The last point is likely where LLMs are ahead in cases like this (having been trained on “all the Internet’s data”), though wouldn’t be the same for some niche, or work internal projects.
The LLMs suggestions are still ver much localised, thus they cannot really fix up the structure of the code too much – or maybe I’m not using the right tools, of course. And this is where my future big ask would lie: don’t just tell me how to fix this line, rather tell me that the entire block is no longer needed / could be merged with another part of the code / could be broken out to its own module that would help over there… Of course, this is moving the goal post a bit of what LLM programmers’ look like, though I also think that the current “fix this line” is something I most definitely want to have enough practice with that I don’t really need to ask (though it could suggest if there are good practices I haven’t picked up yet).
Where do I go from here?
This adsbox project is mostly obsolete, as I’ve found a bunch of other tools that are better, and better supported now (adsb_deku, tar1090), but surprising it still have stuff that are better here and in other tools (the plane’s status icons, some data displayed here that is not in others, showing what sort of packets (what Downlink Format or DF numbers) were received for the aircraft, etc… So there might be still value in using it occasionally, so there might be value.
Even if I could get a kick out of it, it’s likely useful to keep things time-boxed or constrained to some topics: change the map; add comments as I find them; fix issues if they arise; package it up for ArchLinux. That’s about it, but these should be generally useful (e.g. using OpenFreeMap for other projets in the future or rewriting the aforementioned Taiwan WWII Map project to use that).
My current fixes live in my fork in GitHub imrehg/adsbox, with no guarantees. Since the project also doesn’t have a license (just a note of “free for non-commercial use”, which doesn’t cover modifications), I’m probably keeping it simple for now.
I also got the hang of software defined radio again, and there’s just so much fun to have…
What’s the most useful is seeing in practice, what does software need to be maintainable almost a decade later, and what’s missing in most projects: explanatory comments to understand what is being done and why, and tests to know whether things are running correctly or not. And maube then both my future self, my colleagues, and any potential AI pair programmer would have a better chance of succeeding at “maintain all the things!”
-
Refreshing Airplane Tracking Software With and Without AI
A bit like last time this post is about a bit of programmer hubris, a bit of AI, a bit of failure… Though I also took away more lessons this time about software engineering, with or without fancy tools. This is about rabbit-holing myself into an old software project that I had very little knowhow to go on…
The story starts with me rediscovering a DVB-T receiver USB stick, that I had for probably close to decade. It’s been “barnacled” by time spent in the Taiwanese climate, so I wasn’t sure if it still works, but it’s such a versatile tool, that it was worth trying to revive it.
When these receivers function, they can receive digital TV (that’s the DVB-T), but also FM radio, DAB, and also they can act as software defined radio (SDR). This last thing makes them able to receive all kinds of transitions that are immediately quite high on the fun level, in particular airplane (ADS-B transmission) and ship (AIS) tracking. Naturally, there are websites to do both if you just want to see it (for example Flightradar24 and MarineTraffic, respectively, are popular aggregators for that data but there are tons), but doing your own data collection opens doors to all kinds of other use cases.
So on I go, trying to find, what software tools people use these days to use these receivers. Mine is a pretty simple one (find out everything about it by following the “RTL-SDR” keywords wherever you like to do that :) and so I remembered there were many tools. However also time passed, I forgot most that I knew, and also there were new projects coming and going.
ADSBox
While I was searching, I found the adsbox project, that was interesting both kinda working straight out of box for me, while it was also last updated some 9 years ago, so it’s an old code base that tickles my “let’s maintain all the things!” drive…
The tool is written mostly in C, while it also hosts its own server for a web interface, for listing flights, and (back in the day) supporting things like Google Maps and Google Earth.
The adsbox plane listing interface.Both the Google Maps and Earth parts seem completely: Maps has changed a lot since, as I also had to update my Taiwan WWII Map Overlays project over time too (the requirement of using API keys to even load the map, changes to the JavaScript API…). Earth I haven’t tried, but I’m thinking that went the way of the dodo on the the desktop?
So in the supur of the this-is-the-weekend-and-I-have-energy-to-code moment, I started to think of the options:
- could fix up the map, either with the Google Maps changes, or bring in some other map?
- the project has barely any readme, and I mainly managed to make it work by looking at old articles from the time when
adsboxwaas new, could fix those up? - during the compilation, loads of warnings happened, that seem to call for some “better quality” coding, let’s fix stuff until
-Werror(making all warnings errors) passes too! This would be a learning experience - I’m sure I can find other tasks to do as well, like an error message here, a strange behaviour there…
Here’s the kicker though: I don’t really know C. I spend most of my time in Python-land, and haven’t done a C project in anger yet. Is it worth trying to dig in, while there are other ADS-B projects that a) work better, b) are in languages that I’m more looking to learn, such as Rust?
There was an additional drive of curiosity, just like in my last post: can I use Large Language Models (LLMs) to complement me on things I lack, such as knowledge of the exact programming language at hand?
With this I thought let’s dig in, and let’s dig into the C code: that seemed immediately tractable, more limited in scope, and thus would help build up (hopefully) some successes and I’ll learn my way around the codebase better.
On the LLM side I have GitHub Copilot – though it seems somewhat crippled in my open source Code Server installation of VS Code, rather than the official VS Code, in particular the context menus and Copilot Chat seems missing, and thus it was only communicating with me through TAB-completions and me adding comments to guide or suggest. That’s not very practical, so didn’t push it too far for the relevant tasks of explanation and exploration of options that I wanted to do.
I also have Claude that I can chat with. If I wasn’t working on my 13 year old Lenovo ThinkPad X201, I’d probably set up Ollama, but that’s just excruciating with even the smallest models on this machine (until I upgrade something newer, or run the questions on my work M1 MacBook). So Claude it is for now.
Hello Fixes
I guess it’s one sign of hubris (or unlimited optimism), to jump into fixing compilation warnings, without knowing anything much of the codebase yet. This started in areas where the airplane tracking interacts with SQLite, for example had warnings about casting pointers to integers of different size while shuffling around SQLite query results:
int * t = (int *) sqlite3_value_int(argv[0]);This was also part of a larger code section (formatting integers into hexadecimal or octal strings, for example for the ICAO codes…), and thus had to play around how much context to give to Claude to actually have something useful.
A segment from a discussion with Claude.A bit of mocking around there seemed to have worked, and while I should have asked more software architecture & best practices questions, probably knew about it enough to be dangerous, and left it as it was so far.
Having said that, after this change it turned out that some part of the interface now displaying stuff differently: the 24-bit ICAO airplane registration codes had useless leading zeros for 8 hex digits, rather than the expected 6 digits – since the fix was done without this context. Here we go, manual adaptation on this regression.
Now there were cases when “sprintf may write a terminating nul past the end of the destination“, as the code seems to have written its data back into the same place as this:
sprintf(data->avr_data, "*%s", data->avr_data + 13);This ended up being again about a much bigger context (interative reading, processing, and passing on of recorded ADS-B packets), where based on the Claude’s suggestions I couldn’t really get to anything useful. The real point was always one step further:
- instead of the line look at the nearby lines
- instead of the near by lines, look at the whole funciton
- instead of the whole function, look at the wider codebase with its configuration
These are of course no-brainers. However Claude with its chat interface cannot really do that, while Copilot without its chat interface also cannot do this digging. Catch-22? Since in the end I admitted myself (for the nth time) that I need to understand the purpose of the code better before “fixing” it. Then due to the lack of comments in the codebase + lack of natural intuition of the built in C functions’ behaviour, I’ve just left them as they were for now, since they do work.
From here I turned to other parts. The webserver was not serving some files with the correct MIME type, due to its hand-rolled file extension extraction (splitting filenames at the first
.rather than the last), this was easy to fix – with a bit of StackOverflow this time, rather than asking Claude.Then there was an issue with the tool apparently not playing back the recorded packet data, which I fixed with a combo of regular ol’ debug printouts, StackOverflow, and just thinking about how it could work (it’s the issue of explicitly filling in daylight saving data in the relevant
tmstruct –tm_isdst– and thus IMHO it’s doing a regular “undefined” behaviour: in this case jumped the first timestamp’s time ahead by an hour, and thus would have needed to wait an hour to pass as the playback (following the real timingof the packets) catch up and start actually replaying. Still weird, why only the first packet’s data was shifted, and could I do a more solid fix than setting it once as the code never seem to overwrite it? These are the questions that are more addressing C-knowledge or potential best practice of the code’s structure overall…Finally I’ve started on replacing Google Maps with OpenFreeMap and got as far as displaying the map (which is the easy step:). The whole replacement would likely be a lot more, also given the amount of barely documented JavaScript code in the project – but hopefully I have more working knowledge of JS than C.
Lessons Learned
First lesson is that I likely have a “saviour complex”, trying to fix up every code I see being imperferct in some way, whether or not I am capable of doing it or not. This is something to meditate further on for sure.
When using LLMs for code work, they are just as useful as another mid-level coder without much context – almost not at all. The context of code is always relevant, so either the LLM would have to get it itself, or the person pairing with the LLM would have to provide it. Thus the work is always there, just not always possible.
It’s very nice that I can do things in programming languages that I don’t really understand, but that’s only the case if I either spend much-much time actually getting to know things so I can start to judge whether the changes even have a chance to be correct or not; or I don’t care whether they are correct or not (but is this really an option?)
Overall the LLMs need the same things as humans to do a good job, and cannot pretend that they really can do work without these (even if they might appear being able to do without these for some time):
- good comment in the code so the intention can be ascertained as well
- tests that show what the correct behaviour should be, and catch regressions or unintentional breakages
- have domain knowledge to form better mental models about what should happen
The first two wasn’t true in this project. The last point is likely where LLMs are ahead in cases like this (having been trained on “all the Internet’s data”), though wouldn’t be the same for some niche, or work internal projects.
The LLMs suggestions are still ver much localised, thus they cannot really fix up the structure of the code too much – or maybe I’m not using the right tools, of course. And this is where my future big ask would lie: don’t just tell me how to fix this line, rather tell me that the entire block is no longer needed / could be merged with another part of the code / could be broken out to its own module that would help over there… Of course, this is moving the goal post a bit of what LLM programmers’ look like, though I also think that the current “fix this line” is something I most definitely want to have enough practice with that I don’t really need to ask (though it could suggest if there are good practices I haven’t picked up yet).
Where do I go from here?
This adsbox project is mostly obsolete, as I’ve found a bunch of other tools that are better, and better supported now (adsb_deku, tar1090), but surprising it still have stuff that are better here and in other tools (the plane’s status icons, some data displayed here that is not in others, showing what sort of packets (what Downlink Format or DF numbers) were received for the aircraft, etc… So there might be still value in using it occasionally, so there might be value.
Even if I could get a kick out of it, it’s likely useful to keep things time-boxed or constrained to some topics: change the map; add comments as I find them; fix issues if they arise; package it up for ArchLinux. That’s about it, but these should be generally useful (e.g. using OpenFreeMap for other projets in the future or rewriting the aforementioned Taiwan WWII Map project to use that).
My current fixes live in my fork in GitHub imrehg/adsbox, with no guarantees. Since the project also doesn’t have a license (just a note of “free for non-commercial use”, which doesn’t cover modifications), I’m probably keeping it simple for now.
I also got the hang of software defined radio again, and there’s just so much fun to have…
What’s the most useful is seeing in practice, what does software need to be maintainable almost a decade later, and what’s missing in most projects: explanatory comments to understand what is being done and why, and tests to know whether things are running correctly or not. And maube then both my future self, my colleagues, and any potential AI pair programmer would have a better chance of succeeding at “maintain all the things!”
-
Making a USB Mute Button for Online Meetings
I use Google Meet every day for (potentially hours of) online meetings at work, so it’s very easy to notice when things change and for example new features are available. Recently I’ve found a new “Call Control” section in the settings that promised a lot of fun, connecting USB devices to control my calls.
Google Meet Settings menu during a call, witht the Call control section
As someone who enjoys (or drawn to, or sort-of obscessed with) hacking on hardware, this was a nice call of action: let’s cobble together a custom USB button that can do some kind of call control1: say muting myself in the call, showing mute status, hanging up, etc.
This kicked off such a deep rabbit hole that I barely made it back up to the top, but one that seeded a crazy amount of future opportunities.
And as a shortcut, there’s a demo below to showcase where I got to.
Finding suitable hardware
This step was harder than I’ve expected, given that I have drawers and drawers of gadgets, but I’m likely a bit out of practice, and also out of date. What I was looking for is
- Being able to show up as a USB device (must)
- Have built in button (optional) or easy connectivity of buttons without breadboard for now
- Have built in LED (optional) or some other way of showing 1 bit of information
This doesn’t sound hard, right?
ReSpeaker
The first option that came up was Seeed Studio’s ReSpeaker Core that I had two of at hand: Arduino Leonardo compatibility, touch sensors for buttons, and an LED ring (the “Pixel Ring”). Turns out that they have been discontinued – which should be fine for now; but also my models are two different pre-release prototypes Seeed gave away for testers. Thus they are not quite like the final version, have different hardware on board here and there, so an experimental experience is expected.
ReSpeaker core samples to work with
The earlier prototype only has touch sensors on one side, the pixel ring lights up, but I couldn’t control it with Seeed’s ReSpeaker Arduino library. The later prototype has two sides of sensors (effectively two buttons), but the lights don’t seem to work2. Regardless this
Aside: alternatives considered
It was illuminating to see how much abandoned, obsolete, discontinued, or not quite useful hardware boards do I have.
One is RFDuino, that I got from Kickstarter, I’m yet to use, and all the project’s websites have already disappeared – fortunately not the code repo. This would have been a more complex solution anyways, but wireless! Use one RFDuino to expose a USB Telephony device, and communicate wirelessly to another that operates the light and button on battery. Pretty cool. Also, it might not have worked if the chip used cannot do the cruicial “expose a USB [device]” part of the plan.
Other option that popped up was an Arduino Nano + my own made GroveHat + a Grove Button. Except, the Nano definitely cannot be a custom USB device, so there goes nothing.
Besides these, I’ve found plenty of:
- single board computers (old or obsolete),
- FPGAs (never used, and would be a whole different project to implement something on them), and
- other microcontrollers that all have interesting specialties, but don’t tick the mandatory boxes…
These boards might not be right for now, but definitely there are projects in store for them (if only thre’s time).
Back to ReSpeaker then…
Plugging in the USB
The next thing is to figure out what’s really happening when an USB device is plugged in and it shows the operating system that it can do certain things. That is, how does Meet know that there’s a compatible device to connect to?
The USB HID docs
This is answered by the USB Human Interface Devices (HID) specs — one that is pretty complicated, has a lot of legacy bits, and need a different kind of mindset. In a nutshell, though, with my current, partial understanding:
On connection the device sends a “report” to the OS that details on what can it do, including:
- what kind (or kinds!) of device it is?
- what functionality of the kind is available in this particular implementation?
- what’s the data layout to pass control information back-and-forth for this implementation?
In our example, a very minimal setup would would be:
- I’m a Telephony Device (Usage page 0x0B)
- I implement a generic “Phone” (Usage ID 0x01)
- I have capability to do a “Phone Mute” (Usage ID 0x2F)
- Here’s the 1 bit of a 1 byte payload that conveys that phone mute status
Getting started with Telephony devices from the HID Usage Tables
This course does not take into account other functionality, e.g.
- I can also hang up – Hook Switch, Usage ID 0x20;
- I have status LEDs – that’s a whole fun of redefining functions on the LED Page 0x08;
and so on. But for the time being this should be enough.
Call Control functionality for Telefony devicesDevice implementation
Fortunately we can stand on the shoulders of giants, that is the Arduino HID Project which implemented a bunch of different devices. And even though a “phone” like this is not among them, we can make some reasonable guesses how it would work.
Having said that, from a forum post that was also trying to do something similar (but based on the TinyUSB library):
HID report descriptor is very difficult thing to come up by oneself. You should google around, or dump report descriptor from existing device to copy/follow it.
Okay, then do not come up with this stuff, instead let’s look for tools. The USB HID homepage links to the Microsoft HID Tools to generate HID reports from a TOML-like language. Except it needs C# and I just wasn’t ready to dive in a side-quest to install & learn a new toolchain.
So being lazy this way, a bit more sleuthing turned up someone’s example HID report for a device very close to what I’m trying to do, hurray!
I took this and started to poke around the HID project to see how other devices are implemented. Troubleshooting by using the ReSpeaker’s touch to adjust screen brightness up / down (as a “Consumer Device”) was also pretty neat! In the end I took the system buttons example and run with that one.
Having said that, the HID report is really just the interface. The devil is in how to implement actually creating the data packages that passes data according to the report definition. And this is the case when I wish I knew more C++ but copy-paste and some guesswork will have to do.
Our minimal viable mute button’s HID report (source)
The current result lives in the “phone” branch of my HID Project fork, check for the “Phone” bits in “src/HID-APIs” and “MultiReport” folders, if interested.
Minimal viable mute
The implementation from this point on was pretty straightforward – since we cut back the scope so much…
The code to run on the ReSpeaker then just has to do the following:
- when touching one side, send a report with “Phone Mute” on
- when touching the other, send a report with “Phone Mute” off
And this is sort of simple3 :
Sending data on touch events in the simplest way
For the full use case there would be a lot more complexity for both reading and writing data from the host, controlling multiple peripherals (LEDs and buttons) and the whole logic around it. But for now, it’s good enough for a demo:
A very quick demo
The code repository is available on Github at imrehg/arduino-usb-phone-hid.
Notes and Future workThe specs
It’s great that stuff from 20+ years ago still works mostly the same way. The latest 1.4 version of the HID Tables is nicely formatted, has a lot more device typed defined, but has much less support text. Originally I’ve read the 1.12v2 version as that showed up in my search. Back then in 2004 they had an “examples” section (see the Telephone at Appendix 10!) which is useful to grok more of the fundamentals.
The newer version also has some devices types that looked suitable, but weren’t really: Generic Desktop Page (0x01) and 0xE0-E2 Usage IDs for Call Active LED, Call Mute Toggle, and Call Mute LED respectively. These didn’t seem to work with Meet, so it might be interesting to try implementing a device that does both and try other online call software.
I should also have read the spec more before diving into hacking on the HID implementation fork, as there’s a lot more information in the HID Device Class Definition, including how to construct the values for many of the fields (I’m looking at you “INPUT (Cnst,Var,Abs)“). RTFM is and remains a solid advice – and not just when one thinks there’s time.
Also regarding the specs: some of them I only find in the Internet Archive’s Wayback Machine. If you encounter a good source that should be kept, always add it to the Wayback Machine and preserve it for your future selves and others!
This exploration of USB HID pulled on so many threads, and left so much unfinished, that it’s a fertile ground for the future, even more than most previous projects.
More call functionality
The most obvious thing is to implement the whole setup with the buttons. I’ve tried Hook Switch to hang up a call, that works too. Could add status lights, maybe throw in some “Active Call” LEDs, or so on. This requires better understanding how data is sent over the wire for USB and how to handle incoming data. The Arduino examples rarely seem to use the “Output” fields (ie. incoming data, output from the host’s point of view, but maybe TinyUSB does ?
For this, it would be nice to find a different hardware platform that would make this more seamless (so I can concentrate on the software side more). If that platform would lend itself to be reproduced or made stand alone, that would be even nicer: imaging brining my little call control box that can be used with other computers easily as well…
Implement more USB HID devices
The Arduino HID project has a bunch of devices implemented, but there are an infinite numbers that could be added. Unfortunately for Arduino it is harder to add more device types as an add-on to this library versus the current “forked” approach4, so new decices should be in the main project, eventually.
So far there’s no Telephony device implemented there and it would be nice to find the right level of abstraction that works. The library doesn’t implement specific HID table pages, but specific usages or a subset of a usage. Thus like always, the hardest part would likely be setting the right interface (the right specs and “API”) for a new device to implement both the HID reports and the functions that manipulate what’s being sent and when.
On the other hand, that does sound like a fun experiment, and I’d look forward to adding 3D Game Controllers (Game Controls Page 0x05), Environmental Sensors (Sensors Page 0x20, Usage ID 0x30-3B), … or even a Submarine Simulation Device (Simulation Device page 0x02, usage id 0x05). These are stuff I go to Hackerspaces for…
WebHID for internet plus USB
While debugging this HID device behaviour, I found also WebHID that brings such devices to the web. This feature seems to be behind Meet’s and other phone systems like 3CX expanding USB support outside of the OS and into the browser. And no, Firefox does not support it, furthermore declined supporting it.
Nonetheless it’s very cool that (if I upskill a bit), I can create a web page that would help me debug such HID development:
- request devices that are filtered in various ways (vendor, product is standard, but usage page and explicit usage is the main key). This is likely what Meet does as well, “just gimme devices with Telephony usage page (or Phone usage? Need to check exactly)
- read the HID report collections sent by the device, so the results can be debugged, and
- read device input events that we can then either log for debugging or in an application react to to it
This opens a lot more mashup opportunities by the dozen.
Finally
Unlike most other projects I had where I’m focused on one specific outcome, this turned out to be more focusing on getting a new toolkit (custom USB devices) up and running, so I can think about a wider types of projects to do. In that sense, this feels a big success, even if I know how little I know about programming outside of my day-to-day environment. But ignorance is not a bliss.
And now, going on mute.
- Many moons past I used to use a Jabra Evolve 80, that has a USB accessory controlling call features, so I did have first hand example of what sort of experience I’d like. ↩︎
- I’ve tried reviewing the hardware schematics, looking into the pixel ring control functions, and given that the LEDs seems standard I’ve also attempted to use the FastLED library to drive them instead, so far nothing. I still bet on hardware differences from final schematic + my inability to debug it, but it can be faulty hardware just as well. Needs more effort – in the future. ↩︎
- The Arduino code became more “simple” once I realised that things set up this way do not need debouncing for the touch sensors. In other cases that would be essential, there’s sooo much flaky signal to use those terminals as momentary switches or similar. ↩︎
- At least I don’t know how nicely extend a library for C++, if that’s even possible. Keen to learn, though. ↩︎
#arduino #c #seeed-studio #usb #usb-hid #maker #prog
Original post: https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/
-
RE: https://famichiki.jp/@lukas/116654850042061656
Would be nice to have more remote roles in the wider Asia region too. Taiwan represent!
-
Just finished Look Again by Tali Sharot and Cass R. Sunstein.
Wasn't what I've expected from the title/subtitle, but that's fine in the end.
It was about habituation, it's many forms, and when it does & doesn't work, and when is it helpful or harmful.It's a pretty fast read, and I don't think there were many thing that were new (for me), but it was put together effectively.
One outcome: I'll try my best not to habituate to - and thus tolerate - bad shit around me.
https://www.simonandschuster.com/books/Look-Again/Tali-Sharot/9781668008218
-
I'm back and it's weird.
-
RE: https://masto.ai/@transworld/116617650000346898
I can barely fathom, how people come with such things, not even sure fueled by what? Dislike? Discomfort? The idea of potential discomfort if someone else can and does express themselves?
And when you contort yourself into self-contradictions arguments to make things work (as it seems in this analysis), that should be the sign to stop, as your premises might be (very) wrong...
-
One way to fix my doom-scrolling: having to leave my phone at the Sony service centre for 3-5 workdays, and not having a replacement phone.
See ya! 👋 -
Note to self, because this was a couple of hours debug, and it didn't need to be...
https://gergely.imreh.net/blog/2026/03/tableaus-3834d197-error-pivot-tables-in-google-sheets/
-
Aebleskriver in takoyaki shapes due to the lack of purpose-built pan: check. #hygge
-
A 117 day run with #AntimatterDimensions What a ride/roller-coaster/battle...
We'll meet again
Don't know where, don't know when
But I know we'll meet again some sunny day -
Here we are, two years later, and I definitely didn't (properly) kick #AntimatterDimensions
I'm not sure that it's a good sign that I got further this time so far - and also learning a bunch of life-lessons from it. At least that's how I interpret the fallout of this binge 😅
-
I really appreciate that pep talk, Antimatter Dimensions, yes, I can stop now, I could stop now, I really need to stop now. And somehow probably I won't. 🫠
https://ivark.github.io/AntimatterDimensions/ #AntimatterDimensions
-
Go, go, Relatable Raven! #MrLovenstein
-
Just updated my #ArchLinuxARM system, and zsh was hanging on login.
Fortunately I could get in through ssh and forcing bash. Rebuilding zsh-5.9-5 locally (while disabling architecture checks) fixed things up.
Very much suspect, that the re-built package is maybe 30% larger (+2MB to a total of 8MB) than the one from the offical repos, did something go wrong with the official builds?
So far the ARM-version broke more things for me, than the official #ArchLinux team, so hm....
-
If it's the weekend, let's code a bit and write a lot about the little coding that was done...
https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/
-
If it's the weekend, let's code a bit and write a lot about the little coding that was done...
https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/
-
If it's the weekend, let's code a bit and write a lot about the little coding that was done...
https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/
-
If it's the weekend, let's code a bit and write a lot about the little coding that was done...
https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/
-
If it's the weekend, let's code a bit and write a lot about the little coding that was done...
https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/
-
Done a new #ArchLinux package, "abctl" to control local #Airbyte installations.
https://aur.archlinux.org/packages/abctl
This was the first one in a long while, had to look up a lot of things about PKGBUILDs again...
-
I fully endorse & recommend #Mykita glasses 🤓.
Mine just took a full slap in the face, flown across the room, landed, looked like a broken bird but was back in service in a minute. That is some resilient eyewear, and I am glad because it wasn't cheap.
-
Setting up Fastmail with my domain to migrate the interesting parts of my communication from Gmail, and KonMariing the heck out of it, there goes 20k various notifications & other garbage 🚮. Let's ♻️ that disk space :) #WinterCleaning #KonMari
-
Never been not relevant.
James Acaster tells it how it is.https://youtu.be/x73PkUvArJY?si=m-fgQEnf91kJLYhC
#JamesAcaster #BritishMuseum #ElginMarbles current news. So, keep looking at the stuff! :)
-
New Boozoo Bajou, and it's beautiful...
I <3 Tough Times, but all others too.
-
@shu_wang_gong I think it's a given that Churchill's memoires are branding for him, in sort of a "you tell your story the way you want it to be heard, or someone else will tell it in a way you won't like it one bit" manner...
On the other hand, I don't expect anything less from Chiang however little I know about him. He strikes me as a person who'd totally lie to himself (drink his own kool-aid). And just because there is not other audience... there is, just not explicitly.