Une bonne structure des topics UNS est ce qui rend un Unified Namespace navigable : quiconque connaît l'usine peut deviner où se trouve une valeur sans ouvrir la documentation. Ce guide vous fournit des arborescences de topics prêtes à l'emploi pour la fabrication discrète et les industries de process, les règles de nommage et de payload qui les gardent propres, et un petit validateur à exécuter en CI ou sur la passerelle pour bloquer les mauvais topics avant qu'ils n'atteignent le broker.
Les principes d'une structure de topics UNS
Tous les exemples de cet article suivent les cinq mêmes principes. Si vous adaptez les arborescences, conservez les principes.
- Modéliser l'usine, pas la technologie. Les topics décrivent où se trouve un élément et ce qu'il est, pas le protocole ou la marque de PLC qui l'a produit.
opcua/ets7/n'ont rien à faire dans le chemin. - La hiérarchie d'abord, l'ISA-95 comme colonne vertébrale. Entreprise, site, zone, ligne ou cellule, et équipement forment une structure que l'exploitation comprend déjà. Le guide sur la hiérarchie des équipements ISA-95 explique chaque niveau.
- Une profondeur fixe quand c'est possible. Lorsque chaque machine se trouve au même niveau, des abonnements avec wildcards comme
+/+/+/+/telemetryfonctionnent sur toute l'entreprise. - Un petit ensemble de types de feuilles. Terminez chaque branche d'équipement par un ensemble prévisible d'espaces comme
telemetry,state,alarms,eventsetcmd. - Des identifiants stables. Des noms courts, en minuscules et avec tirets, qui survivent aux réorganisations. Les numéros d'actifs valent souvent mieux que des noms descriptifs qui changent.
Exemple 1 : fabrication discrète
Une usine discrète avec des lignes d'assemblage, des cellules d'usinage et des utilités partagées :
acme/ entreprise
dallas/ site
machining/ zone
cell-03/ cellule de travail
cnc-01/ équipement
telemetry {"spindle_rpm":..., "load_pct":..., "ts":...}
state "running" | "idle" | "down" (retenu)
alarms liste des alarmes actives (retenue)
events/cycle-complete un message par pièce terminée
cmd/ commandes, requête/réponse
robot-01/
telemetry
state
assembly/
line-02/ ligne de production
station-10/
telemetry
events/part-scanned
station-20/
telemetry
line-02/kpi/oee valeurs calculées au niveau de la ligne
utilities/
compressors/
comp-01/telemetry
Remarquez la branche kpi au niveau de la ligne. Les valeurs calculées comme l'OEE (TRS) ou le débit appartiennent au niveau qu'elles décrivent et sont publiées par l'application qui les calcule. Les données brutes des machines et les données dérivées restent ainsi clairement séparées tout en vivant dans la même arborescence.
Exemple 2 : industrie de process
Les usines de process raisonnent en cellules de process et en unités plutôt qu'en lignes et en postes. L'ISA-95 couvre les deux cas : l'arborescence change de vocabulaire, pas de forme.
acme/
izmir/ site
brewing/ zone
brewhouse-1/ cellule de process
mash-tun/ unité
telemetry {"temp_c":..., "level_pct":..., "ts":...}
state "heating" | "resting" | "transferring"
batch id de lot et recette en cours (retenu)
lauter-tun/
telemetry
fermentation/
fv-07/
telemetry
batch
utilities/
boiler-1/telemetry
water-treatment/ro-1/telemetry
La feuille batch est l'équivalent, en industrie de process, d'un ordre de fabrication : retenue, légère et mise à jour quand le lot change. Les consommateurs associent le contexte du lot à la télémétrie via le chemin du topic, sans consultation d'une base de données séparée.
Exemple 3 : entreprise multisite avec services partagés
Lorsque plusieurs sites partagent un broker ou un namespace relié par bridge, ajoutez une branche de premier niveau pour les systèmes d'entreprise, afin que les données MES, ERP et qualité aient leur place sans se faire passer pour des équipements :
acme/dallas/... arborescences de site comme ci-dessus
acme/izmir/...
acme/_enterprise/erp/work-orders/dallas ordres de fabrication par site (retenus)
acme/_enterprise/quality/spc/dallas/line-02
acme/_enterprise/mes/schedule/izmir
Le tiret bas initial classe la branche à part des noms de sites et indique clairement qu'il ne s'agit pas d'un lieu physique.
La place de Sparkplug B dans une structure de topics UNS
Sparkplug B utilise son propre format de topic fixe, spBv1.0/<group>/<message type>/<edge node>/<device>. Ce format est optimisé pour la gestion d'état entre edge nodes et applications hôtes, pas pour la navigation selon la hiérarchie de l'usine. Notre article sur le namespace des topics Sparkplug l'explique en détail.
Vous n'avez pas à choisir. Un modèle courant conserve Sparkplug pour le trafic edge-vers-hôte et republie les valeurs dans l'arborescence ISA-95 pour tous les autres. ConnectMQ le fait automatiquement pour le trafic Sparkplug B : il décode le payload Protobuf ou JSON et le republie dans des topics ISA-95, si bien que spBv1.0/factory1/DDATA/line1/cnc1 devient connectmq/factory1/production/line1/cnc1/telemetry. Les tableaux de bord et les historians s'abonnent à du JSON lisible dans l'arborescence ISA-95, tandis que les hôtes SCADA continuent d'utiliser Sparkplug natif.
Règles de nommage et de payload
| Règle | Correct | À éviter |
|---|---|---|
| Minuscules uniquement | line-02 |
Line_02, LINE02 |
| Tirets, pas d'espaces | mash-tun |
mash tun, mash%20tun |
| Pas de slash initial ni final | acme/dallas/... |
/acme/dallas/ |
Pas de wildcard ni de $ dans les noms |
cnc-01 |
cnc#1, $cnc |
| Unités dans les noms de champs | temp_c, speed_bpm |
temp, speed |
| Horodatage dans les payloads | "ts": "2026-10-16T08:00:00Z" |
Se fier à l'heure d'arrivée |
| Retenir l'état courant | state, batch, alarms |
Retenir des flux d'événements |
| Versionner les payloads | "v": 2 |
Changements cassants silencieux |
Le slash initial est une erreur classique : il crée un premier niveau vide, si bien que /acme/# et acme/# sont deux abonnements différents. La casse mixte en est une autre : les topics MQTT sont sensibles à la casse, et Line-02 et line-02 deviennent deux branches distinctes qui scindent discrètement vos données.
Valider les topics avant qu'ils n'atteignent le broker
Le script ci-dessous vérifie les topics par rapport aux règles ci-dessus et à la structure d'équipement à cinq niveaux. Utilisez-le dans une passerelle, dans un test CI sur votre fichier de mapping de tags, ou comme abonné de supervision qui signale les violations.
import re
LEVEL = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
LEAVES = {"telemetry", "state", "alarms", "batch", "events", "cmd", "kpi"}
def validate(topic: str, depth: int = 5) -> list[str]:
"""Return a list of problems; an empty list means the topic is valid."""
problems = []
if topic.startswith("/") or topic.endswith("/"):
problems.append("leading or trailing slash")
levels = topic.strip("/").split("/")
if any(ch in topic for ch in "+#$"):
problems.append("wildcard or $ character in topic name")
if any(" " in level for level in levels):
problems.append("space in topic level")
if len(levels) < depth + 1:
problems.append(f"expected at least {depth + 1} levels, got {len(levels)}")
return problems
for level in levels[:depth]:
if not (LEVEL.match(level) or level.startswith("_")):
problems.append(f"level '{level}' is not lowercase-hyphenated")
if levels[depth] not in LEAVES:
problems.append(f"leaf '{levels[depth]}' not in {sorted(LEAVES)}")
return problems
if __name__ == "__main__":
tests = [
"acme/dallas/machining/cell-03/cnc-01/telemetry",
"acme/dallas/machining/cell-03/CNC_01/telemetry",
"/acme/dallas/assembly/line-02/station-10/telemetry",
"acme/dallas/assembly/line-02/station-10/temperature",
]
for t in tests:
result = validate(t)
print("OK " if not result else "FAIL", t, "" if not result else result)
Exécutez-le avec python validate_topics.py et ajustez LEAVES et depth selon votre norme.
Faire évoluer la structure sans casser les consommateurs
Aucune structure de topics ne sort indemne de la confrontation avec une vraie usine. Des lignes sont reconstruites, des machines changent de cellule, un nouveau site est racheté avec ses propres habitudes de nommage. L'objectif n'est pas d'éviter le changement, mais de le rendre sûr.
- Ajouter, ne jamais renommer sur place. Lorsqu'une branche doit changer, publiez en parallèle sur le nouveau et l'ancien chemin pendant une période définie, puis retirez l'ancien. Annoncez la date de fin à chaque responsable de consommateur.
- Effacer les retained messages lors du retrait. Une branche retirée renvoie toujours ses valeurs retenues aux nouveaux abonnés. Publiez un retained message vide sur chaque ancien topic d'état pour le supprimer.
- Tenir un registre. Un simple fichier sous contrôle de version listant chaque branche, son responsable, ses types de feuilles et la version de son schéma de payload suffit. Le validateur ci-dessus peut lire ses règles depuis ce fichier.
- Versionner les payloads, pas les topics. Ajoutez un champ
vdans le payload quand le schéma change. Les topics contenant/v2/dans le chemin ont tendance à se multiplier et à semer la confusion dans les abonnements avec wildcards. - Relire les nouvelles branches. Une courte revue par le responsable du namespace avant la mise en service d'une passerelle détecte la plupart des problèmes tant qu'ils sont encore peu coûteux à corriger.
Traitez la structure comme une API dont dépend toute l'usine, car c'est exactement ce qu'elle devient dès que des tableaux de bord, des historians, des intégrations MES ou un jumeau numérique s'y abonnent.
Tester la structure sur un broker en direct
Avant de déployer une structure, publiez quelques messages d'exemple et parcourez-les. Sur le serveur MQTT public gratuit broker.connectmq.com, vous pouvez le faire sans compte, à condition d'utiliser un préfixe unique et de garder à l'esprit que l'espace public est lisible par tous et réservé aux tests. Le serveur public autorise 8 niveaux de topic : connectmq/demo/<id>/ plus l'arborescence à cinq niveaux et une feuille tiennent donc exactement si vous retirez le niveau entreprise :
mosquitto_pub -h broker.connectmq.com -p 1883 -i uns-test-pub-q7 -r \
-t "connectmq/demo/q7w2/dallas/machining/cell-03/cnc-01/state" -m "running"
mosquitto_sub -h broker.connectmq.com -p 1883 -i uns-test-sub-q7 \
-t "connectmq/demo/q7w2/dallas/+/+/+/state" -v
Sur un broker ConnectMQ privé, vous pouvez utiliser l'arborescence complète sans le préfixe de démo, et l'explorateur de topics en direct ainsi que la vue des appareils ISA-95 du portail montrent d'un coup d'œil si les appareils arrivent dans la bonne entreprise, le bon site, la bonne zone et la bonne ligne. Pour les règles d'encodage étape par étape, poursuivez avec les topics MQTT ISA-95, et pour le processus de construction complet, consultez comment construire un Unified Namespace. La vue d'ensemble se trouve dans notre guide MQTT pour l'IoT industriel.
Déployez votre structure de topics UNS sur ConnectMQ
Une structure de topics ne vaut que par le broker qui la transporte et la visibilité dont vous disposez sur elle. ConnectMQ est un broker MQTT managé qui détecte les topics ISA-95 et Unified Namespace, décode Sparkplug B et le republie dans votre arborescence ISA-95. Créez un broker avec l'offre gratuite Serverless sur app.connectmq.com, sans carte bancaire, et publiez votre première branche de namespace en quelques minutes.
Questions fréquentes
Combien de niveaux doit compter une structure de topics UNS ?
La plupart des usines en utilisent cinq ou six : entreprise, site, zone, ligne ou cellule, équipement, et une feuille comme telemetry ou state. Une profondeur fixe garde les abonnements avec wildcards simples.
Chaque mesure doit-elle avoir son propre topic ?
Les deux approches fonctionnent. Un objet JSON par topic de télémétrie d'équipement est plus simple et moins coûteux ; un topic par mesure convient aux outils qui associent directement les topics à des tags. Choisissez une approche par type de feuille et appliquez-la de manière cohérente.
Où placer les KPI calculés ?
Au niveau qu'ils décrivent, publiés par l'application qui les calcule, par exemple dans une branche kpi/oee sous la ligne.
Les topics Sparkplug B peuvent-ils faire partie d'un UNS ?
Oui, mais ils ne sont pas organisés selon la hiérarchie de l'usine. Republiez les valeurs Sparkplug dans des topics ISA-95 pour que tous les consommateurs puissent parcourir une seule arborescence.



