When Reyax offered me to send the RYR30D NFC module, I got excited to see that the module was compatible with the Apple Wallet VAS and Google SmartTap pass systems. These are state of the art NFC systems that enable most of todays mobile payment and transit systems so learning how to utilize them in a tinkering environment is an interesting challenge.
To demonstrate the capabilities of the RYRR30D modules, I set a goal to create an access log system that will send the data of the entry/exit events to a Notion database. By building this entry access log system, you'll be able to track when someone enters or exits a building or room.
NFC, or Near Field Communication, is a technology often used in contactless payment systems, access controls, and more because of its convenience and versatility. This project harnesses the capabilities of NFC by leveraging these communication tags and your mobile devices to easily register and log entries and exits. The use of Google Wallet adds the convenience of using digital cards, making it a nifty and modern application of NFC.
Additionally, we will use the Notion API to store and manage the collected data in Notion, a popular note-taking and organization tool. This integration will allow us to keep a systematic record of access logs within a designated Notion page. By the end of this tutorial, you'll see how technology can make it easier to keep track of access in a smart, organized way.
Digikey store: https://www.digikey.com/en/products/detail/reyax/RYRR30D/24714598
Amazon store: https://www.amazon.com/dp/B0DC61Q8WM
Tools and materials
- Reyax RYRR30D NFC Module: https://reyax.com/products/RYRR30D
- NodeMCU Development board - https://s.click.aliexpress.com/e/_oFSzYOF
You can fins some other tools and materials on the links below. These are affiliate links, so by purchasing through them, you support me and my work without any additional cost to you.
- ESP32 Development Board - https://s.click.aliexpress.com/e/_oDfFRiJ
- Sensors Kit - https://s.click.aliexpress.com/e/_oEHzkPN
- Multimeter - https://s.click.aliexpress.com/e/_oDhsLD9
- Bench Power Supply - https://s.click.aliexpress.com/e/_omSMd8F
- Soldering Station - https://s.click.aliexpress.com/e/_oDn78XN
- LCR tester - https://s.click.aliexpress.com/e/_olmYynd
- Basic Components Kit - https://s.click.aliexpress.com/e/_oFozE3z
Wiring
Getting your wiring set up is one of the first steps in building the NFC entry access log system. To start, we'll need to connect the RYRR30D NFC module to a microcontroller. In this setup, we'll use a UART (Universal Asynchronous Receiver-Transmitter) connection, which allows our microcontroller to communicate effectively with the NFC module using serial communication.
Here's a simple approach to get started. The RYRR30D module has a set of pins you'll need to connect to your microcontroller:
- Connect the VCC pin on the RYRR30D module to a 5V (Vin) power source from your microcontroller. Remember, the module operates at 5V for power but uses 3.3V logic, so ensure your microcontroller's logic level aligns to prevent any damage.
- Connect the GND pin on the module to a ground (GND) pin on your microcontroller to ensure a common ground reference.
- Connect the RX (receive) pin of the module to the TX (transmit) (D6) pin of your microcontroller. Similarly, connect the TX pin of the module to the RX (D5) pin of your microcontroller. This forms the basis of serial communication between the devices.
The wiring step is crucial, as a proper connection ensures smooth communication and functionality of the system. Once your wiring is done, we can proceed to configuring the module and starting with the software setup!
Mode Configuration
The RYRR30D NFC module offers two modes of operation: command mode and standalone mode. Understanding these two modes and setting up your module correctly is key to ensuring it performs as intended for your entry access log system.
When your module is in command mode, it waits for instructions sent via AT commands. This mode allows you to configure various parameters such as the baud rate, the type of cards to recognize, and other settings. It is how the module comes configured from the factory. You initiate command mode to set up your NFC module's basic operation and make changes as needed, directly from your microcontroller.
The second mode is the standalone mode. Once your module is set to standalone mode, it listens and responds to the NFC tags you want it to recognize without needing further instructions from a microcontroller for every tag read. This mode is ideal for continuous operation once your configuration is complete, as it automatically starts scanning for NFC tags.
To switch between these modes, you need to send specific AT commands (AT+MODE) to the module via the UART interface. For your project:
- First, ensure your module is in command mode to configure initial settings properly.
- Then, switch to standalone mode once set up so the module can autonomously handle NFC scanning for your system.
Integrating with Google Wallet
Integrating your system with Google Wallet allows you to use digital cards on your mobile phone as NFC tags, enhancing the convenience of the setup. To be able to issue your own SmartTap cards, you will need to go through the process of setting them up with Google. This is outside of the scope of this tutorial but for testing purposes, Reyax provides an integration and a card already set up that we can you.
To add the card to the wallet, we can go to the link provided by Reyax (you need to contact them for this) and from there you gonna get the option to add the card to your phone.
Once the card is added, we need to configure the RYRR30D module with the provided Google key so that the data of the card can be decrypted. This key can be added by a special command and once set, the module will be able to recognize and read the added card.
Integrating with Notion
Integrating the NFC entry access system with Notion provides an interesting way to manage your log data. Notion is a great tool for organizing information due to its customizable and flexible database structure. Here’s how you can set up the integration to store entry and exit logs captured by your system.
Step 1: Create Your Notion API Integration
Start by setting up a Notion API integration. Head over to the Notion developers portal and generate an integration, which will give you an integration token. This token allows your Arduino setup to communicate with your Notion account without manual intervention. Make sure to note this integration secret, as you will need it to authenticate requests from your device.
Step 2: Prepare Your Notion Databases
Create a dedicated page in your Notion account for storing the access logs. In the demo, I use two tables: one for users, containing user information and assigned tags, and another for the access logs themselves. The logs table would have fields for entries like name, timestamp, and the type of event (entry or exit).
Step 3: Configure Permission Access
With your integration token and databases ready, you need to authorize your integration to read and write to these tables. Go to the settings of your Notion page or database and grant the created integration the necessary permissions to manage data on your behalf.
Your Arduino would then connect to the Notion API, allowing it to update the log each time a registered entry or exit takes place. This works by matching scanned NFC IDs against the user table, then logging activity in the access logs with associated details.
Code
The full code for the example is provided below. Keep in mind that you will need to create your own secrets.h file for the WiFi details as well as the Notion API key and the identifiers for the Users and Access Log tables.
#define WIFI_ID "YOUR WIFI NAME"
#define WIFI_PASSWORD "yourwifipassword"
#define NOTION_API_KEY "ntn_api-key"
#define MOTION_USERS_TABLE "users_table_id"
#define NOTION_ACCESS_LOG_TABLE "access_log_table_id"
Code on the Entry Device:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <SoftwareSerial.h>
#include <ArduinoJson.h>
#include <map>
#include "secrets.h"
#define RXD2 14
#define TXD2 12
SoftwareSerial mySerial(RXD2, TXD2);
String content = "";
// Create a map to hold the keyed users
std::map<String, std::pair<String, String>> users;
void setup() {
Serial.begin(115200);
mySerial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_ID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
getPagesInDatabase(MOTION_USERS_TABLE);
}
void loop() {
if (Serial.available()){
Serial.println("Writing");
content = Serial.readString();
content.trim();
Serial.println();
content = content + "\r\n";
char* bufc = (char*) malloc(sizeof(char) * content.length() + 1);
content.toCharArray(bufc, content.length() + 1);
mySerial.write(bufc);
free(bufc);
}
parseAndPrintID();
}
void parseAndPrintID() {
// Check if data is available from the module
while (mySerial.available()) {
String input = mySerial.readStringUntil('\n');
input.trim(); // Remove any extra whitespace
String id = "";
if (input.startsWith("+ISO14443A=")) {
// Extract the ID part of the string
id = input.substring(11);
Serial.println("ID: " + id);
} else if (input.startsWith("+GOOGLE=1,")) {
id = input.substring(10);
Serial.println("ID: " + id);
}
if(id != "") {
if (users.find(id) != users.end()) {
// Entry exists, retrieve it
auto userDetails = users[id];
Serial.print("User Details for Identifier ");
Serial.println(id);
Serial.print(" Name: ");
Serial.println(userDetails.first); // User Name
Serial.print(" User ID: ");
Serial.println(userDetails.second); // User ID
registerEntry(userDetails.second);
} else {
Serial.println("Identifier not found.");
}
}
}
}
void getPagesInDatabase(const char* databaseId) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
WiFiClientSecure client;
client.setInsecure(); // Use this line to skip certificate validation (Testing only)
String apiUrl = String("https://api.notion.com/v1/databases/") + databaseId + "/query";
http.begin(client, apiUrl.c_str());
http.addHeader("Authorization", String("Bearer ") + NOTION_API_KEY);
http.addHeader("Notion-Version", "2022-06-28");
http.addHeader("Content-Type", "application/json");
// Since we are ignoring filters, send an empty JSON payload or minimal where applicable
String jsonPayload = R"({
"sorts": [
{
"property": "ID",
"direction": "ascending"
}
]
})";
int httpResponseCode = http.POST(jsonPayload);
if (httpResponseCode > 0) {
String response = http.getString();
//Serial.println(httpResponseCode);
//Serial.println(response);
parsePagesJson(response);
} else {
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
http.end(); // End the HTTP connection
} else {
Serial.println("Error in Wi-Fi connection");
}
}
void parsePagesJson(String jsonResponse) {
// Allocate a size buffer for the JSON document
DynamicJsonDocument doc(4096);
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, jsonResponse);
// Check for errors in deserialization
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
JsonObject list = doc.as<JsonObject>();
JsonArray results = list["results"];
for (JsonObject result : results) {
String identifier = result["properties"]["Identifier"]["rich_text"][0]["plain_text"].as<String>();
String name = result["properties"]["Name"]["title"][0]["plain_text"].as<String>();
String userId = result["id"].as<String>();
// Store into map by identifier, with a pair containing name and userId
users[identifier] = std::make_pair(name, userId);
}
// Print results
for (const auto& entry : users) {
Serial.print("Identifier: ");
Serial.println(entry.first);
Serial.print(" Name: ");
Serial.println(entry.second.first);
Serial.print(" User ID: ");
Serial.println(entry.second.second);
}
}
void registerEntry(String user_id) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
WiFiClientSecure client;
client.setInsecure(); // Use this line to skip certificate validation (Testing only)
http.begin(client, String("https://api.notion.com/v1/pages"));
http.addHeader("Authorization", String("Bearer ") + NOTION_API_KEY);
http.addHeader("Content-Type", "application/json");
http.addHeader("Notion-Version", "2022-06-28");
String jsonPayload = String(R"(
{
"parent": { "database_id": ")") + NOTION_ACCESS_LOG_TABLE + R"(" },
"properties": {
"Event Type": {
"title": [
{
"text": {
"content": "ENTRY"
}
}
]
},
"Users": {
"relation": [
{ "id": ")" + user_id + R"(" }
]
}
}
}
)";
int httpResponseCode = http.POST(jsonPayload); // Make the POST request
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println(httpResponseCode);
if (httpResponseCode == 200) {
for(int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, LOW);
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
}
}
//Serial.println(response);
} else {
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
digitalWrite(LED_BUILTIN, LOW);
delay(2000);
digitalWrite(LED_BUILTIN, HIGH);
}
http.end(); // End the HTTP connection
} else {
Serial.println("Error in WiFi connection");
}
}
The exit device uses the exact same code but replaces "ENTRY" with "EXIT".
Security Considerations
Keep in mind that this is just a demo project and that it is not intended for production use. If you are to build a system based on the RYRR30D module, you need to make sure that you go over the process of issuing your own cards or passes and making sure to add additional security measures in your system.
Conclusion
To wrap up the project, we've successfully built an NFC entry access log system that integrates seamlessly with Google Wallet and Notion through their API. Through the use of the RYRR30D module, we've brought together different technologies to create an interesting solution for tracking entries and exits in a given space.
With this setup, users can use their mobile devices loaded with digital cards or traditional NFC tags to record their presence. The integration with Notion offers an organized and easily accessible way to store and review access logs. You now have the power to customize this project further to match your specific use cases, such as expanding security features or adding user management capabilities.
This project serves as a solid starting point to explore the potential of NFC technology in various applications. Remember to handle the integration secrets securely and always maintain awareness of the security considerations we've discussed. I hope you enjoyed building this project and feel inspired to continue creating and exploring the exciting world of NFC technology and automation. If you have any questions, feel free to reach out, and don’t forget to share your versions of this system!
For additional projects, consider subscribing to my YouTube channel.