Skip to content

Releases

v1.4.0 — catalog_info options, Rosa3D catalogue example, TigerSystem

Choose a tag to compare

@BenGlut BenGlut released this 06 Nov 08:26
b6a30ce

Added

Changed

  • The catalogue example in the README, the docstrings and the playground is now product
    2673739332, Rosa3D PLA Rainbow - Fire 1000 g: 3527039449 (Elegoo Rapid TPU 95A - Black)
    left the catalogue. The tests that read the bundled copy use it too.
  • The copyright and trademark holder is named TigerSystem (formerly TigerTag Corp) in the
    licence, the source headers and the README.
  • CI tests Python 3.8 on ubuntu-22.04, since ubuntu-latest no longer ships it.
  • catalog_info() now takes the same options as the JS SDK's catalogInfo(): data_dir
    (alias of cache_dir) and offline (accepted for symmetry with load_catalog(); the
    function only reads local files, so it never uses the network).

v1.3.0 — protocol v2.2, catalogue, offline reference data, unified playground

Choose a tag to compare

@TigerTag-Project TigerTag-Project released this 01 Oct 05:56
2ebbf72

Added

  • Unified playground: tools/playground.html is now one page, byte-for-byte identical in the
    JavaScript and Python SDKs. Each tools/server.* implements the same server contract
    (docs/playground-api.md): GET /api/version (now { version, sdk, label, repo, install, server, style } — the page takes its SDK names, links and the create() code style from it),
    POST /api/parse / /api/build (snake_case create() fields, measure_available) /
    /api/diff, GET /api/catalog/info / <id>, POST /api/catalog/refresh, GET /api/db/info,
    POST /api/db/update, GET /api/db/table/<file>, GET /api/nfc/events (Server-Sent Events,
    chips already present replayed on connect), POST /api/nfc/read / burn / plan. The page
    talks to the readers through SSE + HTTP on both servers (TIGERTAG_PLAYGROUND_NO_NFC=1 starts the server without readers; /api/parse and card:detected now carry pretty, describe, verify, raw_dict, dict, validate; burn results and /api/nfc/plan report signature_dropped).
    scripts/check_playground_sync.py fails when the two copies differ (the local checkout next to
    this one, else GitHub main); the test suite runs it and skips it when neither is reachable.
    From the other SDK's page: Read / Burn modes with per-mode panels, the merged Offline · Catalogue / Online · API product loader, twin tag mode, SDK Input create() / HEX / Pages, the decluttered layout with info bubbles, bytes always built by the SDK on the server (POST /api/build).

  • to_bytes() and patch() refuse a measure_available above measure (ValueError);
    reading such a chip still works and validate() still reports it. The playground's
    Generate refuses it too.

  • Tag index / tag count (protocol v2.2, spec section 2.11). Page 0x0D byte 3
    (payload offset +39), previously reserved, is now read and written as tag_info:
    the high nibble is the tag index — which of the item's TigerTags this one is, from 1
    (0 = unknown) — and the low nibble is the tag count — how many TigerTags the item
    carries (0 = unknown, 1 = single tag, 2 = twin tag, up to 15). A TigerTag identifies
    any item — a filament spool, a resin bottle…; what the item is comes from id_type. The hex reads like
    "index/count": 0x11 single tag, 0x12 / 0x22 twin tag 1 of 2 / 2 of 2,
    0x02 two tags with the index unknown, 0x00 unknown (tags written before v2.2).

    • TigerTag.tag_info field (u8) with read-only tag_index and tag_count properties.
    • TigerTag.create(..., tag_count=0, tag_index=0) packs both values into tag_info
      ((tag_index << 4) | tag_count); as_init() writes 0x00.
    • tag.patch(tag_count=..., tag_index=...) as a shortcut for tag_info (either one
      alone keeps the other nibble). create() and patch() raise ValueError for a value
      outside 0–15.
    • validate() warns when the tag index exceeds a known tag count, or when
      tag_info does not fit in one byte.
    • to_raw_dict() gains "tag_info"; to_dict() gains "tag_count" and
      "tag_index" (None when unknown); pretty() gains a Tag 1 of 2 line;
      describe() mentions the tag position when the count is known, naming the item
      from id_type ("Tag 1 of 2 on this filament.", "on this item" when unknown).
  • Same changes in the standalone parse_tigertag.py.

  • Playground (tools/playground.html): "Tag index" / "Tag count" inputs, byte +39
    written and read back (build, .bin import / export), a "Tag" row in the
    Traceability card and in pretty(), tag_info in to_raw_dict(), tag_count /
    tag_index in to_dict(), and a "validate() · Python SDK" card listing the SDK's
    warnings.

  • Playground server (tools/server.py): POST /api/parse (payload hex → raw dict,
    tag index / count, validate() warnings) and POST /api/build (TigerTag.create()
    keyword arguments → payload hex), and GET /api/version, so the playground's header
    badge shows the installed SDK version instead of a hard-coded "v1.0".

  • Playground ecosystem panel: Tiger Scale V3 photo (was the previous-generation
    scale), new TigerSpool and TigerPOD Mini cards, and repository links to
    Tiger-Scale-V3, TigerSpool-RFID and TigerPOD, plus TigerSystem-Docs and
    TigerTag-SDK-JS.

  • Playground: an info bubble on "Tag index" and "Tag count" explains both values.

  • Playground: "SDK Input" panel — the exact TigerTag.create() call, the HEX that
    Burn writes (144 bytes, pages 0x04–0x27) and the same bytes page by page.

  • Playground: twin tag mode — with two or more readers holding a chip, Tag count is
    set to the number of readers, each reader gets its own payload (tag index 1…n,
    same data and Timestamp), shown as #1 / #2 in SDK Input and SDK Output, and Burn
    writes each chip with its own payload.

  • Playground: "Manufacturing date" is the Timestamp of the moment you click Generate
    (read-only; it is also the twin tag ID), instead of a hand-picked date.

  • Playground: NFC reader support (ACS ACR122U or any PC/SC reader), matching the JS
    playground. Header chips list connected readers ("No reader" plus the install
    command when reader support is missing); a chip placed on a reader is read
    (pages 0x04–0x27, 80-byte fallback), parsed by the SDK and loaded into the form;
    Burn writes the current payload to every reader with a chip after a
    confirmation (never pages 0x00–0x03 or the configuration pages 0x28+);
    Raw Read shows an annotated hex dump per reader. The server pushes
    events over Server-Sent Events (GET /api/nfc/events, same messages as the JS
    WebSocket) and takes POST /api/nfc/read / POST /api/nfc/burn. Reader access
    uses pyscard, an optional extra: pip install "tigertag[nfc]". ACR122U APDU helpers
    live in tools/nfc_reader.py, with unit tests that need neither pyscard nor hardware.

  • Playground: Burn never writes a signature and never leaves a stale one. It always
    writes the full 144-byte image, pages 0x04–0x27 (36 pages, pagesWritten: 36), with
    the signature pages 0x18–0x27 set to 00 whatever the payload — only a certified
    manufacturer can issue a valid signature (it covers the chip UID), so the playground
    only reads signatures to verify them. A signature carried by the loaded data (e.g.
    read from a signed chip) is not copied. Pages 0x00–0x03 and 0x28+ are never touched.
    The SDK Input HEX / Pages tabs and the burn confirmations show the 144-byte image;
    POST /api/nfc/plan returns the APDUs a burn would send (and signatureDropped)
    without touching a reader.

  • Playground: TigerTag favicon (assets/favicon.svg, with assets/apple-touch-icon.png).

  • TigerTag+ from the official catalogue. TigerTag.from_catalog(product_id, *, catalog=None, uid=None, tag_count=0, tag_index=0, timestamp=None, db=None) builds a complete TigerTag+ from
    the product ID alone, using the entry's RFID_Data (data1 diameter, data2/data3 nozzle,
    data4/data5 drying, data6/data7 bed; null values, incl. id_aspect2, → 0; colours 2/3 from
    color_r2…/color_r3… or color_info). New module tigertag.catalog: load_catalog()
    (downloads id_catalog.json from TigerTag-RFID-Guide once, about 12 MB, and caches it in the
    user cache directory; refreshed after 24 h; the cached copy is used offline),
    refresh_catalog() (forced update, ETag / Last-Modified so an unchanged file is not
    downloaded again), catalog_info() (count, fetched / checked time, source URL) and
    catalog_entry() (title, brand, SKU, barcode, image). The catalogue is not bundled.
    Same API in the standalone parse_tigertag.py.

  • Playground: in the TigerTag+ tab, a Product ID field with Load from catalogue fills the
    whole form, shows the catalogue title, brand, SKU, barcode and photo, switches to Burn and
    builds the preview (twin tag with two readers); Update catalogue forces a download and
    the status line shows "Catalogue: N products · updated …" ("not downloaded yet" before the
    first load). Server: GET /api/catalog/<id>, GET /api/catalog/info,
    POST /api/catalog/refresh.

  • Reference data always available offline, kept fresh, refreshable, disableable.
    The package now bundles the TigerTag+ catalogue (database/id_catalog.json.gz, about
    1 MB) next to the 7 reference tables; both are refreshed daily by the sync workflow and
    before every release build (scripts/sync_bundled_data.py). TigerTagDB gains
    data_dir=, offline=, auto_update=, max_age=, update(force=False, catalog=False),
    info() and catalog(); per table it uses your own folder exclusively when db_path is
    given, else the newest of the downloaded copy (user cache directory, TIGERTAG_DATA_DIR)
    and the bundled copy by last_update.json timestamps. load_catalog() /
    TigerTag.from_catalog() share the data directory and the offline switch and fall back to
    the bundled catalogue. CLI: tigertag update [--force] [--catalog] [--data-dir PATH] and
    --offline / --data-dir for parsing. Playground: "Update reference tables" with a status
    line, server endpoints GET /api/db/info, POST /api/db/update, GET /api/db/table/<file>
    (the page loads the tables in use from the server).

  • Playground: in the TigerTag+ tab, one Product ID field with two sources — Offline ·
    Catalogue
    (bundled / cached official catalogue, no internet) and Online · API (live
    data from api.tigertag.io, mapped onto the form by label) — and one Load button; the
    chosen source is remembered. Unknown IDs suggest the other source.

  • Playground: decluttered — on screen only short labels, values, buttons and status words
    ("Tables · up to date", "Catalogue · 14 164 · 1 oct."); every explanation (TigerTag+ and
    Init descriptions, data-source hints, catalogue and table details, tag index / count hint,
    Read / Burn banners, HEX / Pages captions, demo-preset notes) moved into info bubbles, kept
    inside the sidebar or the viewport.

  • Playground: Read mode...

Read more

v1.2.1 — fix Python 3.8 source installs

Choose a tag to compare

@TigerTag-Project TigerTag-Project released this 10 Jul 14:12

Patch release. No functional change; the licence is Apache-2.0, as in 1.2.0.

Fixed — 1.2.0 required setuptools>=77 at build time (for PEP 639 licence fields). setuptools 77 dropped Python 3.8, so installing from source on 3.8 failed:

ERROR: No matching distribution found for setuptools>=77

Installing the published py3-none-any wheel was never affected — only pip install ., pip install git+..., and --no-binary.

The licence is now declared as license = {text = "Apache-2.0"} with the matching trove classifier. It builds on every supported Python, and LICENSE remains bundled in both the wheel and the sdist.

Verified on Python 3.8, 3.10 and 3.12.

v1.2.0 — Apache-2.0

Choose a tag to compare

@TigerTag-Project TigerTag-Project released this 10 Jul 13:33

License changed from GPLv3 to Apache-2.0.

The TigerTag protocol specification is now published as an open standard:

  • Specification — CC-BY-4.0
  • Reference database — CC0-1.0 (public domain)
  • Code, including this SDK — Apache-2.0 (express patent grant)

TigerTag Corp grants an irrevocable, worldwide, royalty-free right to implement this specification in any product or software, open source or proprietary, without restriction and without further permission.

Implementing the TigerTag protocol requires no licence and no payment, at any volume. See LICENSING.md.

Versions published up to and including the previous release remain under GPLv3. This change applies from this release onward.

v1.1.1

Choose a tag to compare

@TigerTag-Project TigerTag-Project released this 20 May 22:47

Breaking change

  • from_pages(uid, payload) — UID is now the first argument, payload second.
    Previously from_pages(payload, uid). Update all call sites.

What changed

All call sites, tests, examples, tools, README, CHANGELOG and llms.txt updated to reflect the new argument order.

v1.1.0

Choose a tag to compare

@TigerTag-Project TigerTag-Project released this 19 May 20:35

What's new in v1.1.0

Added

  • TigerTag.create() — build a new tag from scratch with all fields
  • TigerTag.as_init(uid) — create a blank TigerTag Init chip ready for programming
  • TigerTag.erase() — return 80 zero bytes to wipe a chip back to blank NDEF
  • tag.patch(**kwargs) — immutable surgical field update, signature-safe (protected fields: id_tigertag, id_product, uid, signature_r/s)
  • tag.patch_from_api() — auto-apply cloud API values to chip fields; returns patched tag + applied diffs
  • tag.diff_api() — compare all chip fields vs TigerTag+ cloud API; covers nozzle, bed, drying, type, material, brand, diameter, aspects, colors, quantity, unit
  • tag.raw_api() — fetch live TigerTag+ cloud product data (requires requests)
  • ApiDiff namedtuple — (field, chip_value, api_value) — exported from main package
  • ID_TIGERTAG, ID_TIGERTAG_PLUS, ID_TIGERTAG_INIT, MAKER_PRODUCT_ID, INIT_PRODUCT_ID — exported constants
  • Playground (tools/playground.html) — interactive 3-column browser UI for parsing, previewing and diff-checking tags
  • Dev server (tools/server.py) — serves playground and exposes POST /api/diff REST endpoint backed by the Python SDK

Fixed

  • from_pages(144_bytes, uid=uid) is correctly documented as verifiable — the previous README table incorrectly stated 144 bytes was "not verifiable"
  • Aspect "none" vs "none" is no longer reported as a diff in diff_api()

Install: pip install tigertag or pip install tigertag[full]