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 noktaya | Unified Namespace | |
|---|---|---|
| Entegrasyonlar | Her sistem çifti için bir | Her sistem için bir (broker'a) |
| Tüketici eklemek | Kaynakta yeni arayüz | Bir topic'e subscribe olmak |
| Güncel durum | Veritabanlarına dağılmış | Broker'da retained |
| Veri akışı | Polling, batch | Olay güdümlü, değişimde |
| Sahiplik | Her 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 | Örnek | Topic seviyesi |
|---|---|---|
| Şirket | Acme Foods | acme |
| Tesis | Dallas fabrikası | dallas |
| Alan | Paketleme | packaging |
| Hat (work center) | Hat 1 | line1 |
| Hücre (work unit) | Dolum makinesi | filler |
| Veri | Hız, durum, sayaçlar | speed, 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:
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 retainedBir 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, aslakepware3/channel2/tag17değil. Kaynaklar değişir, hat kalır. - Bir dal içinde seviye derinliğini sabit tutun, böylece
acme/+/packaging/+/filler/statetü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.5olmaz); 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:
{ "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:
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:
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şım | Nasıl çalışır | Ne zaman uygun |
|---|---|---|
| Düz MQTT ile UNS | Üreticiler JSON'u doğrudan ISA-95 topic'lerine publish eder | Karışık BT/OT tüketicileri, basit araçlar, okunur topic'ler |
| Edge'de Sparkplug, üstte UNS | Edge 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 Sparkplug | Tüm tüketiciler Sparkplug anlar | Homojen 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
- Yeni subscriber testi:
acme/<site>/#topic'ine subscribe olan yeni bir istemci her varlığın güncel durumunu anında alır (hepsi retained). - Olay testi: olaylar canlı gelir ama yeni bir subscriber'a yeniden oynatılmaz.
- Kaynak değiştirme testi: bir üreticiyi değiştirin (simüle gateway → gerçek gateway); tüketiciler hiçbir şey fark etmez.
- Ölü kaynak testi: bir üreticiyi öldürün;
statustopic'i Last Will sayesindeofflineolur. - ACL testi: bir gateway'in kimlik bilgileriyle başka bir hattın dalına publish etmeyi deneyin; reddedilmelidir.
- 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.

