Skip to content

Zones

A zone is a geofence — polygon, circle, or rectangle — used by the RTLS to fire entry/exit events when tags move in or out. Zones come in two flavors: static (a fixed shape on the floorplan) and dynamic (the shape follows a tag's position).

Quick reference

Method What it does
client.zones.list() All zones in scope.
client.zones.get(uid) Fetch one zone by uid.
client.zones.create(name, *, dynamic=False, tag_uid=None, **fields) Create a zone; for dynamic zones, bind a tag in the same call. Geometry (shape, points, radius_m) is passed through **fields.
client.zones.update(uid, *, tag_uid=None, **fields) Update; reconciles the dynamic-zone binding if it changed.
client.zones.delete(uid) Delete; clears any dynamic-zone reference on the bound tag.
client.zones.history(start, end) Time series of geometry changes in the window.
client.zones.list_custom_prototypes() Server-defined zone-type prototypes available in this deployment.
client.zones.create_raw / update_raw / delete_raw Single-call REST escape hatches.
client.zones.download_request(tag_uids, *, action="UPDATE") Trigger (or verify) the SZM→tag zone-download wire push for one or more tags.
client.zones.download_status(tag_uid=None) Per-tag zone-download sync status — all tags, or one.

Static vs dynamic zones

A static zone has a fixed shape (polygon points, circle radius). A dynamic zone is bound to a tag — the shape follows that tag's last known position. Useful for "exclusion bubble around the forklift" or "follow-the-operator" workflows.

# Static polygon
static = client.zones.create(
    name="Loading dock",
    shape="polygon",
    points=[(0, 0), (100, 0), (100, 50), (0, 50)],
)

# Dynamic: 5 m bubble that follows tag t-1
dynamic = client.zones.create(
    name="Forklift bubble",
    shape="circle",
    radius_m=5.0,
    dynamic=True,
    tag_uid="t-1",
)

For a dynamic zone, create performs the zone-create + tags.update (setting self_zone_uid) in one compound call. Rollback on partial failure raises PartialFailureError.

Update — dynamic-zone re-binding

If tag_uid changes on a dynamic zone, update clears the old binding and sets the new one — also a compound, also with rollback. The partial-failure case "old binding cleared but new binding failed" leaves completed_steps=["clear_old_binding"] so a retry knows where to resume.

client.zones.update(dynamic.uid, tag_uid="t-2")

Delete

client.zones.delete(zone.uid)

For dynamic zones, delete also clears the tag's self_zone_uid reference. The *_raw variant deletes only the zone row — leaves a stale reference on the tag.

Zone download (SZM → tag LZM sync)

Zones only take effect on a tag once they're pushed down and the tag's Local Zone Manager (LZM) confirms it. download_request triggers the push (same action as SiteWise's "start zone download" button); download_status polls the per-tag sync outcome. The request call does not block on the push completing — poll status separately.

client.zones.download_request(["t-1"])
# ... poll until synced ...
statuses = client.zones.download_status("t-1")
assert statuses[0].download_status == "UPDATED"

Pass action="VERIFY" to ask the tag to report its current state without re-pushing. download_request accepts multiple tags in one call:

client.zones.download_request(["t-1", "t-2", "t-3"])

download_status() with no argument returns every tag's status, not just one:

for status in client.zones.download_status():
    if status.download_status != "UPDATED":
        print(f"{status.tag_uid}: {status.download_status}")

download_status rows are keyed by tag_uid, not the zone's own uid. The two are unrelated identifiers — a status row tells you whether this tag's current zone set has synced, not which zone is out of date. To find which zones are stale for a tag, cross-reference tags.get(uid).self_zone_uid and zones.list() separately.

Model — Zone

Field Type Notes
uid str Server-assigned.
name str Required.
shape str \| None "polygon", "circle", etc.
dynamic bool True if the zone follows a tag.
tag_uid str \| None The bound tag's uid (dynamic only).

Geometry inputs (points, radius_m) are accepted on create via **fields but are not surfaced as typed fields on the returned Zone.

Full field list.

Model — ZoneDownloadStatus

Field Type Notes
tag_uid str The tag this sync-status row is for. SDK-canonical name for the server's trackable_uid.
download_status str One of "OUTDATED", "IN_PROCESS", "UPDATED", "OOSYNC" — the server's own vocabulary, kept verbatim.
ts datetime \| None When this status was last updated, if the server reports one.
reason str \| None Present on some rows (e.g. why a sync is OOSYNC), absent on others.
sync_requested bool \| None Present on some rows, absent on others.

Full field list.

  • Tags: a dynamic zone's tag_uid points at a Tag. tags.create(attached_zone=...) is the inverse helper. download_request / download_status are also keyed by tag — see Tags for the entity itself.
  • Areas: zones live inside an Area, set via the area_uid create input.
  • Events: zone entry/exit fire as ZoneEvents — see Events.

See also

  • Error handling — PartialFailureError.failed_step strings: create_zone, set_tag_binding, load_zone, clear_old_binding, set_new_binding, update_zone.
  • Compound workflows — the dynamic-zone binding saga.