DIY Access Control
and Burglar alarm
founder: crowdsourcing
depends on:
interested: harvie
software license:
hardware license:

For hackerspace more secure and without the annoyance of physical keys. DIY digital lock control, open/closed space status monitor and burglar alarm.

System architecture: Raspberry Pi + Adafruit PN532 shield. Supports ISO14443 cards (Mifare Classic, Desfire, Yubikey, you could even use Visa/Mastercard NFC payment cards; Android NFC Host Card Emulation could be used as well with some changes). Authentication: via UID, challenge-response with Yubikey Neo, signed public-key cryptography (Ed25519) messages with Desfire cards.

Unlocking the Door

Executive summary, how to get in without a key - arrange registering your RFID card (ISO-14443A, e.g. Mifare Classic, Mifare DESFire) with council at the meetup (or over mail rada _at_ brmlab.cz). After adding your card to brmdoor DB, you will be able to unlock the door by placing the card next to the reader.

BrmDoor Hardware

  • MCU/controller: Raspberry PI (all versions supported - 1, 2, 3)
  • OS: Raspbian or Ubuntu (other may work as well if you can get required packages to build and install)
  • Lock device - BERA-E electromagnetic lock:
    • From inside, it is possible to open the door anytime by just pushing the handle.
    • From outside, it is possible to open the door by turning the lock by the key, OR by pushing the handle if the voltage is applied.
    • Lock specs say 12-24V should be used, but from experience 12 V is not enough. Use 24 V.

Communication is over SPI: both SEL0 and SEL1 are shorted which turns communication to be over SPI.

Documentation of Adafruit PN532 shield (our revision is 1.2):

BrmDoor Firmware

List of authorized cards

Card list is on brmlab VPS (vps.brmlab.cz) are exported from JendaSAP, on /root/sap/cards.txt.

Adding a new card to JendaSAP and import to brmdoor

Put the card next to the reader, then look into a log (on brmdoor raspi in /root/brmdoor_libnfc/brmdoor.log) for Unknown UID line.

Login to vps.brmlab.cz. In /root/sap/members, find member's file and add line with the card UID (4, 7 or 10 byte UID), e.g.

card 0102ab89

On vps.brmlab.cz in /root/sap directory, run parse.py script:

cd /root/sap

This will create cards.txt. Copy the cards.txt to brmdoor and run on brmdoor raspi:

cd brmdoor_libnfc/; ./import_jendasap_cards.py /path/to/cards.txt brmdoor.sqlite

No need to restart brmdoor daemon. Note that the import can take even a minute since the brmdoor Raspberry 1 is fucking slow.

Commit the changes to members directory on vps.brmlab.cz.

In the members directory, commit the changed card with

git commit -m "Added card for member Ctulhu" 1234_member_uid_file

Adding a new Desfire with authentication to JendaSAP and import to brmdoor

This is similar to above, but has extra step in programming the Desfire.

The Desfire needs to be programmed with correct signature first, otherwise brmdoor will reject it.

Writing a signature on a Desfire card (can be done on raspi or using PN532 reader that is in the lab). You must know the private Ed25519 key matching the public key in brmdoor's config to be able to program the Desfire correctly.

./write_signed_ndef_on_desfire.py private_key_in_hex

Similar to above, but you add line “desfire” instead of “card” in JendaSAP:

desfire 04631982cc2280

The parse.py mentioned above will also create cards_desfire.txt. Copy the cards_desfire.txt to brmdoor and run on brmdoor raspi:

cd brmdoor_libnfc/; ./import_jendasap_cards.py --desfire /path/to/cards_desfire.txt brmdoor.sqlite

Checking that the signature on Desfire

Can be done with brmdoor, PN352 reader on PC or also on mobile app that can show NFC NDEF data:

cd brmdoor_libnfc/; ./test_nfc.py desfire-ndef4

You should see something like:

{"brmdoorSignature": "ebb7191d3a1133e375bd4bcfe9b271b8246d086c6c93f0753a3a09c6bbc253e7fc3e2fc34f3351989c8b31bd9937747e05173f9377f57a445e7f61c74b4d7388"}

Restarting brmdoor remotely

If brmdoor stops responding for some reason, restart it using:

systemctl restart brmdoor.service

In order to get to brmdoor from outside, you'll need to find a hop server accessible from outside, like bbs.brmlab.cz

Sample entry in ~/.ssh/config:

Host = bbs.brmlab.cz
VerifyHostKeyDNS = yes
User = root
IdentityFile = ~/.ssh/your_key
ForwardX11 = no
UsePrivilegedPort = no
Protocol 2

Host = brmdoor-external
ProxyCommand = ssh bbs.brmlab.cz nc %h 22
Hostname =
Port = 22
User = root
IdentityFile = ~/.ssh/your_key
ForwardX11 = no
UsePrivilegedPort = no
Protocol 2

OPEN/CLOSED switch with update of topic on IRC and SpaceAPI format on VPS

In brmdoor_nfc.config, look at the section [open_switch]. IRC must be enabled in [irc] section for status update to work.

The first part of the topic until | character will be replaced by OPEN/CLOSED (if there is no pipe character, OPEN/CLOSED will be prepended).

Configuration needs setting a file that is read once per second, open_value determines which value means “open”. Thus you can use any daemon/cron script/whatever that just writes a predetermined value to file which will be read by brmdoor daemon.

For a simple switch (that just closes/opens the electrical connection) connected to GPIO PINs, you need to configure a PIN in input mode and turn on internal pullup on the input PIN. An example of this is in the brmdoor_start.sh script below. Connect one cable of the switch to an input PIN and the other to the ground.

export PIN=22
if [ '!' -d /sys/class/gpio/gpio$PIN ]; then
    echo $PIN > /sys/class/gpio/export
    echo in > /sys/class/gpio/gpio$PIN/direction
python -c "import wiringpi; wiringpi.wiringPiSetupGpio(); wiringpi.pinMode($PIN, wiringpi.INPUT); wiringpi.pullUpDnControl($PIN, wiringpi.PUD_UP)"

If the switch is in open position (connected to ground), the “open” value will be 0, the close value will be 1 (effect of the internal pull-up).

The numbering scheme is the same as in the lock configuration (BCM GPIO numbering, https://projects.drogon.net/raspberry-pi/wiringpi/pins/). A copy of the mapping is in gpio_vs_wiringpi_numbering_scheme.png file) in case the webpage goes away.

Changing OPEN/CLOSED status remotely with software

Any IRC user in #brmlab channel can change the topic by using the /topic command. This value will stay until the physical switch changes the value.

Reporting/uploading status in SpaceAPI format

Currently since v 0.2 brmdoor can upload the status and information in SpaceAPI.net format.

The status JSON is mapped currently is mapped to https://brmlab.cz/spaceapi/status.json. The interesting non-static part of json is in under “state” key - “open” (boolean) and “lastchange” (Unix timestamp).

Currently to be compatible with old URL (https://status.brmlab.cz/brmd/brmstatus.json) for the spaceAPI.net since we can't change it and can't submit new, there is alias in /etc/apache2/sites-available/status.brmlab.cz.conf to directory /home/brmdoor-web/spaceapi-status where status file is uploaded by brmdoor (it's over SFTP with internal-sftp chroot, ssh-key login, so that in case of compromise of brmdoor there is not much the attacker could do with it (and password can't be bruteforced).

PIN assignments

General GPIO PIN assignments are configurable, communication (SPI/I2C) must follow the definition in Raspberry Pi pinouts. Raspi pinouts for all versions: http://pi4j.com/pins/model-3b-rev1.html

Numbering scheme used by brmdoor for lock and open switch (based on BCM GPIO numbering, different from P1 header physical PIN numbers): https://projects.drogon.net/raspberry-pi/wiringpi/pins/

PIN assignemnts (physical PINs on P1 header, with BCM GPIO numbers used in config):

  • 5V power into Raspberry: physical #1
  • Ground from power source to Raspberry: physical #9
  • 5V power out into Adafruit PN532 reader: #4
  • Ground for Adafruit PN352: physical #6
  • BERA-E lock open/close: physical #22, BCM GPIO #25
  • Open/close switch input PIN: physical #15, BCM GPIO #22
  • Ground for open/close switch: physical #25
  • SPI pins for Adafruit PN532 reader - SPI PINs on Raspberry - physical #19, #21, #23, #24

GitHub, last commits

Photos of cable connections of Raspi + PN532 shield (location Ke kaplicce 18)

Brmdoor HOWTO (displayed after you login as root, in /etc/motd)

Current brmdoor directory is `/root/brmdoor_libnfc`
Config is in the file: `/root/brmdoor_libnfc/brmdoor_nfc.config`

Full README is at https://github.com/hiviah/brmdoor_libnfc/blob/master/README.md

A preferred way to add a card is to add it to JendaSAP, then import (see below).

## Import cards.txt from JendaSAP's cards.txt (WARNING: THIS WILL OVERWRITE THE TABLE WITH UIDs)

    cd brmdoor_libnfc/
    ./import_jendasap_cards.py cards.txt brmdoor.sqlite

If `brmdoor.sqlite` does not exist, it will be created. If it exists, the `authorized_uids`
table will be replaced with UIDs/nick pairs from `cards.txt` (other tables are not touched).

## Adding card by UID

Note: this is useful for adding card temporarily since import from JendaSAP will remove it

- find out the UID:
  1. put the card near the reader,
  2. as root, look into the log, currently /root/brmdoor_libnfc/brmdoor.log
- look into the log for the unknown UID, look for `Unknown UID` message
- the following command will add a card as authenticated by UID, for other methods see full README

    cd brmdoor_libnfc/
    ./brmdoor_adduser.py -c brmdoor_nfc.config -a uid 1234ABCD SomeUserName

## List authorized cards UIDs + nicks from DB

    sqlite3 ~/brmdoor_libnfc/brmdoor.sqlite 'select nick, uid_hex from authorized_uids;'

## Start/stop daemon

systemctl start brmdoor.service
systemctl stop brmdoor.service
Systemd unit location: `/etc/systemd/system/brmdoor.service`


Source: brmdoor_libnfc

Requires libnfc, libfreefare and WiringPi2


  • Clean, documented and extensible code
  • Authentication data is stored in SQLite DB - no need to restart daemon to make any change; extensible DB schemas
  • NFC smartcard communication support (ISO 14443-4)
  • Multiple authentication schemes supported
  • Dedicated configuration file and logging facilities

Missing features:

  • No sound produced (can be fixed via WiringPi)
  • Setting topic is not finished (python-irc has fairly bad API to retrieve topic)

Remote access from outside brmlab

Add following to your ~/.ssh/config, edit your key if necessary (the key needs to be added on brmbar and on brmdoor):

Host = brmbar-external
VerifyHostKeyDNS = no
Hostname = hrach.eu
Port = 22715
User = brmlab
IdentityFile = ~/.ssh/id_rsa
ForwardX11 = no
UsePrivilegedPort = no
Protocol 2

Host = brmdoor-external
ProxyCommand = ssh brmbar-external nc -q1 %h 22
Hostname =
Port = 22715
User = root
IdentityFile = ~/.ssh/id_rsa
ForwardX11 = no
UsePrivilegedPort = no
Protocol 2

Then ssh brmdoor-external will get you brmdoor shell.

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki