MU|TH|UR v1.5 - PTT and two Telegram bots

Back when we ran High Frontier: The Drake Objective in 2024 I used a Raspberry Pi to turn Telegram messages into the "sad computer voice" prevalent in sci-fi movies.

This was a surprise hit in the game but there were a few problems...

  • One of our players is very hard of hearing - so unable to engage with much pure audio content
  • It's really easy to miss random out of the blue messages from a walkie-talkie unless you're actively engaging with it in the moment. Doubly so if somebody is talking to you in person at the time. We were asked to repeat messages all the time.
  • It used voice activation on the walkie-talkie doing the transmitting which wasn't totally reliable and it would occasionally clip the start of messages despite making a "beep" before talking
All of these were related to me just bashing it together in the fortnight before the event while also working on other stuff.

For High Frontier: The Weyland Factor we wanted to fix these and perhaps also have it transcribing incoming messages from the walkie-talkies for MU|TH|UR v2.0.

I started on the update then quickly decided to drop the transcription and constrain the project to just fixing the acknowledged problems before doing something that could suck a load of time and effort. 

The frequency range of audio transmitted by PMR walkie-talkies is limited and it can be hard for a person paying attention to distinguish speech sometimes so I surmised automated transcription would do more poorly, even the cloud based 'AI' version of it.

My original version had a single Telegram bot that was part of a group chat with a simple command interface. The event GMs could chat in the group normally but anything prefixed with the command "/say" would be turned into speech and sent to the PMR. The bot was just one of Telegram's example bots and Microsoft's Azure speech to text example smushed together, but it worked well. With no WiFi on-site I relied on a 4G dongle I had kicking around that "just worked" in the Raspberry Pi.

Everything looks like a nail

As Telegram worked well for the GM group and I had a load of Android tablets with LTE modems from other events, the obvious way to give the players a text channel to interact with MU|TH|UR through was just another group chat in Telegram.

While I had physical carry cases for the tablets the interface couldn't be skinned to be "diegetic" with the time I had. They just had some Android Tablets and Telegram but this is not an immersion destroying thing and to do anything else would have been a big pile of work. A custom Android app or Progressive Web App is something that's in my wish list for the future but wasn't realistic for this event.

So with two chat groups that created a requirement for two bots if I wanted to "separate control messages from user messages" which is a good design pattern even though this isn't exactly a highly sensitive application.

Two bots, one script

All the main Telegram bot Python examples are for one bot, which is fair enough. I am not a Python programmer and quickly found that the 'blocking but async event driven' default way of writing bots with the common library is inimical to running two bots at once. Well not exactly but you then can't use the 'convenience' methods and have to engage with the Telegram API at a lower level. Several people have asked for a multiple bot example but the library maintainer's response was of the vaguely dismissive "read the docs/now draw the rest of the owl" variety. Likewise lots of other responses kicking around on a search have pseudocode partial examples that just didn't run even when I tried to fill in the blanks.

So, sledgehammer to crack a nut time and I quickly taught myself how to use the multiprocessing library in Python. Wasteful but it's only a Telegram bot talking to webhooks on a system with one job to do. The two bots talk to each other via a multiprocessor Queue: player messages are passed to the GM bot and GM messages intended for distribution are passed to the player bot. Not unexpectedly there seems to be a lot of subtlety about whether certain things are thread safe in Python when using the async.io method the Telegram library uses itself. I think using the multiprocessing library and its own inter-process communication method insulates me from that but like I say I'm no Python programmer, my usual playground is C++ and FreeRTOS.

While I was doing this I added a tiny bit more subtlety to the control. Messages prefixed "/say" would go to the player group chat as well as being broadcast as speech. Messages prefixed "/send" would just go to the group chat. This was a speculative feature but ended up being useful.

Push to talk

There's no standard for connecting things to PMR walkie talkies but they do share a kind of common pattern. I used the same circuit as I did for MU|TH|UR v1 to match impedance/levels and added in a relay that grounds the 'tip' connection when you want to transmit.

From this it was simply a case of triggering a GPIO pin before 'speaking' to latch the relay and then release it afterwards.

The end result meant triggering the PMR was now much more reliable and receiving PMRs received the messages more consistently.

When 3G is no longer enough

With not long to go I had it all working and plugged in the dongle to do a bit of a final test. Which then stubbornly refused to work. I spent far too long trying to troubleshoot this, cursing bitrot and version creep in Raspbian but when it occurred to me to try the dongle in my laptop it didn't work there either.

Despite being listed as "4G" in some specs that show up when you search it turns out the dongle I'd been using for ages was actually some variant of 3G that the big switchoff made non-functional. Well it did come from e-waste, which is where it'll go back to. I've got an otherwise usable phone with the same problem.

This prompted a quick panic order of a Waveshare SIM7600G-H dongle from PiHut. There's a certain clunkiness to it as it's intended for industrial/hobbyist use rather than consumers but that at least means no weird gimped branded up firmware and at least some technical information on their Wiki.

Getting it working was definitely not a consumer job, sending AT commands over a USB serial port and then having to reconfigure Network Manager in Raspbian to not set the DNS servers: another frustrating half day rabbithole but with it configured it connects quickly and reliably. The external antenna probably helps.

As it's also possible to use this via an onboard UART I may see if I can use this from embedded hardware like an ESP32 but that's a project for another time.

Sticking it in a box

The new dongle and external antenna meant there was no way the original enclosure where I repurposed an external mains socket box was going to work any more.

So I settled on using a 9l "Really Useful Box" and 3D printed a mounting plate for it all. There's also a fascia with a status LED, a button to shutdown/restart it and some places to cable-tie the cables in place to stop them getting yanked out of the internals. The box isn't properly waterproof long term but will stand use outdoors for the couple of days at a time that we need it.

All the external leads are hugely long. It's powered from a 12v lead-acid battery which needs tucking away somewhere safe and the PMR used to transmit needs some height to help with coverage and ends up tied to a pole high up.

Sometimes the wrong thing is the right thing

Once I'd reached this point of it working reliably and was thinking about how we'd use it in the game it popped into my head we could use What3Words to send the player group directions.

I'm no fan of this attempt to do corporate capture of something there should be an open standard for (there is one but it is a tad clunky) and the failings of their word choice algorithm for safety critical situations have been explored extensively by people smarter than me. However in this case, smacking the W3W app onto the tablets the players were already carrying and then sending locations into the chat as a clickable link that opened the app was a fair choice and we'd used it a little in the past.

Until the event I didn't even get to test it, and when we started using it the "/send" option where MU|TH|UR didn't read out the words was needed because otherwise it was a tide of unintelligible blah when we forgot.

Much as I have reservations about W3W it worked mostly OK for this, only once sending them in completely the wrong direction which was probably a GM mistake, and I think we'll be using this again next year.

Want to build your own?


I've now backed this all up and once I've had time to write an "installer" of sorts I'll update the previous instructions on GitHub.

Looks like love at first sight to me

Recently we finished up our four-episode LARP series, High Frontier: Gods and Monsters, which has been stuck in my consciousness ever since mid-2019. The pandemic delayed the first episode but we've run one episode a year since 2022 and it felt like I always had something for it on my to-do list.

Despite being set in our variant of the Alien/Prometheus universe we had not so far featured any Xenomorphs in the game and that was about to change.

An obvious way to signal this in advance is to feature the iconic visual of a Facehugger in a huge glass tube. I've been meaning to make one of these for years and had an earlier version that never really worked I junked.

Buying a large enough clear tube for the task was something I looked at over time but anything the right size was simply outside our prop budget. Knowing we really wanted this in the game I decided to bend a sheet of 3mm acrylic. How hard could it be?

Turns out it was quite hard.

I picked up a 1800x900mm 3mm acrylic sheet and used this halved as my basis to scale everything else, allowing me to make two tubes.

Not being an RPF level prop maker all my stuff just needs to look "about right". I always prioritise it being repeatably makeable and able to stand transport and handling by random people in the LARP.

You can bend acrylic with heat and last time I need to do larger pieces for ORAC I put them in an oven, which worked fantastically. Short of asking a local bakery nobody has an oven that's going to take square sheets this large. Which meant progressive use of a hot air gun was about the only option open to me.

Having done the calculation on the size of tube this would make it turned out I had a large cardboard tube close so I clamped the acrylic to this and repeatedly formed the sheets over this in a process that ended up taking a couple of days.

Meanwhile I found some reference photos of the original props and started doing a rough replica in CAD for 3D printing. There's a reason I own a large format bed slinger 3D printer, it's slow unfashionable and fairly low quality but it allows me to print larger items like this.

Some time back I had found a 3D poseable printable model of a Facehugger model and had printed all the parts for a couple as I'd planned to make two tubes. These ended up being really quite difficult to assemble even when following the printing instructions. The joints are super tight and even with careful printing on my newer printer and some sanding of the 'knuckles' they were prone to snapping when forced together. In the end I think I printed enough to make three and managed to get two completed ones.

I'd designed the top/bottom sections that hold the tube with a small groove in that should hold the acrylic into its tube shape and make the whole thing kind of seamless so as I got the first pieces off the printer I started to assemble things. Here I realised my mistake, I could see the tube wasn't perfect but 'almost round' and hoped constraining it into the printed pieces would even things out. Getting frustrated I tried to force it in and snapped a large corner chunk off, acrylic is quite brittle.

So we were down to one tube and I spent yet more hours trying to get that acrylic tube properly round.

The two Facehuggers got a rudimentary paint job. I'm a fan of heavy coats of generic DIY emulsion paint and varnish to cover layer lines on organic shapes and it worked out OK. The second Facehugger would still end up getting used laid out on a table.

The top and bottom sections got proper priming and sanding as they needed to look like metal close up.

When I came to fit the remaining tube, despite spending a long time bending it I still struggled to get it to fit, even with constraining it with straps and now realise I should have put a bevel in at least the inside of the slot it's supposed to fit otherwise it's just too hard to do singlehanded. With the LARP only a week away I didn't have time for a second costly mistake so I just taped the tube outside the top/bottom sections and up the back to cover the now large gap. I know it's not right but in the final analysis the players just saw a cool large prop so it did the job.

People with a decent memory of the original will see the control panel piece in the top section never got modelled and printed. I hit "perfect is the enemy of good" quite quickly once we were close to the event so I simply left it out. Now we're past it and I've got an interesting if huge prop to display in my house I think I'll go back and finish it up. I may even try to remove the tape and fit the acrylic properly, perhaps re-printing the round sections with a larger, tapered groove.