I love projects that blend the virtual world with the real world. I also love projects that are fun.

This is both. Starting out as just a 9v battery, a button and a buzzer, it became common to give one on the buzzer when leaving or entering the space. This encouraged me to add the functionality in so that those not physically present could press it as well.

It allows people in a group chat to set a buzzer off at the hackerspace, and people in the space to acknowledge (or silence!) the buzz which lets the group chat know that it’s been heard. This can be useful when someone online wants to see if anyone is in the space or get the attention of people in the space, who aren’t looking at their phones.

Here’s the controller, it’s the industrial switch in the middle. The green button is the acknowledge button, and the nice big red button is the Do Not Disturb button. The LEDs are added in to make it obvious from a distance the state of the system. And yes, rule 0 of our hackerspace, Hackspace Manchester, is “Do Not Be On Fire”.

Minimalist Minimum Viable Product

I started with reducing the idea down to just the core parts – the Minimum Viable Product:

When a user posts “/buzz” in a chat that the bot is in, the bot should communicate with a WiFi device in the hackerspace. The WiFi device should then sound the buzzer for 500ms. When the acknowledge button is pressed after the buzzer being sounded, the WiFi board should reply with an acknowledgement, which the chatbot will post on the group.

I reduced it further to the M2VP to cut out any hardware that could cause issues:
user posts “/buzz”, WiFi board lights the inbuilt LED for 500ms. Connecting a pin to ground will send the reply. 

I reduced it further to the M3VP to just testing that MQTT works and the pin is being read:
user posts “/buzz”, WiFi board lights the inbuilt LED. Connecting a pin to ground turns the LED off.

I reduced it further, but you get the idea. This worked well for me – I could focus on doing the fun part without getting caught by common gotchas.


The Circuit

In this diagram, black wires are ground, red is +5v, orange are outputs, and blue inputs.

Inputs – the buttons

Pin D3 (DND button) and D6 (acknowledge button) are connected to buttons which are connected to ground. I’ve setup the pin for each button as INPUT_PULLUP so that the pin isn’t floating when the button isn’t pressed, instead it will be HIGH normally, and LOW when pressed. This simplifies the circuitry by removing the need for pull down resistors.

Outputs – LEDs and the buzzer

I made the DND button illuminate by placing a red LED behind it, which was connected to pin D7. I found a resistor wasn’t needed, I don’t mind driving LEDs a little hard and in my experience they last as long as the project has.

2 by 2 addressable LED square

As that LED was a little dim from a distance, I also connected a 2 by 2 square of addressable RGB LEDs to pin D1 to visually display the state of the communicator from a distance with the following meanings:

  • One green corner = normal operation
  • One red corner = DND mode active
  • Flashing diagonal purple = buzz pending
  • Four red = WiFi or MQTT error
  • White = buzzer is sounding

The buzzer itself requires 9V to operate so I used a battery to power the buzzer which is only used for a few seconds a day.  Connecting the ground of the battery with the ground of the Wemos D1 mini, it was then possible to have the 9V buzzer sound when the Wemos pin was set to HIGH by using an NPN transistor.

Interface and enclosure

I had a spare industrial start and emergency stop module (as you do as a hacker) and decided this would be a neat interface for the communicator. The buttons have a nice feel and the label bevels perfectly fitted my 2 by 2 WS2812b LED square.

I enclosed the Wemos D1 mini and 9v battery in an enclosure with a clear lid so you can see what was inside.

The buzzer needed mounting outside for maximum volume. Potentially an enclosure like this one would be more suited, at about £3 from AliExpress, it’s super cheap to get one delivered and would enclose everything nicely including vents for the buzzer module.

An alternative is an external sounder, but I am confident this would get removed with force! A key consideration was making sure the buzz sounded noticeable without people thinking it was anything else such as the doorbell or fire alarm, or it being so annoying that people turned the system off. The current solution is a nice compromise though possibly a bit quiet.

The Code

I’ve uploaded the code for this on GitHub: https://github.com/conorriches/hackerspace-communicator

The code is split across three sections, the bot which sits in a group chat, the communication medium (MQTT), and the code on the WiFi board which buzzes and reports any acknowledgements.


The beef of the code is found https://github.com/conorriches/hackerspace-communicator/blob/master/index.js and this contains the commands that the bot will listen for, and utility functions for posting messages to Telegram.

I’ve coded the chatbot to edit the original message with any further updates so that people buzzing it before an acknowledgement doesn’t spam everyone with notifications.

This allows a nice history of when the buzz happened, subsequent ignored buzzes, and finally the acknowledgement.


I decided on the three topics to use:

  • buzz/syn – sending a buzz
  • buzz/ack – acknowledging a buzz
  • buzz/dnd – reporting that the DND plunger has been depressed or that a buzz has been ignored.

I namespaced all topics with buzz to keep it separate from other functions.

I have assumed in this project that the MQTT channel is secured and all parties with access are trusted. This is because the rate limiting code is on the bot. Spamming the MQTT channel will sound the buzzer. If your channel isn’t isolated or secure, you’ll want to move the rate limiting code over to the WiFi board.

WiFi board

My Arduino code is here https://github.com/conorriches/hackerspace-communicator/blob/master/hackspaceCommunicator/hackspaceCommunicator.ino

You’ll need to plug in your MQTT and WiFi details, and make sure the pin numbers match if you’re using a different board, but it should all just work.

Things to note are the unintuitive digitalRead()’s – as I was lazy and didn’t want to implement physical pull down resistors, I used the internal pull up resistors. This means that normally the pin reads HIGH when not pressed, and LOW when pressed. This is an easy compromise but may catch you out if you’re not expecting it.


It all ended up working quite nicely, it gets used by people and is a nice way of knowing if anyone is in the space when people are not looking at their phones.