A Mock de validation IoBase + Asystom + DAP
Cette page décrit un serveur Python de test qui simule IoBase, Asystom et DAP en local. Ce n'est pas le Cockpit CloudGate, l'interface web embarquée dans la passerelle qui sert au pilotage quotidien (suivi des balises, réglages, variables).
Ce mock a servi à valider la chaîne avant que les vraies plateformes soient joignables.
Depuis, IoBase et Asystom sont configurés sur leurs vraies URL — les valeurs
192.168.42.122:9000 ci-dessous sont historiques, elles ne reflètent plus
la configuration en service.
Pourquoi un mock ?
ni IoBase ni Asystom Advisor ne sont accessibles depuis la CG (URLs prod, credentials). Pour valider que toute la chaîne canvas fonctionne avant ces dépendances, on a écrit un serveur Python local qui simule les 3 APIs avec validation stricte des contrats spec.
Le fichier
| Path | <project>/mock_cockpit.py |
|---|---|
| Stack | Python 3 stdlib uniquement (http.server + json) — zéro dépendance |
| Port | 9000 (bind 0.0.0.0 → joignable depuis CG via 192.168.42.122) |
| Lancement | python3 mock_cockpit.py |
| Dashboard | http://localhost:9000/dashboard |
Endpoints simulés
| Endpoint | Spec source | Validation |
|---|---|---|
POST /register | DAP IoBase intercom | Body {name}. Génère device_code, auto-validate. |
POST /Token | DAP IoBase intercom | Body {device_code, client_id}. 425 si pas validé. |
POST /refresh | DAP IoBase intercom | Body {refresh_token, client_id}. 401 si refresh_token consommé. |
POST /v1/payloads | API IoBase v1.0 | Bearer + 6 champs body + ISO 8601. 400 si manquant. |
POST /gateway/health | Implicite spec | Bearer match access_token de la session. |
POST /lorawan | API Asystom Advisor | Basic auth + header X-Network. |
GET /getPendingMsgs?client=… | API Asystom Advisor | Réponse {device_list, payload, cmd}. |
POST /api/inject_downlink | cockpit-only | Permet au dashboard de planifier un downlink à recevoir au prochain poll. |
GET /api/state | cockpit-only | Retourne tout l'état RAM (uplinks, healths, dap_log, session, stats). |
Le dashboard
Auto-refresh toutes les 2 secondes. 5 cartes de validation + topologie animée.
Topologie
Vue [CloudGate]──5 flèches──[Mock Cockpit]. Chaque flèche s'allume vert quand le flux a eu de l'activité dans les 60 dernières secondes (badge "actif"), grise sinon.
Carte DAP
4 KPIs : register / Token / refresh / total. Fields device_code, validated, access_token, refresh_token, last call. Badge :
- 🔘 pas enrôlé : aucun device_code
- 🟠 enrôlé pas de token : device_code reçu mais pas encore Token (pending validation)
- 🟢 enrôlé · token actif : access_token + refresh_token stockés
Carte IoBase Flux 01
4 KPIs : uplinks count, DevEUI distincts, equipment_model du dernier, site du dernier. Affichage de la dernière trame avec X-CloudGate-Id, X-Device-Id, body keys, payload tronqué.
Carte Asystom Flux 02
Similaire à IoBase mais avec network header + format Loriot-like.
Carte Flux 03 Downlink
Affiche les polls reçus, downlinks en queue, dispatched (consommés par le dernier poll).
Bouton « Inject downlink » : permet de planifier un payload + cmd + DevEUI dans la queue. Au prochain poll Asystom (60s max), la chaîne CG le récupère et l'envoie en LoRa downlink.
Carte Flux 04 Health
7 KPIs : POSTs reçus, life_counter, uptime, lora_uplinks_count, lora_status, gsm_rssi, operator. Affichage du dernier health POST en clair.
Comment lancer
cd <project>
python3 mock_cockpit.py
# → http://localhost:9000/dashboard
# Le canvas LuvitRED de la CG doit avoir ses globals pointés vers le mock :
# global.iobase_host = '192.168.42.122:9000'
# global.dap_host = '192.168.42.122:9000'
# global.asystom_url = 'http://192.168.42.122:9000'
# global.asystom_auth_b64 = 'dGVyZWdhOnRlc3Q=' (admin:test, dummy)
# global.asystom_client = 'client_id'
Tests automatisés via curl
# Login pour obtenir une session LuvitRED
curl -c /tmp/lc.cookies -X POST -H "Content-Type: application/json" \
-d '{"username":"admin","password":"$ADMIN_PASS"}' \
http://192.168.42.1/api/login
# Trigger DAP register
curl -b /tmp/lc.cookies -X POST http://192.168.42.1:8080/inject/<DAP_REGISTER_ID>
# Trigger DAP get token (~2s plus tard)
curl -b /tmp/lc.cookies -X POST http://192.168.42.1:8080/inject/<DAP_TOKEN_ID>
# Vérifier l'état mock
curl http://localhost:9000/api/state | python3 -m json.tool
# Reset mock pour test propre
curl -X POST http://localhost:9000/api/clear
Migration mock → prod
Le passage en prod est une simple modification des globals dans fn_startup_init :
| Global | Mock value | Prod value (à configurer/Asystom) |
|---|---|---|
iobase_host | 192.168.42.122:9000 | iobase.example.com |
dap_host | 192.168.42.122:9000 | dap.example.com |
asystom_url | http://192.168.42.122:9000 | https://advisor.example.com |
asystom_auth_b64 | dGVyZWdhOnRlc3Q= | <real base64> |
iobase_site | TODO_SITE | site_a |
iobase_datasource | TODO_DATASOURCE | transportation |
| Site, source de données et métriques ne sont plus des valeurs globales : ils se règlent par balise dans le cockpit depuis le 2 août 2026. | ||
Aucune modification du canvas n'est nécessaire. Les chaînes pivotent automatiquement.