Uygulamalı Eğitimler

MQTT ile Unified Namespace (UNS) Kurun

MQTT ile Unified Namespace nasıl kurulur: ISA-95 topic hiyerarşisi, retained durum, payload kuralları, Sparkplug B'nin yeri ve test için örnek betikler.

Güncellendi · 9 dk okuma

MQTT ile Unified Namespace (UNS) Kurun

Unified Namespace (UNS), bir şirketteki her sistemin güncel durumunu publish ettiği, olay güdümlü tek bir yerdir; veriler onları hangi yazılımın ürettiğine göre değil, işletmede nerede olduklarına göre düzenlenir. Pratikte bu bir MQTT broker'ı ve bir topic hiyerarşisidir; hiyerarşi genellikle ISA-95'e göre şekillenir (şirket / tesis / alan / hat / hücre) ve retained mesajlar her şeyin son değerini tutar.

Bu eğitim; bu hiyerarşiyi nasıl tasarlayacağınızı, neyi retained tutacağınıza nasıl karar vereceğinizi, payload kurallarını, Sparkplug B'nin nereye oturduğunu ve namespace'i birkaç küçük betikle nasıl test edeceğinizi gösteriyor.

Noktadan noktaya entegrasyon yerine neden UNS

Klasik tesisler sistemleri tek tek entegre eder: MES SCADA'yı sorgular, ERP MES'ten bir CSV içe aktarır, bir dashboard historian'ı sorgular. Her yeni tüketici yeni bir entegrasyon demektir ve kimsenin operasyonun güncel durumunu görebileceği tek bir yeri yoktur.

UNS bunu bir hub ile değiştirir:

Noktadan noktayaUnified Namespace
EntegrasyonlarHer sistem çifti için birHer sistem için bir (broker'a)
Tüketici eklemekKaynakta yeni arayüzBir topic'e subscribe olmak
Güncel durumVeritabanlarına dağılmışBroker'da retained
Veri akışıPolling, batchOlay güdümlü, değişimde
SahiplikHer arayüz ayrı ayrıMerkezi yönetilen tek namespace

Üreticiler (PLC gateway'leri, MES, kalite sistemleri, ERP adaptörleri) ağacın kendi dallarına publish eder. Tüketiciler ihtiyaç duydukları şeye subscribe olur. Kimsenin başka kimin bağlı olduğunu bilmesi gerekmez.

ISA-95 hiyerarşisini tasarlayın

ISA-95, bir tesisin fiziksel ve organizasyonel yapısı için bir kelime dağarcığı sunar. Bunu doğrudan topic seviyelerine eşlemek namespace'i hem OT hem BT ekipleri için okunur kılar:

SeviyeÖrnekTopic seviyesi
ŞirketAcme Foodsacme
TesisDallas fabrikasıdallas
AlanPaketlemepackaging
Hat (work center)Hat 1line1
Hücre (work unit)Dolum makinesifiller
VeriHız, durum, sayaçlarspeed, state, good-count

Böylece dolum makinesinin hızı acme/dallas/packaging/line1/filler/speed altında yaşar. ISA-95 seviyelerinin altına, tüketicilerin durumu olaylardan ayırt edebilmesi için veri türüne göre küçük bir alt alan seti ekleyin:

Namespace'in bir dalı
acme/dallas/packaging/line1/filler/state            "running"       retained
acme/dallas/packaging/line1/filler/speed            {"v":118,...}   retained
acme/dallas/packaging/line1/filler/good-count       {"v":48211,...} retained
acme/dallas/packaging/line1/filler/events/fault     {"code":"E14"}  not retained
acme/dallas/packaging/line1/mes/work-order          {"id":"WO-881"} retained
acme/dallas/packaging/line1/quality/last-check      {"result":"ok"} retained
acme/dallas/packaging/line1/filler/cmd/setpoint     (restricted)    not retained

Bir namespace'i yıllarca sağlıklı tutan kurallar:

  • Küçük harf, boşluksuz, yalnızca ASCII; seviye içinde tire kullanın. Topic'ler büyük/küçük harfe duyarlıdır ve karışık yazım kopyaları garanti eder.
  • Kaynağa göre değil yere göre adlandırın. line1/filler/speed, asla kepware3/channel2/tag17 değil. Kaynaklar değişir, hat kalır.
  • Bir dal içinde seviye derinliğini sabit tutun, böylece acme/+/packaging/+/filler/state tüm tesislerde çalışır.
  • Komutları ayırın: cmd/ altında toplayın ve ACL'lerle koruyun; üreticilerin çoğu oraya asla yazamamalı.
  • Değerleri topic adına koymayın (.../temp/21.5 olmaz); değer payload'a aittir.

Genel ilkeler topic tasarımı en iyi uygulamaları yazısında. Bir yapıya bağlanmadan önce subscription kalıplarınızı topic matcher ile deneyin.

Retained durum UNS'in kalbidir

Namespace, bir saniye önce bağlanan bir istemciye "şu anda ne oluyor?" sorusunun cevabını vermelidir. Retained mesajlar tam olarak bunu yapar: broker her topic için son retained mesajı saklar ve her yeni subscriber'a hemen teslim eder.

  • Durumu retained tutun: değerler, durumlar, güncel iş emri, son kalite sonucu, setpoint'ler.
  • Olayları retained yapmayın: tetiklenen arızalar, reddedilen parçalar, komutlar. Yeni bir subscriber dünkü arızayı yeni olmuş gibi görmemeli.
  • Eskimiş topic'leri temizleyin: bir makine devreden çıkarıldığında boş bir retained payload publish edin; yoksa namespace yavaş yavaş hayaletlerle dolar.
  • MQTT 5 message expiry kullanın: yenilenmediğinde anlamını yitiren durumlarda eski değerler yalan söylemek yerine kaybolsun.

Her üreticiye retained bir status topic'i ve bir Last Will (offline) verin; Modbus gateway eğitiminde gösterildiği gibi. Böylece tüketiciler sabit bir değeri ölü bir kaynaktan ayırt edebilir.

Payload kuralları

Durum için tek bir payload biçiminde anlaşın ve ona sadık kalın. Basit, kendini açıklayan bir JSON iyi çalışır:

Durum payload'u
{ "v": 118, "unit": "bpm", "ts": "2026-10-17T08:41:07.214Z", "q": "good" }

v değerdir, unit tahmin etmeyi önler, ts UTC cinsinden kaynak zaman damgasıdır, q ise kalitedir. Statik meta veriler (açıklamalar, aralıklar, mühendislik birimleri) retained bir _meta kardeş topic'inde durabilir; böylece sıcak yol küçük kalır.

Bir test namespace'i doldurun ve gezin

paho-mqtt 2.x ile yazılmış iki küçük betik, henüz gerçek bir üretici yokken deney yapmanızı sağlar. İlki, küçük bir tesisin retained anlık görüntüsünü bir saatlik expiry ile publish eder:

seed_uns.py
import json, time
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties

ROOT = "testmqtt/uns/acme/dallas/packaging/line1"
STATE = {
    "filler/state":      "running",
    "filler/speed":      {"v": 118, "unit": "bpm"},
    "filler/good-count": {"v": 48211, "unit": "pcs"},
    "capper/state":      "idle",
    "mes/work-order":    {"id": "WO-881", "product": "SKU-330ml"},
}

props = Properties(PacketTypes.PUBLISH)
props.MessageExpiryInterval = 3600          # saniye

c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
c.connect("broker.connectmq.com", 1883)
c.loop_start()
now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
for path, value in STATE.items():
    body = value if isinstance(value, str) else json.dumps({**value, "ts": now})
    c.publish(f"{ROOT}/{path}", body, qos=1, retain=True, properties=props).wait_for_publish()
c.loop_stop()
c.disconnect()
print("seeded", len(STATE), "topics")

İkincisi yepyeni bir istemci olarak bağlanır, birkaç saniye boyunca broker'ın verdiği her şeyi toplar ve namespace'i ağaç olarak yazdırır; yeni bir tüketicinin göreceği şey tam olarak budur:

browse_uns.py
import time
import paho.mqtt.client as mqtt

FILTER = "testmqtt/uns/acme/#"
seen = {}

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(FILTER, qos=1)

def on_message(client, userdata, msg):
    seen[msg.topic] = (msg.payload.decode(errors="replace"), msg.retain)

c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
c.on_connect, c.on_message = on_connect, on_message
c.connect("broker.connectmq.com", 1883)
c.loop_start()
time.sleep(3)
c.loop_stop()

for topic in sorted(seen):
    payload, retained = seen[topic]
    depth = topic.count("/") - FILTER.count("/") + 1
    print("  " * depth + topic.rsplit("/", 1)[1], "=", payload, "(retained)" if retained else "")

Tarayıcı betik doldurulan her topic'i (retained) olarak işaretli yazdırıyorsa durum katmanınız çalışıyor demektir. Aynı kontrolü online MQTT istemcisinde görsel olarak da yapabilirsiniz:

Test namespace'ini tarayıcıda gezin

Paylaşılan endpoint yapıyı denemek için yeterlidir. Gerçek bir namespace operasyonunuzun canlı durumunu tutar; bu yüzden onu kontrol ettiğiniz bir broker'da çalıştırın.

Sparkplug B nereye oturur

Sparkplug B, endüstriyel cihazlar için MQTT üzerine kurulu bir spesifikasyondur: sabit bir topic yapısı (spBv1.0/<group>/<message type>/<edge node>/<device>), Protobuf payload'lar, birth/death sertifikaları ve durumu takip eden bir primary host. Edge sorununu çok iyi çözer, ancak topic'leri ISA-95'e göre değil, mesaj türüne ve edge node'a göre düzenlenmiştir.

YaklaşımNasıl çalışırNe zaman uygun
Düz MQTT ile UNSÜreticiler JSON'u doğrudan ISA-95 topic'lerine publish ederKarışık BT/OT tüketicileri, basit araçlar, okunur topic'ler
Edge'de Sparkplug, üstte UNSEdge node'lar Sparkplug konuşur; bir host veya köprü ISA-95 topic'lerine yeniden publish ederÇok sayıda cihaz, standart durum yönetimi ve kompakt payload ihtiyacı
Yalnızca SparkplugTüm tüketiciler Sparkplug anlarHomojen SCADA ekosistemi

Hibrit modelin popüler olmasının bir nedeni var: cihazlar Sparkplug'ın durum yönetimini, şirketin geri kalanı ise okunur bir namespace'i alır. Artı ve eksiler Sparkplug ve düz MQTT yazısında ele alınıyor. OPC UA sunucularından gelen veriler de bir OPC UA MQTT köprüsü ile aynı ağaca girebilir.

Namespace'iniz için test kontrol listesi

  1. Yeni subscriber testi: acme/<site>/# topic'ine subscribe olan yeni bir istemci her varlığın güncel durumunu anında alır (hepsi retained).
  2. Olay testi: olaylar canlı gelir ama yeni bir subscriber'a yeniden oynatılmaz.
  3. Kaynak değiştirme testi: bir üreticiyi değiştirin (simüle gateway → gerçek gateway); tüketiciler hiçbir şey fark etmez.
  4. Ölü kaynak testi: bir üreticiyi öldürün; status topic'i Last Will sayesinde offline olur.
  5. ACL testi: bir gateway'in kimlik bilgileriyle başka bir hattın dalına publish etmeyi deneyin; reddedilmelidir.
  6. Wildcard testi: her dashboard filtresi topic matcher'da tam olarak hedeflenen topic'lerle eşleşir.

Unified Namespace teknolojiden çok bir uzlaşmayla ilgilidir: tek bir broker, herkesin anladığı tek bir hiyerarşi, şimdiki zaman için retained durum ve kimin nereye publish edeceğine dair net kurallar. Tek bir hatla başlayın, doldurun, gezin, bilerek bozun; ağacı ancak ilk dal kendini kanıtladığında büyütün.

Sıkça sorulan sorular

Unified Namespace bir ürün mü?

Hayır. UNS bir mimari kalıptır: her sistemin güncel durumunu ortak, işletmenin yapısına göre şekillenmiş bir topic hiyerarşisine publish ettiği, olay güdümlü tek bir hub; genellikle bir MQTT broker'ı. Bir broker, isimlendirme kuralları ve publish/subscribe eden istemcilerle kurulur.

Unified Namespace için Sparkplug B gerekli mi?

Hayır. Birçok UNS uygulaması JSON payload'lu düz MQTT ve ISA-95 biçimli topic'ler kullanır. Sparkplug B, standart birth/death durumu ve kompakt payload'ları sayesinde edge'de faydalıdır; yaygın bir kalıp, cihazlardan bir host'a Sparkplug kullanmak ve host'un veriyi ISA-95 namespace'ine yeniden publish etmesidir.

UNS'teki her mesaj retained olmalı mı?

Güncel durumu (değerler, durumlar, setpoint'ler) retained tutun ki yeni her tüketici şimdiki durumu anında görsün. Tetiklenen alarmlar, üretilen parçalar veya komutlar gibi olayları retained yapmayın; bunlar gerçekleştikleri ana ve sonrasında bir historian'a aittir.