Web NFC (and writing to NFC tags)

Posted on
  • Hi, I'll try and turn this into a tutorial at some point, but it turns out you can now use 'Web NFC' on Android to read and write NFC tags including Puck.js/Pixl.js.

    HTML looks like this:

    <html>
    <body>
    <script>
    /* Starting a scan at startup stops Android from
    moving away from the Chrome window when a tag is found*/
    const reader = new NDEFReader();
    const writer = new NDEFWriter();
    reader.scan();
    
    function send(msg) {
      writer.write(msg).then(_=>console.log("W­ritten ",msg));
    }
    </script>
    <button onclick="send('red')">Red</button>
    <button onclick="send('green')">Green</button>
    <button onclick="send('blue')">Blue</button>
    </body>
    </html>
    

    Puck.js/Pixl.js code is a bit more complex as right now it's emulating an NFC tag in JS:

    var data = new Uint8Array(10+64);
    var header = NRF.nfcStart();
    var written = false;
    data.set(header,0); // NFC device header
    data.set([0,0,0xE1,0x10,(data.length-10)­/8,0,0,3,0,0xFe], 0x0A); // NDEF tag header
    // 0,0,e1
    NRF.on('NFCrx', function(rx) {
      var idx = rx[1]*4;
      switch(rx[0]) {
        case 0x30: //command: READ
          NRF.nfcSend(new Uint8Array(data.buffer, idx, 16));
          break;
        case 0xa2: //command: WRITE
          written = true;
          if(idx > data.length) {
            NRF.nfcSend(0x0);
          } else {
            data.set(new Uint8Array(rx, 2, 4), idx);
            NRF.nfcSend(0xA);
          }
          break;
        default:   //just, re-enable rx
          NRF.nfcSend();
          break;
        }
    });
    NRF.on("NFCoff",function() {
      if (written) 
        onWritten(E.toString(new Uint8Array(data.buffer,26,data[21]-3)));­
      written = false;
    });
    
    function onWritten(data) {
      console.log("NFC written", data);
      var colors = {
        red : 1,
        green : 2,
        blue : 4,
      };
      if (colors[data]) {
        digitalWrite([LED3,LED2,LED1], colors[data]); //  onwards
        setTimeout(function() {
          digitalWrite([LED3,LED2,LED1], 0);
        },1000);
      }
    }
    

    But basically this lets you send strings of data over NFC (no bluetooth connection needed). You just hold the phone near, tap 'red/green/blue' and then when you move the phone away Puck.js reads the text in the tag and decides what colour to make itself...

  • NDEFWriter has been merged into NDEFReader recently. See https://github.com/espruino/EspruinoDocs­/pull/589

  • Thanks! Updated code is here: http://www.espruino.com/Web+NFC

  • Hi. Looking at this code it would seem that programming is done with an Android device. Is there an option to do so by program ? The idea would be to dynamically change the Tag content. The NRF.nfcURL is stated to advertise an URL. Would that be as a tag and can this url be updated with subsequent calls to this function ?

  • Hi. Looking at this code it would seem that programming is done with an Android device. Is there an option to do so by program ? The idea would be to dynamically change the Tag content. The NRF.nfcURL is stated to advertise an URL. Would that be as a tag and can this url be updated with subsequent calls to this function ?

  • The NRF.nfcURL is stated to advertise an URL. Would that be as a tag and can this url be updated with subsequent calls to this function ?

    Yes - absolutely! So once called, if the Puck.js/etc is scanned with a device then that device will grab the URL. You can change the URL as often as you like so can transfer information that way if you wish.

  • Yes this works however it seem to be some kind of unwarranted size limitation. The TAG has a max message size of 246 bytes (256-10 I guess) while the capabilities NDEF Capability container has 992 bytes. I assume this is set during initialization before the actual URL is set. Adding a longer URL just truncate it... Any clue on how to fix this ?

  • Adding a longer URL just truncate it

    you mean you need url over 246 characters?

    Any clue on how to fix this ?

    I think this line is the issue, it saves length as single byte
    https://github.com/espruino/Espruino/blo­b/master/libs/bluetooth/jswrap_bluetooth­.c#L2456
    also mentioned here https://github.com/espruino/Espruino/blo­b/master/libs/bluetooth/bluetooth.h#L335­
    Most probably this limit is because the SR bit for short record is set in the header so the payload length is really using only 1 byte.

    Fortunately there is also the NRF.nfcRaw where you can build whole array as you wish including short bit cleared and payload length stored in 32 bits.
    More info about the structure e.g. here https://w3c.github.io/web-nfc/#the-ndef-­record-and-fields
    Maybe easiest is to use NFC TagWriter to write such long url over NFC and see how the array looks and start from that and build it with NRF.nfcRaw yourself?

  • Yes I need a longer URL. To give some context I am including a signature in the URL over the payload and that stretches well beyond the current limit but may be viable if the 900+ available space.
    Thank you for the assistance and I now know how to attack this.

  • Oh, actually when checking nfcRaw method it has same limitation :-(
    https://github.com/espruino/Espruino/blo­b/master/libs/bluetooth/jswrap_bluetooth­.c#L2638
    So it is not as raw as one would expect.

  • Bummer so major surgery is needed. But thanks I now where to look to correct this. I have to check if we want to go this route and take it from there.

  • I have reported it here https://github.com/espruino/Espruino/iss­ues/2406

    Looks like bug as all the allocations and adding termination part uses full length.

    Until that is fixed you could also use the code above in post #1 which emulates whole NFC tag including everything.

  • Made a PR with a fix, both NRF.nfcUrl and NRF.nfcRaw should work with NDEF block length over 254 bytes. It works for me.

  • Thanks for your work on this @fanoush! I'm just back from holidays today but I'll give this a check over and merge ASAP

  • It was good timing. Never tried NFC before but now I am testing those 52832 based keychain NFC tags https://forum.espruino.com/conversations­/388395/

    They are simple - no sensors, just button, two leds, piezo and NFC, but they are small and cheap and even have 32kHz crystal and DC/DC enabled. Espruino on the keychain is cool and NFC and piezo speaker is a nice bonus, typical smart watch is missing both.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Web NFC (and writing to NFC tags)

Posted by Avatar for Gordon @Gordon

Actions