01 Architecture & Flux de données
Topologie globale et détail des 4 flux applicatifs
Vue d'ensemble
La CloudGate CG8102 est à la fois la gateway LoRa (packet forwarder), le LoRaWAN Network Server et l'Application Server. Elle remplace une combinaison gateway + LNS cloud classique. Tout le code applicatif est implanté dans le canvas LuvitRED (port Lua/Luvit de Node-RED, embarqué dans le firmware CG).
Balise Asystom #1
Sentinel · FPort 1/4 uplink
FPort 64/70 downlink
FPort 64/70 downlink
Balise #2 .. #N
jusqu'à 30 par CG
Class A LoRaWAN
Class A LoRaWAN
LoRa Class A · OTAA
CloudGate CG8102
LuvitRED canvas · Lua/Luvit
LoRa NS + AS · LTE/Ethernet
Stockage local 15 j
LoRa NS + AS · LTE/Ethernet
Stockage local 15 j
file out append
Audit local
/mnt/data/luvitred/
uplinks-YYYY-MM-DD.jsonl
rétention 15 j
uplinks-YYYY-MM-DD.jsonl
rétention 15 j
HTTPS · Bearer DAP
IoBase (Indaba)
data lake
POST /api/v1/cloudgate/payloads
POST /gateway/health
POST /api/v1/cloudgate/payloads
POST /gateway/health
HTTPS · Basic + X-Network
Asystom Advisor
analyse vibratoire
POST /lorawan (uplinks)
GET /getPendingMsgs (dl)
POST /lorawan (uplinks)
GET /getPendingMsgs (dl)
Les 4 flux applicatifs
FLUX 01
Payload brute capteurs → IoBase
Chaque trame LoRa reçue est transformée en POST
/api/v1/cloudgate/payloads avec Bearer DAP. Body au format spec v1.0 : equipment_model, payload (hex), site, datasource, metrics[], timestamp ISO 8601. Headers X-CloudGate-Id + X-Device-Id. Voir Chap. 03.FLUX 02
Payload brute capteurs → Asystom Advisor
Mêmes trames, en parallèle, vers Asystom. POST
/lorawan avec Basic auth + header X-Network. Body Loriot-like : endDevice.devEui, fPort, fCntUp, payload, recvTime, dataRate, gwInfo[]. Voir Chap. 04.FLUX 03
Asystom downlink polling → balises
Toutes les 60s, GET
/getPendingMsgs?client=<id>. Si la réponse contient des device_list/payload/cmd, la chaîne parse_asystom_dl émet un msg.app = { queue = { [DevEUI] = { data, fport, confirmed=false } } } vers le node lora-app qui en fait un downlink LoRa Class A.FLUX 04
Santé CloudGate → IoBase
Heartbeat 1×/h + 1× par event capteur. POST
/gateway/health. Body : life_counter, uptime, lora_uplinks_count, lora_status (active/idle/stale), gsm_rssi, gsm_operator, gsm_technology, gsm_rfband, modem_model, last_iobase_ok_ts, last_asystom_ok_ts.Anatomie d'une trame uplink
Une trame LoRa reçue est fan-out en 3 destinations parallèles depuis la CloudGate : IoBase (cloud), Asystom Advisor (cloud), et un audit local sur disque. Cliquer Lancer pour visualiser le timing.
📡
Balise Asystom
Sentinel · FPort 4
LoRa Class A
CloudGate
on_lora_message · fan-out 3 destinations
file out append
Audit local
/mnt/data/luvitred/
uplinks-YYYY-MM-DD.jsonl
uplinks-YYYY-MM-DD.jsonl
HTTPS Bearer DAP
IoBase
POST /api/v1/cloudgate/payloads
HTTPS Basic + X-Network
Asystom Advisor
POST /lorawan
— prêt —
Composants du canvas (résumé)
| Catégorie | Nodes | Rôle |
|---|---|---|
| Entrée LoRa | lora-srv · lora-app · Balise-01 (lora device) |
Packet forwarder + LNS + AppServer + flow-node device-spécifique. Sortie vers on_lora_message. |
| Dispatcher | on_lora_message (function) |
Compteurs + 5 wires sortantes : lora out, build_iobase, build_audit, build_asystom, build_health. |
| Flux 01 IoBase | build_iobase_msg → iobase POST (queueenabled) → handle_iobase_resp |
Build body spec v1.0 + headers, POST avec Bearer, queue offline si 5xx/timeout. |
| Flux 02 Asystom | build_asystom_msg → asystom POST (queueenabled) → handle_asystom_resp |
Build body Loriot-like + Basic auth + X-Network header, POST. |
| Flux 03 DL polling | asystom downlink poll (cron 60s) → build_asystom_dl_get → http GET → parse_asystom_dl → lora-app |
GET getPendingMsgs, parse JSON, multi-msg vers lora-app.queue par DevEUI. |
| Flux 04 Health | health hourly (cron 3600s) + on_lora_message → build_health_msg → health POST → handle_health_resp |
Body 11 champs métriques. POST 1×/h + à chaque event capteur. |
| Audit local | build_audit_line → audit jsonl (file out append) + audit rotate daily 02:00 (cron) → audit_rotate → file out delete |
JSONL append per day dans /mnt/data, cleanup > 15 jours quotidien. |
| DAP auth | 3 inject + 3 build + dap POST + handle_dap_resp + persist_dap + save dap state + chaîne restore au boot |
Register/Token/refresh single-use protégé par mutex. Persistance flash. Voir Chap. 02. |
| Heartbeat life | life tick 1s → life_tick → life counter file out + load life @startup → file in → life_restore |
Compteur 0→32000 cyclique persisté toutes les 60s, restauré au boot. |
| CG métriques | cg admin login + cg metrics poll (cron 300s) → 3 endpoints (internet/diag wwan0/sim) → handle_cg_metrics |
Récupère GSM RSSI, opérateur, technology, RF band depuis l'admin local CG. |
| Queue offline | queueing config klaud_offline (config node) |
RAM 50 + flash 15000 entries dans /mnt/data/luvitred/queue/. Replay auto à la reconnexion. |
| Init | startup init → fn_startup_init |
Set globals au boot : start_time, hosts, credentials, defaults. |
Stockage local
/mnt/data/luvitred/
ubifs ~79 Mo libres. Toutes les données runtime persistantes.
└─ life_counter.json
Compteur de vie persisté toutes les 60s. Restauré au boot.
└─ dap_state.json
device_code + access_token + refresh_token + saved_at. Re-écrit à chaque token update. Restauré au boot.
└─ uplinks-YYYY-MM-DD.jsonl
Append-only des trames LoRa, 1 ligne JSON par uplink. Rétention 15 j par cron quotidien.
└─ queue/
Queue offline du node http-request natif (queueenabled=true). 15000 entries max, FIFO retry.
/overlay/etc/luvitred/store/lora_db/
jffs2 16 Mo. LevelDB du node lora-app : sessions OTAA, AppSKey/NwkSKey/DevAddr/FCnt persistés.
Resilience & KPIs
Coupure WAN courte
Trames mises en queue par
queueenabled=true. Replay automatique à la reconnexion.Coupure WAN longue (> 1 h)
Détection transition WAN false→true par
cg metrics poll → trigger refresh DAP préventif → puis replay queue.Token DAP expiré
POST → 401 →
fn_trigger_refresh_on_401 → build_dap_refresh (mutex) → nouveau token → la trame est replay automatiquement avec le nouveau token (queueenabled).Reboot CG
Tokens restaurés depuis
dap_state.json au boot. life_counter restauré. Aucun re-enrôlement administrateur nécessaire.Refresh concurrent
Mutex
global.dap_refreshing → 1 seul appel /refresh à la fois. Protège le single-use du refresh_token.Stockage queue
15000 entries × ~500 bytes = ~7,5 Mo. Au pic 1 trame/min × 15 j = 21600 trames. Rétention > 15 j garantie pour cadence ≤ 1 trame/min.