T3 API IoBase
Flux 01 — Sensor uplinks
on_lora_message → build_iobase_msg
Bearer DAP + X-CloudGate-Id + X-Device-Id
décodé + écrit Indaba
→ build_dap_refresh (mutex) → retry
Endpoint
| URL | POST <iobase_host>/v1/payloads |
|---|---|
| Méthode | POST |
| Content-Type | application/json |
La spécification API_IoBase_CloudGate_v1.0.pdf annonce
/api/v1/cloudgate/payloads. Ce chemin renvoie un 404 systématique :
le chemin réellement déployé, confirmé par Terega le 31/07/2026, est
/v1/payloads. Le reste de la spec (headers et corps du message) est correct.
Headers obligatoires
| Header | Source canvas | Description |
|---|---|---|
X-CloudGate-Id | global.cloudgate_device_name | Identifiant unique de la passerelle |
X-Device-Id | msg.DevEUI | DevEUI de la balise émettrice |
Authorization | 'Bearer ' .. global.iobase_token | Bearer DAP. Voir Chap. 02. |
Content-Type | hardcoded | application/json |
Body JSON (champs requis)
| Champ | Type | Requis | Source canvas / valeur |
|---|---|---|---|
equipment_model | String | Oui | Configuré par balise dans le Cockpit CloudGate (onglet Balises → Modifier) |
payload | String hex | Oui | Hex lowercase de msg.payload (trame LoRa raw) |
site | String | Oui | Configuré par balise dans le Cockpit CloudGate (onglet Balises → Modifier) |
datasource | String | Oui | Configuré par balise dans le Cockpit CloudGate (onglet Balises → Modifier) |
metrics | Array[String] | Oui | Configuré par balise. Au moins une valeur : IoBase rejette une liste vide. |
options | String | Non | global.iobase_options. Omis du body si vide. |
timestamp | String ISO 8601 | Oui | os.date('!%Y-%m-%dT%H:%M:%SZ', os.time()) |
Exemple de POST réel
POST /v1/payloads HTTP/1.1
Host: terega-staging.iot-cloud-gate.api.indasuite.io-base.com
Content-Type: application/json
Authorization: Bearer AT9d8f7a6e5b4c3d2e1a0f9e8d7c6b5a4e
X-CloudGate-Id: cloudgate-XX
X-Device-Id: 0004A30B010593C1
{
"equipment_model": "asystom_sentinel",
"payload": "00a2070e4c210239360be184f67dd87c417cc87a...",
"site": "usine_nord",
"datasource": "transportation",
"metrics": ["50001m_iot_pit002", "50001m_iot_tt002"],
"timestamp": "2026-04-25T14:35:22Z"
}
Codes de réponse
| Code | Statut | Comportement canvas |
|---|---|---|
| 200 | OK décodé + écrit Indaba | global.last_iobase_ok_ts = os.time() |
| 202 | Accepted (queued pour traitement) | Idem 200 |
| 400 | Bad Request (champ obligatoire manquant) | Log erreur. Pas de retry. À investiguer côté config (probablement global.iobase_* mal set). |
| 401/403 | Authentication failed | fn_trigger_refresh_on_401 → build_dap_refresh → retry du POST avec nouveau token |
| 500 | Erreur serveur | Journalisé. La mesure n'est pas rejouée — il n'existe pas de file sur cette passerelle |
Flux 04 — Health
Endpoint
| URL | POST <iobase_host>/gateway/health |
|---|---|
| Méthode | POST |
| Content-Type | application/json |
| Auth | Bearer <global.iobase_token> |
Cadence d'émission
- Cron horaire (3600s) :
health hourlyinject - + 1 fire à chaque event capteur
Body Health
{
"timestamp": 1714056789,
"source": "cloudgate",
"device_id": "cloudgate-XX",
"life_counter": 6579,
"uptime_seconds": 6833,
"lora_uplinks_count": 33,
"last_lora_ts": 1714056772,
"last_iobase_ok_ts": 1714056774,
"last_asystom_ok_ts": 1714056775,
"lora_status": "active",
"gsm_rssi": -85,
"gsm_signal_quality": null,
"gsm_operator": "F-Bouygues Telecom",
"gsm_technology": "GSM",
"gsm_rfband": "GSM 900",
"modem_model": "BG96",
"sim_status": null
}
Sémantique des champs
os.time() - global.start_time. Reset à chaque reboot, pas à chaque deploy.active (< 5 min), idle (< 30 min), stale (≥ 30 min)./api/diagnostics?device=wwan0. Plage typique -50 (excellent) à -110 (perdu).Compatibilité legacy
POST /sensor/data (ancien format des premières versions de la chaîne) en réponse 201, pour compatibilité avec les flow exports des sessions de dev. Le canvas actuel utilise exclusivement /v1/payloads.
Deux environnements IoBase
La passerelle peut servir deux environnements IoBase distincts — par exemple une recette et une production. Ils ne partagent rien : chacun a son adresse, ses identifiants, son jeton, son verrou de renouvellement et son propre fichier d'état d'authentification.
| Environnement | Variables | Fichier d'état |
|---|---|---|
| Principal (défaut) | iobase_host, dap_host,
dap_client_id, dap_api_key |
dap_state.json |
| Second | les mêmes, suffixées _b |
dap_state_b.json |
Chaque balise porte l'environnement vers lequel partent ses mesures, choisi dans le cockpit (onglet Balises → ✎ Modifier). Une balise sans consigne suit l'environnement principal.
Tant que iobase_host_b est vide, le second environnement n'existe pas : une balise
qui lui serait affectée repart sur l'environnement principal plutôt que d'échouer,
en le signalant dans le journal par IOBASE_ENV_FALLBACK. Le cockpit ne propose
d'ailleurs le choix qu'une fois l'adresse renseignée — proposer une destination vers laquelle la
passerelle refuse d'envoyer serait mentir à l'opérateur.
Les quatre valeurs du second environnement se saisissent dans le cockpit, sans redéploiement du flux. Son enrôlement, en revanche, exige une validation par un administrateur côté plateforme, comme pour le premier.
Ce qui empêche une mesure de partir
Quatre champs sont obligatoires par balise : site, source de données, modèle
d'équipement et métriques. S'il en manque un, la passerelle n'envoie pas et
journalise IOBASE_SKIP avec la liste des champs absents — plutôt que d'essuyer un
refus 400 dont le motif serait à deviner. Le compteur d'abandons et le détail du dernier sont
visibles dans les variables iobase_skip_count et iobase_last_skip.
Un capteur déclaré generic emprunte exactement la même chaîne : seule la
transmission vers Asystom est coupée. Voir Ajouter un capteur.
Configuration
Deux niveaux, à ne pas confondre :
| Niveau | Ce qui s'y règle | Où |
|---|---|---|
| Par balise | site, source de données, modèle d'équipement, métriques, type de capteur, environnement de destination | Cockpit, onglet Balises → ✎ Modifier |
| Global | adresses des plateformes, identifiants d'authentification, noms des environnements | Cockpit, onglet Globals (rôle admin) — voir la référence des variables |
Jusqu'au 2 août 2026, iobase_site, iobase_datasource et
iobase_equipment_model fournissaient une valeur par défaut à toutes les balises. Ces
champs sont désormais obligatoires par balise et ces variables ne sont plus jamais
lues par le traitement des mesures. Le cockpit les masque. La variable
iobase_metrics_default, elle, n'existe plus du tout.