Repository navigation
Releases
v1.4.0 — catalog_info options, Rosa3D catalogue example, TigerSystem
Added
- Showcase site (
site/), published on GitHub Pages at
https://tigertag-project.github.io/TigerTag-SDK-Python/ by.github/workflows/pages.yml,
in eleven languages, with a "Get started with Python" button at the top of the README.
Not part of the package.
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'scatalogInfo():data_dir
(alias ofcache_dir) andoffline(accepted for symmetry withload_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
Added
-
Unified playground:
tools/playground.htmlis now one page, byte-for-byte identical in the
JavaScript and Python SDKs. Eachtools/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 thecreate()code style from it),
POST /api/parse//api/build(snake_casecreate()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=1starts the server without readers;/api/parseandcard:detectednow carrypretty,describe,verify,raw_dict,dict,validate; burn results and/api/nfc/planreportsignature_dropped).
scripts/check_playground_sync.pyfails when the two copies differ (the local checkout next to
this one, else GitHubmain); 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()andpatch()refuse ameasure_availableabovemeasure(ValueError);
reading such a chip still works andvalidate()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 astag_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 fromid_type. The hex reads like
"index/count":0x11single tag,0x12/0x22twin tag 1 of 2 / 2 of 2,
0x02two tags with the index unknown,0x00unknown (tags written before v2.2).TigerTag.tag_infofield (u8) with read-onlytag_indexandtag_countproperties.TigerTag.create(..., tag_count=0, tag_index=0)packs both values intotag_info
((tag_index << 4) | tag_count);as_init()writes0x00.tag.patch(tag_count=..., tag_index=...)as a shortcut fortag_info(either one
alone keeps the other nibble).create()andpatch()raiseValueErrorfor a value
outside 0–15.validate()warns when the tag index exceeds a known tag count, or when
tag_infodoes not fit in one byte.to_raw_dict()gains"tag_info";to_dict()gains"tag_count"and
"tag_index"(Nonewhen unknown);pretty()gains aTag 1 of 2line;
describe()mentions the tag position when the count is known, naming the item
fromid_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,.binimport / export), a "Tag" row in the
Traceability card and inpretty(),tag_infointo_raw_dict(),tag_count/
tag_indexinto_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) andPOST /api/build(TigerTag.create()
keyword arguments → payload hex), andGET /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 takesPOST /api/nfc/read/POST /api/nfc/burn. Reader access
usespyscard, an optional extra:pip install "tigertag[nfc]". ACR122U APDU helpers
live intools/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 to00whatever 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/planreturns the APDUs a burn would send (andsignatureDropped)
without touching a reader. -
Playground: TigerTag favicon (
assets/favicon.svg, withassets/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'sRFID_Data(data1 diameter, data2/data3 nozzle,
data4/data5 drying, data6/data7 bed;nullvalues, incl.id_aspect2, → 0; colours 2/3 from
color_r2…/color_r3…orcolor_info). New moduletigertag.catalog:load_catalog()
(downloadsid_catalog.jsonfrom 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-Modifiedso 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 standaloneparse_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).TigerTagDBgains
data_dir=,offline=,auto_update=,max_age=,update(force=False, catalog=False),
info()andcatalog(); per table it uses your own folder exclusively whendb_pathis
given, else the newest of the downloaded copy (user cache directory,TIGERTAG_DATA_DIR)
and the bundled copy bylast_update.jsontimestamps.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-dirfor parsing. Playground: "Update reference tables" with a status
line, server endpointsGET /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...
v1.2.1 — fix Python 3.8 source installs
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
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
Breaking change
from_pages(uid, payload)— UID is now the first argument, payload second.
Previouslyfrom_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
What's new in v1.1.0
Added
TigerTag.create()— build a new tag from scratch with all fieldsTigerTag.as_init(uid)— create a blank TigerTag Init chip ready for programmingTigerTag.erase()— return 80 zero bytes to wipe a chip back to blank NDEFtag.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 diffstag.diff_api()— compare all chip fields vs TigerTag+ cloud API; covers nozzle, bed, drying, type, material, brand, diameter, aspects, colors, quantity, unittag.raw_api()— fetch live TigerTag+ cloud product data (requires requests)ApiDiffnamedtuple — (field, chip_value, api_value) — exported from main packageID_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 exposesPOST /api/diffREST 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]