Appearance
Historical Data – Timestream Module (History)
This chapter explains how application developers use the Timestream module of the Coldwave Backend to work with historical data and events. It focuses on typical UI and analytics use‑cases and assumes you already understand devices, services and properties from the Service and Schema chapters.
1. What the Timestream module does
The Timestream module provides read‑only access to historical data and events that the Coldwave Backend has stored for your devices. It is the basis for:
- Dashboards (trend graphs, KPIs, long‑term monitoring)
- Analytics views (comparison of devices, weekly/daily patterns)
- Forensics (what happened before an alarm, investigation of incidents)
- Reporting (export of data for further offline processing)
Internally, the backend organizes history by device, service and property and stores time‑stamped values and events. The Timestream API gives you a flexible way to filter this data and retrieve it in batches.
1.1 History vs. Service vs. Streams
For orientation, use the modules as follows:
| Module | Purpose | Typical UI usage |
|---|---|---|
| Service | Current, live state of devices | Device detail views, current value tables, controls |
| Streams | Live streaming of selected properties | Live charts, oscilloscope‑like views, log consoles |
| Timestream | Historical data and events over time | Dashboards, trend charts, analytics, reports |
The same devices, services and properties are visible across all three modules. Service and Streams give you the current values and live updates, Timestream gives you the history for the same identifiers.
2. High‑level query model
Timestream queries are always iterative:
- You start a query with a POST request to
/api/v2/timestream/iterator(or/api/v1/timestream/iteratorif your backend version does not support v2 yet). - The backend responds with:
data: a dictionary with history values (optional)events: a dictionary with history events (optional)done: whether all data has been processednextToken: a token to request the next batch (ifdoneis false)estimatedQueryProgress: a percentage telling you how far the backend is with scanning the history
- While
doneis false, you continue calling/api/v2/timestream/next/:nextTokento fetch additional batches until all data is delivered.
The query itself is controlled through a JSON body that lets you filter what you want (devices, services, properties, event types) and which time range you are interested in.
3. Typical workflow for a history view
From an application developer’s perspective, a typical “history view” (e.g. a trend chart) follows this flow:
User selects context
- A device (or a group of devices)
- One or more services
- One or more properties (e.g.
temperature,doorState) - A time range (e.g. last 24 hours, last 7 days, custom range)
Frontend builds a Timestream query
- Translates the selection into
deviceIdentifier,serviceIdentifierandpropertyIdentifierlists. - Defines
fromandtotimestamps in UTC milliseconds. - Chooses whether to fetch data, events, or both.
- Translates the selection into
Start Timestream query
- POST
/api/v2/timestream/iterator - Store the returned
nextTokenand the first batch ofdata/eventsin your local application state.
- POST
Iteratively fetch remaining batches
- While
doneisfalse, call/api/v2/timestream/next/:nextToken. - Append
dataandeventsfrom each batch to your local structures. - Use
estimatedQueryProgressto update a progress indicator if you like.
- While
Transform the result for visualization
- Flatten dictionaries into arrays suitable for your charting library.
- Optionally merge events into the timeline (e.g. vertical markers or event lists below the chart).
- Compute derived KPIs (min/avg/max, energy consumption per day, etc.).
Render
- Plot time‑series for each property.
- Overlay events and highlight relevant situations.
- Allow the user to change the time range or selection and restart the workflow.
4. Requesting historical data
The main endpoint for starting a history query is:
http
POST /api/v2/timestream/iteratorThe request body is a JSON object with the following important fields:
queryData(bool, defaulttrue): whether to return time‑series data.queryEvents(bool, defaulttrue): whether to return persisted events.serviceIdentifier(array of string, optional): services to include.deviceIdentifier(array of string, optional): devices to include.propertyIdentifier(array of string, optional): properties to include.events(array, optional): event types to include.from/to(integers, optional): time range in UTC milliseconds.limit(integer, optional): number of values to return per batch (default100).prependFirstValue(bool, optional): adds one value beforefromto get a correct baseline for step functions in graphs.
4.1 Minimal example – last 24 hours of a single property
This example shows how to fetch the last 24 hours of a single property of a single device and service.
jsonc
POST /api/v2/timestream/iterator
Content-Type: application/json
{
"queryData": true,
"queryEvents": false,
"deviceIdentifier": ["DEVICE_123"],
"serviceIdentifier": ["lift.status"],
"propertyIdentifier": ["0x0001.UINT16"], // or the internal identifier your backend uses
"from": 1732200000000, // example timestamps, UTC ms
"to": 1732286400000,
"limit": 1000,
"prependFirstValue": true
}In practice you calculate from/to in your client (for example: to = now, from = now - 24h).
4.2 Filtering by devices, services and properties
- Devices: Use the
deviceIdentifiervalues from the Service module (/api/v1/devicesor/api/v1/services/:serviceIdentifier/devices). These identifiers are consistent across Service, Streams and Timestream. - Services: Use
serviceIdentifiervalues from the Service or Schema module (e.g."lift.status","hvac.zoneControl"). - Properties: For Timestream,
propertyIdentifieris an array of strings that identify properties. These are usually the typed property identifiers used by the backend (for example in the format0x0001.UINT16). Use the Schema module to discover which properties a service exposes and how they map to human‑readable names.
TIP
Use the Schema module to drive your UI and keep an internal mapping from human names (for the user) to property identifiers (for Timestream queries). This keeps your queries robust even if you later add translations or adjust display names.
4.3 Data vs. events
- Set
queryDatatotrueif you need time‑series data (for charts, KPIs, etc.). - Set
queryEventstotrueif you also want to know what happened in the same time range (alarms, status changes, system events, etc.). - If you only need values for plotting, you can set
queryEventstofalseto speed up queries. - If you only need an event timeline, set
queryDatatofalseandqueryEventstotrue.
5. Iterating over result batches
After starting a query, the backend returns a response like this (simplified):
jsonc
{
"done": false,
"nextToken": "abc123",
"estimatedQueryProgress": 32.5,
"data": {
"...": "history data grouped by device and service"
},
"events": {
"...": "events grouped by device"
}
}As long as done is false, you should call the next endpoint:
http
POST /api/v2/timestream/next/:nextTokenExample client‑side loop (pseudo‑code):
ts
async function loadHistory(requestBody: TimestreamRequest): Promise<HistoryResult> {
let combinedData = emptyHistoryStructure();
let combinedEvents = emptyEventsStructure();
// 1. Start query
let res = await fetch("/api/v2/timestream/iterator", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(requestBody),
});
let payload = await res.json();
mergeHistory(combinedData, payload.data);
mergeEvents(combinedEvents, payload.events);
// 2. Fetch further batches while not done
while (!payload.done && payload.nextToken) {
const nextRes = await fetch(`/api/v2/timestream/next/${encodeURIComponent(payload.nextToken)}`, {
method: "POST"
});
payload = await nextRes.json();
mergeHistory(combinedData, payload.data);
mergeEvents(combinedEvents, payload.events);
}
return { data: combinedData, events: combinedEvents };
}Keep in mind:
estimatedQueryProgresscan reach 100 before all data has been sent to the client. It means “all important rows have been scanned, but they might still be streaming to you.”/nextmay temporarily return no data while the backend is still processing a large query. Do not treat an empty batch as an error as long asdoneisfalse.
6. Understanding the response structure
The documentation defines data and events as dictionaries. The exact shape can evolve over time, but the important part for application developers is that:
- data is grouped by device and then by service.
- events are grouped by device.
A typical conceptual shape looks like this (simplified example, not a literal schema):
jsonc
{
"data": {
"DEVICE_123": {
"lift.status": {
"0x0001.UINT16": [
{ "timestamp": 1732200000000, "value": 12 },
{ "timestamp": 1732203600000, "value": 13 }
],
"0x0002.BOOL": [
{ "timestamp": 1732200100000, "value": true }
]
}
},
"DEVICE_456": {
"lift.status": {
"0x0001.UINT16": [ /* ... */ ]
}
}
},
"events": {
"DEVICE_123": [
{
"timestamp": 1732200500000,
"type": "ALARM_TRIGGERED",
"serviceIdentifier": "lift.status",
"details": { /* event specific payload */ }
}
]
}
}When you build your UI, you usually:
- Flatten this structure per property for input into your chart library, for example
[{ x: timestamp, y: value }, ...]. - Group events by type or severity and attach them to the same time axis, e.g. as markers, colored bands or a separate event list.
7. Step charts and prependFirstValue
Many Coldwave properties behave like state variables: a value changes only occasionally and is otherwise constant (e.g. door open/closed, current floor, elevator mode). For these properties, UI often uses step charts.
If you only query data inside your time range, the first visible value might start in the middle of the chart and you do not know what the value was before the range.
The prependFirstValue flag solves this:
- If
true, the backend will add one value right before thefromtimestamp (if available). - This allows you to draw a step chart with the correct initial value at the left border of your graph.
- The backend has to look further back in time, so the query may take longer.
Use prependFirstValue when:
- You show stateful properties as step charts.
- The visual correctness of the initial state is important (e.g. “Was the door already open at 08:00?”).
You can usually keep it false for fast‑changing numeric measurements where the first missing sample is not critical for interpretation.
8. Events in Timestream vs. live events
Timestream can return historical events alongside property values. These events are usually the persisted form of the same event types you see via the Websocket module (for example alarms, status changes, firmware updates, etc.).
Use them in your UI to:
- Annotate trend charts (e.g. vertical lines for alarm start/clear).
- Build timelines (“what happened around this time?”).
- Provide drill‑down for investigations (“show me all events for this device last week”).
Remember that:
- Timestream events are historical records, independent of whether an alarm is currently active.
- For current alarm state, use the Alarms module. For “what alarms did this device have in the last 30 days?”, Timestream is the right place.
9. Naming and Schema integration
The Timestream module itself only defines deviceIdentifier, serviceIdentifier and propertyIdentifier, without dictating how you present them to end‑users. The Schema module is what makes them human‑readable.
Recommended pattern:
- Use the Schema module to:
- Discover which services exist and which properties they provide.
- Get human‑oriented names, units, ranges and groups for properties.
- Drive your UI (labels, tooltips, grouping, etc.).
- Internally, keep a mapping:
- Human‑readable service name →
serviceIdentifier - Human‑readable property name →
propertyIdentifier
- Human‑readable service name →
- When building Timestream queries:
- Translate the user’s selection into the corresponding identifiers.
- Use those identifiers in
serviceIdentifierandpropertyIdentifierarrays.
For URL‑based endpoints (for example in the Service and Streams modules), many paths accept either:
- A typed hex property identifier like
0x0001.UINT16, or - The property name from the schema.
This is convenient but comes with an important caveat:
WARNING
If you change service or property names in the Schema after building links based on them, URLs that used those names may stop resolving. For long‑lived integrations, prefer identifiers that are stable across schema updates (like the hex property IDs) and keep the mapping to human names internal to your application.
10. Best practices and pitfalls
Prefer the v2 endpoints
Use /api/v2/timestream/iterator and /api/v2/timestream/next/:nextToken whenever possible. They offer better filtering, event support and improved performance compared to v1 and the deprecated GET variants.
Limit your scope
- Always filter by
deviceIdentifierand/orserviceIdentifierwhere possible. - Only include
propertyIdentifiervalues you actually need for the current view. - Avoid “global” queries without filters; they can become expensive quickly.
Choose sensible limits
- Use the
limitparameter to cap the number of points per batch. - If you need very long time ranges, consider down‑sampling or aggregating data on your side (e.g. daily averages) instead of displaying every single sample.
Handle empty batches
- While
estimatedQueryProgress < 100,/nextmay return emptydata/eventseven thoughdoneisfalse. - Treat this as “still processing”, not as an error.
Keep identifiers stable in your UI
- Base your UI on Schema names, but keep internal identifiers stable.
- If you must rename properties in the Schema, plan a migration story for any persistent URLs that used those names directly.
11. Summary
- Timestream is the history layer of the Coldwave Backend: it stores and returns time‑stamped values and events for your devices.
- Queries are iterative: you start them with
/iteratorand fetch all batches via/next. - Use Schema + Service to discover devices, services and properties, and then query their history via Timestream.
- Design your UI around time ranges, device/service/property filters and combined views of data and events.
- Prefer stable property identifiers in APIs and use Schema names for end‑user presentation.
With these patterns you can build dashboards, analytics views and reports that use the full power of the Coldwave Backend while keeping your integration robust and maintainable.