OpenTag3D Standard

Current Version: 0.003

Hardware Standard

The OpenTag3D standard is designed for the NTAG213/215/216 13.56MHz NFC chips. These tags are cheap and common, and have plenty of space to store the required information. NFC tags can be read/written with smartphones. 13.56 MHz RFID modules are plentiful, low-cost and Arduino-compatible, allowing for easy integration.

Tag Type Capacity Compatibility
NTAG213 144 bytes Core
NTAG215 504 bytes Core + Extended
NTAG216 888 bytes Core + Extended

NFC NTAG213/215/216 was chosen over MIFARE 1K Classic tags, which is what the Bambu Lab AMS uses, for the following reasons:

  • Smartphone Support: NTAG213/215/216 can be read from smartphones, while MF1K requires a dedicated reader
  • Backwards Compatible: The RFID hardware used for reading MF1K tags typically supports NTAG tags as well
  • Non-Encrypted: MF1K uses 25% of its memory to encrypt the data, which is unsuitable for an open source standard

Note

Originally, the NTAG216 was specifically selected as it had more usable memory (888 bytes) than the MF1K (768 bytes). However, it was later determined that the core data required for functionality could be stored within 144 bytes, and additional data could be stored within 504 bytes. So, the NTAG213 and NTAG215 were added as cheaper spec-compliant options.

Mechanical Standard

The NFC tags should be placed on the spools as follows:

  • The center should be 56.0mm away from the center of the spool (see pic)
  • The tag should never be more than 4.0mm away from the external surface of the spool
    • For spool sides thicker than 4mm, there must be a cutout to embed the tag, or the tag should be fixed to the outside of the spool
  • Two tags should be used, one on each end of the spool, directly across from each other

Data Structure Standard

This is a list of data that will live on the RFID chip, separated into required and optional data. All REQUIRED data must be populated to be compliant with this open source RFID protocol.

NTAG213 tags have 144 bytes of usable memory, which is the minimum requirement for OpenTag3D. NTAG216 tags have 888 bytes of usable memory.

All strings are UTF-8 unless specified otherwise. All integers are unsigned, big endian, unless specified otherwise.

Temperatures are stored in Celsius, divided by 5.

Memory Map - OpenTag3D Core

This is designed to fit within the 144 bytes of writable space on the NTAG213, the smallest and cheapest variant of compatible tags.

Address Range: 0x100x9F

Name Type Unit Start Length Usage Examples Description
Tag Format* ascii string 0x10 2 operational OT This is always “OT”, this helps differentiate between the OpenTag3D and other formats.
Tag Version* int version 0x12 2 operational 1234 RFID tag data format version, with 3 implied decimal points. Eg 1000 → version 1.000.
Filament Manufacturer* utf8 string 0x14 16 display Polar Filament Name of filament manufacturer. Long names should be abbreviated or truncated.
Base Material Name* utf8 string 0x24 5 display PLA, PETG, PCTFE, TPU Material name in plain text, excluding any modifiers.
Material Modifiers utf8 string 0x29 5 display CF, HF, Pro, Silk, 95A Material subcategory or modifier in plain text. Long modifiers may need to be abbreviated.
Color Name utf8 string 0x2E 32 display Blue, Electric Watermelon Color in plain text.
Color Hex* rgba RGBA 0x4E 4 display 255, 166, 77, 255 Color stored as 4 separate 1-byte integers for red, green, blue and alpha, in the sRGB color space.
Target Diameter* int mm ÷ 0.001 0x52 2 operational 1750, 2850 Filament diameter (target) in µm (micrometers). Eg 17501.750mm.
Target Weight* int g 0x54 2 operational 1000, 5000, 750 Filament weight in grams, excluding spool weight. This is the TARGET weight (e.g., 1kg). Actual measured weight is stored in a different field.
Print Temperature* int ºC ÷ 5 0x56 1 operational 42 Recommended print temperature in degrees Celsius, divided by 5. For example, 42 = 210°C.
Bed Temperature* int ºC ÷ 5 0x57 1 operational 12, 16 Recommended bed temperature in degrees Celsius, divided by 5. For example, 12 = 60°C.
Density* int g/cm³ ÷ 0.001 0x58 2 operational 1240, 3900 Filament density in µg (micrograms) per cubic centimeter. Eg 12401.240g/cm³.
Online Data URL ascii string 0x6D 32 operational pfil.us?i=8078-RQSR URL to access online JSON additional parameters. Formatted without https to save space.

Memory Map - OpenTag3D Extended

This is additional data that not all manufacturers will implement, typically due to technological restrictions.

These fields should be populated if available. All unused fields must be populated with “-1” (all 1’s in binary, eg 0xFFFFFFFFFFFFFFFF).

This memory address starts just outside the range of NTAG213; an NTAG215/216 must be used to store this data.

Address Range: 0xA00x1FF

Name Type Unit Start Length Usage Examples Description
Serial Number / Batch ID utf8   0xA0 16 display 1234-ABCD, 2024-01-23-1234 Manufacturer’s identifier for a spool batch or serial number.
Manufacture Date int[4] YYYY,MM,DD 0xB0 4 display 2024, 1, 23 Stored as 2 bytes for year, then 1 byte for month and 1 byte for day.
Manufacture Time int[3] UTC hh:mm:ss 0xB4 3 display 10, 30, 45 Stored as 1 byte each for hour, minute, and second in 24-hour UTC.
Spool Core Diameter int mm 0xB7 1 operational 100, 80 Core diameter in mm (millimeters).
MFI Temp int ºC ÷ 5 0xB8 1 operational 210 MFI test temperature, divided by 5. For example, 42 = 210ºC.
MFI Load int g ÷ 10 0xB9 1 operational 216 MFI test load grams, divided by 10. For example, 216 = 2.16kg.
MFI Value int g/10min ÷ 10 0xBA 1 operational 63 MFI value, divided by 10.
Measured Tolerance int µm 0xBB 1 operational 20, 55 Measured tolerance in µm (micrometers).
Empty Spool Weight int g 0xBC 2 operational 105 Weight of empty spool in grams.
Measured Filament Weight int g 0xBE 2 operational 1002 Weight of filament only.
Measured Filament Length int m 0xC0 2 operational 336 Length in meters.
Transmission Distance (TD) int µm 0xC2 2 operational 2540 Opaque thickness in µm (micrometers).
Max Dry Temp int ºC ÷ 5 0xC4 1 operational 10, 11 Max safe drying temp, divided by 5.
Dry Time int hr 0xC5 1 operational 4, 8, 12 Recommended drying time.
Min Print Temp int ºC ÷ 5 0xC6 1 operational 38 Minimum nozzle temp, divided by 5. For example, 38 = 190ºC.
Max Print Temp int ºC ÷ 5 0xC7 1 operational 45 Maximum nozzle temp, divided by 5.
Min Volumetric Speed int mm³/s 0xC8 1 operational 20 Min speed recommendation.
Max Volumetric Speed int mm³/s 0xC9 1 operational 120 Max safe speed.
Target Volumetric Speed int mm³/s 0xCA 1 operational 80 Default recommended speed.

Web API Standard

Sometimes a filament manufacturer may want to include supplemental data for advanced users that doesn’t fit or otherwise cannot be stored on the RFID tag itself. One example is a diameter graph, which is too much data to be stored within only 888 bytes of memory. OpenTag3D defines a field for a “web API” URL which can be used to look up this information.

Note

The web API will only be used for advanced supplemental data and will never be used for critical information required by printers in order to print the material properly.

At this time, the web API is only a placeholder for future implementation, as the OpenTag3D specification has not determined what information should be included in the web API standard. For now, it only defines the structure.

The “Online Data URL” field should be populated with the URL that responds with the web API data. The URL must return JSON data when the Accept HTTP header is set to application/json. Implementers are welcome to create a user-friendly UI if the Accept header is set to anything else, but it must return JSON format if the client calls for it.

The URL should respond with the following JSON:

{
  "opentag_version": "0.003"
}

Reader Implementation Guidelines

While every implementation for reading OpenTag3D RFID tags will be different, this specification aims to set a few requirements to ensure that functionality is consistent across printers and other hardware – we’ll call these the “reader” for continuity.

When attempting to read an RFID tag, the reader should check for the presence of the tag format field and check if it is “OT” (0x4F54). If it is not set to “OT”, it is not an OpenTag3D tag.

The reader should then check the tag version. If the tag version is a newer minor version than the reader expects, display a warning to the user and attempt to parse anyways. If the tag version is a newer major version, the reader should display an error to the user and not attempt to parse the data.

Caution

During the early beta of the tag format, it should be assumed that any and every version update is a major version. Once v1.000 of the tag specification is released, this caution note will no longer apply.

Previous Considerations

These are topics that were heavily discussed during the development of OpenTag3D. Below is a quick summary of each topic, and why we decided to settle on the standards we defined.

  • NTAG vs MIFARE
    • NTAG213/215/216 is compatible with smartphones
    • NTAG216 has slightly more usable memory than MIFARE tags
    • MIFARE uses about 25% of memory to encrypt data, preventing read/write operations, which is not applicable for OpenTag3D because of the open-source nature
    • The hardware used for reading MIFARE tags is typically compatible with NTAG tags, meaning existing RFID printer hardware would not need replacement
  • JSON vs Memory Map
    • Formats such as JSON (human-readable text) take up considerably more memory than memory mapped
      • For example, defining something like Printing Temperature would be PrintTemp:225 which is 13 bytes, instead of storing a memory mapped 2-byte number. Tokens could be reduced, but that also defeats the purpose of using JSON in the first place, which is often for readability
    • NTAG216 tags only have 888 bytes of usable memory, and NTAG213 tags only have 144 bytes, which would be eaten up quickly
      • With memory mapping, the core data was able to easily fit in 144 bytes
  • Lookup Tables
    • OpenTag3D does NOT use lookup tables, which would be too difficult to maintain due to the decentralized nature of this standard
    • Lookup tables can quickly become outdated, which would require regular updates to tag readers to make sure they’ve downloaded the most recent table
    • Storing lookup tables consumes more memory on the device that reads tags
    • On-demand lookup (via the internet) would require someone to host a database
      • Hosting this data would have costs associated with it, and would also put the control of the entire OpenTag3D format in the hands of a single person/company
    • Rather than representing data as a number (such as “company #123 = Example Company”), the plain-text company name should be used instead