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
📡
Balise #2 .. #N
jusqu'à 30 par CG
Class A LoRaWAN
📦
CloudGate CG8102
LuvitRED canvas · Lua/Luvit
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
HTTPS · Bearer DAP
☁️
IoBase (Indaba)
data lake
POST /api/v1/cloudgate/payloads
POST /gateway/health
HTTPS · Basic + X-Network
☁️
Asystom Advisor
analyse vibratoire
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
📦
CloudGate
on_lora_message · fan-out 3 destinations
file out append
💾
Audit local
/mnt/data/luvitred/
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égorieNodesRô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_msgiobase POST (queueenabled) → handle_iobase_resp Build body spec v1.0 + headers, POST avec Bearer, queue offline si 5xx/timeout.
Flux 02 Asystom build_asystom_msgasystom 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_gethttp GETparse_asystom_dllora-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_msghealth POSThandle_health_resp Body 11 champs métriques. POST 1×/h + à chaque event capteur.
Audit local build_audit_lineaudit jsonl (file out append) + audit rotate daily 02:00 (cron) → audit_rotatefile 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 1slife_ticklife counter file out + load life @startupfile inlife_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 initfn_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_401build_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.