ESP8266 NodeMCU LED Busy Server

I built a Slack status light because it looked awesome and simple, and at that time I knew nothing about DIY electronics. As I learned more, I outlined how to build a cheaper one on a Raspberry Pi. Then my friend then informed me that you can do it even cheaper with an ESP32 NodeMCU board. He was right. Here’s how I built a IoT busy light for around $5.

For this example, I opted for the older ESP8266 ESP12-E NodeMCU board, it is only $2.65 + 1.73 shipping and has everything needed. Pair that with a cheap RGB shared cathode LED $0.50-$2.00, and a few cents for resistors, for a grand total of around $5* in parts.

I won’t go into the details on the boards, but if unfamiliar it, the tl;dr is you write some C/Lua code using the Ardunio IDE, include WIFI for ESP8266 and Web Server libraries (here’s hello world example code and a great setup video) and add some handlers to toggle the GPIO pins on certain requests, then flash that code onto the board over USB. If never used before, I assure you it’s not as hard or complicated as it may sound or appear. When the board is plugged in, it fires up, the code executes, connecting to WIFI, and this tiny board becomes a server in your local network.

Here’s the wiring I did:

& here’s the code I flashed onto it (note you will need to add your WIFI credentials):

From there, I added a simple CURL request into my app that’s currently handling the updating of my other busy light based on a polling of Slack status.

I placed this downstairs in my kitchen as a sort of satellite Slack Busy Light, so my family could check in on my status while not in our upstairs hallway:

If you have a common anode RGB LED, be aware the mixing of colours (on startup and when ‘away’) probably won’t work out of the box. Mixing colours on a common anode RGB requires some sort of pulsing frequency – can probably Google for more info on this or a library. Also the script will need to be edited, changing LOWs to HIGHs and OUTPUTs to INPUTs, and vice versa. I’ve updated the script to use a library to get the mixed colours more accurate for both common anode and common cathode.

* despite this low cost, I personally didn’t want to wait for shipping overseas, so instead I went with a Canadian supplier and bought a pre-wired no soldering RGB LED for $3.95 and the board for $9.98 (on sale). There was a $12 shipping fee, but I order a lot from them so that cost is hardly noticed. Even so, that’s just $14 (+ $12 shipping). Amazon and many other stores also has low prices for these parts.

Learning To Count To 5 With a Raspberry Pi

Prototyping a small counting game – pressing a button to count up to 5 with LEDs and on an OLED screen – then celebrating once reached.

My daughter loves to help me build simple circuits, turning LED lights on and off on a breadboard. Not yet grasping her 1-2-3’s or A-B-C’s, I thought building a small game would be an engaging way to get her learning with the things she likes.

To put this together I used the following setup:

Wired as so:

By no means am I a Python developer, so I’m just swinging away here – the codes very repetitive, but hey, it does the trick easy enough.

Run the script with python3 If the script fails and you get a warning about missing modules, the modules can be installed usually with sudo pip3 install <module_name>, for the GPIO if that’s missing, it can be installed with sudo apt-get install python3-rpi.gpio --assume-yes.

A Cheaper DIY Status Light

Building that thing I just built, but cheaper.

I recognize that my last post about a DIY Status Light the project had a total cost over $100 (and that wasn’t evening including SD cards, power supply, shipping & taxes). And that high cost wasn’t for core functionality, it was for aesthetics.

I wondered if I over did it, and how much it would cost and what we be involved, to build a status light for as cheap as possible. I quickly found the answer (from the store I frequent):

Raspiberry Pi Zero WH$20.95
4GB SD Card$5.95
Squid RGB LED$3.95

Building this out, you’ll notice in the images on this post, I’m using a breadboard instead of the Squid. I did this because I had all the parts of the Squid already from separate kits just not assembled. Note everything in the pictures used is the exact same as the Squid, the Squids just pre-assembled and the cheapest way to get exactly what is needed and nothing more.

Because there is no big led matrix panel, I found a normal phone charger or laptop can be used to power the Pi and light instead of a proper >2 amp power supply. This saved about $5-10.

This is a solder-less approach, so there’s some extra cost in getting the Zero WH instead of just the Zero W and the pre-wired RGB LED, if you know how to solder and have the equipment and can shop around for cheaper parts or cheaper shipping, you may further shave a few bucks off.

Of course you’d need to get creative on a way to mount this at a place appropriate for your use case. Thinking back to when I used to work in an office setting, this would of been great to have stuck the Pi to the rear of my monitor and put this LED at the top corner of my monitor.

Never using GPIO pins before, the code to control this light was way easier than I thought it would be. I had a bit of a curve ball as it took me a while to realize my LED used a shared anode, not a shared cathode (like the Squid is) as both kinds exist, but the code changes to toggle the two is minor. Here’s the script for both and the wiring mentioned inline to test it out (I used $ pinout on my Pi to get the pin labelling):

Common anode (left), common cathode (right)

Edit this script if you’re using a common anode, set commonCath = False. This script can be run by passing the status as a single arg: python3 <avaliable|busy|offline>. Example: $ python3 busy

Forking the busy server, or setting up a new Flask server to run the code for adjusting this light as shown in the code snippet wouldn’t be a big lift at all (though you’ll have to take my word as I’m too pinched for time to prove that).

This was a fun 30 minute project – and a good way to save $60+ if function is greater than form to you.

(Case used in images is Zebra Zero GPIO Case by C4Labs).

UPDATE: My good friend, after reading this post, informed me there’s much much cheaper ways to do this using a $2 ESP32 board. I can’t wait to try that out.

DIY Slack Busy Light

My adventure of recreating this DIY Raspberry Pi Busy Light by @eliostruyf for Slack.

A few months back, after listening to Deep Work and trying it out, I was hooked. I found I could accomplish the most difficult and daunting of tasks with absolute understanding and concentration. Though working from a small home with a young family and a couple of pets, needing to communicate at work, and my own personality traits, the absolute best I can do is 90 minute spans. 90 minutes of head down, no notifications, no distractions, no Slack, concentrated work – followed by a bit of a break, then another session. (I realize this is likely more Pomodoro technique than off-to-a-cabin-for-a-week true deep work, however the high level premise is the same, I get into a state of flow).

Setting up less notifications in my life, filtering all input, building timers, blocking out time for sessions, remembering to do it, and sticking to it, was all the easy stuff. Avoiding my family’s interruptions, was impossible. My wife, three year old daughter, and eleven month old son are all living their lives in our small home, feet away from me at any given time. They would randomly pop in, yell, knock, throw things, cry, text, ask, poke, question, hug etc. Breaking the session. Not only demotivating as it scratches the record on my focus that I just mentally committed too, but it would take around ten or more minutes to refocus and realign after they had left, leaving me a bit scrambled and a bit behind. Best illustrated in this comic:

My wife sympathized with me, and we both knew we needed some sort of way to indicate I was in these sessions, or on a call. The classic ‘door open/close’ or ‘headphones on/off’ wouldn’t work in our family, and shooting a text seemed unideal as that may backfire, ignite a conversation or trigger some reminder that may fill the brain with life instead of work. We both agreed that some sort of red light outside the door would be best.

I was thinking just a single LED light. I’d drill a hole in the door jam, and run some wires from a Raspberry Pi or other small computer or bluetooth device to turn the light on or off. This was the plan.

Then searching “DIY Busy Light” to see what else others have done, returned an amazing post by the very impressive @estruyf (which to my surprise, had only been posted days earlier) that took me away. It amazed me how good it looked and sounded. The code written for the project was minimal and well done. The parts looks awesome. I had never played with a Raspberry PI, or any DIY hardware, but this all excited me a great deal. I quickly ordered up everything.

I won’t go into detail on the hardware side as @estruyf’s post explains it all, but after a lengthy international shipping wait, it was easy enough put together.

I opted to not get the Pibow case and picked my own, but I was unable to put everything together because of the way my case and the holes of the board aligned the same, opposed to the Pibow that is wider and doesn’t use the Pis back two holes. Having no long tiny screws around to makeshift something myself, I ended up purchasing some legitimate standoffs and they worked well to pinch the whole thing together while giving the correct amount of even space between. Overall I was happy with how it turned out and I liked the darker backing and bolts:

On the software side, I use Slack for my work instead of Microsoft Teams as the tutorial guides for. And despite how my family will see only green or red, I recognized that I have more than just two states, each state needing to reflect differently in both Slack and on the Busy Light.

I began by defining those states in a JSON file, now hosted on Gist:

Life is complicated, so to me it was understandable to have this many different states. Basically, there are times I don’t want to be interrupted by work, other times family, sometimes both, and sometimes I welcome interruptions, and am open to new chats. Additionally, at my job communication is oxygen, so I do like to be explicit about why I’m not responsive during my normal work hours, and what state I’m in instead of just online or offline. (The rainbow status is just for fun, it’s available in the API so we’ve made it a signal that I want a hug from my daughter).

I next needed a consistent and quick method to reference and set these statuses. I didn’t want to memorize this table, or second guess myself on which version of an emoji to use. Even with knowing the keyboard shortcuts, I find the Slack UI a bit clunky for status setting – so I wrote a small Alfred workflow in PHP:

This Alfred Workflow pulls down, caches, and parses that JSON file of my statuses, displays them for quick selection, then when selected fires off a simple CURL to the Slack API, which sets my emoji status and online/offline presence. (I’ve opted to not share this code as it uses Slack Legacy Tokens, which are now unavailable).

Though I never forget to switch a status when I step out for a break or lunch, knowing myself, there was about a 100% chance of me forgetting to set an “In a meeting” status as I prepare and log into one. I automated this status setter with the Google Calendar Slack App. This app reads my meetings calendar and adjusts my Slack Status while in a scheduled meeting.

I furthered this automation to my Pomodoro timer (which I use to block out and keep on track of my 90min deep work sessions) so when my timer starts up, theres a call to an external workflow, triggering the Slack Status Workflow to set to DeepWork and go offline. Once the timer completes it clears the emoji and sets me to Active.

Everything boiled down to Slack being the canonical source of my current state, and defining a small pool of what that could be. Slack allows for easy automation and integration, and my JSON file allowed for easy editing and modifications. With this setup, the Busy Light just needed to read and reflect Slacks state.

To poll Slack, compare the emoji status and online/offline presence to the list of statuses, and determine the colour and send a request for the Busy Light, I thought about running a cron job on the Raspberry Pi itself, a single Python script that’d be under 100 lines, however, for several reasons I explain further below I opted to keep the RPI as a standalone server that only handled request. I only wanted the stable and simple Flask server by @estruyf on it.

So to bridge Slack and the Busy Light, instead I built a widget on my personal Dashboard “Albert”. Albert is an Express app that displays data from a personal PHP data API I have for myself (called ‘Artemis’, which supplies data to the Dashboard from other APIs like Google, current weather, stats on, etc).

The widget I wrote for the Dashboard in my API Service polls every 15 seconds, reading Slack, figuring out the status, and sending off a request to the Busy Light if it differs from the previous state sent. Making the Busy Light responsive within a quarter of a minute.

Besides being easier to debug and work on and writing in PHP instead of Python, another big draw of not writing the script on the Pi itself was that my Dashboard has a UI and a setup that allows for easily creating beautiful views for the data. Here’s some screen shots of the widget in four different sample states:

This Dashboard and widget is open all day on my second monitor, providing me a constant glimpse of Slack (despite the app not being open) and the Busy Light (despite the door being closed), which has proven very helpful for preventing accidental incorrect statuses.

So does it work?

A fair amount of time and energy (both things I don’t have) went into setting this up. It would be funny if for all the investments made that the light was ignored and useless. However, I’ve had the light up for about two weeks now and it’s been great. It works consistently, reliably, without fail, and most importantly the “red” is respected in our household. I’m getting in around 2-3 (uninterrupted) deep work sessions a day.

If I had to do it all over again:

I would opt out of using the Pogo pins. Despite how easy they look in the video on their site, for me I found they had to be tapped every so slightly in just the right angle after they were installed and already snug, nudged just right to get the lights up running. This problem would take about 5 extra minutes every time it was moved. I ended up switching which pins I used for ground and power and that helped a little, but it was just annoying to fix every time I worked on it. Luckily, I won’t be moving it anymore so this is a non-issue now and I will keep it as is, but I’d recommend instead to get a Zero WH and Unicorn HAT Mini so there’s a tight, solid, and reliable connection without all the fussing.

Secondly, when buying standoffs, I’d look for a kit that included longer screws, the small one-size provided in the kit I chose presented some challenges when putting the Pi on the case together, and made a simple task a litter harder and less secure than it ought to be.

Lastly, in my list statuses, there’s a few states that are starting to feel redundant and perhaps not as unique and useful as I had thought, like ‘On a Call’ vs ‘In a Meeting’. If I was starting up, I’d likley make the list as small as possible and grow it based on need instead of starting with a big list. Luckily, Alfred results in workflows order by frequency of use by default, so right about now after weeks of use, it will be evident which states I don’t use, and I can trim them off, refining the list.

Ah, this thing is so cool:

Links to build your own:

Stop Alerts From Shared Google Calendars in iOS / macOS

Tips for silencing calendar events that don’t matter, leaving only the ones that do.

At work, I’m shared a whole bunch of Google Apps / G Suite calendars that are very relevant for looking up events, but none of which I need to actually alert me. For several weeks, I was plagued with dozens of notifications that weren’t relevant to me whatsoever, and made a sea of noise that took away from the few importance of the tasks I actually needed to alert me. Meetings were missed.

I tinkered with Notification settings over and over, but nothing worked. For me for whatever reason, the solution to this wasn’t straight forward. It turns out you need to explicitly silence specific calendar alerts – here’s how:


  1. right click the noisy calendar in the sidebar
  2. Get Info
  3. Select “Ignore Alerts”


  1. Calendars
  2. Hit the (i) button for the noisy calendar
  3. Turn off “Event Alerts”

I presume there’s a similar process for watchOS.

Troubleshooting xdebug setup on VVV with VS Code

Some tips for troubleshooting setting up xdebug on VVV while using VSCode and Felix Becker’s PHP Debug extension and BrianGilbert_‘s Xdebug Helper for Firefox add-on.

Ensure xdebug is turned on within vvv

You may check xdebug status by taking a peak at your servers http://vvv.test/phpinfo/ page. If not on, via we can toggle it on by accessing the virtual machine via ssh, then running a command that will turn xdebug on and restart PHP:

$ cd ~/your/location/for/vvv/
$ vagrant ssh
$ /vagrant/config/homebin/xdebug_on

The xdebug_on command is supposed to work without the full path, but I haven’t much luck with that. As a second saver, I store this full path in my text expanded since every time the machine is restarted xdebug being on does not persist and it will need to be manually turned on. A bash_alias entry could be made as well.

Ensure the browser extension is turned on

Yes, simple, but often forgotten.

Ensure you’ve started debugging in VS Code

Again, yes, simple, but often forgotten.

Ensure VVV is up to date

Older versions of vvv have compatibility issues with xdebug and php. Ensure you’re running the latest version of vvv, that vagrant itself is up to date, and that you’re using the latest version of php.

Turn off “Everything” breaks

Sometimes xdebug works while setting it up, VSCode pops up, but it stops on a breakpoint that isn’t the one you specified, it’s a random file from your app. This is an error that was picked up and xdebug stoped on because the default VSCode extension has it specified to break on “everything”. Unselect this in the Debug sidebar:

Check the xdebug profile is correct

Via the debug sidebar (shift+cmd+d), we’ll view our xdebug configuration file. Here’s an example of a WordPress plugin delete-thumbnails and the path I used

    "version": "0.2.0",
    "configurations": [
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                "/srv/www/vvv-vip/public_html/wp-content/plugins/delete-thumbnails": "${workspaceFolder}"

Two important notes:

  • VVV has two initial paths to get to your sites, /srv/and /vagrant/, the latter is a symbolic link which xdebug does not understand, you must use /srv/
  • Other tutorials may say to use ${workspaceRoot}, this variable is deprecated in favor of ${workspaceFolder}

Try a breakpoint outside of your current script

We usually want our breakpoints on what we’re working on, and we’re frustrated when xdebug doesn’t pick up on the breakpoint, so we dig around our config to check what’s wrong. Let’s first make sure that our desired code is actually running and capable of breakpointing, after all, the code not running might be why we’re firing up xdebug!

Add a breakpoint at the root of your application, somewhere you know runs 100% for sure. In WordPress, this will often be in either WordPress’ /index.php file, or the primary file in your current theme or plugin. For this plugin I’m working on, I checked that the plugin is activated, and I’ve placed a breakpoints on a fake var on the main fire which I know for sure loads:

Is your VSCode the nightly build?

I’ve heard of users being unable to run xdebug while using their beta releases. Best to always use the stable releases.