Su şebekelerinde MQTT telemetrisi; dağınık pompa istasyonlarını, depoları, hidrofor istasyonlarını ve atık su terfi istasyonlarını operatörlerin, mühendislerin ve planlama araçlarının hepsinin abone olabileceği tek bir canlı veri katmanında toplar. Bu rehber, bu telemetrinin nasıl yapılandırılacağını, hangi sinyallerin nasıl yayınlanacağını ve bir depo boşalmadan veya bir ıslak kuyu taşmadan önce seviyeler ve basınçlar için eşik alarmlarının nasıl üretileceğini gösteriyor. Ayrıca gerçek ekipmana uyarlayabileceğiniz küçük bir istasyon simülatörü ve bir alarm yardımcısı çalıştıracaksınız.
Su Şebekelerinde Telemetri Sorunu
Tipik bir su işletmesi, hizmet alanına yayılmış onlarca ila yüzlerce uzak sahayı işletir. Bunların çoğu on yıllar boyunca farklı RTU'lar, radyolar ve protokollerle bağlanmış ve merkezi bir SCADA master'ı tarafından sorgulanmıştır. Bu düzen çalışır, ancak bilinen sıkıntılar yaratır:
- Paylaşılan radyoda yavaş taramalar. Her sahayı sırayla sorgulamak, bir seviye alarmının bir sonraki taramayı beklemesi anlamına gelebilir.
- SCADA'ya kilitlenmiş veriler. Varlık yönetimi, hidrolik modelleme ve enerji ekipleri dışa aktarım talep eder veya kırılgan noktadan noktaya arayüzler kurar.
- Farklı nesillerden ekipman. Her yeni saha tipi bir sürücü ve bir register haritası daha ekler.
- Her yerde hücresel sahalar. Yeni sahalar, gelen sorgulama yerine cihazın başlattığı, giden bağlantıları tercih eden hücresel modemler kullanır.
MQTT yönü tersine çevirir: her istasyon kendi değişikliklerini bir broker'a yayınlar ve SCADA dahil her tüketici abone olur. Bu geçişin SCADA tarafını planlıyorsanız bu rehberle birlikte SCADA sistemlerinde MQTT yazısını okuyun.
Her Sahadan Ne Yayınlanmalı?
RTU'nun register listesinden değil, operasyonel sorulardan başlayın. Aşağıdaki tablo su ve atık su sahaları için pratik bir temel sunar.
| Saha tipi | Sinyal | Birim | Yayın kuralı | Alarm fikri |
|---|---|---|---|---|
| Depo / tank | Seviye | m | Ölü bant 2 ila 5 cm, heartbeat 15 dk | Düşük ve yüksek seviye |
| Depo / tank | Giriş vanası pozisyonu | % | %2 değişimde | Seviye düşerken vana takılı |
| Hidrofor veya pompa istasyonu | Çıkış basıncı | bar | Ölü bant 0,05 ila 0,1 bar | Yüksek ve düşük basınç |
| Hidrofor veya pompa istasyonu | Debi | m3/h | Ölü bant ölçüm aralığının %2 ila 5'i | Pompa dururken debi var |
| Hidrofor veya pompa istasyonu | Pompa çalışma durumu | bool | Her değişiklikte | Saatte çok fazla kalkış |
| Atık su terfi istasyonu | Islak kuyu seviyesi | m | Ölü bant 2 cm, daha sık heartbeat | Yüksek seviye, taşma riski |
| Tüm sahalar | Şebeke enerjisi, izinsiz giriş, haberleşme | bool | Her değişiklikte, retained | Herhangi bir değişiklik |
| Arıtma noktaları | Bakiye klor | mg/L | Ölü bant 0,02 mg/L | Hedef bandın altında veya üstünde |
Bu tabloyu işler kılan iki kural vardır. Analog değerleri, enstrüman doğruluğuna göre boyutlandırılmış bir ölü bantla report by exception olarak yayınlayın ve her durum değişikliğini anında yayınlayın. Report-by-exception rehberi ölü bant boyutlandırmasını ve bir heartbeat'in neden yine de gerekli olduğunu açıklıyor.
Bir Su Şebekesi İçin Topic Tasarımı
Topic'ler operatörlerin şebekeyi nasıl düşündüğünü yansıtmalıdır: bölge, saha, varlık, ölçüm. ISA-95 anlayışında bir hiyerarşi bunu tutarlı tutar:
waterco/north/reservoir-hilltop/tank1/level
waterco/north/booster-ridge/pump2/running
waterco/north/booster-ridge/discharge/pressure
waterco/south/lift-station-07/wetwell/level
waterco/south/lift-station-07/site/status
İleride karşılığını veren yönergeler:
- Saha ve varlık adlarını sabit ve küçük harfli tutun; bunlar sonraki her sistemde tanımlayıcı haline gelir.
- Topic başına bir ölçüm veya varlık başına küçük bir JSON nesnesi koyun ve işletme genelinde tek bir yaklaşım seçin.
- Her sahaya Last Will içeren retained bir
site/statustopic'i verin; böylece kopan bir hücresel bağlantı donmuş değerler yerineofflineolarak görünür. - RTU register numaralarını topic'lere kodlamayın. Mühendislerin bunlara ihtiyacı varsa bir
sourcealanında tutun.
Mevcut SCADA tag adları zaten bir kurala uyuyorsa, SCADA'daki noktaları yeniden adlandırmak yerine bunları gateway'de yeni hiyerarşiye eşleyin. Operatörler bildikleri adları korurken her yeni tüketici temiz ve öngörülebilir topic'ler elde eder. Eşlemeyi bir kez belgeleyin ve her saha eklendiğinde gözden geçirin; çünkü tutarsızlıkları ikinci sahada düzeltmek ellinci sahada düzeltmekten çok daha ucuzdur.
Örnek: Pompa İstasyonu Simülatörü
Aşağıdaki betik, beslediği bir depoyla birlikte bir hidrofor istasyonunu simüle eder: iki pompa, çıkış basıncı ve depo seviyesi. Heartbeat'ler ve bir Last Will ile report by exception yayınlar; bu da panoları ve alarmları tasarlarken onu iyi bir yedek yapar. Herkese açık MQTT test broker'ını kullandığı için yalnızca rastgele bir önek altında simüle edilmiş değerler gönderir.
import json
import random
import time
import uuid
import paho.mqtt.client as mqtt
BROKER, PORT = "broker.connectmq.com", 1883 # üretim: kendi broker'ınız, port 8883 + TLS
CLIENT_ID = f"booster-sim-{uuid.uuid4().hex[:6]}" # üretim: "YOUR_CLIENT_ID"
BASE = f"connectmq/demo/{uuid.uuid4().hex[:6]}/north/booster-ridge"
HEARTBEAT = 300
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code, "- publishing under", BASE)
client.publish(f"{BASE}/site/status", "online", qos=1, retain=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.will_set(f"{BASE}/site/status", "offline", qos=1, retain=True)
client.on_connect = on_connect
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
level, pumps = 3.2, [False, False]
last = {}
last_full = 0.0
def publish(name, value, deadband=None, unit=None, retain=False):
prev = last.get(name)
if prev is not None and not force:
if deadband is None and value == prev:
return
if deadband is not None and abs(value - prev) < deadband:
return
payload = {"value": value, "ts": int(time.time())}
if unit:
payload["unit"] = unit
client.publish(f"{BASE}/{name}", json.dumps(payload), qos=1, retain=retain)
last[name] = value
while True:
force = time.time() - last_full >= HEARTBEAT
demand = random.uniform(0.010, 0.020)
supply = 0.018 * sum(pumps)
level = round(max(0.0, level + supply - demand), 3)
# Basit seviye kontrolü: depo düştüğünde pompaları çalıştır, dolunca durdur
if level < 2.8:
pumps = [True, level < 2.4]
elif level > 3.6:
pumps = [False, False]
pressure = round(1.2 + 2.1 * sum(pumps) + random.uniform(-0.03, 0.03), 2)
publish("reservoir/level", level, deadband=0.03, unit="m")
publish("discharge/pressure", pressure, deadband=0.08, unit="bar")
publish("pump1/running", pumps[0], retain=True)
publish("pump2/running", pumps[1], retain=True)
if force:
last_full = time.time()
time.sleep(5)
İstasyonu başka bir terminalden izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i booster-watch-01 \
-t 'connectmq/demo/+/north/booster-ridge/#' -v
Deponun yavaşça düştüğünü, pompaların çalıştığını, çıkış basıncının sıçradığını ve seviyenin toparlandığını göreceksiniz; beş saniyelik döngüye rağmen dakikada yalnızca birkaç mesajla.
Seviyeler ve Basınçlar İçin Eşik Alarmları
Telemetri, birine bir sorunu erkenden bildirdiğinde değerini kanıtlar. Özel bir ConnectMQ broker'ında portala, 1,5 m'nin altındaki bir depo seviyesi veya 6 bar'ın üzerindeki bir çıkış basıncı gibi eşik tabanlı alarm kuralları ekleyebilir ve tetiklenen her alarmı alarm günlüğünde inceleyebilirsiniz. Bu, mühendislere bir pilot sırasında veya SCADA'nın yanında kritik limitlerin hızlı ve bağımsız bir görünümünü sağlar.
Bazı koşullar tek bir eşikten ibaret değildir. Örneğin pompanın sık devreye girip çıkması (short-cycling), zaman içindeki kalkış sayısıdır. Bu tür bir mantık için dürüst model, broker'a sıradan bir MQTT client olarak bağlanan küçük bir abone servisidir:
import json
import time
from collections import deque
import paho.mqtt.client as mqtt
MAX_STARTS_PER_HOUR = 6
starts = {} # topic -> kalkış zaman damgalarının deque'su
state = {}
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe("connectmq/demo/+/north/+/+/running", qos=1)
def on_message(client, userdata, msg):
running = json.loads(msg.payload)["value"]
was_running = state.get(msg.topic, running)
state[msg.topic] = running
if running and not was_running:
window = starts.setdefault(msg.topic, deque())
now = time.time()
window.append(now)
while window and now - window[0] > 3600:
window.popleft()
if len(window) > MAX_STARTS_PER_HOUR:
print(f"ALERT short-cycling: {msg.topic} started {len(window)} times in 1 h")
# Burada çağrı, SMS veya ticket aracınıza iletin.
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"shortcycle-{time.time_ns() % 1000000}")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
Aynı yaklaşım Node-RED veya MQTT destekli herhangi bir araçla da çalışır. Bildirim iletimi, operasyon ekibinizin zaten kullandığı araçta kalır.
Güvenlik ve Güvenilirlik Kontrol Listesi
Su işletmeleri kritik altyapıdır; bu yüzden çıta tipik bir IoT projesinden daha yüksektir.
- Her istasyon için 8883 portunda TLS; telemetriyi hücresel veya genel ağlar üzerinden asla açık metin olarak göndermeyin.
- İstasyon başına, ayrı ayrı iptal edilebilen benzersiz bir kullanıcı adı, parola ve client ID.
- İstasyonlardan yalnızca giden bağlantılar; modemlerde açık gelen port yok.
- İzleme kontrolden ayrılmış. Pompalara ve vanalara yönelik komutlar, incelenmiş bir tasarım aksini söylemedikçe kilitlemeleriyle birlikte SCADA'da kalır.
- Last Will içeren retained saha durumu ve beklenmedik
offlinedurumunda alarm. - Kısa kesintilerin mevzuat açısından önemli verilerde boşluk yaratmaması için istasyonlarda yerel tamponlama.
- Doğru olay sıralaması için kaynakta zaman senkronizasyonu.
- Tek bir ekibin sahiplendiği ve her yeni sahaya uygulanan belgelenmiş bir topic standardı.
Broker'ın Nerede Çalışacağını Seçmek
Bazı sahaları özel radyoda, diğerleri hücreselde olan karışık bağlantılı işletmeler, her yerden TLS ile erişilebilen bir broker'dan fayda sağlar. Bir barındırılan MQTT broker, yamaları ve sertifika yenilemelerini işletmenin iş yükünden çıkarır. ConnectMQ; MQTT 3.1.1 ve 5.0, sahaları ve varlıkları gruplayan bir ISA-95 cihazlar görünümü ve izole bir kümeye veya kendi bulut hesabında dağıtıma ihtiyaç duyan işletmeler için Dedicated ya da BYOC seçenekleri sunar. İstasyon PLC'leri, gateway'ler ve SCADA yönlendirmesi arasındaki mimari tercihler için PLC verisini buluta aktarma, hücresel modem davranışı için hücresel üzerinden MQTT yazılarına bakın. MQTT ile endüstriyel IoT rehberi bu parçaları bir araya getiriyor.
ConnectMQ ile Bir Su Telemetrisi Pilotu Başlatın
Bir depo ve bir pompa istasyonu seçin, bunları bir bulut MQTT broker çözümüne bağlayın ve en önemli seviyeler ile basınçlar için alarmlar kurun. app.connectmq.com adresinde kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun ve canlı istasyon verilerini bugün topic gezgininde görün.
Sık Sorulan Sorular
MQTT, su SCADA sistemimizin yerini alabilir mi?
MQTT genellikle SCADA fonksiyonlarının değil, telemetri taşımasının yerini alır. SCADA operasyonlar için broker'a abone olurken diğer ekipler aynı veriyi bağımsız olarak tüketir.
Bir pompa istasyonunun haberleşmeyi kaybettiğini nasıl anlarız?
Her istasyona retained bir durum topic'inde bir Last Will verin. Keep alive süresi dolduğunda broker offline yayınlar ve aboneler veya alarm kuralları hemen tepki verir.
Depo seviyeleri için hangi ölü bandı kullanmalıyız?
Enstrüman doğruluğuna ve seviyenin ne kadar hızlı değiştiğine bağlı olarak birkaç santimetre tipiktir. Sabit bir seviyenin de istasyonun canlı olduğunu kanıtlaması için bunu periyodik bir heartbeat ile birleştirin.
MQTT kritik su altyapısı için yeterince güvenli mi?
TLS, istasyon başına kimlik bilgileri, yalnızca giden bağlantılar ve izlemenin kontrolden ayrılmasıyla MQTT güçlü bir temel oluşturur. Bunu işletmenizin daha geniş siber güvenlik programıyla birlikte uygulayın.



