SDK · Datapoints & history
Reading a datapoint once, subscribing to it over the realtime channel, and reading recorded history as samples or aggregated buckets.
Generated from the SDK’s own source. The SDK Reference is the narrative; this page is every member, in the order the SDK declares them.
DatapointsApi
A robot’s exposed values, reachable as client.datapoints: the latest
one, a live subscription to it, and — for a datapoint configured with
retention — its recorded history.
get()
get(robotId: string, slug: string): Promise<{ slug: string; value: unknown; timestamp_ms: number }>
Reads the datapoint’s latest value over REST, once. It carries the bridge’s own capture time, so a caller can tell a fresh value from a stale one without a subscription.
| Parameter | Type | Required | Description |
|---|---|---|---|
robotId |
string |
yes |
|
slug |
string |
yes |
Returns Promise<{ slug: string; value: unknown; timestamp_ms: number }>.
subscribe()
subscribe(robotId: string, slug: string, handlers: DatapointSubscriptionHandlers): DatapointSubscription
Subscribes over the realtime channel. Reconnect and re-authentication
are handled by the shared RealtimeChannel; this resends its
subscribe frame after every (re)connect, so a network drop is
invisible to the caller beyond a gap in events.
Reference-counted per (robotId, slug): two subscriptions to the same
pair share one wire subscription. Unsubscribing one never affects the
other — the unsubscribe frame is sent only when the last subscriber
on that pair goes away. In practice: two widgets showing the same
battery value, or a component mounted twice under React StrictMode,
subscribe to the same key. That count is shared with
actions.subscribe and services.call — a slug is one namespace across
kinds, and so is its subscription.
| Parameter | Type | Required | Description |
|---|---|---|---|
robotId |
string |
yes |
|
slug |
string |
yes |
|
handlers |
DatapointSubscriptionHandlers |
yes |
Returns DatapointSubscription.
References: DatapointSubscriptionHandlers, DatapointSubscription
history()
history(robotId: string, slug: string, options: HistoryOptions & { aggregate: HistoryAggregation }): Promise<{ slug: string; kind: "buckets"; window_ms: number; agg: "max" | "min" | "avg"; buckets: ({ bucket_start_ms: number; value: number | null; sample_count: number })[] }>
Reads recorded history for a retention: true datapoint over REST — no
realtime channel involved, the same way cameras.snapshot isn’t. This
overload is the aggregated one: aggregate is given, so it resolves
with HistoryBucketsResponse (kind: 'buckets') — one row per window,
reduced by aggregate.agg. Leave aggregate out and the other overload
gives you raw samples instead.
Two overloads rather than one union, so a caller who already knows which
one they asked for isn’t forced to narrow it. kind carries the same
information either way, so dynamic code can still branch on it.
Rejects, does not silently empty out, two specific refusals —
unlike cameras.snapshot’s absorption of no_snapshot_yet into a null
read, these two must reach the caller as a rejected FleetlessError:
not_recorded— the slug exists and is granted, but is configured live-only. An empty result here would look exactly like “recorded, but nothing in this window”, and the two need opposite fixes: turn recording on, versus look at a different range.not_aggregatable—aggregatewas given for a value that isn’t a number and no numericaggregate.fieldwas named.
| Parameter | Type | Required | Description |
|---|---|---|---|
robotId |
string |
yes |
|
slug |
string |
yes |
|
options |
HistoryOptions & { aggregate: HistoryAggregation } |
yes |
Returns Promise<{ slug: string; kind: "buckets"; window_ms: number; agg: "max" | "min" | "avg"; buckets: ({ bucket_start_ms: number; value: number | null; sample_count: number })[] }>.
References: HistoryOptions, HistoryAggregation
history(robotId: string, slug: string, options: HistoryOptions & { aggregate?: undefined }): Promise<{ slug: string; kind: "samples"; samples: ({ timestamp_ms: number; value: unknown })[]; truncated: boolean; truncated_by: "bytes" | "limit" | null }>
The same read without aggregate: resolves with
HistorySamplesResponse (kind: 'samples'), every recorded sample in
the window as a timestamp_ms and a value. timestamp_ms is the
bridge’s own capture time, the same instant the live value carried, so a
recorded point and a live one sit on one axis without apology.
Read truncated. The platform caps how much one read returns, by
row count or by bytes, and truncated_by says which. A short array that
does not admit it is indistinguishable from a quiet period, and the two
lead to opposite conclusions. Refuses not_recorded the same way the
aggregated overload does.
| Parameter | Type | Required | Description |
|---|---|---|---|
robotId |
string |
yes |
|
slug |
string |
yes |
|
options |
HistoryOptions & { aggregate?: undefined } |
yes |
Returns Promise<{ slug: string; kind: "samples"; samples: ({ timestamp_ms: number; value: unknown })[]; truncated: boolean; truncated_by: "bytes" | "limit" | null }>.
References: HistoryOptions
DatapointSubscription
A live datapoint subscription, returned by datapoints.subscribe.
unsubscribe()
unsubscribe(): void
Stops this subscription. The unsubscribe frame reaches the server only
when this was the last holder of the robot/slug pair and the channel
is connected — subscriptions are reference-counted across kinds, so
releasing this one while a datapoints.subscribe, actions.subscribe or
in-flight services.call still holds the same pair leaves that one’s
stream running. Safe to call more than once.
Returns void.
DatapointSubscriptionHandlers
The callbacks datapoints.subscribe reports through: one for values, one
for a refusal. onEvent fires immediately with the current value and
again on every change.
onEvent()
onEvent(event: { type: "datapoint"; robot_id: string; slug: string; value: unknown; timestamp_ms: number }): void
Called with the current value on subscribe, then again on every change.
| Parameter | Type | Required | Description |
|---|---|---|---|
event |
{ type: "datapoint"; robot_id: string; slug: string; value: unknown; timestamp_ms: number } |
yes |
Returns void.
onError()
onError?(error: FleetlessError): void
Optional — a caller need not implement it.
Called once if the subscription is refused, e.g. forbidden or unknown_datapoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
error |
FleetlessError |
yes |
Returns void.
References: FleetlessError
HistoryOptions
The window datapoints.history reads. aggregate decides whether the
response is raw samples or aggregated buckets.
| Property | Type | Required | Description |
|---|---|---|---|
from |
string |
yes |
now-30s / now-5m / now-1h, or absolute unix milliseconds — as a string either way, exactly as the wire query expects it. The SDK does not accept a Date or a number and stringify it for you: that would be a convenience that quietly decides which of the two forms you meant, and the next person reading the wire traffic would not know which of us made that call. |
to |
string |
no |
Same two forms as from. Defaults to now. |
limit |
number |
no |
The most rows to return. The platform applies its own ceiling regardless. |
aggregate |
HistoryAggregation |
no |
Present: the result is aggregated buckets. Absent: raw samples. |
References: HistoryAggregation
HistoryAggregation
Window aggregation for datapoints.history. window and agg always
travel together on the wire — the cloud refuses one without the other
rather than defaulting either, since a silently chosen aggregation is a
chart that lies quietly — so they live in one object instead of two
optional fields a caller could set only one of. Same reasoning as
cameraSource’s discriminated union: make the impossible combination
unrepresentable, not merely rejected.
| Property | Type | Required | Description |
|---|---|---|---|
window |
string |
yes |
Bucket width, e.g. 10s, 1m. |
agg |
"max" | "min" | "avg" |
yes |
How to reduce each bucket’s samples to one number. |
field |
string |
no |
A numeric field inside an object value, e.g. pose.x. Only meaningful when the datapoint’s own value is not itself a number. |
DatapointValue
The datapoint-value wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.
DatapointEvent
The datapoint-event wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.
HistorySamplesResponse
The history-samples-response wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.
HistoryBucketsResponse
The history-buckets-response wire schema, re-exported so app code and the SDK agree on the shape — see API Schemas for its fields.