API - Temps réel
API - Temps réel
Cette page détaille la consommation des flux temps réel Phyling : ouverture de la connexion Socket.IO, souscriptions aux rooms disponibles, sélection des signaux de télémétrie et exécution de commandes RPC.
Snapshot REST indispensable
Avant d'ouvrir la socket, constituez un snapshot complet de chaque device via la route settings. Ce référentiel vous permet de connaître les modules disponibles, les commandes RPC, les clés temps réel et d'appliquer correctement les patchs reçus en flux.
Récupérer les réglages device
GET /devices/rt/{client_id}/{device_number}/settings
Authorization: Bearer <access_token> || ApiKey <key>La réponse sert de snapshot de référence pour le device. On y retrouve :
- Les métadonnées globales (
battery,state,version,timezone,sport, etc.). - Les rattachements (
client,group,user) avec leurs identifiants. - Un résumé des modules de la config avec des infos dessus.
- Le dictionnaire
featureslistant toutes les commandes RPC disponibles (voir §4). - Les clés temps réel (quand disponibles) via
realtime_data_keysetrealtime_indicator_keys.
Extrait simplifié :
{
"number": 10300378,
"name": "Maxi 378",
"state": "record",
"is_connected": true,
"battery": 39,
"timezone": "Europe/Paris",
"epoch": 1762441207,
"recTime": 23.142,
"selectionStartTime": 0,
"startRecTimeSinceEpoch": 0,
"deviceRecId": 42,
"features": {
"record": { "cmd_start": "v1.record.rec.start", "cmd_stop": "v1.record.rec.stop" },
"restart": { "cmd": "v1.board.restart" },
"...": "..."
},
"modules": {
"gps": { "id": 1, "is_connected": false, "realtime": false, "type": "gps" },
"imu": { "id": 2, "is_connected": true, "realtime": true, "type": "imu" }
},
"realtime_data_keys": [
{ "name": "gps.gpstimeUs", "label": "gps.gpstimeUs", "description": "", "unit": "us", "precision": 3, "yRange": [] },
{ "name": "gps.gpsTimeAccuracyNs", "label": "gps.gpsTimeAccuracyNs", "description": "", "unit": "ns", "precision": 3, "yRange": [] },
{ "...": "..." }
],
"realtime_indicator_keys": [
{ "unit": { "fr": "cpm", "en": "spm" }, "description": { "fr": "Cadence", "en": "Cadence" }, "precision": 1, "enabled": true, "name": "cadence", "type": "number" },
{ "...": "..." }
],
"client": { "id": 2, "name": "phyling" },
"group": { "id": 1, "name": "phyling" },
"user": { "active": true, "firstname": "<firstname>", "id": 42, "lastname": "<lastname>", "mail": "<mail>" },
"sport": { "display_name": "Aviron", "name": "aviron" },
"version": "v7.0.1",
"...": "..."
}Fusionner settings et status
Les événements Socket.IO app/device/{device}/board/status émettent des patchs partiels qui réutilisent la même structure que settings. Après chaque patch, effectuez un merge profond avec votre snapshot local pour conserver l'état à jour (batterie, modules connectés, nouvelles clés temps réel, etc.). Les exemples realtime.html et single-device.html fournis dans ce dépôt contiennent une fonction deepMerge réutilisable si besoin.
1. Connexion Socket.IO
- Déduisez l'URL Socket.IO à partir de l'URL API REST : même host/port,
ws://lorsque l'API est en HTTP,wss://sinon.
const apiBase = 'https://api.app.phyling.fr';
const socketBase = 'wss://api.app.phyling.fr';
const socket = io(socketBase, { transports: ['websocket'] });- Attendez l'événement
connectpour garantir que la socket est prête. - Émettez
subscribepour chaque room à écouter en incluant le token d'accès.
socket.emit('subscribe', {
authorization: accessToken,
room: `app/client/${clientId}/device/list_connected`
});- Sur
disconnect, relancez la connexion puis réémettez les souscriptions actives. - Pour quitter une room, envoyez
socket.emit('unsubscribe', { room }).
🔐 Chaque
subscribedoit inclure{ token: <access_token>, room: <room> }. Sans token valide, la socket rejette l'abonnement.
2. Rooms disponibles
| Room | Description | Payload reçu |
|---|---|---|
app/client/{client_id}/device/list_connectedRenvoie sur app/client/device/list_connected | Liste complète des devices d'un client avec leur état de connexion. | Tableau d'objets { number, name, is_connected, state, ... } pour détecter les (dé)connexions et initialiser vos stores. |
app/device/{device_number}/ind/json/allRenvoie sur app/device/ind/json/all | Instantané des indicateurs calculés pour un device. | Objet { number, recTime, indicators: { ... } } exploitable pour du monitoring. |
app/device/{device_number}/board/statusRenvoie sur app/device/board/status | Patchs d'état à fusionner avec settings. | Mises à jour de batterie, state, modules, clés temps réel, etc. |
app/device/{device_number}/data/json/allRenvoie sur app/device/data/json/all | Flux temps réel des mesures sélectionnées. | Objet { number, recTime, data: { module: { T:[], <signal>:[] } } }; timestamps fournis dans T ou dérivés de recTime. |
3. Sélectionner les signaux diffusés
Avant de recevoir app/device/{device}/data/json/all, adressez la sélection désirée via la route REST dédiée.
POST /devices/rt/{client_id}/{device_number}/realtime
Authorization: Bearer <access_token>
Content-Type: application/json
{
"realtime_data_keys": [
"imu.acc_x",
"imu.acc_y",
"imu.acc_z"
]
}Vous pouvez également activer des modules entiers :
POST /devices/rt/{client_id}/{device_number}/realtime
Authorization: Bearer <access_token>
Content-Type: application/json
{
"modules": ["imu"]
}- Référez-vous aux noms listés dans
realtime_data_keys(route settings ou dernier status). - Envoyer une liste vide coupe immédiatement le flux temps réel pour ce device.
- Répétez périodiquement la sélection (~30 s) pour maintenir la diffusion active.
- L'activation est réalisée au niveau module : demander
imu.acc_xactive tout le moduleimu. Si un autre client activegps, tout le monde reçoit à la fois imu et gps.
4. Exécuter des commandes (RPC)
Les commandes device transitent par :
POST /devices/rt/{client_id}/{device_number}/rpc/request
Authorization: Bearer <access_token>
{
"feature": "record",
"cmd_type": "cmd_start",
"params": {},
"timeout": -1
}feature/cmd_typedoivent correspondre aux clés desettings.features. Exemple :settings.features.record.cmd_start⇒feature = "record"etcmd_type = "cmd_start".- Alternative : envoyer directement
method: "v1.board.restart"ou toute valeur listée dansfeatures.*. - Exemples courants : démarrer un enregistrement (
record+cmd_start), arrêter (cmd_stop), modifier une configuration (config+cmd_set), redémarrer (method: "v1.board.restart").
La réponse confirme uniquement que la requête va être envoyée ; surveillez ensuite app/device/{device}/board/status pour voir l'état fusionné avec vos settings locaux.
5. Ressources complémentaires
- La documentation Swagger fournie avec l'API inventorie l'ensemble des routes REST (login, refresh, devices, temps réel, RPC).
- Les exemples front-end (
minimal_oauth.py,minimal_apikey.html,realtime.html,single-device.html) illustrent l'authentification, le mergesettings+status, la sélection périodique des clés temps réel et la manipulation des payloads.