In just two days we succeeded in building a system that can unlock the door based on your public transport card (OV-chipkaart), the presence of other people in the office or using a button upstairs. The system is already up and running and we’re currently in the process of tuning the sensors and hiding the mess of cables we created.
How you get into our office from now on
Once the night lock is switched off by the first person entering the building, The Hodor takes over. Registered visitors can open the door by holding their card in front of our NFC reader; the Q42 logo will light up and the door can be opened.
Regular clients visiting probably won’t be able to unlock the door themselves and often colleagues working upstairs have a direct view of the door, but have to walk all the way through the office to open it. For them a button is available that they can push to unlock the door. The logo will again light up to indicate the door is opened and everybody can get back to work!
The last scenario we wanted to support is that people tend to chat around the coffee machine near the door. They often have to interrupt their conversation to quickly open the door for regular clients without a key. Now a sensor will detect people in that area and keep the door unlocked. The logo will light up and the visitor can see he or she can just pull the door open.
The technical setup
This all works because we have a Raspberry Pi 3 hooked up to a relay board that can unlock our door and switch on LEDs in the little box we mounted on the door. The Pi runs a daemon written in Python that controls the relay board by looking at messages from a message queue (Mosquitto) and checking them against a JSON file with allowed tokens that may unlock the door.
The message queue is populated by another daemon that is connected to the NFC reader and just populates the queue with the identifiers of cards it discovers. The “unlock daemon” will also flash the logo if it encounters invalid values to show that a read occurred, but the door won’t open.
The button and PIR sensors are connected to an Arduino Leonardo. This Arduino also connects to the message queue hosted on the Raspberry Pi. It submits messages with tokens to the queue to make it unlock the door.
Keeping it secure
During the hackathon we brainstormed about a gazillion components that could open the door. During this brainstorm a few principles were defined that helped us create a secure system:
- The door may only be unlocked by someone with a direct line of sight to the door
- Admins must be able to disable components that malfunction
- Admins must be able to revoke access for users that may no longer open the door
By only creating components that are mounted at a specific place in the office, we make sure the user unlocking the door is in a location with a direct line of sight to the visitor that is entering. In addition to this we’ve made the message queue only available on the local employee network so that a component outside of the network can never connect, so taking the hardware with you will not help to gain access.
Admins can disable components that malfunction easily because every component has its own account on the message queue. Just revoking that account is enough to disable it, even if you’re not sure about its physical whereabouts. This helps if the PIR goes mad detecting movement that isn’t there, for example.
The last security measure is that all NFC cards that can unlock the door are in a simple JSON file. When on the local network, a special administrator mobile app can read this file and help you add/remove ids based on email addresses. This makes it easy to revoke access for users that may not enter the building anymore.
Keeping it up and running
Another thing we worried about was stability. If the system requires too much maintenance or just doesn’t work for too many users, it would cause more frustration than joy to our users (and ourselves as maintainers). We did two things to ensure the system will run as smoothly as possible:
- Make everything rebootable/restart on crash
- Use independent microservices for each component
Everything on the Raspberry runs as a simple Python script that is kept running by systemd. If the Raspberry reboots or the script crashes, systemd will just launch it again. This protects us from basic problems like making a programming mistake somewhere and causing weird crashes: the Raspberry will recover from most of those without us having to do anything.
The Arduino runs a simple C program. The nice thing about the Arduino is that it by default launches this program on boot, and it’s quite robust, so we can just power cycle the whole thing in the case of a freeze.
In the rare case that one of our services doesn’t work, the message queue comes in. This queue helped us make small microservices that don’t have a hard dependency on each other. So if one component crashes, the others will just keep running. During the hackathon this already proved to be robust and easily debuggable.
Learnings from building The Hodor
So I’m very excited to see the first people unlocking the door with their cards and super proud of all team members that made this possible. Reflecting on this awesome project I would summarize our biggest learnings as: Keep it small, adjust quickly and be honest.
To create a finished product requires a team with a refreshing amount of candor and courage. We killed a macOS app someone started building on, threw away a whole CMS in Meteor. All because it turned out to be the wrong decision. It was hard to do, but it got us a finished product that’s better than it would have been with those features we couldn’t finish or that made the system too complex.