Endüstriyel IoT

MQTT Sistemlerinde Report by Exception (RBE): Deadband, Heartbeat ve Gateway Örneği

Report by exception, bir değeri yalnızca anlamlı şekilde değiştiğinde yayınlar. Deadband, hız sınırı ve heartbeat'in birlikte nasıl çalıştığını öğrenin ve MQTT'ye yayınlamadan önce RBE uygulayan bir Python gateway çalıştırın.

Bir MQTT gateway'de sorgulanan örnekleri deadband filtresinden sonraki report by exception yayınlarıyla karşılaştıran grafik
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

Report by exception (RBE, değişimde raporlama), sorgulanan her örneği göndermek yerine bir değeri yalnızca anlamlı bir miktarda değiştiğinde yayınlama yöntemidir. Endüstriyel MQTT sistemlerindeki en basit ve en etkili tekniklerden biridir. Bu yazıda deadband'lerin, minimum aralıkların ve heartbeat'lerin nasıl bir araya geldiğini öğrenecek ve bir broker'a yayınlamadan önce RBE uygulayan bir Python gateway çalıştıracaksınız.

Sorgulama vs Report by Exception

Geleneksel SCADA ve birçok Modbus veya OPC UA entegrasyonu sorgulama (polling) ile çalışır: her tag sabit bir döngüde okunur ve her sonuç iletilir. Bu basittir, ancak endüstriyel değerlerin çoğu yavaş değişir. Bir saat boyunca her saniye okunan bir tank sıcaklığı, içinde yalnızca birkaç anlamlı değişiklik bulunabilecek 3.600 mesaj üretir.

MQTT bunun tam tersi bir tarz için tasarlanmıştır. Client'lar bir şey olduğunda yayın yapar ve broker yeni değeri her aboneye iletir. RBE ikisini birleştirir: gateway cihazı yine yerel olarak sorgular (çünkü cihaz protokolü bunu gerektirir), ancak yukarıya yalnızca değer önemli olacak kadar değiştiğinde yayın yapar.

Yaklaşım Gönderilen mesajlar Güncellik Tipik risk
Sabit aralıklı yayın Her örnek Öngörülebilir Boşa giden bant genişliği, depolama ve işlem
Saf report by exception Yalnızca değişimde Değişimlerde anında Sessiz bir değer, ölü bir cihazla aynı görünür
Heartbeat'li RBE Değişimler ve periyodik yenileme Anında, sınırlı bayatlıkla Biraz daha fazla mantık gerektirir

Pratikte istediğiniz üçüncü satırdır.

Report by Exception'ın Yapı Taşları

Deadband

Deadband (ölü bant), "farklı" sayılan minimum değişimdir. Sensör gürültüsünü ve önemsiz kaymaları filtreler.

  • Mutlak deadband: yeni değer ile son yayınlanan değer arasındaki mutlak fark örneğin en az 0,5 derece ise yayınla.
  • Yüzde deadband: değişim son değerin ya da daha sağlam bir yaklaşımla enstrüman ölçüm aralığının (span) belirli bir yüzdesini aşarsa yayınla. Span tabanlı yüzde sıfıra yakın değerlerde daha güvenlidir; çünkü orada değerin yüzdesi küçük dalgalanmaları devasa gösterir.

Her zaman son örneklenen değerle değil, son yayınlanan değerle karşılaştırın. Bir önceki örnekle karşılaştırmak, her adım deadband'in altında kaldığı için yavaş bir kaymanın sonsuza kadar fark edilmeden sızmasına izin verir.

Minimum Aralık (Hız Sınırı)

Gürültülü veya salınan bir sinyal deadband'i yine de tekrar tekrar aşabilir. Örneğin tag başına bir saniyelik bir minimum aralık bu hızı sınırlar. Alarmlar ve durum değişiklikleri için dikkatli ayarlayın: bunları genellikle anında istersiniz, bu yüzden onlara sıfır minimum aralık verin.

Heartbeat (Maksimum Aralık)

Bir değer hiç değişmezse RBE onu hiç yayınlamaz ve tüketiciler "sabit" ile "gateway ölü" durumunu ayırt edemez. Heartbeat, değişiklik olmasa bile maksimum bir sessizlik süresinden sonra, örneğin her beş dakikada bir, mevcut değeri yayınlar. Gateway'in durum topic'indeki bir MQTT Last Will ile birleştiğinde aboneler sessiz bir değeri kopmuş bir bağlantıdan her zaman ayırt edebilir.

Kalite Değişimleri

Veri kalitesindeki bir değişim (bir sensör okumasının başarısız olması, bir cihazın çevrim dışı olması) deadband'den bağımsız olarak her zaman yayınlanmalıdır. Aslında arızalı bir cihazdan gelen bayat bir "GOOD" değer, hiç değer olmamasından daha kötüdür.

Deadband Seçimi: Pratik Yönergeler

  1. Enstrümanın doğruluğundan başlayın. Sensörün doğruluğundan küçük bir deadband yalnızca gürültüyü iletir.
  2. Tüketiciye hangi çözünürlüğe ihtiyacı olduğunu sorun. Tam dereceleri gösteren bir panelin 0,01 derecelik değişimlere ihtiyacı yoktur.
  3. Ayrık değerler için sıfır deadband kullanın: durumlar, modlar, alarmlar, sayaçlar ve set değerleri.
  4. Toplayıcılar ve enerji sayaçlarında dikkatli olun. Faturalama tarzı hesaplamaların doğru kalması için sayacın biriminde bir deadband ve düzenli bir heartbeat kullanın.
  5. Devreye aldıktan sonra tag başına mesaj hızlarını karşılaştırarak deadband'leri gözden geçirin; çoğu zaman birkaç geveze tag trafiğe hâkim olur.

Report by Exception Uygulayan Bir Python Gateway

Bu örnek her 500 ms'de okunan beş tag'i simüle eder, tag başına deadband, minimum aralık ve heartbeat kurallarını uygular ve değişimleri broker.connectmq.com'un genel test alanına retained JSON mesajları olarak yayınlar. Kaç örnek okunduğunu ve kaç mesaj gönderildiğini yazdırır; böylece etkiyi doğrudan görebilirsiniz. paho-mqtt 2.x ve Python 3.10 veya üstünü kullanır.

import json
import random
import time
from dataclasses import dataclass
from datetime import datetime, timezone

import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PORT = 1883
CLIENT_ID = "rbe-gateway-6e41"
BASE = "connectmq/demo/rbe-6e41/plant1/boiler1"
POLL_S = 0.5


@dataclass
class Tag:
    name: str
    deadband: float            # mutlak, mühendislik biriminde (0 = her değişim)
    min_interval: float = 1.0  # yayınlar arası saniye
    heartbeat: float = 300.0   # saniye, değişiklik olmasa da yayınla
    last_value: float | None = None
    last_quality: str | None = None
    last_ts: float = 0.0

    def should_publish(self, value, quality, now):
        if self.last_value is None or quality != self.last_quality:
            return True                                   # ilk değer veya kalite değişimi
        if now - self.last_ts >= self.heartbeat:
            return True                                   # heartbeat
        if now - self.last_ts < self.min_interval:
            return False                                  # hız sınırı
        if self.deadband == 0:
            return value != self.last_value
        return abs(value - self.last_value) >= self.deadband

    def mark(self, value, quality, now):
        self.last_value, self.last_quality, self.last_ts = value, quality, now


TAGS = {
    "temperature_c": Tag("temperature_c", deadband=0.5),
    "pressure_bar":  Tag("pressure_bar", deadband=0.05),
    "flow_m3h":      Tag("flow_m3h", deadband=0.2),
    "burner_on":     Tag("burner_on", deadband=0, min_interval=0),
    "alarm_code":    Tag("alarm_code", deadband=0, min_interval=0),
}

state = {"temperature_c": 82.0, "pressure_bar": 3.20, "flow_m3h": 12.0,
         "burner_on": 1, "alarm_code": 0}


def poll_device():
    """Simulate a device read: small noise plus occasional real changes."""
    state["temperature_c"] += random.gauss(0, 0.08)
    state["pressure_bar"] += random.gauss(0, 0.008)
    state["flow_m3h"] += random.gauss(0, 0.03)
    if random.random() < 0.005:
        state["burner_on"] = 1 - state["burner_on"]
    quality = "BAD" if random.random() < 0.002 else "GOOD"
    return {k: round(v, 3) for k, v in state.items()}, quality


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.publish(f"{BASE}/status", "online", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.will_set(f"{BASE}/status", "offline", qos=1, retain=True)
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()

samples = sent = 0
started = time.monotonic()
try:
    while True:
        values, quality = poll_device()
        now = time.monotonic()
        for name, value in values.items():
            samples += 1
            tag = TAGS[name]
            if tag.should_publish(value, quality, now):
                payload = {
                    "v": value,
                    "q": quality,
                    "ts": datetime.now(timezone.utc).isoformat(timespec="milliseconds"),
                }
                client.publish(f"{BASE}/{name}", json.dumps(payload), qos=1, retain=True)
                tag.mark(value, quality, now)
                sent += 1
        if now - started >= 60:
            print(f"last 60 s: {samples} samples read, {sent} messages published "
                  f"({100 * sent / samples:.1f} %)")
            samples = sent = 0
            started = now
        time.sleep(POLL_S)
except KeyboardInterrupt:
    client.loop_stop()
    client.disconnect()

Sonucu izleyin:

mosquitto_sub -h broker.connectmq.com -p 1883 -i rbe-6e41-viewer -t "connectmq/demo/rbe-6e41/#" -v

Dakikada bir yazdırılan özet satırı, sorgulanan verinin ne kadarının gerçekten gönderilmesi gerektiğini gösterir. Gerçekçi deadband'lerle azalma büyüktür ve geriye kalan mesajlar bilgi taşıyan mesajlardır. Deadband'leri ayarlayın ve oranın nasıl değiştiğini izleyin.

Report by Exception ile Retained Mesajlar Neden Önemli?

Değerler yalnızca değişimde yayınlandığında, şimdi bağlanan bir abone aksi halde bir sonraki güncellemeyi dakikalarca bekleyebilir. Her tag'i retained message olarak yayınlamak bunu çözer: broker topic başına son değeri saklar ve her yeni aboneye anında iletir. Bunun için tek büyük bir JSON bloğu yerine tag başına bir topic daha iyi çalışır, çünkü her tag kendi retained son değerini korur. Teslim garantileri konusunda hafızanızı tazelemek isterseniz MQTT QoS seviyeleri yazısına bakın.

Sparkplug B'de RBE

Report by exception, Sparkplug B spesifikasyonunun içine yerleşiktir. Edge düğümleri bağlandıklarında her metriği içeren tam bir birth certificate gönderir, ardından DATA mesajlarında yalnızca değişen metrikleri gönderir. Bir host uygulaması takibi kaybederse rebirth ister. Bu da Sparkplug'a, düz MQTT'deki retained mesajlar artı RBE ile aynı "bağlanınca tam durum, sonrasında değişimler" davranışını kazandırır. ConnectMQ, Sparkplug B payload'larını çözümleyip okunabilir ISA-95 topic'lerine yeniden yayınlayabilir; böylece RBE için optimize edilmiş Sparkplug trafiği incelemesi kolay kalır.

RBE'nin En Çok Kazandırdığı Yerler

  • Ölçümlü veya kısıtlı bağlantılar. Hücresel ve uydu bağlantılarında her bayt önemlidir. Hücresel ağ üzerinden MQTT yazısında anlatıldığı gibi RBE genellikle uygulanacak ilk optimizasyondur.
  • Store-and-forward tamponları. Daha az mesaj, bir kesintinin tamponu daha yavaş doldurması ve daha hızlı yeniden oynatılması demektir; bkz. MQTT için store-and-forward.
  • Historian'lar ve depolama. Değişime dayalı veri iyi sıkışır ve sinyali deadband dahilinde yine de yeniden oluşturur.
  • Broker kotaları. Mesaj hızı ve bağlantı sınırları her broker'da geçerlidir. Örneğin genel test alanında her client saniyede 10 mesaj gönderebilir.

RBE genellikle protokol sürücülerinin yanında, bir IIoT edge gateway içinde uygulanır. Daha büyük mimari tablo için MQTT ile endüstriyel IoT rehberine bakın.

Yaygın Hatalar

  1. Heartbeat olmaması. Tüketiciler sabit bir değeri ölü bir gateway'den ayırt edemez.
  2. Son yayınlanan değer yerine bir önceki örnekle karşılaştırmak; bu, kaymanın fark edilmeden sızmasına izin verir.
  3. Ayrık sinyallerde deadband kullanmak. 1'den 2'ye bir durum değişimi asla filtrelenmemelidir.
  4. Değerleri retained yapmamak. Yeni aboneler bir sonraki değişime kadar hiçbir şey görmez.
  5. Her tag için tek bir deadband. Doğruluğa ve tüketici ihtiyaçlarına göre tag bazında ayarlayın.

ConnectMQ ile Daha Akıllı Yayın Yapın

RBE gönderdiğiniz veriyi azaltır; güvenilir bir broker ise gönderdiğinizin ulaşmasını sağlar. ConnectMQ; retained mesajlar, MQTT 5, TLS ve tag başına trafiği kontrol etmek için canlı bir topic gezgini sunan yönetilen bir MQTT broker'dır ve yukarıdaki örneği önce ücretsiz genel MQTT broker üzerinde test edebilirsiniz. Hazır olduğunuzda app.connectmq.com adresinde kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun.

Sık Sorulan Sorular

Report by exception basitçe nedir?

Bir değeri her okumada değil, yalnızca anlamlı şekilde değiştiğinde göndermek demektir. "Anlamlı" olanı deadband tanımlar; heartbeat ise değerin ara sıra yine de gönderilmesini sağlar.

Report by exception veri kaybına yol açar mı?

Tasarımı gereği deadband'den küçük değişimleri atar. Deadband'leri sensör doğruluğuna ve tüketicilerin gerçekten neye ihtiyaç duyduğuna göre seçin; mühendislerin daha sonra tam çözünürlüğe ihtiyaç duyabileceği durumlarda ham veriyi yerelde saklayın.

İyi bir heartbeat aralığı nedir?

Yaygın tercihler bir ila on beş dakika arasındadır. Bu süre, bir tüketicinin bir değeri bayat kabul edeceği süreden kısa olmalıdır.

Alarmlarda report by exception kullanılmalı mı?

Evet; her geçişin anında yayınlanması için sıfır deadband ve minimum aralık olmadan.

İlgili yazılar

CODESYS MQTT Client: PLC Değişkenlerini Bir Broker'a Yayınlama

CODESYS IIoT MQTT Client kütüphanesini PLC değişkenlerini JSON olarak yayınlayacak şekilde yapılandırın, broker.connectmq.com üzerinde doğrulayın, ardından kimlik bilgileri ve TLS içeren özel bir broker'a geçin.

6 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.