w3c / web-nfc

Web NFC
https://w3c.github.io/web-nfc/
Other
308 stars 68 forks source link

TNEP research/explainer #567

Open kenchris opened 4 years ago

kenchris commented 4 years ago

TNEP - Tag NDEF Exchange Protocol

TNEP is a protocol based on top of NDEF. It extends NDEF with 3 new record types, one for the reader device (e.g. phone) and two for the tag device.

A tag device would be a smart device (active, powered) that emulates a tag type (Type 2, 3, 4, 5 are supported) which is able to expose NDEF when read and change the data exposed given some timing constraints.

The three record types are

NDEF implementations like our NDEFReader that does not support TNEP should ignore these records.

The Service Parameter records, in addition to the service name and operation mode (single return, or service specific) includes a bit of extra data which is very implementation specific, like max size of NDEFMessage it will return, protocol version, the minimum time to prepare a response as well as time extensions for slower operations.

As NDEF is polling based, it means that the poller should not read (or need to poll) before a certain minimum time. But as some operations might take long on a device (like doing some calculations) the device can also set a maximum extension value (repetitions version minimum time) before timing out a response.

The Android API doesn't have fine-grained control over the polling, to my knowledge, but as it seems that new values might be exposed as a new read, making single return works seems doable on top of what we have.

"single response" operation mode

This could work like with the current implementation without relying on the exact time to read.

select record => start timer for timeout => read new records (data + status) => stop timer.

"service specific" operation mode

This might be harder to implement correctly as it is a way to create custom protocols, like for instance a service that returns a new temperature reading every second until being deselected.

This operation mode also always first response with a status message and potential other data records.

When a status message with error is returned at some other point, the service should still not be deselected automatically.

Questions:

API shape

Something like the below seems to make sense for the single return case.

TNEPReader extends NDEFReader {
  Promise<sequence<NDEFRecord>> select(service);
  deselect();

  attribute EventHandler onservicefound;
}

Unfortunately, the service specific mode, would require our existing write() and onmessage event handler, which makes it a bit weird that the first response data is returned as part of select().

An alternative option would be to just let select() return a Promise<void> when successful and a rejected promise with the error code when not. From there on you would have to read and handle the data yourself. This means moving the FrozenArray from the event argument onto the TNEPReader (makes sense to do for NDEFReader as well then) in alignment with Generic Sensors, thus:

TNEPReader extends NDEFReader {
  Promise<void> select(service);
  deselect();

  attribute FrozenArray<NDEFRecord> records; // inherited

  attribute EventHandler onservicefound;
  attribute EventHandler onerror; // inherited
  attribute EventHandler onreading; // inherited
}

The service records would basically just need to expose service name url and communication mode and the implementation should take care of the rest.

TNEPService {
   readonly attribute USVString name;
   readonly attribute TNEPCommMode communicationMode;
}

If we need to expose more in the future that is totally doable, but it doesn't seem useful at this point.

TNEPService {
   readonly attribute USVString name;
   readonly attribute TNEPCommMode communicationMode;
   readonly attribute octet tnepVersionMajor;
   readonly attribute octet tnepVersionMinor;
   readonly attribute long minWaitTime;
   readonly attribute long maxWaitExtensions;
   readonly attribute long maxMessageSize; 
}
kenchris commented 4 years ago

Open Q: When deselecting a service (select with empty string basically) OR when selecting an unknown service, no status message is returned, so question is when do give up. If you select an unknown service, then we don't know the polling time.

kenchris commented 4 years ago

is timeout (max extensions * min time) per message or just the initial response?

Assumption, it is at least for the initial response, as status and data are delivered together, so this timeout should also count for initial response for service specific mode.

Assumption, this would be the same time constrains between messages (need to confirm)

Confirmed:

For sequential NDEF Read Procedures, twait is the time measured between the end of the last command of an NDEF Read Procedure and the start of the first command of the following NDEF Read Procedure.

kenchris commented 4 years ago

Selection

Selecting a new service while one is already selected, will (tag device requirement) auto deselect the existing service.

The reader SHOULD deselect a service after being done using it (single response - received data or error status).

Implementation: If a status record indicating success is received out of band (not in return to select) the current service should be deselected.

Note: this allows service specific services to auto deselect themselves and still use the status message to indicate errors.

Note: this probably means that after a service is deselected (other than by selecting a new service) you will receive a new onservicefound event.

After timeout (no messages received within time constraints) the reader should deselect the service

zolkis commented 4 years ago

What data would onservicefound carry?

I'd prefer the alternative option, plus a FrozenArray<TNEPService> services?

kenchris commented 4 years ago

@zolkis Yes, something like that. It makes sense to keep it on the main object as you probably want to select other services later

zolkis commented 4 years ago

Good! We can move records to the reader object already now.

kenchris commented 4 years ago

We can move records to the reader object already now.

Yes, and I suggested that before. There might be a few issue with regard to micro tasks so make sure it is never replaces while being used from JavaScript, but @anssiko will probably know how that was fixed in Generic Sensors

kenchris commented 4 years ago

Use-cases

TNEP allows for device communication like Bluetooth and USB does.

It is not high bandwidth like USB so it is probably more comparable to Bluetooth. The big difference is that it requires close proximity to the device which is better for privacy:

Also keep in mind that there is a new NFC Handover Record for Bluetooth LE that allows to handover communication to Bluetooth if requires/advantageous.

Examples

Today with my smart valves, I have to connect to the devices remotely (Bluetooth or Mesh network) but I need to press the valve to enable Bluetooth broadcast and additionally for the valve to show a number so that I can identify who I am talking to. All of that would be solved with TNEP and NFC.

First tap to the valve could load the URL to the web app (common NFC record) and a second tap allows me to get additional info from the valve as well as start a bluetooth handover. Potentially one tap would be all that is requires if we allow loading and then immediately share the read data with the web site as it instantiates a TNEPReader - but that is an implementation thing.

My smart valve might have a lot of info to share, like humidity and temperature over some time period, and using TNEP it would be possible to immediately share this info with the reading web app without Bluetooth and so on.

Example 2

A technician needs to debug a machine and can immediately read the machine info as well as debugging info using a simple TNEP enabled web app.

spencerc99 commented 5 months ago

hi! i was investigating the feasibility of a project involving a web app that allows phones to tap together to exchange info and did a deep-dive on the latest on p2p / HCE support for web-nfc.

I saw that the local peer-to-peer proposal has made it out into a prototype repo https://github.com/WICG/local-peer-to-peer but it seems like it uses local network for discovery and doesn't support NFC (correct me if I've read it wrong).

Curious what the latest status of TNEP is and how it might be integrated into that specification or other future ones. thank you!

anssiko commented 5 months ago

Quickly on the Local Peer-to-Peer API connection: NFC was discussed in the context of that API in https://github.com/WICG/proposals/issues/103#issuecomment-1680472714 when we initially submitted the proposal for community feedback. It remains a possible investigation topic when the foundations are in place as noted earlier.

TNEP and other proposed new features have been noted and the best way for the community members to contribute at this stage is to share in this repo more elaborate real-world use cases.

spencerc99 commented 5 months ago

great thank you for the overview!

To add some more detail to the use case I had in mind, I wanted to run an interactive workshop around how computers can be more commaunl facilitated by a web app that acts as a "Link Jar." Upon entering the site, people submit a link that has been meaningful to them lately. After, they are prompted to find someone else to work together to get a prize from the jar. I wanted to use web NFC here to facilitate a phone-to-phone tap that activates the interaction. To continue getting all the links, they have to continue the game with new people (unique pairs). I think supporting some form of peer-to-peer communication facilitated by NFCs would open up a whole world of interesting physical interactions and games with mobile devices, so looking forward to seeing the development on this front!