Communicate an NFC reader with a web application
Gautier Darchen
- 23 🎂
-
Fullstack dev at Takima since 2018
Working at Cartier in a lab- React
- Node.js
- Java / Spring
- Devops
- Easily know the remaining tasks to be performed on a piece of jewelry for a given person
- Bar code / QR code
-
Innovation & a lot of data to hold
-
Innovation & a lot of data to hold
-
RFID- Short-range
- Short-range
- NFC ✅
NFC today
- Omnipresent in our daily life
- Contactless payment, access badge, etc.
- Cheap (NTAG 213 : about $ 0.08 per chip)
- Different types: frequency, encryption, etc.
Target application 🎯
Loading page
Result page
Local server NFC Reader and web-sockets
1st iteration
Summary
-
Buy a NFC Reader 💸
- ACR 122U — USB NFC Reader
Advanced Card System Ltd.
- ACR 122U — USB NFC Reader
- Node.js server on the client ➡️ plugged devices 🔌
- Use a PC/SC library 📕
- Communicate the read payload to the web app via web-sockets 🧦
Connection workflow
NTAG 213
Memory organization
Local server
// src/index.js
// ...
io.on('connection', (socket) => {
socket.on('require-scan', () => {
const nfc = new NFC();
nfc.on('reader', (reader) => {
const pageNumber = 4;
const bufferLength = 48;
reader.on('card', async (card) => {
try {
const data = await reader.read(pageNumber, bufferLength);
const extractedPayload = data.toString().split('/')[1];
socket.emit('nfc-tag-scanned', extractedPayload);
} catch (err) {
// boilerplate code to handle the error
}
});
});
});
});
Client app
// src/pages/home/components/HomeContainer.jsx
// ...
const HomeContainer = () => {
const [socket, setSocket] = useState();
const [readTag, setReadTag] = useState();
useEffect(() => {
setSocket(SocketIO.connect(APILocalSocketUrl));
}, [APILocalSocketUrl]);
useEffect(() => {
if (!socket) {
return () => {};
}
socket.emit("require-scan");
socket.on("nfc-tag-scanned", payload => {
setReadTag(payload);
});
return () => socket.close();
}, [socket]);
return <Home readTag={readTag} />;
};
export default HomeContainer;
Demo 1
Cons
- Node.js on the client 🛠
- Start the web-socket server 👷
-
Update on each client web-socket server if needed 🔄
- Works well on servers, what about desktop apps?
- Change our distribution mode
Pros
- Last version of the app ⚡️
Key learnings
- Easy installation 🛠️
- Easy distribution 🚚
- Desktop app 🖥️
How to do it with web technologies? 🤔
Electron application using a NFC Reader
2nd iteration
Electron
Build cross platform desktop apps with JavaScript, HTML, and CSS
- Easy installation on the client side
- Node.js server on the client side
- File-system, hardware, etc.
Summary
-
NFC reader bought for solution #1
- Electron ➡️ plugged devices 🔌
- Use a PC/SC library that we already master 📕
Use the library
const HomeContainer = () => {
const nfc = new NFC();
const [readTag, setReadTag] = useState(undefined);
nfc.on("reader", reader => {
const pageNumber = 4;
const bufferLength = 48;
reader.on("card", card => {
reader.read(pageNumber, bufferLength).then(data => {
const extractedPayload = data.toString().split("/")[1];
setReadTag(extractedPayload);
});
});
});
return <Home readTag={readTag} />;
};
Demo 2
Limits
- Build for each target platform
- Reinstall on each device after updates
- Packaging and installation
- Slow and heavy release cycles
- Configuration to use native modules
Dream solution
- Web app 🌐
- Nothing installed client-side 🤤
Using WebUSB and an Arduino board
3rd iteration
WebUSB API
- API implemented in the browser 🌐
- "Plug and play" devices for web apps 🔌
- Security: "web origins" (white list) 🛡
-
Equivalent to CORS for HTTP requests
-
Equivalent to CORS for HTTP requests
- Native code & SDKs ➡️ cross-platform & "web-ready" libraries 📚
W3C spec draft: wicg.github.io/webusb
WebUSB API
Workflow
NFC Reader
- Arduino Leonardo
Compatible devices here:
https://github.com/webusb/arduino#compatible-hardware
- Adafruit PN532 NFC/RFID Controller Shield
- A bit of solder 👨🏭
1/2
NFC Reader
- $50 per device 💵
- Handicraft and not yet industrialized 👨🔬
- Will be subcontracted
2/2
Arduino programming
Import libraries and configure the WebUSB Serial
// NFC Reading libraries
#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
// WebUSB library
#include <WebUSB.h>
// Web origin
#define PROTOCOL_HTTP 0 /* http:// */
WebUSB WebUSBSerial(PROTOCOL_HTTP, "localhost:3000");
// NFC Shield configuration
PN532_I2C pn532_i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532_i2c);
#define BAUD_RATE 9600
Arduino programming
Reading loop
void loop() {
if (nfc.tagPresent()){
NfcTag tag = nfc.read();
if (tag.hasNdefMessage()) { // If your tag has a message
NdefMessage message = tag.getNdefMessage();
// If you have more than 1 record then it will cycle through them
int recordCount = message.getRecordCount();
for (int i = 0; i < recordCount; i++) {
NdefRecord record = message.getRecord(i);
int payloadLength = record.getPayloadLength();
byte payload[payloadLength];
record.getPayload(payload);
String payloadAsString = ""; // Processes the message as a string vs as a HEX value
for (int c = 0; c < payloadLength; c++) {
payloadAsString += (char)payload[c];
}
WebUSBSerial.write(payloadAsString.c_str());
}
}
};
WebUSBSerial.flush();
delay(250);
}
Client live coding
👨💻
Working zone 🚧
- Draft Community status (since Aug. 2019)
- Enabled in Chrome 61 (Sept. 2017)
- Disabled for several months (security)
- Only available in secured context (HTTPs)
Production 🏭
- Only client-side code
- https://gdarchen.github.io/webusb-arduino-nfc/
Thank you! 🙏
Light - Communicate a NFC Reader with a web application
By Gautier Darchen
Light - Communicate a NFC Reader with a web application
Lorsqu'on développe un outil qui interagit avec un périphérique, nous sommes encore forcés de développer des clients lourds ou d'utiliser des conteneurs comme Electron. Pourquoi ne pas directement utiliser le navigateur? Eh oui, vos browsers, et notamment Chrome, ont de plus en plus d'APIs vous permettant d'accéder à des parties natives de vos équipements. Viens découvrir la WebUSB API à travers un exemple simple : la réalisation d'un lecteur de carte NFC en 100% web.
- 1,172