NFC - Near Field Communication

The nfc extension allows you to read and write nfc tags through the system. There are a variety of supported readers that you can use.

It is important that you pay attention to the type of tag and reader you are using. Not all readers work with all tags and not all readers have all the features of others.

To get a little more familiar with NFC it is suggested that you download an NFC app on your phone and try reading/writing to a tag. Most newer phones support NFC but usually it has to be enabled in settings.


Extension Configuration

Here are the settings to provide a NFC reader/writer connection that can communicate with tags.

OptionTypeRequiredDescription
key[String]YesUnique slug id for the component
address[String]YesAddress of NFC reader. i.e. usb:072f:2200 If no address is set MudPi will try to find a default using the model. If no address or model is set then an error will be raised.
name[String]NoFriendly display name of component. Useful for UI.
model[String]NoModel of the reader. Used if no address is set to attempt and find default address. See options here
beep_enabled[Boolean]NoSet to True if reader should beep when tag is scanned (if hardware supports it). Default: false
writing[Boolean]NoSet to true to enable writing to tags. Default: false
tracking[Boolean]NoSet to true to enable writing simple tracking data to tags. Default: false. You must have writing enabled to use tracking.
persist_records[Boolean]NoIf true any existing records will be kept on tag during and writes. Only tracking data will be updated. Default: true
tags[Dict]NoA dict of tags keyed by the tag serial to preregister to the system.
save_tags[Boolean]NoSet to true to save any scanned tags into tags in the config. Default: false
default_records[Array]NoA list of default records to write to each tag if writing is true.
store_logs[Boolean]NoLog a list of recent tag scans if set to true. Default false
log_length[Integer]NoWhen store_logs is enabled this is the max length of the log. Default: 100
read_delay[Float]NoTime in seconds to wait between read attempts. Default: 0.5

Config Examples

Here is the config of a complete NFC setup.

"nfc": {
    "key": "nfc_usb_reader",
    "address": "usb:072f:2200",
    "model": "ACR122U",
    "beep_enabled": false,
    "tracking": false,
    "persist_records": true,
    "save_tags": false,
    "writing": true,
    "default_records": [
        {
            "type": "text",
            "data": "MudPi",
            "position":0
        },
        {
            "type": "uri",
            "data": "https://mudpi.app/docs",
            "position":1
        }
    ]
}

Tag Events

Once you have configured a NFC reader in MudPi you can now scan tags / cards. Anytime you scan a tag MudPi will emit a NFCTagScanned event on the nfc topic. This event will contain data about the tag including and NDEF data found.

The tag will be considered new if if was not previously read and not found in the tags config dict. When a new tag is found a NFCNewTagScanned event is emitted with data about the tag including any NDEF data.

Another useful feature is that you may want to know when a tag was removed from the reader. This can be useful if you want to enable features only while a tag is present. To listen when a tag is removed you can check for a NFCTagRemoved event on the nfc topic when the tag is removed.

Writing to Tags

MudPi can also write to the tag as well if your hardware supports it. Be sure to verify the card type before writing to it and that your writer supports it. Writing to tags is disabled by default but if you wish to enable it you can set writing to true in you configs.

Default Tag Records

Data written to tags is in the form of NDEF. MudPi will write some basic data such as some text and a link to the nfc docs to the tag for you if writing is enabled. If you wish to disbale this default data you can set default_records to an empty list.

If you wish to provide your own default records then you can provide a list of dict objects with the following options:

OptionTypeRequiredDescription
data[String]YesData to write to card. If its a URI be sure to include any protocols or headers such as http://.
type[String]NoType of NDEF data to write. Options text and uri. Default is text.
position[Integer]NoPosition you want data inserted into records list. List is 0 based index. If no position is set the data is appended to end.

Tracking

Another useful feature with writing to tags is tracking. If enabled tracking provides some simple records that will be wrote the the tag to add additional use information. By default MudPi will only rememebr the tag serial number. This data is forgot on every reset if save_tags is not enabled as it is only stored in memory.

When you enable tracking MudPi will write two additional records to the tag including a count:# and a last_scan:{datetime}. The count is a simple counter that gets incremented everytime the card is scanned. This can be useful to track scan totals. The other data stored is a last scan datetime. This just informs us the last time the card was scanned.

Tag UID

Each tag comes with a unique serial number that cannot be changed and is set by the manufacture. This serial number, or tag_id, is often the main way to track a tag and how MudPi tracks tag scans by default. As an added security measure when writing is enabled MudPi will generate a uuid for the card that will be stored. This uuid paired with the tag serial number allows MudPi to detect copies of cards or if data was altered outside of MudPi. In the event a mismatching uuid is found then MudPi will emit a warning event NFCTagUIDMismatch you can hook into. MudPi also provides two other security events NFCTagUIDMissing and NFCDuplicateUID for you to monitor as well.

Preregister Tags

You may want to preregister tags in the system so that MudPi can perform additional operations. If you want to preregister a tag you can do so in the tags option of the configuration. The tags is a dict object keyed by the serial number of the tag and contains the tag data such as a tag_uid. If you want MudPi to generate a tag_uid for you then omit this option and set save_tags to true so MudPi will save a new one on the next scan.

If you wish to provide default_records specific for a tag then you can provide them here in the same format as described above. Put them under a key default_records for the tag you want them to be wrote to.

Here is an example of a preregistered tag with a serial of 123456789ABCD:

"nfc": {
    ...
    "tags": {
        '123456789ABCD': {
            "tag_uid": "123113-12313123-123123131-1331231",
            "default_records": [
                {
                    "type": "text",
                    "data": "Custom Default Record for Tag",
                    "position":0
                }
            ]
        }
    }
}

If you have save_tags set to true then MudPi will update this tags dict for you with new tags as they are scanned in the system.


Trigger Interface

The NFC extensions also provides a trigger interface that listens to nfc scan events. While in most cases a state trigger is the suggested option sometimes it can be useful for additional behavor such as only responding to new tags scanned in the system. This is where the nfc trigger interface is useful.

OptionTypeRequiredDescription
key[String]YesUnique slug id for the component
source[String]YesComponent key to check for new state. Typically a serial tag_id or the key of the nfc reader.
nested_source[String]NoIf the data is an object this is the key from that object to fetch. Can be used to extract keyed data from tags.
frequency[String]NoNumber of times to trigger actions once trigger is active. Options: once, many. Default: once
name[String]NoFriendly display name of component. Useful for UI.
type[String]NoNFC trigger type which determines the event to be listened too. Options: tag_scanned, new_tag, tag_removed. Default: tag_scanned
actions[List]NoList of registered actions to fire.
thresholds[Array]NoArray of threshold configuration objects to evaluate the reading data to.

Config Examples

Here is a config of a trigger that checks for when a specific tag is scanned. This configuration would turn_on all toggles if a tag is scanned with a serial tag_id of ABCDEF12345789.

"trigger": [{
    "key": "nfc_trigger",
    "interface": "nfc",
    "source": "ABCDEF12345789",
    "name": "Tag Scanned",
    "type":"tag_scanned",
    "frequency":"many",
    "actions": ["toggle.turn_on"]
}]

When no tresholds are set this triggers anytime a tag is scanned based on what we set in the source. Instead of putting a tag_id in the source you could also provide the key from the NFC extension config and then the trigger will fire for only tags scanned by that reader.

Here is a config of a trigger that checks for when only new tags are scanned for a specific reader with a key of usb_nfc_reader.

"trigger": [{
    "key": "nfc_new_tag_trigger",
    "interface": "nfc",
    "source": "usb_nfc_reader",
    "name": "New Tag Scanned",
    "type":"new_tag",
    "frequency":"many",
    "actions": ["toggle.turn_on"]
}]

For this config we used the key of the nfc reader config as our source. This trigger will fire anytime a new tag is scanned on our nfc reader that has a key of usb_nfc_reader.


Sensor Interface

The NFC extensions also provides a sensor interface that listens to nfc scan events for a tag. The nfc extension handles the reader configuration and emits events when tags are scanned. The extension can store a log of recent tags but in some cases you may want to track a specific tags data in MudPi. This is where the sensor interface is used.

OptionTypeRequiredDescription
key[String]YesUnique slug id for the component
name[String]NoFriendly display name of component. Useful for UI.
tag_uid[String]Yes*A tag UID to filter events for.
tag_id[String]Yes*A tag serial ID to filter events for.
reader_id[String]NoA nfc reader key to filter events by.
security[Integer]NoSecurity level for tag. Options: 0, 1, 2. Default: 0

Configuring the NFC Tag Sensor

The most important setting for the sensor and how it knows what tag to track is based on the tag_id or tag_uid. You only need one but can provide both for more precise filtering. The tag_id is burned to the tag on a hardware level and can not be changed where the tag_uid is set by MudPi and can be changed. It's up to you to provide which makes more sense for your needs. You can also provide a reader_id which matches a key set on the nfc extension config for a reader. This would filter out events and make it so your tag sensor only updates when its scanned on a specific reader set by this reader_id.

NFC Tag Security

One aspect of NFC tags is to use them for authorization and security purposes. An example of this may be enabling a button only after a NFC tag was scanned with proper data attached. To help with security of these tags MudPi offers some general features to help prevent possible unauthorized access. One way MudPi does this is by generating and attaching a UUID for each card if writing is enabled. This UUID is paired with the non-changeable tag serial ID. The combination of the two IDs allows MudPi to determine if a card was copied or altered outside of MudPi. While this is not always a result of malicious intent it can be a clear indicator that something not normal is going on.

By default these security checks are disabled. You can change the security setting in your tag config to enable the different security levels. The default 0 is disabled. Setting security to 1 enables the checks but does not enable any action from MudPi. Using 1 is a way to enable just monitoring. MudPi will emit an event if it detects a problem with the tag data and add a security_check attribute to the tag data if it encounters anything.

If you wish to enable full security then change security to 2. This will enable MudPi to perform checks and also in the event it detects one it will then lock the tag form working in MudPi. This tag will be locked out of the MudPi system and it will no longer perform actions. You can still scan the tag but MudPi will notify you the card is locked for security reasons. You will need to restart MudPi or run the unlock action on the tag to re-enable it. This is just another way MudPi can help prevent unauthorized NFC tags and help detect any possible issues.

Config Examples

Here is a config of a trigger that checks for when a specific tag is scanned. This configuration would turn_on all toggles if a tag is scanned with a serial tag_id of ABCDEF12345789.

"sensor": [{
    "key": "nfc_tag_1",
    "interface": "nfc",
    "name": "MudPi NFC Tag 1",
    "tag_id": "123456789ABCDF"
}]

This tag sensor would be updated anytime a tag is scanned that has a serial id of 123456789ABCDF.

Here is another example that also provides a tag_uid and reader_id to listen for even more specific tag events.

"sensor": [{
    "key": "nfc_tag_1",
    "interface": "nfc",
    "name": "MudPi NFC Tag 1",
    "tag_uid": "67aaa6956-aaaa-aaaa-aaaa-a1b2f12f9a38",
    "tag_id": "123456789ABCDF",
    "reader_id": "nfc_usb_reader",
    "security": 0
}]

With this configuration the sensor would only update the tag if it was scanned on the reader with a key of nfc_usb_reader and the tag data has both the matching tag_id and tag_uid.


Setting Up NFC on Raspberry Pi or Linux

There are a number of readers you can choose from, I personally found success with the usb readers. On most linux distributions the needed drivers will already be installed. You should visit the reader manufactures page to get any missing drivers if you get errors. The NFC reader has a default address you can use or you can look up the address by running the nfc module with the following command.

python3 -m nfc

This should output some information about any discovered readers and their address. It is likely that you will run into permission errors on your first run. This is because you need to add some rules and groups that will be suggested to you when running the command above.

On the raspberry pi I ran the following command to give proper permissions to the reader through a plugdev group:

sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"072f\", ATTRS{idProduct}==\"2200\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules' 

I than ran the next command and reattached the reader:

sudo udevadm control -R

You will also need to be sure the user account is a member of this plugdev group we just setup permissions for.

sudo adduser mudpi plugdev