Ocupado – An Internet Connected Restroom Occupancy Detector


Here at Quick Left (Boulder), the office has a single restroom, and like ~30 or so employees. With that, employees were often faced with the harsh reality of making numerous trips to the restroom only to find it occupied, and subsequently needing to walk back to their desks. trollface

As our slogan states, “We turn hard problems into great software”, and thus we set out to find a solution to this problem, but of course no ordinary solution would do. We also needed something that would satisfy the inner geek in all of us.

The following is a description of what we came up with, now affectionately known as “Ocupado”.


Sam Breed had recently come back from a JS conference brandishing a new Spark Core, and thus we decided to hop on the Internet of Things bandwagon use that as a starting point. If you aren’t familiar with Spark, they essentially provide a low barrier entry point into the world of WiFi enabled Arduino compatible hardware. Spark also provides a rich suite of tools for fully building out your connected project, including a Web idE, a REST API with pub/sub messaging, CLI tools and more.

Next, we needed some type of sensor to detect restroom occupancy. For some rooms, such as a meeting room which might be unoccupied and simultaneously have the door closed, occupancy detection might have involved PIR motion sensors or other methods, but for our restroom, a simple reed switch triggered upon door opening/closing was sufficient. Pretty simple really – if the door is closed, the room is assumed to be occupied, if the door is open, the room is assumed to be unoccupied.

Next, we needed a means to communicate the occupancy status to others throughout the office. As the Quick Left Boulder office has numerous easily visible lights, and because it would surely be cool looking, we decided to implement the initial communication pathway via color changing Hue lights.

Quick Left office lights

animated lights

As we (im)patiently awaited the lights to arrive, we introduced another communication pathway by integrating Ocupado with our company Slack chat software via Slack’s “Incoming webhooks” service integration and also with a custom hubot command. These tools however, were less than ideal for our use case for two reasons, and will likely soon be deactivated. First, unless Slack notifications were disabled, something that not everyone in the office does, things would quickly become too noisy. Second, the lack of the bot’s ability to reply privately through the hubot-slack adapter made status inquiries a little too public.

ocupado toolbar

Lastly, as an alternative to the Slack implementation issues described above, and perhaps as somewhat of an excuse to learn and experiment with Github’s cool atom-shell project that allows you to build desktop apps using CSS, HTML, and JavaScript, we also implemented a toolbar app that displays the current state of the restroom sensor. Note that the icons will likely soon change as color alone is generally not the best way to differentiate states. Regardless, development of this little app proved to be quick, fun, easy, and the resulting software is perhaps the most useful of all.

ocupado toolbar

Quick Lefters and office guests rejoice! With these tools in place, you can now simply glance at the lights or at your toolbar to see if the restroom is free. Problem solved and dare I say, minutes saved.


Okay, by this point you are probably saying, “That all sounds fine and good, but how is everything connected and how does everything communicate?” Who knows, perhaps you may even want to build your own “baño-bot”. Let’s look at the overall architecture in a bit more detail.

ocupado architecture

Wiring the Sensor

The Spark core and door sensor are wired as shown in the following photo and breadboard diagram. By the way, for those not already familiar with it, the diagram was created with the excellent and free Fritzing software. The components were then securely placed inside an Altoids case for protection. …yes, the mints.

breadboard diagram

breadboard photo

Below are links to the precise hardware used.

Power Supply

Originally, the hardware design also included a 3.7v LiPoly battery and a built in USB charger, but it was quickly determined that the power drain from the WiFi connectivity would result in an unacceptably short battery life – several days at most. Spark does have some means to further optimize power usage, such as placing the unit in sleep mode, but it did not appear that it would make enough of a difference for our use case. We opted to add a new power outlet nearby and plug the unit in directly.

It should be noted that there are other technologies out there that would allow much greater battery life. ZigBee for example, was designed from the ground up for low power consumption. While there are many factors at play, using ZigBee, battery life can enter the multi-year range, but that is another architecture and another story.

Firmware and a Free API

Next, we had to write a surprisingly small amount Wiring firmware code and upload it to the Spark Core. This process was really easy via the Spark Web idE. The entirety of the code is shown below.

int reed = 0;
int led = 7;
int state = 0;
int previousState = 0;
char stateString[20];

void setup() {
  Spark.variable("state", &stateString, STRING);
  pinMode(reed, INPUT);
  pinMode(led, OUTPUT);

void loop() {
  previousState = state;
  state = digitalRead(reed);
  strcpy(stateString, state > 0 ? "ocupado" : "desocupado");

  if (state != previousState) {
    Spark.publish("state", stateString);
    digitalWrite(led, state > 0 ? HIGH : LOW);

The above code does several things. First, it listens for changes to the door sensor and activates the onboard LED. This was particularly useful during development before anything else was connected and also during the physical installation. At the same time, the code also publishes these state change events to the Spark Cloud using the built in Spark.publish command and exposes the current state via the Spark.variable command. These commands leverage Spark Cloud functionality to subsequently provide REST API endpoints to get the current sensor state and also to serve a stream of Server Sent Events. This “free” API functionality was a really nice surprise as it otherwise would have had to have been built manually. Check out the Spark Cloud documentation on this subject for more details.

Ocupado Node App

Note the “Node.js App” in the architecture diagram above. While it certainly didn’t have to be written in Node.js, this element was an essential piece of the puzzle, and Node.js actually fit the bill quite nicely. This app subscribes to the Server Sent Events stream provided by the Spark Cloud and takes appropriate actions when events occur, namely changing the color of the Hue lights and posting messages to Slack.

It is important to note that, due to a limitation in the Hue API which does not allow remote control from outside the local network, this process unfortunately had to be run on a local machine, as opposed to Heroku, AWS EC2, or similar cloud based service. Some folks have hacked their way around this limitation, but everything that I came across at the time felt… well, like a hack.

Ocupado Toolbar App

The Ocupado toolbar app similarly utilizes the Server Sent Events stream to keep abreast of and respond to occupancy changes. It however also needs to be aware of and tolerant to changes in network connectivity. As this app was built using the Chromium based atom-shell, it supports online/offline event detection using navigator.onLine. Using navigator.onLine in a traditional web environment usually proves challenging due to the varied browser interpretations and implementations. Fortunately this is not the case here as we are only dealing with one browser. This functionality was implemented as described in the following tutorial.


Aside from the need to install an additional electrical outlet, the installation was straightforward. It involved attaching the unit to the wall, attaching the sensor to the door and frame, and running the wire in between.

case and outlet

door sensor


This was a fun pet project in which I learned quite a bit about the landscape of the Internet of Things and got to experiment with a number of other projects and API’s to which would not have otherwise been exposed. I must also add that I found something uniquely satisfying about connecting internet software with tangible items in the physical world. It is not something that we software developers get exposed to often, but something that I find myself wanting more of.

There is much innovation happening in this space and it is all rather exciting. Along those lines, I would like to experiment with other hardware options such as the JavaScripty Tessel, and Espruino, and also the Arduino Yún – a WiFi enabled Arduino device with an additional processor running Linux.

For example, using the Arduino Yún as an alternative to the Spark Core in this project would have allowed the unit to be entirely self contained. The Ocupado Node.js app could actually run on the device itself, and not require a separate local server. This would of course have necessitated writing a separate API to replace that which was provided by Spark and also writing additional firmware code to post events to the API as well, but nothing insurmountable. That all being said, the Spark Core certainly lived up to its reputation for ease of use.

Looking forward, I am curious to see what additional features may be added to Ocupado in the future and also to what my next Internet of Things project will be.

Best of luck on your project, and thanks for reading!

Ocupado Repos