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.
Here are the settings to provide a NFC reader/writer connection that can communicate with tags.
Option | Type | Required | Description |
key | [String] | Yes | Unique slug id for the component |
address | [String] | Yes | Address 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] | No | Friendly display name of component. Useful for UI. |
model | [String] | No | Model of the reader. Used if no address is set to attempt and find default address. See options here |
beep_enabled | [Boolean] | No | Set to True if reader should beep when tag is scanned (if hardware supports it). Default: false |
writing | [Boolean] | No | Set to true to enable writing to tags. Default: false |
tracking | [Boolean] | No | Set to true to enable writing simple tracking data to tags. Default: false . You must have writing enabled to use tracking. |
persist_records | [Boolean] | No | If true any existing records will be kept on tag during and writes. Only tracking data will be updated. Default: true |
tags | [Dict] | No | A dict of tags keyed by the tag serial to preregister to the system. |
save_tags | [Boolean] | No | Set to true to save any scanned tags into tags in the config. Default: false |
default_records | [Array] | No | A list of default records to write to each tag if writing is true. |
store_logs | [Boolean] | No | Log a list of recent tag scans if set to true. Default false |
log_length | [Integer] | No | When store_logs is enabled this is the max length of the log. Default: 100 |
read_delay | [Float] | No | Time in seconds to wait between read attempts. Default: 0.5 |
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
}
]
}
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.
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.
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:
Option | Type | Required | Description |
data | [String] | Yes | Data to write to card. If its a URI be sure to include any protocols or headers such as http:// . |
type | [String] | No | Type of NDEF data to write. Options text and uri . Default is text . |
position | [Integer] | No | Position you want data inserted into records list. List is 0 based index. If no position is set the data is appended to end. |
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.
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.
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.
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.
Option | Type | Required | Description |
key | [String] | Yes | Unique slug id for the component |
source | [String] | Yes | Component key to check for new state. Typically a serial tag_id or the key of the nfc reader. |
nested_source | [String] | No | If 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] | No | Number of times to trigger actions once trigger is active. Options: once , many . Default: once |
name | [String] | No | Friendly display name of component. Useful for UI. |
type | [String] | No | NFC trigger type which determines the event to be listened too. Options: tag_scanned , new_tag , tag_removed . Default: tag_scanned |
actions | [List] | No | List of registered actions to fire. |
thresholds | [Array] | No | Array of threshold configuration objects to evaluate the reading data to. |
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
.
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.
Option | Type | Required | Description |
key | [String] | Yes | Unique slug id for the component |
name | [String] | No | Friendly 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] | No | A nfc reader key to filter events by. |
security | [Integer] | No | Security level for tag. Options: 0 , 1 , 2 . Default: 0 |
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
.
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.
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
.
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