23 Oct 2024
Streaming Data: Unifying Multiple IOT Streams with Tandem API
This article will show you how to query multiple streams in a single call using the new Tandem Stream API.
Get Latest Stream Readings
There are situations where you may want to retrieve the latest stream values. Previously, this was possible with the existing API:
GET timeseries/models/{modelID}/streams/{elementID}
However, you had to query each stream individually. Now, a new endpoint allows you to query multiple streams in one call, returning their latest data along with the timestamp:
POST timeseries/models/{modelID}/streams
The input payload is a list of stream keys, for example:
{
"keys": [
"AQAAAGFmZjYzZmU2LWZiZmEtNGUAAAAA",
"AQAAAMwHmpqulkf3i-4yPlA4wiAAAAAA"
]
}
The response is a map of keys to stream values:
{
"AQAAAGFmZjYzZmU2LWZiZmEtNGUAAAAA": {
"z:Dg": {
"1729667711972": 11.11
}
},
"AQAAAMwHmpqulkf3i-4yPlA4wiAAAAAA": {
"z:GQ": {
"1729666530871": 1
}
}
}
This new endpoint improves performance, particularly when you only need the latest stream data.
Discrete values
Originally, streams only supported numeric values. However, some customers requested the ability to use text—for example, to represent the status of a door ("Closed" vs. "Open"). The workaround was to map string values to numbers (Closed = 0, Open = 2), but this wasn’t always intuitive.
Now, streams support string values as well:
- Define a parameter of type "text" with a list of allowed values.
- Add the parameter to a classification.
- Apply the classification to the stream.
To send a value to the stream, use the following payload:
{
"status": "Closed"
}
When reading stream data, you'll receive a response like this:
{
"AQAAAFW1JHFT1UmtmoFr8rHA-CkAAAAA": {
"z:GQ": {
"1729666590282": 1
}
}
}
In this response, the stream key (AQAAAFW1JHFT1UmtmoFr8rHA-CkAAAAA), parameter ID (z:GQ), timestamp (1729666590282), and value (1) are shown.
You might wonder why the value is a number. The stream stores the value’s ID rather than the actual text.
To retrieve the actual value, you need to refer to the parameter definition:
{
id: "z:GQ",
fam: "z",
col: "GQ",
name: "Door Status",
category: "Streams",
dataType: 20,
flags: 20,
allowedValues: {
list: [
"Closed",
"Open"
],
map: {
Closed: 1,
Open: 2
},
},
context: "e"
}
You can map the value ID back to the actual value using the following approach:
const valueMap = new Map();
for (const [ name, value ] of Object.entries(propDef.allowedValues.map)) {
valueMap.set(value, name);
}
const value = valueMap.get(id);
Wrap Up
For a complete example, you can check out the GitHub repository, which includes both JavaScript and Python versions. Feel free to reach out if you have any questions: aps.help@autodesk.com.
You can also submit your questions via StackOverflow and mark them using autodesk-tandem tag.