Connettore UNS (Unified Namespace)
Panoramica
Sezione intitolata “Panoramica”Il connettore UNS (Unified Namespace) è un processore che costruisce una gerarchia di topic allineata a ISA-95 dalla configurazione del connettore e dal payload in ingresso, quindi emette un payload JSON con una chiave _uns_topic iniettata o un envelope in stile SparkplugB che avvolge i dati in un array di metriche. È il blocco costitutivo canonico per organizzare i dati di pianta in un Unified Namespace come reso popolare da Walker Reynolds e dallo standard ISA-95.
Tipi Connettore:
UNS- Processore senza stato che decora i payload con un topic ISA-95 e rimodella l’output come JSON o SparkplugB
Caratteristiche
Sezione intitolata “Caratteristiche”- ✅ Gerarchia ISA-95: Enterprise / Site / Area / Line / Cell
- ✅ Livelli di topic dinamici opzionali guidati dal payload (mapping)
- ✅ Due formati di output:
json(passthrough +_uns_topic) esparkplugb(envelope con array di metriche) - ✅ Salta livelli gerarchici vuoti con grazia
- ✅ Timestamp per messaggio (millisecondi Unix) sull’output SparkplugB
Configurazione di Base
Sezione intitolata “Configurazione di Base”Gerarchia ISA-95 Statica con Output JSON
Sezione intitolata “Gerarchia ISA-95 Statica con Output JSON”{ "type": "UNS", "config": { "enterprise": "Acme", "site": "Milan", "area": "Assembly", "line": "Line1", "cell": "Station3", "outputFormat": "json" }}Livelli di Topic Dinamici dal Payload
Sezione intitolata “Livelli di Topic Dinamici dal Payload”{ "type": "UNS", "config": { "enterprise": "Acme", "site": "Milan", "area": "Assembly", "mappings": [ { "inputKey": "machine_id", "topicLevel": "machine" }, { "inputKey": "shift_id", "topicLevel": "shift" } ], "outputFormat": "json" }}Output Envelope SparkplugB
Sezione intitolata “Output Envelope SparkplugB”{ "type": "UNS", "config": { "enterprise": "Acme", "site": "Milan", "area": "Packaging", "line": "Line2", "outputFormat": "sparkplugb" }}Parametri di Configurazione
Sezione intitolata “Parametri di Configurazione”Enterprise
Sezione intitolata “Enterprise”Richiesto. L’enterprise ISA-95 di primo livello (nome azienda/divisione).
{ "enterprise": "Acme" }Richiesto. Il sito fisico (impianto, fabbrica, edificio).
{ "site": "Milan" }Opzionale. Un’area funzionale all’interno del sito.
{ "area": "Assembly" }Opzionale. Una linea di produzione all’interno dell’area.
{ "line": "Line1" }Opzionale. Una cella specifica o stazione di lavoro all’interno della linea.
{ "cell": "Station3" }Mappings
Sezione intitolata “Mappings”Opzionale. Un array di mapping da payload a livello di topic. Per ogni mapping, il connettore cerca data[inputKey] e aggiunge <topicLevel>/<value> al topic.
{ "mappings": [ { "inputKey": "machine_id", "topicLevel": "machine" }, { "inputKey": "shift_id", "topicLevel": "shift" } ]}Comportamento:
- Sia
inputKeychetopicLevelsono richiesti per ogni voce - Le chiavi di input mancanti vengono riportate tramite il canale di errore; il livello del topic viene omesso
- I valori di input non stringa vengono convertiti con
fmt.Sprintf("%v", ...)
Output Format
Sezione intitolata “Output Format”Richiesto. Deve essere uno tra:
json- Passthrough del payload originale con_uns_topiciniettatosparkplugb- Envelope{ topic, timestamp, metrics }dove metrics è una lista di coppie{ name, value }
{ "outputFormat": "sparkplugb" }Costruzione del Topic
Sezione intitolata “Costruzione del Topic”I livelli del topic sono uniti con /. I livelli opzionali vuoti (Area, Line, Cell) vengono saltati. I mapping appaiono nell’ordine in cui sono dichiarati.
Esempio:
Configurazione:
{ "enterprise": "Acme", "site": "Milan", "area": "Assembly", "line": "Line1", "mappings": [ { "inputKey": "machine_id", "topicLevel": "machine" } ]}Payload in ingresso:
{ "machine_id": "M-007", "temperature": 24.5 }Topic risultante:
Acme/Milan/Assembly/Line1/machine/M-007Esempi di Payload di Output
Sezione intitolata “Esempi di Payload di Output”Output JSON
Sezione intitolata “Output JSON”Input:
{ "machine_id": "M-007", "temperature": 24.5, "pressure": 5.2}Configurazione:
{ "enterprise": "Acme", "site": "Milan", "area": "Assembly", "line": "Line1", "mappings": [ { "inputKey": "machine_id", "topicLevel": "machine" } ], "outputFormat": "json"}Output:
{ "machine_id": "M-007", "temperature": 24.5, "pressure": 5.2, "_uns_topic": "Acme/Milan/Assembly/Line1/machine/M-007"}Output Envelope SparkplugB
Sezione intitolata “Output Envelope SparkplugB”Stesso input e configurazione di base con outputFormat: sparkplugb:
{ "topic": "Acme/Milan/Assembly/Line1/machine/M-007", "timestamp": 1747740875123, "metrics": [ { "name": "machine_id", "value": "M-007" }, { "name": "temperature", "value": 24.5 }, { "name": "pressure", "value": 5.2 } ]}Il timestamp è in millisecondi Unix al momento dell’elaborazione. Nota che l’ordine delle voci metrics non è garantito (l’iterazione delle map Go è non ordinata).
Flusso di Dati
Sezione intitolata “Flusso di Dati”DataPayload → UNS → DataPayload + _uns_topic (json) OPPURE { topic, timestamp, metrics } (sparkplugb)Casi d’Uso Comuni
Sezione intitolata “Casi d’Uso Comuni”1. Bridge di Dati PLC a MQTT con Topic ISA-95
Sezione intitolata “1. Bridge di Dati PLC a MQTT con Topic ISA-95”Rimodella payload PLC raw in un topic MQTT conforme a UNS:
{ "type": "UNS", "config": { "enterprise": "Acme", "site": "Detroit", "area": "Stamping", "line": "PressLine1", "outputFormat": "json" }}Un MqttV5Writer a valle utilizza poi _uns_topic come topic di pubblicazione tramite uno step Reshape che mappa _uns_topic → topic MQTT.
2. Pubblicazione SparkplugB per Ignition o HiveMQ
Sezione intitolata “2. Pubblicazione SparkplugB per Ignition o HiveMQ”Molte piattaforme SCADA (Ignition, HiveMQ, ecc.) si aspettano envelope SparkplugB. Usa l’output sparkplugb per allinearti:
{ "type": "UNS", "config": { "enterprise": "Acme", "site": "Milan", "area": "Bottling", "line": "Filler1", "outputFormat": "sparkplugb" }}3. Routing Topic Multi-Tenant per Cliente
Sezione intitolata “3. Routing Topic Multi-Tenant per Cliente”Usa mapping dinamici per incorporare l’identificatore del cliente nel topic:
{ "type": "UNS", "config": { "enterprise": "ConnectCo", "site": "Cloud", "mappings": [ { "inputKey": "tenant_id", "topicLevel": "tenant" }, { "inputKey": "site_id", "topicLevel": "customer-site" }, { "inputKey": "device_id", "topicLevel": "device" } ], "outputFormat": "json" }}Topic risultante per {tenant_id: "T-1", site_id: "S-99", device_id: "D-42"}:
ConnectCo/Cloud/tenant/T-1/customer-site/S-99/device/D-42Risoluzione dei Problemi
Sezione intitolata “Risoluzione dei Problemi”_uns_topic Mancante nell’Output
Sezione intitolata “_uns_topic Mancante nell’Output”Problema: Il consumer a valle non vede la chiave _uns_topic
Soluzioni:
- Conferma che
outputFormat: jsonsia impostato (l’envelope SparkplugB sostituisce interamente il payload; hatopical livello superiore invece di_uns_topic) - Verifica che il connettore UNS sia effettivamente nella pipeline — usa un writer
Logper dumpare payload intermedi
Errori input key %q not found in payload
Sezione intitolata “Errori input key %q not found in payload”Problema: Un mapping configurato fa riferimento a una chiave non presente nel payload
Soluzioni:
- Verifica che la chiave di input corrisponda esattamente al payload a monte (case-sensitive)
- Usa un
ReshapeoTransforma monte per assicurarti che le chiavi richieste esistano - Se la chiave a volte manca, considera di renderla parte di
area/line/cellstatici invece
Array metrics Vuoto nell’Output SparkplugB
Sezione intitolata “Array metrics Vuoto nell’Output SparkplugB”Problema: L’envelope di output è { topic, timestamp, metrics: [] }
Soluzioni:
- L’array metrics è costruito dalle chiavi del payload di input. Un input vuoto → metrics vuoto
- Verifica che il connettore a monte stia consegnando payload non vuoti
Il Topic Ha Slash Inattesi o Segmenti Vuoti
Sezione intitolata “Il Topic Ha Slash Inattesi o Segmenti Vuoti”Problema: Il topic contiene // o slash di coda
Soluzioni:
- Non includere slash in
enterprise,site, ecc. — il connettore li inserisce. Slash incorporati produrranno percorsi malformati - Evita stringhe vuote per livelli opzionali — lascia il campo non impostato invece di passare
""
Problemi di Ordinamento per Metriche SparkplugB
Sezione intitolata “Problemi di Ordinamento per Metriche SparkplugB”Problema: L’ordinamento delle metriche è incoerente tra esecuzioni
Soluzioni:
- L’iterazione delle map Go è intenzionalmente non ordinata. Se i consumer a valle si preoccupano dell’ordine, ordina a monte tramite un
Reshapeche converte le metriche in una lista esplicita prima di raggiungere questo connettore - Oppure fai sì che il consumer ordini per
namealla ricezione
Migliori Pratiche
Sezione intitolata “Migliori Pratiche”1. Tratta il Topic UNS Come un Contratto
Sezione intitolata “1. Tratta il Topic UNS Come un Contratto”La gerarchia di topic è consumata da dashboard, historian e altre pipeline Meddle. Una volta pubblicata, trattala come un’interfaccia stabile — rinominare area o line dopo i fatti rompe i consumer a valle.
2. Usa Livelli Statici per Gerarchie Stabili
Sezione intitolata “2. Usa Livelli Statici per Gerarchie Stabili”Preferisci enterprise/site/area/line/cell statici ai mapping ogni volta che la gerarchia non dipende dal payload. I mapping sono potenti ma aggiungono una dipendenza dalla forma del payload.
3. Preferisci JSON per Greenfield, SparkplugB per Bridge SCADA
Sezione intitolata “3. Preferisci JSON per Greenfield, SparkplugB per Bridge SCADA”json è più semplice e funziona con qualsiasi consumer a valle. Usa sparkplugb solo quando devi interoperare con un ecosistema SparkplugB esistente (Ignition, HiveMQ Edge, ecc.).
4. Abbina a un Reshape Prima di MQTT
Sezione intitolata “4. Abbina a un Reshape Prima di MQTT”La maggior parte dei writer MQTT richiede che il topic sia impostato esplicitamente. Dopo il connettore UNS, usa uno step Reshape che promuova _uns_topic al campo topic di pubblicazione:
... → UNS → Reshape (sposta _uns_topic → topic) → MqttV5Writer5. Documenta il Tuo UNS a Livello Organizzativo
Sezione intitolata “5. Documenta il Tuo UNS a Livello Organizzativo”Scegli uno schema ISA-95 una volta per l’intera organizzazione e applicalo coerentemente su tutti i siti e le linee. Il drift di schema tra deployment Meddle crea alberi di topic incompatibili.
Esempi di Flussi
Sezione intitolata “Esempi di Flussi”PLC → UNS → MQTT (Broker Cloud)
Sezione intitolata “PLC → UNS → MQTT (Broker Cloud)”ModbusReader → Reshape → UNS → Reshape → MqttV5Writer- ModbusReader: Estrae dati raw di registro da un PLC
- Reshape: Rinomina gli indirizzi raw in chiavi leggibili
- UNS: Decora con
_uns_topic - Reshape: Promuove
_uns_topical campotopicMQTT - MqttV5Writer: Pubblica a un broker cloud, organizzato sotto l’UNS
Edge Gateway SparkplugB
Sezione intitolata “Edge Gateway SparkplugB”OpcuaReader → Predictive → UNS (sparkplugb) → MqttV5Writer- OpcuaReader: Aggrega da più endpoint OPC UA
- Predictive: Aggiunge trend/RUL/health-score
- UNS: Avvolge il payload arricchito in un envelope SparkplugB
- MqttV5Writer: Pubblica a un broker capace di SparkplugB (es. HiveMQ Edge → Ignition)
Aggregazione Multi-Sito
Sezione intitolata “Aggregazione Multi-Sito”[pipeline Sito A] ─┐[pipeline Sito B] ─┼─→ UNS → InfluxDb2Writer[pipeline Sito C] ─┘Ogni pipeline di sito etichetta i propri dati con la propria configurazione UNS, garantendo che i consumer a valle possano disambiguare per topic solo.
Connettori Correlati
Sezione intitolata “Connettori Correlati”- MQTT v5 - Pubblica payload decorati UNS su un broker
- MQTT v3 - Pubblicazione MQTT legacy
- Reshape - Promuovi
_uns_topical campo topic del writer - Filter - Filtra per pattern di
_uns_topic - Router - Routing branchiato basato sulla gerarchia UNS
Risorse Aggiuntive
Sezione intitolata “Risorse Aggiuntive”- Standard ISA-95 - Enterprise-Control System Integration
- Concetto Unified Namespace (Walker Reynolds) - Primer di settore
- Specifica SparkplugB (Eclipse Tahu) - PDF della specifica ufficiale
- Risorse Sparkplug di HiveMQ - Broker di riferimento e strumenti
- Modulo Sparkplug di Ignition - Esempio di integrazione SCADA