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
       
  • RFID
    • 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.
       
  • 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
       
  • Native code & SDKs  ➡️ cross-platform & "web-ready" libraries 📚

W3C spec draft: wicg.github.io/webusb

WebUSB API

Workflow

NFC Reader

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 🏭

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,123