Diagram: IoT sensors connect to all brokers + OpenRemote UI linked (ORM->UI)

This commit is contained in:
Eric FELIXINE
2026-05-04 21:05:50 -04:00
parent 25e490c758
commit 428dec8509
2 changed files with 427 additions and 435 deletions

View File

@@ -1,464 +1,453 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fr"> <html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head> <head>
<meta charset="UTF-8"> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="pandoc" />
<title>Smart City Digital Twin - Flux de Données</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> <title>data-flow-diagram</title>
<style> <style>
* { /* Default styles provided by pandoc.
margin: 0; ** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
padding: 0; */
box-sizing: border-box; html {
color: #1a1a1a;
background-color: #fdfdfd;
} }
body { body {
font-family: 'JetBrains Mono', monospace;
background: #020617;
min-height: 100vh;
padding: 2rem;
color: white;
}
.container {
max-width: 1400px;
margin: 0 auto; margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
} }
@media (max-width: 600px) {
.header { body {
margin-bottom: 2rem; font-size: 0.9em;
padding: 12px;
} }
.header-row {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.5rem;
}
.pulse-dot {
width: 12px;
height: 12px;
background: #22d3ee;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
h1 { h1 {
font-size: 1.5rem; font-size: 1.8em;
font-weight: 700;
letter-spacing: -0.025em;
} }
.subtitle {
color: #94a3b8;
font-size: 0.875rem;
margin-left: 1.75rem;
} }
@media print {
.diagram-container { html {
background: rgba(15, 23, 42, 0.5); background-color: white;
border-radius: 1rem; }
border: 1px solid #1e293b; body {
padding: 1.5rem; background-color: transparent;
overflow-x: auto; color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
} }
svg { svg {
height: auto;
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
border: none;
border-top: 1px solid #1a1a1a;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%; width: 100%;
min-width: 1200px; overflow-x: auto;
display: block; display: block;
font-variant-numeric: lining-nums tabular-nums;
} }
table caption {
.cards { margin-bottom: 0.75em;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin-top: 2rem;
} }
tbody {
.card { margin-top: 0.5em;
background: rgba(15, 23, 42, 0.5); border-top: 1px solid #1a1a1a;
border-radius: 0.75rem; border-bottom: 1px solid #1a1a1a;
border: 1px solid #1e293b;
padding: 1.25rem;
} }
th {
.card-header { border-top: 1px solid #1a1a1a;
display: flex; padding: 0.25em 0.5em 0.25em 0.5em;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
} }
td {
.card-dot { padding: 0.125em 0.5em 0.25em 0.5em;
width: 8px;
height: 8px;
border-radius: 50%;
} }
header {
.card-dot.cyan { background: #22d3ee; } margin-bottom: 4em;
.card-dot.emerald { background: #34d399; }
.card-dot.violet { background: #a78bfa; }
.card-dot.amber { background: #fbbf24; }
.card-dot.rose { background: #fb7185; }
.card-dot.orange { background: #fb923c; }
.card h3 {
font-size: 0.875rem;
font-weight: 600;
}
.card ul {
list-style: none;
color: #94a3b8;
font-size: 0.75rem;
}
.card li {
margin-bottom: 0.375rem;
}
.footer {
text-align: center; text-align: center;
margin-top: 1.5rem;
color: #475569;
font-size: 0.75rem;
} }
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <nav id="TOC" role="doc-toc">
<!-- Header --> <ul>
<div class="header"> <li><a href="#smart-city-digital-twin-diagramme-des-flux-de-données"
<div class="header-row"> id="toc-smart-city-digital-twin-diagramme-des-flux-de-données">Smart
<div class="pulse-dot"></div> City Digital Twin — Diagramme des Flux de Données</a>
<h1>Smart City Digital Twin — Flux de Données</h1> <ul>
</div> <li><a href="#vue-densemble" id="toc-vue-densemble">Vue
<p class="subtitle">Martinique • Simulator → Brokers → Context Brokers → Visualization</p> densemble</a></li>
</div> <li><a href="#diagramme-mermaid" id="toc-diagramme-mermaid">Diagramme
Mermaid</a></li>
<li><a href="#description-des-flux"
id="toc-description-des-flux">Description des flux</a>
<ul>
<li><a href="#génération-des-données-simulator"
id="toc-génération-des-données-simulator">1. <strong>Génération des
données (Simulator)</strong></a></li>
<li><a href="#ingestion-mqtt-brokers" id="toc-ingestion-mqtt-brokers">2.
<strong>Ingestion MQTT (Brokers)</strong></a></li>
<li><a href="#context-brokers-ngsi-ld-sensorthings"
id="toc-context-brokers-ngsi-ld-sensorthings">3. <strong>Context Brokers
(NGSI-LD &amp; SensorThings)</strong></a></li>
<li><a href="#plateforme-iot-openremote"
id="toc-plateforme-iot-openremote">4. <strong>Plateforme IoT
(OpenRemote)</strong></a></li>
<li><a href="#stockage-métriques" id="toc-stockage-métriques">5.
<strong>Stockage &amp; Métriques</strong></a></li>
<li><a href="#visualisation-analyse" id="toc-visualisation-analyse">6.
<strong>Visualisation &amp; Analyse</strong></a></li>
</ul></li>
<li><a href="#technologies-clés" id="toc-technologies-clés">Technologies
clés</a></li>
<li><a href="#fichiers-associés" id="toc-fichiers-associés">Fichiers
associés</a></li>
</ul></li>
</ul>
</nav>
<h1 id="smart-city-digital-twin-diagramme-des-flux-de-données">Smart
City Digital Twin — Diagramme des Flux de Données</h1>
<h2 id="vue-densemble">Vue densemble</h2>
<p>Ce diagramme illustre le flux complet des données IoT du simulateur
vers les différentes couches de traitement, de stockage et de
visualisation.</p>
<hr />
<h2 id="diagramme-mermaid">Diagramme Mermaid</h2>
<pre class="mermaid"><code>graph TB
SIM[Smart City Simulator]
SENS[Capteurs IoT Reels]
EMQ[EMQX]
MOS[Mosquitto]
BUN[BunkerM]
ORI[Orion-LD]
STE[Stellio]
FRO[FROST-Server]
ORM[OpenRemote Manager]
KC[Keycloak]
INF[InfluxDB]
PRO[Prometheus]
GEO[GeoServer]
GRA[Grafana]
MAP[MapStore]
UI[OpenRemote UI]
<!-- Main Diagram --> SIM --&gt; EMQ
<div class="diagram-container"> SIM --&gt; MOS
<svg viewBox="0 0 1300 750"> SIM --&gt; BUN
<!-- Definitions --> SENS --&gt; EMQ
<defs> SENS --&gt; MOS
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> SENS --&gt; BUN
<polygon points="0 0, 10 3.5, 0 7" fill="#64748b" /> SENS -.-&gt; ORM
</marker> EMQ --&gt; ORI
<marker id="arrowhead-cyan" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> EMQ --&gt; STE
<polygon points="0 0, 10 3.5, 0 7" fill="#22d3ee" /> EMQ --&gt; FRO
</marker> EMQ --&gt; ORM
<marker id="arrowhead-emerald" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> MOS --&gt; ORM
<polygon points="0 0, 10 3.5, 0 7" fill="#34d399" /> BUN --&gt; ORM
</marker> ORM --&gt; UI
<marker id="arrowhead-orange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto"> ORM -.-&gt; KC
<polygon points="0 0, 10 3.5, 0 7" fill="#fb923c" /> SIM --&gt; INF
</marker> ORI --&gt; GRA
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse"> STE --&gt; GRA
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1e293b" stroke-width="0.5"/> FRO --&gt; GRA
</pattern> ORI -.-&gt; GEO
</defs> STE -.-&gt; GEO
FRO -.-&gt; GEO
<!-- Background Grid --> GEO --&gt; MAP
<rect width="100%" height="100%" fill="url(#grid)" /> ORM --&gt; GRA
EMQ -.-&gt; PRO
<!-- ===== LAYER 1: Data Sources ===== --> ORI -.-&gt; PRO
<text x="30" y="30" fill="#94a3b8" font-size="12" font-weight="600">📡 COUCHE 1 : SOURCES DE DONNÉES</text> STE -.-&gt; PRO
ORM -.-&gt; PRO</code></pre>
<!-- Smart City Simulator --> <hr />
<rect x="30" y="50" width="180" height="70" rx="6" fill="#0f172a"/> <h2 id="description-des-flux">Description des flux</h2>
<rect x="30" y="50" width="180" height="70" rx="6" fill="rgba(251, 146, 60, 0.3)" stroke="#fb923c" stroke-width="1.5"/> <h3 id="génération-des-données-simulator">1. <strong>Génération des
<text x="120" y="80" fill="white" font-size="12" font-weight="600" text-anchor="middle">Smart City Simulator</text> données (Simulator)</strong></h3>
<text x="120" y="96" fill="#94a3b8" font-size="9" text-anchor="middle">Python • 10 capteurs</text> <ul>
<text x="120" y="112" fill="#fb923c" font-size="8" text-anchor="middle">MQTT + REST API</text> <li><strong>Smart City Simulator</strong> (Python) génère des données
pour 10 capteurs (Traffic, Air Quality, Parking, Noise, Weather,
<!-- ===== LAYER 2: MQTT BROKERS ===== --> Light)</li>
<text x="30" y="170" fill="#94a3b8" font-size="12" font-weight="600">📡 COUCHE 2 : MQTT BROKERS</text> <li>Intervalle de publication : 10 secondes</li>
<li>Protocoles : MQTT (vers brokers uniquement)</li>
<!-- EMQX --> <li><strong>⚠️ Projet</strong> : Le simulateur nenvoie PAS directement
<rect x="30" y="190" width="140" height="60" rx="6" fill="#0f172a"/> à OpenRemote (pas de REST API)</li>
<rect x="30" y="190" width="140" height="60" rx="6" fill="rgba(34, 211, 238, 0.3)" stroke="#22d3ee" stroke-width="1.5"/> </ul>
<text x="100" y="215" fill="white" font-size="11" font-weight="600" text-anchor="middle">EMQX</text> <h3 id="ingestion-mqtt-brokers">2. <strong>Ingestion MQTT
<text x="100" y="231" fill="#94a3b8" font-size="9" text-anchor="middle">Port 11883 (MQTT)</text> (Brokers)</strong></h3>
<ul>
<!-- Mosquitto --> <li><strong>EMQX</strong> (port 11883) : Broker public, reçoit tous les
<rect x="190" y="190" width="140" height="60" rx="6" fill="#0f172a"/> capteurs</li>
<rect x="190" y="190" width="140" height="60" rx="6" fill="rgba(34, 211, 238, 0.3)" stroke="#22d3ee" stroke-width="1.5"/> <li><strong>Mosquitto</strong> (port 1883) : Via Traefik, accès
<text x="260" y="215" fill="white" font-size="11" font-weight="600" text-anchor="middle">Mosquitto</text> externe</li>
<text x="260" y="231" fill="#94a3b8" font-size="9" text-anchor="middle">Port 1883 (MQTT)</text> <li><strong>BunkerM</strong> (port 1900) : MQTTS (TLS), accès
sécurisé</li>
<!-- BunkerM --> </ul>
<rect x="350" y="190" width="140" height="60" rx="6" fill="#0f172a"/> <h3 id="context-brokers-ngsi-ld-sensorthings">3. <strong>Context Brokers
<rect x="350" y="190" width="140" height="60" rx="6" fill="rgba(34, 211, 238, 0.3)" stroke="#22d3ee" stroke-width="1.5"/> (NGSI-LD &amp; SensorThings)</strong></h3>
<text x="420" y="215" fill="white" font-size="11" font-weight="600" text-anchor="middle">BunkerM</text> <ul>
<text x="420" y="231" fill="#94a3b8" font-size="9" text-anchor="middle">Port 1900 (MQTTS)</text> <li><strong>Orion-LD</strong> : Reçoit les données au format NGSI-LD
<ul>
<!-- ===== LAYER 3: CONTEXT BROKERS ===== --> <li>10 entités (TrafficFlowObserved, AirQualityObserved, etc.)</li>
<text x="30" y="290" fill="#94a3b8" font-size="12" font-weight="600">🔄 COUCHE 3 : CONTEXT BROKERS (NGSI-LD)</text> <li>Smart Data Models utilisés</li>
</ul></li>
<!-- Orion-LD --> <li><strong>Stellio</strong> : Alternative NGSI-LD
<rect x="30" y="310" width="160" height="80" rx="6" fill="#0f172a"/> <ul>
<rect x="30" y="310" width="160" height="80" rx="6" fill="rgba(52, 211, 153, 0.3)" stroke="#34d399" stroke-width="1.5"/> <li>14 payloads entités</li>
<text x="110" y="335" fill="white" font-size="11" font-weight="600" text-anchor="middle">Orion-LD</text> <li>Contexte :
<text x="110" y="351" fill="#94a3b8" font-size="9" text-anchor="middle">NGSI-LD</text> <code>https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld</code></li>
<text x="110" y="367" fill="#94a3b8" font-size="8" text-anchor="middle">Port 1026</text> </ul></li>
<text x="110" y="383" fill="#34d399" font-size="8" text-anchor="middle">Entities: Traffic, Air</text> <li><strong>FROST-Server</strong> : SensorThings API
<ul>
<!-- Stellio --> <li>21 256+ observations</li>
<rect x="210" y="310" width="160" height="80" rx="6" fill="#0f172a"/> <li>PostgreSQL + TimescaleDB</li>
<rect x="210" y="310" width="160" height="80" rx="6" fill="rgba(52, 211, 153, 0.3)" stroke="#34d399" stroke-width="1.5"/> </ul></li>
<text x="290" y="335" fill="white" font-size="11" font-weight="600" text-anchor="middle">Stellio</text> </ul>
<text x="290" y="351" fill="#94a3b8" font-size="9" text-anchor="middle">NGSI-LD</text> <h3 id="plateforme-iot-openremote">4. <strong>Plateforme IoT
<text x="290" y="367" fill="#94a3b8" font-size="8" text-anchor="middle">Port 8080</text> (OpenRemote)</strong></h3>
<text x="290" y="383" fill="#34d399" font-size="8" text-anchor="middle">14 payloads entities</text> <ul>
<li><strong>OpenRemote Manager</strong> (realm <code>smartcity</code>)
<!-- FROST-Server --> <ul>
<rect x="390" y="310" width="160" height="80" rx="6" fill="#0f172a"/> <li>33 assets IoT configurés</li>
<rect x="390" y="310" width="160" height="80" rx="6" fill="rgba(52, 211, 153, 0.3)" stroke="#34d399" stroke-width="1.5"/> <li>Carte Martinique (mapsettings.json)</li>
<text x="470" y="335" fill="white" font-size="11" font-weight="600" text-anchor="middle">FROST-Server</text> <li>Réception via <strong>MQTT Agent</strong> depuis les brokers (EMQX,
<text x="470" y="351" fill="#94a3b8" font-size="9" text-anchor="middle">SensorThings API</text> Mosquitto, BunkerM)</li>
<text x="470" y="367" fill="#94a3b8" font-size="8" text-anchor="middle">21k+ observations</text> <li>Peut aussi recevoir directement des capteurs IoT (via MQTT)</li>
<text x="470" y="383" fill="#34d399" font-size="8" text-anchor="middle">PostgreSQL+Timescale</text> </ul></li>
<li><strong>Keycloak</strong> : Authentification OpenID Connect
<!-- ===== LAYER 4: IOT PLATFORM ===== --> <ul>
<text x="30" y="430" fill="#94a3b8" font-size="12" font-weight="600">🏠 COUCHE 4 : PLATEFORME IOT (OpenRemote)</text> <li>Client <code>openremote</code> avec Service Account</li>
<li>Token endpoint :
<!-- OpenRemote Manager --> <code>/auth/realms/smartcity/protocol/openid-connect/token</code></li>
<rect x="30" y="450" width="200" height="90" rx="6" fill="#0f172a"/> </ul></li>
<rect x="30" y="450" width="200" height="90" rx="6" fill="rgba(167, 139, 250, 0.3)" stroke="#a78bfa" stroke-width="1.5"/> </ul>
<text x="130" y="478" fill="white" font-size="12" font-weight="600" text-anchor="middle">OpenRemote Manager</text> <h3 id="stockage-métriques">5. <strong>Stockage &amp;
<text x="130" y="494" fill="#94a3b8" font-size="9" text-anchor="middle">Realm: Smart City</text> Métriques</strong></h3>
<text x="130" y="510" fill="#94a3b8" font-size="8" text-anchor="middle">33 assets IoT</text> <ul>
<text x="130" y="526" fill="#a78bfa" font-size="8" text-anchor="middle">Port 8080 + Keycloak</text> <li><strong>InfluxDB</strong> : Stockage temporel pour Grafana
<ul>
<!-- Keycloak --> <li>Bucket : <code>iot_data</code></li>
<rect x="250" y="465" width="120" height="60" rx="6" fill="#0f172a"/> <li>Datasource dans Grafana</li>
<rect x="250" y="465" width="120" height="60" rx="6" fill="rgba(251, 113, 133, 0.3)" stroke="#fb7185" stroke-width="1.5"/> </ul></li>
<text x="310" y="490" fill="white" font-size="10" font-weight="600" text-anchor="middle">Keycloak</text> <li><strong>Prometheus</strong> : Collecte des métriques
<text x="310" y="506" fill="#94a3b8" font-size="8" text-anchor="middle">Auth OpenID</text> <ul>
<li>MQTT brokers, Context brokers, OpenRemote</li>
<!-- ===== LAYER 5: STORAGE & METRICS ===== --> </ul></li>
<text x="30" y="570" fill="#94a3b8" font-size="12" font-weight="600">💾 COUCHE 5 : STOCKAGE & MÉTRIQUES</text> <li><strong>GeoServer</strong> : Données géospatiales
<ul>
<!-- InfluxDB --> <li>PostGIS pour centralisation</li>
<rect x="30" y="590" width="140" height="60" rx="6" fill="#0f172a"/> <li>WMS/WFS pour MapStore</li>
<rect x="30" y="590" width="140" height="60" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/> </ul></li>
<text x="100" y="615" fill="white" font-size="11" font-weight="600" text-anchor="middle">InfluxDB</text> </ul>
<text x="100" y="631" fill="#94a3b8" font-size="9" text-anchor="middle">IoT Data Bucket</text> <h3 id="visualisation-analyse">6. <strong>Visualisation &amp;
Analyse</strong></h3>
<!-- Prometheus --> <ul>
<rect x="190" y="590" width="140" height="60" rx="6" fill="#0f172a"/> <li><strong>Grafana</strong> (port 3001)
<rect x="190" y="590" width="140" height="60" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/> <ul>
<text x="260" y="615" fill="white" font-size="11" font-weight="600" text-anchor="middle">Prometheus</text> <li>Dashboard : <code>smartcity-martinique-2026</code></li>
<text x="260" y="631" fill="#94a3b8" font-size="9" text-anchor="middle">Metrics + Alerting</text> <li>Datasources : InfluxDB, FROST, Orion-LD</li>
</ul></li>
<!-- GeoServer --> <li><strong>MapStore</strong> : Cartographie
<rect x="350" y="590" width="140" height="60" rx="6" fill="#0f172a"/> <ul>
<rect x="350" y="590" width="140" height="60" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/> <li>Sources WMS/WFS depuis GeoServer</li>
<text x="420" y="615" fill="white" font-size="11" font-weight="600" text-anchor="middle">GeoServer</text> </ul></li>
<text x="420" y="631" fill="#94a3b8" font-size="9" text-anchor="middle">WMS/WFS + PostGIS</text> <li><strong>OpenRemote UI</strong> : Manager Interface
<ul>
<!-- ===== LAYER 6: VISUALIZATION ===== --> <li>Visualisation des assets realm Smart City</li>
<text x="650" y="170" fill="#94a3b8" font-size="12" font-weight="600">📊 COUCHE 6 : VISUALISATION & ANALYSE</text> </ul></li>
</ul>
<!-- Grafana --> <hr />
<rect x="650" y="190" width="160" height="80" rx="6" fill="#0f172a"/> <h2 id="technologies-clés">Technologies clés</h2>
<rect x="650" y="190" width="160" height="80" rx="6" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1.5"/> <table>
<text x="730" y="218" fill="white" font-size="12" font-weight="600" text-anchor="middle">Grafana</text> <thead>
<text x="730" y="234" fill="#94a3b8" font-size="9" text-anchor="middle">Dashboards</text> <tr>
<text x="730" y="250" fill="#94a3b8" font-size="8" text-anchor="middle">Datasources:</text> <th>Composant</th>
<text x="730" y="266" fill="#22d3ee" font-size="8" text-anchor="middle">InfluxDB, FROST, Orion</text> <th>Technologie</th>
<th>Port</th>
<!-- MapStore --> <th>Statut</th>
<rect x="830" y="190" width="160" height="80" rx="6" fill="#0f172a"/> </tr>
<rect x="830" y="190" width="160" height="80" rx="6" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1.5"/> </thead>
<text x="910" y="218" fill="white" font-size="12" font-weight="600" text-anchor="middle">MapStore</text> <tbody>
<text x="910" y="234" fill="#94a3b8" font-size="9" text-anchor="middle">Cartographie</text> <tr>
<text x="910" y="250" fill="#94a3b8" font-size="8" text-anchor="middle">Sources:</text> <td>Simulator</td>
<text x="910" y="266" fill="#22d3ee" font-size="8" text-anchor="middle">GeoServer WMS</text> <td>Python + paho-mqtt</td>
<td>Interne</td>
<!-- OpenRemote UI --> <td>✅ Actif</td>
<rect x="650" y="310" width="160" height="80" rx="6" fill="#0f172a"/> </tr>
<rect x="650" y="310" width="160" height="80" rx="6" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1.5"/> <tr>
<text x="730" y="338" fill="white" font-size="12" font-weight="600" text-anchor="middle">OpenRemote UI</text> <td>EMQX</td>
<text x="730" y="354" fill="#94a3b8" font-size="9" text-anchor="middle">Manager Interface</text> <td>MQTT Broker</td>
<text x="730" y="370" fill="#22d3ee" font-size="8" text-anchor="middle">Realm: Smart City</text> <td>11883</td>
<td>✅ Connecté</td>
<!-- ===== ARROWS: Data Flows ===== --> </tr>
<tr>
<!-- Simulator → MQTT Brokers --> <td>Orion-LD</td>
<line x1="120" y1="120" x2="100" y2="188" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead-orange)"/> <td>NGSI-LD Broker</td>
<text x="95" y="150" fill="#fb923c" font-size="8">MQTT</text> <td>1026</td>
<td>⚠️ À vérifier</td>
<line x1="120" y1="120" x2="260" y2="188" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead-orange)"/> </tr>
<tr>
<line x1="120" y1="120" x2="420" y2="188" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead-orange)"/> <td>Stellio</td>
<td>NGSI-LD Broker</td>
<!-- MQTT Brokers → Context Brokers --> <td>8080</td>
<line x1="100" y1="252" x2="110" y2="308" stroke="#22d3ee" stroke-width="2" marker-end="url(#arrowhead-cyan)"/> <td>⚠️ À vérifier</td>
<text x="85" y="280" fill="#22d3ee" font-size="8">NGSI-LD</text> </tr>
<tr>
<line x1="260" y1="252" x2="290" y2="308" stroke="#22d3ee" stroke-width="2" marker-end="url(#arrowhead-cyan)"/> <td>FROST-Server</td>
<td>SensorThings API</td>
<line x1="420" y1="252" x2="470" y2="308" stroke="#22d3ee" stroke-width="2" marker-end="url(#arrowhead-cyan)"/> <td>8080</td>
<td>⚠️ À vérifier</td>
<!-- Simulator → OpenRemote (REST) --> </tr>
<line x1="180" y1="85" x2="130" y2="448" stroke="#a78bfa" stroke-width="2" stroke-dasharray="5,5" marker-end="url(#arrowhead-emerald)"/> <tr>
<text x="160" y="250" fill="#a78bfa" font-size="8">REST API</text> <td>OpenRemote</td>
<td>IoT Platform</td>
<!-- Simulator → InfluxDB --> <td>8080</td>
<line x1="180" y1="100" x2="100" y2="588" stroke="#fbbf24" stroke-width="2" marker-end="url(#arrowhead)"/> <td>⚠️ 403 (Service Account)</td>
<text x="145" y="340" fill="#fbbf24" font-size="8">HTTP</text> </tr>
<tr>
<!-- Context Brokers → Visualization --> <td>InfluxDB</td>
<line x1="110" y1="392" x2="730" y2="188" stroke="#34d399" stroke-width="2" marker-end="url(#arrowhead-emerald)"/> <td>Time Series DB</td>
<text x="350" y="280" fill="#34d399" font-size="8">Query</text> <td>8086</td>
<td>✅ Configuré</td>
<line x1="290" y1="392" x2="730" y2="188" stroke="#34d399" stroke-width="2" marker-end="url(#arrowhead-emerald)"/> </tr>
<tr>
<line x1="470" y1="392" x2="730" y2="188" stroke="#34d399" stroke-width="2" marker-end="url(#arrowhead-emerald)"/> <td>Grafana</td>
<td>Visualization</td>
<!-- GeoServer → MapStore --> <td>3001</td>
<line x1="420" y1="652" x2="910" y2="268" stroke="#fbbf24" stroke-width="2" marker-end="url(#arrowhead)"/> <td>✅ Dashboard créé</td>
<text x="600" y="440" fill="#fbbf24" font-size="8">WMS/WFS</text> </tr>
<tr>
<!-- Context Brokers → GeoServer (PostGIS) --> <td>GeoServer</td>
<path d="M 110 392 Q 110 500 420 590" fill="none" stroke="#34d399" stroke-width="1.5" stroke-dasharray="3,3"/> <td>GeoServer</td>
<text x="200" y="480" fill="#34d399" font-size="7">DB Sync</text> <td>8080</td>
<td>⚠️ À intégrer</td>
<!-- OpenRemote → Grafana --> </tr>
<line x1="130" y1="542" x2="730" y2="268" stroke="#a78bfa" stroke-width="2" marker-end="url(#arrowhead-emerald)"/> <tr>
<text x="350" y="380" fill="#a78bfa" font-size="8">API Query</text> <td>Prometheus</td>
<td>Metrics</td>
<!-- All → Prometheus (Metrics) --> <td>9090</td>
<line x1="320" y1="500" x2="260" y2="588" stroke="#fbbf24" stroke-width="1.5" stroke-dasharray="4,4"/> <td>✅ En cours</td>
<text x="260" y="540" fill="#fbbf24" font-size="7">Metrics</text> </tr>
</tbody>
<!-- ===== LEGEND ===== --> </table>
<text x="1050" y="30" fill="white" font-size="11" font-weight="600">Légende</text> <hr />
<h2 id="fichiers-associés">Fichiers associés</h2>
<rect x="1050" y="42" width="16" height="12" rx="2" fill="rgba(251, 146, 60, 0.3)" stroke="#fb923c" stroke-width="1"/> <ul>
<text x="1072" y="52" fill="#94a3b8" font-size="9">Source de données</text> <li><strong>Simulator</strong> :
<code>~/smart-city-digital-twin-martinique/simulator.py</code></li>
<rect x="1050" y="60" width="16" height="12" rx="2" fill="rgba(34, 211, 238, 0.3)" stroke="#22d3ee" stroke-width="1"/> <li><strong>Dashboard Grafana</strong> :
<text x="1072" y="70" fill="#94a3b8" font-size="9">MQTT Broker</text> <code>~/smart-city-digital-twin-martinique/grafana_dashboard_smartcity.json</code></li>
<li><strong>Ce diagramme</strong> :
<rect x="1050" y="78" width="16" height="12" rx="2" fill="rgba(52, 211, 153, 0.3)" stroke="#34d399" stroke-width="1"/> <code>~/smart-city-digital-twin-martinique/data-flow-diagram.md</code></li>
<text x="1072" y="88" fill="#94a3b8" font-size="9">Context Broker</text> <li><strong>Session Resume</strong> :
<code>~/smart-city-digital-twin-martinique/session_resume_2026-05-04.md</code></li>
<rect x="1050" y="96" width="16" height="12" rx="2" fill="rgba(167, 139, 250, 0.3)" stroke="#a78bfa" stroke-width="1"/> </ul>
<text x="1072" y="106" fill="#94a3b8" font-size="9">IoT Platform</text> <hr />
<p><strong>Dernière mise à jour :</strong> 04 Mai 2026<br />
<rect x="1050" y="114" width="16" height="12" rx="2" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1"/> <strong>Projet :</strong> Smart City Digital Twin Martinique<br />
<text x="1072" y="124" fill="#94a3b8" font-size="9">Stockage / Métriques</text> <strong>URL Grafana :</strong>
http://localhost:3001/d/smartcity-martinique-2026</p>
<rect x="1050" y="132" width="16" height="12" rx="2" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1"/>
<text x="1072" y="142" fill="#94a3b8" font-size="9">Visualisation</text>
<line x1="1050" y1="156" x2="1066" y2="156" stroke="#34d399" stroke-width="2" marker-end="url(#arrowhead-emerald)"/>
<text x="1072" y="159" fill="#94a3b8" font-size="9">Flux de données</text>
<line x1="1050" y1="174" x2="1066" y2="174" stroke="#fb923c" stroke-width="2" marker-end="url(#arrowhead-orange)"/>
<text x="1072" y="177" fill="#94a3b8" font-size="9">MQTT</text>
<line x1="1050" y1="190" x2="1066" y2="190" stroke="#a78bfa" stroke-width="2" stroke-dasharray="5,5"/>
<text x="1072" y="193" fill="#94a3b8" font-size="9">REST API</text>
</svg>
</div>
<!-- Info Cards -->
<div class="cards">
<div class="card">
<div class="card-header">
<div class="card-dot orange"></div>
<h3>Sources & Simulator</h3>
</div>
<ul>
<li>• Smart City Simulator (Python)</li>
<li>• 10 capteurs : Traffic, Air, Parking, Noise, Weather, Light</li>
<li>• Intervalle : 10 secondes</li>
<li>• Protocoles : MQTT + REST API</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot cyan"></div>
<h3>MQTT Brokers</h3>
</div>
<ul>
<li>• EMQX : Port 11883 (public)</li>
<li>• Mosquitto : Port 1883 (Traefik)</li>
<li>• BunkerM : Port 1900 (TLS)</li>
<li>• OpenRemote : Port 1883 (interne)</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot emerald"></div>
<h3>Context Brokers (NGSI-LD)</h3>
</div>
<ul>
<li>• Orion-LD : 10 entités NGSI-LD</li>
<li>• Stellio : 14 payloads entités</li>
<li>• FROST-Server : 21k+ observations</li>
<li>• Smart Data Models utilisés</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot violet"></div>
<h3>OpenRemote Platform</h3>
</div>
<ul>
<li>• Realm : Smart City Martinique</li>
<li>• 33 assets IoT configurés</li>
<li>• Keycloak pour l'authentification</li>
<li>• REST API pour les capteurs</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot amber"></div>
<h3>Stockage & Métriques</h3>
</div>
<ul>
<li>• InfluxDB : Bucket iot_data</li>
<li>• Prometheus : Metrics brokers</li>
<li>• GeoServer : PostGIS + WMS</li>
<li>• PostgreSQL : OpenRemote + FROST</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot cyan"></div>
<h3>Visualisation & Analyse</h3>
</div>
<ul>
<li>• Grafana : Dashboards (port 3001)</li>
<li>• MapStore : Cartographie WMS</li>
<li>• OpenRemote UI : Manager Smart City</li>
<li>• Datasources : InfluxDB, FROST, Orion</li>
</ul>
</div>
</div>
<!-- Footer -->
<p class="footer">
Smart City Digital Twin Martinique • Stack complet déployé sur digitribe.fr •
Dernière mise à jour : 04 Mai 2026
</p>
</div>
</body> </body>
</html> </html>

View File

@@ -31,6 +31,8 @@ graph TB
SIM --> MOS SIM --> MOS
SIM --> BUN SIM --> BUN
SENS --> EMQ SENS --> EMQ
SENS --> MOS
SENS --> BUN
SENS -.-> ORM SENS -.-> ORM
EMQ --> ORI EMQ --> ORI
EMQ --> STE EMQ --> STE
@@ -38,6 +40,7 @@ graph TB
EMQ --> ORM EMQ --> ORM
MOS --> ORM MOS --> ORM
BUN --> ORM BUN --> ORM
ORM --> UI
ORM -.-> KC ORM -.-> KC
SIM --> INF SIM --> INF
ORI --> GRA ORI --> GRA