Live streaming data
The platform allows Manager users to get a live feed of of data updates for a given device, or for all devices in an ongoing activity.
The streaming API is accessible using the Websocket protocol.
There are three websocket endpoints:
wss://api.asi.swiss/ws/v1/computed-data/{activity}/{timeframe}/
: metrics for a single athletewss://api.asi.swiss/ws/v1/computed-data/{activity}/
: metrics for all athletes in an activitywss://api.asi.swiss/ws/v1/preprocessed-data/{device}/
: sensor data for a single device
All of these endpoints have the same authorization mechanism.
Live data could also be implemented using synchronous (polling) requests to the latest-preprocessed-data endpoint. While this may work for a couple devices during testing, it will not scale well for a production use case. The reason is that it is inefficient, and you may encounter issues related to rate-limiting. Therefore, we highly encourage you to use websockets whenever possible.
This is a more conceptual overview of the live streaming protocols. For more specific details, check out the reference page.
Authorization
Connecting to the websocket endpoint requires an access token for the Manager user that owns the device or activity, or has a READ permission on the timeframe.
The diagram below illustrates the initial message exchanges on a newly initialized websocket connection, that allow the client to provide its token to the server:
The first message ("Authorization needed") can be ignored by the client, meaning that the token can be sent before receiving it.
The API allows all incoming connections to the websocket endpoints (with some possible rate limiting), however, the authentication message containing the access token must be sent by the client within the first 3 seconds. Otherwise, the connection is closed.
Computed data by athlete
The platform allows Manager users to get a live stream of computed data for an ongoing activity, given a timeframe identifier, on the url wss://api.asi.swiss/ws/v1/computed-data/{activity}/{timeframe}/
.
activity
(integer) is the activity identifiertimeframe
(integer) is the timeframe identifier
Important: Manager user must have a read permission on the Athlete linked to the Time frame to live stream their data.
Computed data messages are JSON documents containing the computed data. For example:
{
"total_distance": 83.20118419047552,
"accelerations": {
"threshold_2": {
"threshold": 3,
"values": []
},
"threshold_1": {
"threshold": 2,
"values": []
}
},
"decelerations": {
"threshold_2": {
"threshold": 3,
"values": []
},
"threshold_1": {
"threshold": 2,
"values": []
}
},
"max_speed": 1.1826,
"average_speed": 0.20038889929742307,
"last_timestamp": 1597924127900.0
// other data
}
Note: computed data may vary depending on the activity and time frame configurations.
Computed data by activity
It is also possible to subscribe to all computed data concerning an activity. In that case, the path that needs to be used is /ws/v1/computed-data/{activity}/
.
The Manager is allowed to stream theses data if he's allowed to stream every activity's time frames computed data.
Computed data are still processed for each time frame, so messages received through this socket concerns only one time frame per message.
Each message has a timeframe
key containing the time frame ID for which computed data are processed.
For example:
{
// Time frame id
"timeframe": 86,
// Computed data for this timeframe
"data": {
"total_distance": 83.20118419047552,
"accelerations": {
"threshold_2": {
"threshold": 3,
"values": []
},
"threshold_1": {
"threshold": 2,
"values": []
}
},
"decelerations": {
"threshold_2": {
"threshold": 3,
"values": []
},
"threshold_1": {
"threshold": 2,
"values": []
}
},
"max_speed": 1.1826,
"average_speed": 0.20038889929742307,
"last_timestamp": 1597924127900.0
}
}
This feature is currently not designed for large-scale activities. If your use-case potentially involves tracking more than about 30 devices in a single activity, please contact our API support team. This functionality is currently being tested in specific projects, and will eventually be available on our public platform.
Preprocessed data
Similary to computed data, managers can also subscribe to a WebSocket stream of preprocessed data for a given device.
The path is /ws/v1/preprocessed-data/{device}/
.
Important: Manager user must be the device owner when he subscribe to the WebSocket.
Authentication works the same as with computed data, previously explained.
Parameters
In addition to the token
key in the authentication message, an optional params
key can be specified.
For example:
{
"token": "your_token",
"params": {
"buffer_size": 10,
"drop_older": true,
"flush_timeout": 20
}
}
By default, messages are forwarded to the WebSocket client as soon as they are ready, without any guarantee of arriving in the right order. This problem is inherent to the real-time and distributed architecture but can be mitigated by setting the parameters such that the messages are buffered and reordered first. If buffer_size
is set to some value n > 0
, the last n
messages are held in the buffer and the oldest (according to its timestamp) is released when the buffer exceeds n
messages. This ensures the right ordering of messages up to the last n
messages. By default, buffer_size
is set to 0
meaning that no buffering is performed.
Note: buffering n
messages implies a delay of about n
seconds.
If a message arrives that is older than the last forwarded message (meaning it is about n
seconds late at least), it will still be forwarded unless drop_older
is set to true
, in which case it is simply dropped. Dropping these messages is the only way to completely guarantee the right order.
To ensure all messages are forwarded even after device disconnection, the buffer is flushed (in the right order) after flush_timeout
seconds.
The following table explains the params utility
Param | Possible values | Default | Description |
---|---|---|---|
buffer_size | integer in [0 ,60 ] | 0 | Size of reordering buffer |
drop_older | true | false | false | Control if incoming message older than the last forwarded one should still be sent or dropped |
flush_timeout | integer in [2 ,62 ] | 10 | Timeout after which the messages in the buffer will be forwarded, should be greater or equal to buffer_size + 2 |
Note: in most cases, when messages arrive in wrong order without any params, it is just one message arriving right after its successor. So, a buffer of size 3
would cover a majority of cases, and the delay is not so big (~ 3 seconds)