# Smart City Digital Twin - Data Flow Diagram (Updated 2026-05-12) ## Architecture complète avec LoRaWAN ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ Smart City Simulator (Python) │ │ Publie sur 3 brokers MQTT + REST vers OpenRemote │ └──────────┬────────────────────┬──────────────────────┬───────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ EMQX Broker │ │ Mosquitto Broker │ │ BunkerM Broker │ │ (port 11883) │ │ (port 1883) │ │ (port 1900) │ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ IoT-Agent-EMQX │ │IoT-Agent-Mosquitto│ │IoT-Agent-BunkerM │ │ Port: 4041 │ │ Port: 4042 │ │ Port: 4043 │ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │ │ │ └───────────────────────┴──────────────────────┘ │ ▼ ┌─────────────────────┐ │ Orion-LD Context │ │ Broker (port 1026)│ │ MongoDB backend │ └─────────┬───────────┘ │ │ Subscription → QuantumLeap ▼ ┌─────────────────────┐ │ QuantumLeap │ │ (port 8668) │ └─────────┬───────────┘ │ ▼ ┌─────────────────────┐ │ CrateDB │ │ (ports 5432/4200)│ └─────────┬───────────┘ │ ▼ ┌─────────────────────┐ │ Grafana │ │ (port 3001) │ └─────────────────────┘ ═══════════════════════════════════════════════════════════════════════════════ LoRaWAN Layer ═══════════════════════════════════════════════════════════════════════════════ ┌──────────────────┐ ┌──────────────────┐ │ Gateway LoRaWAN │ UDP │ Gateway LoRaWAN │ │ (EU868) │ 1700 │ (EU868) │ └────────┬─────────┘ └────────┬─────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ ChirpStack LoRaWAN Network Server │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ chirpstack │ │ gateway-bridge │ │ rest-api │ │ │ │ (port 8080) │ │ (UDP 1700) │ │ (port 8090) │ │ │ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ PostgreSQL │ │ Redis │ │ Mosquitto (MQTT) │ │ │ │ (chirpstack DB) │ │ (cache) │ │ (port 1883) │ │ │ └──────────────────┘ └──────────────────┘ └────────┬─────────┘ │ └──────────────────────────────────────────────────────┬─────────────────────┘ │ ▼ ┌──────────────────┐ │ EMQX Broker │ │ (integration) │ └──────────────────┘ ┌─────────────────────────────────────────────────────────────────────────────┐ │ The Things Stack LoRaWAN Network Server │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ tts-stack │ │ tts-postgres │ │ tts-redis │ │ │ │ (port 1885) │ │ (TTN DB) │ │ (cache) │ │ │ └────────┬─────────┘ └──────────────────┘ └──────────────────┘ │ │ │ │ │ │ UDP 1700 (gateways) │ │ │ MQTT 1883 (events) │ │ │ HTTP 1884 (API) │ │ │ HTTP 1885 (Console) │ └───────────┬─────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────┐ │ EMQX Broker │ │ (integration) │ └──────────────────┘ ═══════════════════════════════════════════════════════════════════════════════ OpenRemote Manager ═══════════════════════════════════════════════════════════════════════════════ ┌─────────────────────────────────────────────────────────────────────────────┐ │ OpenRemote Manager (Artemis MQTT) │ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │ │ Manager UI │ │ Keycloak │ │ PostgreSQL │ │ │ │ (port 8080) │ │ (port 8080) │ │ (port 5432) │ │ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ │ │ │ Assets IOTSensor avec agentLink MQTT + location (GeoJSON Point) │ │ Assets visualisés sur la carte Martinique (mapsettings.json) │ └─────────────────────────────────────────────────────────────────────────────┘ ``` ## Flux de données (Step-by-step) 1. **Simulator** publie sur 3 brokers MQTT (EMQX:11883, Mosquitto:1883, BunkerM:1900) - Topic: `smartcity-api-key/{device_id}/attrs` - Format: `{"NO2": 45.5, "temperature": 26.0, "humidity": 70.0}` 2. **3 IoT-Agents** (un par broker) reçoivent les messages - iot-agent-emqx (port 4041) ← EMQX - iot-agent-mosquitto (port 4042) ← Mosquitto - iot-agent-bunkerm (port 4043) ← BunkerM 3. **Orion-LD** reçoit les entités NGSI-v2 - URL: `http://smart-city-orion-ld:1026` - Entité: `urn:ngsi-ld:AirQualityObserved:airquality_001` 4. **Subscription Orion-LD → QuantumLeap** - Notify URL: `http://smart-city-quantumleap:8668/v2/op/notify` 5. **QuantumLeap** stocke dans **CrateDB** - Table: `quantumleap.etairqualityobserved` 6. **Grafana** visualise les données - Datasource: `CrateDB-SmartCity` 7. **ChirpStack** gère les gateways et devices LoRaWAN - Gateway Bridge (UDP 1700) → ChirpStack → MQTT → EMQX - REST API (port 8090) pour gestion des devices/applications 8. **The Things Stack** gère les gateways et devices LoRaWAN (alternative) - Gateway (UDP 1700) → TTS Stack → MQTT/REST API - Console web (port 1885) 9. **OpenRemote** affiche les assets sur la map - Assets IOTSensor avec location GeoJSON - Agents MQTT pour mise à jour des valeurs ## Sous-domaines (Traefik) ### IoT Agents & Brokers - `iot-agent-emqx.digitribe.fr` → IoT-Agent-EMQX (port 4041) - `iot-agent-mosquitto.digitribe.fr` → IoT-Agent-Mosquitto (port 4042) - `iot-agent-bunkerm.digitribe.fr` → IoT-Agent-BunkerM (port 4043) - `orion-ld.digitribe.fr` → Orion-LD (port 1026) - `quantum-leap.digitribe.fr` → QuantumLeap (port 8668) - `grafana.digitribe.fr` → Grafana (port 3001) ### ChirpStack LoRaWAN - `chirpstack.digitribe.fr` → ChirpStack Console (port 8080) - `chirpstack-api.digitribe.fr` → ChirpStack REST API (port 8090) - `chirpstack-ws.digitribe.fr` → Gateway Bridge WebSocket (port 3001) ### The Things Stack LoRaWAN - `tts.digitribe.fr` → TTS Console (port 1885) - `tts-api.digitribe.fr` → TTS REST API (port 1884) ### OpenRemote - `openremote.digitribe.fr` → OpenRemote Manager (port 8080) ## Flux de données (Step-by-step) 1. **Simulator** publie sur 3 brokers MQTT (EMQX:11883, Mosquitto:1883, BunkerM:1900) - Topic: `smartcity-api-key/{device_id}/attrs` - Format: `{"NO2": 45.5, "temperature": 26.0, "humidity": 70.0}` 2. **3 IoT-Agents** (un par broker) reçoivent les messages - iot-agent-emqx (port 4041) ← EMQX - iot-agent-mosquitto (port 4042) ← Mosquitto - iot-agent-bunkerm (port 4043) ← BunkerM - Chaque IoT-Agent a le service `smartcity-api-key` configuré - Chaque IoT-Agent a le device `airquality_001` enregistré 3. **Orion-LD** reçoit les entités NGSI-v2 - URL: `http://smart-city-orion-ld:1026` - Entité: `urn:ngsi-ld:AirQualityObserved:airquality_001` - Type: `AirQualityObserved` 4. **Subscription Orion-LD → QuantumLeap** - ID: `69fbb09af55b82cad2a38008` - Description: "Forward AirQualityObserved to QuantumLeap" - Notify URL: `http://smart-city-quantumleap:8668/v2/op/notify` - Attrs: NO2, temperature, humidity 5. **QuantumLeap** stocke dans **CrateDB** - Table: `quantumleap.etairqualityobserved` - Colonnes: entity_id, time_index, NO2, temperature, humidity 6. **Grafana** visualise les données - Datasource: `CrateDB-SmartCity` (ID: 23) - URL: `smart-city-cratedb:5432` - Database: `quantumleap` ## Services et Devices (provisionnés) ### IoT-Agent-EMQX (port 4041) - Service: `smartcity-api-key` → Orion-LD (`http://smart-city-orion-ld:1026`) - Device: `airquality_001` → `urn:ngsi-ld:AirQualityObserved:airquality_001` ### IoT-Agent-Mosquitto (port 4042) - Service: `smartcity-api-key` → Orion-LD (`http://smart-city-orion-ld:1026`) - Device: `airquality_001` → `urn:ngsi-ld:AirQualityObserved:airquality_001` ### IoT-Agent-BunkerM (port 4043) - Service: `smartcity-api-key` → Orion-LD (`http://smart-city-orion-ld:1026`) - Device: `airquality_001` → `urn:ngsi-ld:AirQualityObserved:airquality_001` ## Sous-domaines (Traefik) - `iot-agent-emqx.digitribe.fr` → IoT-Agent-EMQX (port 4041) - `iot-agent-mosquitto.digitribe.fr` → IoT-Agent-Mosquitto (port 4042) - `iot-agent-bunkerm.digitribe.fr` → IoT-Agent-BunkerM (port 4043) - `orion-ld.digitribe.fr` → Orion-LD (port 1026) - `quantum-leap.digitribe.fr` → QuantumLeap (port 8668) - `grafana.digitribe.fr` → Grafana (port 3001) ## Test du flux complet ```bash # 1. Publier un message MQTT (simuler le simulateur) mosquitto_pub -h localhost -p 11883 -t "smartcity-api-key/airquality_001/attrs" \ -m '{"NO2": 50.5, "temperature": 30.0, "humidity": 90.0}' # 2. Vérifier qu'Orion-LD a reçu l'entité curl -s http://localhost:1026/v2/entities -w "\nHTTP %{http_code}\n" # 3. Vérifier que QuantumLeap a reçu la notification docker logs smart-city-quantumleap --tail 20 | grep -i "notify\|airquality" # 4. Vérifier CrateDB docker exec smart-city-cratedb crash -c "SELECT * FROM quantumleap.etairqualityobserved LIMIT 5;" # 5. Vérifier Grafana curl -s http://localhost:3001/api/datasources -u admin:Digitribe972 | jq '.[] | select(.type=="postgres") | .name' ``` ## Fichiers modifiés (2026-05-06) - `docker-compose.iot-agent.yml` : 3 instances IoT-Agent (emqx, mosquitto, bunkerm) - `docker-compose.orion-ld.yml` : Orion-LD avec MongoDB existant - `docker-compose.quantumleap.yml` : Variables CRATE_HOST/PORT (fix) - `simulator.py` : Publication sur 3 brokers avec format IoT-Agent - `data-flow-diagram.md` : Ce fichier (mis à jour)