Reports¶
Three flows: heatmap (poll until ready), PWS aggregation (materialize an event report), CSV downloads (zone-activity, alarms).
Heatmap — polling¶
from datetime import datetime, timezone
start = datetime(2024, 1, 1, tzinfo=timezone.utc)
end = datetime(2024, 1, 2, tzinfo=timezone.utc)
heatmap = client.reports.heatmap(
start=start,
end=end,
tag_uids=["t-1", "t-2"],
poll_interval=2.0,
timeout=300.0,
)
print(heatmap.image_url)
Behind the scenes: POST /obsolete/report (the live path, despite the
URL — RESEARCH discrepancy #5), then GET-polling until output.url is
populated. The SDK raises:
ReportFailed— server reportederrorin the poll body.ReportTimeout— polling exceededtimeout. The exception carriesreport_uidso you can resume polling viaclient.reports.get(uid)later.
from rtls_sdk import ReportFailed, ReportTimeout
try:
heatmap = client.reports.heatmap(start=start, end=end, tag_uids=["t-1"], timeout=10.0)
except ReportTimeout as exc:
# Resume later with exc.report_uid
...
except ReportFailed:
...
timeout=None (default) is unbounded — useful for batch jobs that
must wait however long the server takes.
PWS event aggregation¶
report = client.reports.pws(
trackable_uid=["t-1", "t-2"],
start=start,
end=end,
timezone="UTC",
)
print(len(report.events))
Materializes every page into one PwsReport. For unbounded windows,
prefer the iterator surface (client.events.iter_pws(...)) — see
pagination.
CSV downloads¶
Zone activity (chunked)¶
blob = client.reports.zone_activity_csv(
start=start,
end=end,
area_uids=["a-1", "a-2"],
)
blob.write_to("zone-activity.csv")
The server returns the CSV in chunks via the content-next-page header.
The SDK follows the chain, strips duplicate header rows, and returns
one coherent CSV blob.
For very large windows, stream directly to disk:
with open("zone-activity.csv", "wb") as fh:
client.reports.zone_activity_csv(
start=start,
end=end,
area_uids=["a-1"],
stream_to=fh,
)
stream_to= returns None; the file is written incrementally.
Alarms¶
blob = client.reports.alarms_csv(
start=start,
end=end,
site_uid="s-1",
alarm_types=["fall", "battery_low"],
include_banner=True,
)
blob.write_to("alarms.csv")
include_banner=True (default) prepends the multi-line `#Site / #From /
To` banner that the JS reference client emits, so downstream tools that¶
match on the banner work unchanged. Pass False for the bare server
CSV.