Input on Building Access Control devices

I am reading up on using Particle hardware to create access control devices and would like guidance/input on design. I have an Argon and 2 Xenons upon which I would like to base the prototype on.

Conceptually, I want the Particle device to wait for an authentication token (in my case they are 125kHz passive RFID fobs scanned into a Wiegand reader) and check it against a list of authorized tokens in the local memory/cache, allowing access if found. If the token is not found in local storage, the device should try to authenticate the token over the network, saving the token to local memory if network authentication passes. It should also be possible to update and overwrite the list of the tokens stored on the device remotely over the network.

Granting access will mean activating a relay or otherwise sending some sort of signal. First use case will be a door with an electric strike. I generally understand how to kludge together code to read Wiegand and to activate a relay.

I do need help learning how to store and look up tokens in memory. A hard requirement of this project is for the device to be tolerant of power and internet outages. The device may be backed up by a battery, but in case it restarts, it needs a “last known” list of tokens saved in non-volatile memory to fall back upon in case there is no internet (internet outages are common). I think 125kHz tag IDs go up to 30-something bits and I expect to store up to a few hundred of those values in memory. I am not sure if that much storage is available on the device.

As far as the networking resource for remote authentication, I have freeIPA/LDAP installed on a server instance that has the master list of active tokens in it. The instance may be on the local network or in AWS. My vague understanding is that I could maybe have the Particle device publish an authentication request and for the server to subscribe to that stream and push replies back somehow. I am not sure if there are better and more secure alternatives. This is something I need most input on.

Thanks for reading!

1 Like

All of the above should be fairly easy to acomplish.
There is definetly enough storage in NVM to store a few hundred 32bit values and once the 2MB external flash memory can be used with a simple API or library you should be good for several thousand.

Also Particle.publish()/Particle.subscribe() is quite secure as it is end-to-end encrypted and when you use an HTTPS webhook the connection between the Particle cloud and your server should bear minimal risk either.

BTW, there is another member here who already has a similar project running: @Mjones

1 Like

I have a project that uses 13.56MHz MiFare cards to control access to a bank of lockers with electronic locks. This is currently based upon Photon but could be ported to Gen3.

The basic idea is to store a database of valid cards on the device so that it can immediately determine whether to allow access to the door or locker without needing an internet connection.

A simple struct can be used for this:

struct Card {
uint32_t number;
uint8_t locker;
};
retained Card cards[200];

For each Authorised Card ID [200 off]
4 Byte - Unsigned Int - User Card ID
1 Byte - locker ID [0=none used, 1-160]
Total 5x200=1000 bytes in retained memory

You then need a couple of getters and setters to add and remove authorised card numbers and to compare the RFID scanned card and determine whether it is in the list of authorised cards. Hope this helps.

5 Likes

Hey @conspiracyx welcome to the forum. I’ll be happy to help if I can, though I wouldn’t have a working product without these guys, so use this to the fullest extent you can and don’t be afraid to ask questions so you understand what’s going on. One mistake I made in the beginning was being handed some code from another user and not knowing how it actually worked, made it almost impossible to troubleshoot when problems arose.

2 Likes

Welcome. If you don’t use the ethernet wing on the devices that are the “readers” - I am assuming the xenons will do this and the argon is a gateway, then you could put an SDcard on each and have a huge space to store tokens and logs etc.

If you do this - then consider using


to create a simple ‘database’ (really a rudimentary indexed table) to read and write the tokens. This will take away some of the issues of managing a large amount of tokens and let you focus on other bits of the code.

You could then call a function (once you have read the tag) something like this

void tagRead(unsigned long tagNum)
{
    for (int recno = 1; recno <= dbRecordsMax; recno++)
    {
        EDB_Status result = edb.readRec(recno, EDB_REC tagRecord);
        if (result)
        {
            printError(result);
            return;
        }
        // check for tagNum in DB
        if (tagRecord.tagNum == tagNum)
        { // found a valid exsting record
            Serial.printlnf("Tag %lu for %s accepted at %s", tagNum, tagRecord.userName, Time.timeStr().c_str());
            strike(on); // activate mechanism
            addLogEntry(tagNum); // save to a log of some sort - could be a Particle.Publish() etc
            return; // done processing, token found
        }
    }

    Serial.printlnf( "Tag %lu not found ", tagNum);
}

to compare your read token to a stored token. There are probably many other ways of doing this that may be faster - up to a few hundred records this is probably fast enough.

2 Likes

@shanevanj - Not sure if I read your post correctly, but the idea was to use both Argon and the Xenons as fully fledged “Access Control Devices” - fob reading, local memory token checking and network querying is to happen on all ACDs. The Argon obviously will be the one supplying network connectivity to all and placed in the most accessible and most used location (in this case front door). The Xenons will be deployed elsewhere to reduce cost to provide their own “rulesets” of access control (valid tokens) to other locations (for example a bank of lockers similar to what @armor did and various power tools that require authorization to use).

I am wary of using an SD card because the current solution that uses a RaspberryPi has been notorious for killing SD cards when power outages happen. I am also assuming SD cards are slower than on board or DIP flash memory.

On that note, the EDB github link is great. Is there more stuff like that our there I can read about? Also any in depth explanations on Argon/Xenon memory use (to help me decide if I need external memory or not)?

Very helpful stuff from everyone so far!

@conspiracyx So - firstly the SD is driven with DMA access and so is pretty fast. Secondly - I call a flush of the card data after each write - and you are only writing when you add a new token or add to a log. The threat of corruption in the method is extremely low, however each device must have a backup battery to ensure that the SD cycle can finish.

Yes the SD is slower than memory however in this scenario you will have sub-second response or better - it is all a matter of how much you need to store.

This is the “writer” function for the EDB library I use

// The read and write handlers for using the EDB Library
// Also blinks the led while writing
// ------------------------------------------------------------------------------
inline void
writer(unsigned long address, const byte *data, unsigned int recsize)
// ------------------------------------------------------------------------------
{
    led(on);
    dbFile.seek(address);
    dbFile.write(data, recsize);
    dbFile.flush();
    led(off);
}

So the EDB library uses a struct and in that I store the token number, last used time etc.

I use Photons with HID proximity cards for access control. I have a new design based on Gen 3 devices that I’ll be publishing as a tutorial or blog post soon. It decodes the Wiegand on the Argon, and has a relay to control a lock strike and an input for the magnetic door open sensor.

2 Likes

You are right to be wary - the SD cards are not likely to be damaged as much as the file system index can get corrupted if a file is open for read or write when the power goes off. The risk can be reduced considerably by careful code design. With Gen3 devices you can add a LiPo battery to act as backup so this should never be an issue! Speed wise - it depends on the SPI bus speed but fast enough such that a user would not notice.

The reference documents are there to help you answer questions about retained memory https://docs.particle.io/support/particle-devices-faq/code-size-tips/#retained-memory

Oh man that’s neat and what I imagine my solution will look like!

Are there any additional resources on webhooks? I have some existing Python code for querying LDAP for token authentication and would like to just extend it with minimal webhook code to listen for events from a Particle device and to post replies back.

Besides the documentation?

https://docs.particle.io/reference/device-cloud/webhooks/

Yes, aha. I meant not specifically for Particle, but for creating the remote end service for Particle to talk to.

1 Like

Webhooks just talk standard HTTP(S) requests GET, POST, PUT, DELETE.
So there isn’t really anything Particle specific to do on the remote end.

Yup, that should be a generic REST interface. Let the internet be your guide and try some Googling, you’ll find more than we could possibly tell you.

1 Like