Endüstriyel IoT

RS-485 ile Modbus RTU'dan MQTT'ye Gateway: Kablolama, Ayarlar ve Kod

RS-485 Modbus RTU enerji sayaçlarını ve sensörleri, okumalarını MQTT üzerinden yayımlayan bir gateway'e bağlayın. Kablolama, sonlandırma, seri ayarlar, register haritaları ve eksiksiz bir Python poller ele alınıyor.

Modbus RTU'dan MQTT'ye mesajları buluta gönderen küçük bir Linux gateway'e bağlı enerji sayaçlarından oluşan RS-485 hattı
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

Bir Modbus RTU'dan MQTT'ye gateway, RS-485 enerji sayaçlarından, debimetrelerden, sürücülerden ve sensörlerden okumalar alıp panoların ve analitiğin kullanabileceği bir broker'a yayımlamanızı sağlar. Bu eğitim, sorunların çoğuna yol açan fiziksel katmanı (kablolama, sonlandırma, seri ayarlar), bir üretici register haritasının nasıl okunacağını ve tek bir hat üzerindeki birkaç cihazı sorgulayıp değerlerini MQTT üzerinden yayımlayan eksiksiz bir Python gateway'i kapsıyor. Takip etmek için bir Raspberry Pi veya USB-RS-485 adaptörlü herhangi bir Linux makinesi yeterlidir.

Modbus RTU'yu Modbus TCP'den Farklı Kılan Nedir?

Modbus veri modeli aynıdır: coil'ler, discrete input'lar, holding register'lar ve input register'lar. Değişen taşıma katmanıdır. Modbus RTU bir seri hat üzerinde, neredeyse her zaman RS-485 üzerinde, çok noktalı (multi-drop) bir hat olarak çalışır. Tek bir master, her biri benzersiz bir unit adresine sahip 247'ye kadar slave cihazı sorgular. Çerçeveler CRC'li ikili verilerdir ve çerçeve sınırları hattaki sessiz boşluklarla belirlenir.

Bunun pratik sonuçları vardır:

  • Hat başına yalnızca bir master. Bir bina yönetim sistemi veya HMI sayaçları zaten sorguluyorsa gateway'iniz aynı kablolara öylece katılamaz. Ayrı bir hatta, ikinci portu olan bir cihaza veya ikisinin önünde duran bir gateway'e ihtiyacınız vardır.
  • Hat yavaş ve paylaşımlıdır. 9600 baud'da her istek ve yanıt onlarca milisaniye sürer ve farklı cihazlara giden istekler sıraya girer. Sorgulama planları önemlidir.
  • Elektriksel sorunlar yazılım sorunu gibi görünür. Eksik sonlandırma veya ters bağlanmış bir çift, hiçbir kodun düzeltemeyeceği zaman aşımlarına ve CRC hatalarına yol açar.

Cihazlarınız Ethernet üzerindeyse bunun yerine Modbus TCP'den MQTT'ye eğitimimizi kullanın.

İhtiyacınız Olan Donanım

  1. Bir gateway bilgisayarı: Raspberry Pi, endüstriyel PC veya herhangi bir Linux makinesi.
  2. Bir USB-RS-485 adaptörü; ideal olarak seçilebilir sonlandırma ve bias dirençlerine sahip, izoleli bir model. İzolasyon, gateway'i panolar arasındaki toprak potansiyel farklarına karşı korur.
  3. Hat için, tercihen ekranlı, sinyal ortak ucu için üçüncü bir iletkeni olan bükümlü çift kablo.
  4. Her cihazın Modbus kılavuzu. Register haritasına ve varsayılan seri ayarlarına ihtiyacınız var.

RS-485 Kablolamasını Doğru Yapmak

RS-485, amaçlandığı gibi kablolandığında sağlam, aksi hâlde sinir bozucudur. Şu kurallara uyun:

  1. Yıldız değil, zincir (daisy chain). Hattı cihazdan cihaza tek bir çizgi hâlinde götürün. Kısa saplamalar tolere edilebilir; uzun dallar yansımalara neden olur.
  2. İki ucu da sonlandırın. Hattın iki fiziksel ucunda A/B çiftinin arasına 120 ohm'luk bir direnç koyun, başka hiçbir yere koymayın. Birçok adaptör ve sayaçta bir sonlandırma anahtarı veya jumper bulunur.
  3. Bias'ı bir kez uygulayın. Bias (fail-safe) dirençleri kimse konuşmazken hattı tanımlı bir durumda tutar. Bunları tek bir yerde, genellikle master adaptörde etkinleştirin.
  4. Ortak ucu bağlayın. "İki telli" adına rağmen, alıcıların ortak bir referansı paylaşması için sinyal toprağını (çoğu zaman GND, COM veya C olarak etiketlenir) cihazlar arasında bağlayın.
  5. A/B etiketlemesine dikkat edin. Üreticiler A'nın pozitif mi negatif mi olduğunda anlaşamaz, bazıları D+ ve D- kullanır. Hiçbir şey yanıt vermiyorsa adaptörde A ile B'nin yerini değiştirmek meşru bir ilk testtir.
  6. Güç kablolarından uzak tutun. Hattı motor ve VFD kablolarından ayrı döşeyin ve ekranı tek uçtan topraklayın.

Seri Ayarlar: Baud, Parite ve Stop Bitleri

Bir hattaki her cihaz aynı ayarları kullanmalı ve her cihazın benzersiz bir adresi olmalıdır.

Ayar Yaygın değerler Notlar
Baud hızı 9600, 19200, 38400 9600 ve 19200 en yaygın varsayılanlardır; uzun kablolar düşük hızları tercih ettirir
Veri bitleri 8 Modbus RTU her zaman 8 veri biti kullanır
Parite Even, None, Odd Modbus spesifikasyonu varsayılan olarak çift (even) pariteyi öngörür, ama birçok cihaz paritesiz (none) gelir
Stop bitleri 1 veya 2 Parite yoksa spesifikasyon 2 stop biti ister, ancak birçok cihaz 1'i de kabul eder
Unit adresi 1 ile 247 arası Cihazın ön panelinden veya yazılımla ayarlanır; hatta benzersiz olmalıdır

Ayarları 9600 8E1 veya 19200 8N2 gibi kısa bir kodla yazıya dökün ve herhangi bir şeyi bağlamadan önce her cihazı buna göre ayarlayın.

Bir Register Haritasını Okumak

Bir cihaz kılavuzu register'ları adres, açıklama, veri tipi, birim ve bazen ölçek faktörü içeren bir tabloda listeler. Aşağıdaki örnek, bu eğitim için kullanılan varsayımsal bir üç fazlı enerji sayacıdır; gerçek sayaçlar farklıdır, bu yüzden adresleri her zaman kendi kılavuzunuzdan alın.

Açıklama Fonksiyon Adres (0 tabanlı) Tip Birim
Gerilim L1-N 04 input 0 float32 V
Akım L1 04 input 6 float32 A
Toplam aktif güç 04 input 52 float32 W
Frekans 04 input 70 float32 Hz
Çekilen aktif enerji 04 input 72 float32 kWh

Her kılavuzda kontrol edilmesi gereken üç şey: adreslerin sıfır tabanlı mı yoksa 30001 tarzında mı yazıldığı (ofseti çıkarın), 32 bit değerlerin önce yüksek word mü yoksa önce düşük word mü sıralamasını kullandığı ve tam sayı register'larının bir ölçek faktörüne ihtiyaç duyup duymadığı.

Gateway Üzerindeki Ön Koşullar

sudo usermod -aG dialout $USER     # seri port erişimine izin ver, ardından oturumu kapatıp yeniden açın
ls -l /dev/serial/by-id/           # adaptörünüz için kalıcı cihaz yolu
python3 -m venv ~/rtu-gw && source ~/rtu-gw/bin/activate
pip install "pymodbus[serial]>=3.8,<3.9" "paho-mqtt>=2.0"

/dev/ttyUSB0 yerine /dev/serial/by-id/... yolunu kullanın, çünkü USB cihaz numaraları yeniden başlatmadan sonra değişebilir.

Modbus RTU'dan MQTT'ye Gateway Kodu

Gateway her sayacı sırayla sorgular, mümkün olduğunda her register bloğunu tek bir istekte okur ve döngü başına sayaç başına bir JSON mesajı yayımlar. Bir sayacın değerlerini tek mesajda toplamak mesaj hızını düşük tutar; yavaş bir hatta ve ölçülü bir uplink'te istediğiniz de budur.

# rtu_mqtt_gateway.py - RS-485 üzerinden Modbus RTU sayaçlarını sorgula, MQTT'ye yayımla
import json, logging, struct, time, uuid
import paho.mqtt.client as mqtt
from pymodbus.client import ModbusSerialClient

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("rtu-gw")

# Üretimde port değerini /dev/serial/by-id/... yolunuzla değiştirin
SERIAL = dict(port="/dev/ttyUSB0", baudrate=9600, parity="E", stopbits=1, bytesize=8, timeout=0.5)
POLL_SECONDS = 10
TOPIC_ROOT = "connectmq/demo/e5a1/plant1/energy"     # kendi rastgele id'nizi kullanın
MQTT_HOST, MQTT_PORT = "broker.connectmq.com", 1883   # üretim: TLS ile 8883
MQTT_USER, MQTT_PASS = None, None                     # üretim: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"rtu-gw-{uuid.uuid4().hex[:8]}"          # üretim: "YOUR_CLIENT_ID"

# Hattaki sayaçlar: Modbus unit adresi -> topic adı
METERS = [
    {"unit": 1, "name": "mdb1_incomer"},
    {"unit": 2, "name": "mdb1_compressors"},
]


def f32(regs, offset, big_endian_words=True):
    words = regs[offset:offset + 2] if big_endian_words else regs[offset:offset + 2][::-1]
    return struct.unpack(">f", struct.pack(">HH", *words))[0]


def read_meter(client, unit):
    """Varsayımsal sayacın float32 input register'larını iki blok isteğinde oku."""
    block_a = client.read_input_registers(0, count=8, slave=unit)        # gerilim, akım
    block_b = client.read_input_registers(52, count=24, slave=unit)      # güç .. enerji
    for rr in (block_a, block_b):
        if rr.isError():
            raise IOError(str(rr))
    a, b = block_a.registers, block_b.registers
    return {
        "voltage_l1": round(f32(a, 0), 1),
        "current_l1": round(f32(a, 6), 2),
        "power_total": round(f32(b, 0), 0),
        "frequency": round(f32(b, 18), 2),
        "energy_import": round(f32(b, 20), 1),
    }


def main():
    mq = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
    if MQTT_USER:
        mq.username_pw_set(MQTT_USER, MQTT_PASS)
        mq.tls_set()
    mq.will_set(f"{TOPIC_ROOT}/gateway", "offline", qos=1, retain=True)
    mq.on_connect = lambda c, u, f, rc, p: c.publish(f"{TOPIC_ROOT}/gateway", "online", qos=1, retain=True)
    mq.connect(MQTT_HOST, MQTT_PORT, keepalive=60)
    mq.loop_start()

    bus = ModbusSerialClient(**SERIAL)
    errors = {m["unit"]: 0 for m in METERS}

    while True:
        cycle_start = time.monotonic()
        if not bus.connected and not bus.connect():
            log.error("cannot open serial port %s", SERIAL["port"])
            time.sleep(5)
            continue
        for meter in METERS:
            topic = f"{TOPIC_ROOT}/{meter['name']}"
            try:
                values = read_meter(bus, meter["unit"])
                errors[meter["unit"]] = 0
                payload = {**values, "quality": "good",
                           "ts": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())}
                mq.publish(topic, json.dumps(payload), qos=1, retain=True)
                log.info("%s %s", meter["name"], values)
            except Exception as exc:
                errors[meter["unit"]] += 1
                log.warning("unit %s: %s", meter["unit"], exc)
                if errors[meter["unit"]] == 3:   # 3 başarısız denemeden sonra bir kez bad kalite yayımla
                    mq.publish(topic, json.dumps({"quality": "bad"}), qos=1, retain=True)
            time.sleep(0.05)                     # hattaki cihazlar arasında küçük bir boşluk
        time.sleep(max(0, POLL_SECONDS - (time.monotonic() - cycle_start)))


if __name__ == "__main__":
    main()

read_meter içindeki ofsetlere dikkat edin: B bloğu register 52'de başlar, dolayısıyla register 70'teki frekans ofset 18, register 72'deki çekilen enerji ise ofset 20'dir. Okumaları gruplarken bu ofsetleri yanlış almak en yaygın hatadır; bu yüzden devreye alma sırasında ham register'ları bir kez yazdırın.

Çalıştırın ve Doğrulayın

Gateway'i çalıştırın, ardından çıktıyı herhangi bir makineden izleyin:

python rtu_mqtt_gateway.py
mosquitto_sub -h broker.connectmq.com -p 1883 -i rtu-viewer-e5a1 -t "connectmq/demo/e5a1/#" -v
connectmq/demo/e5a1/plant1/energy/mdb1_incomer {"voltage_l1": 231.4, "current_l1": 18.72, "power_total": 12890.0, "frequency": 50.01, "energy_import": 48213.6, "quality": "good", "ts": "2026-10-16T10:05:00Z"}

Public MQTT test broker herkes tarafından okunabilir; bu yüzden onu yalnızca test verisi için kullanın. Gerçek bir saha için özel bir broker oluşturun ve kimlik bilgilerinizle 8883 portuna geçin.

Modbus RTU Sorun Giderme

Belirti Olası neden Ne denenmeli
Hiçbir cihazdan yanıt yok A/B ters, yanlış baud veya parite, yanlış port A/B'yi değiştirin, 8E1 ile 8N1'i teyit edin, /dev/serial/by-id yolunu kontrol edin
Bazı cihazlar yanıt veriyor, diğerleri zaman aşımına uğruyor Tekrarlanan veya yanlış unit adresi, kablo kopukluğu Bir cihaz hariç hepsini ayırın ve her birini tek tek test edin
Aralıklı CRC hataları Eksik sonlandırma, yıldız topolojisi, sürücülerden gelen gürültü İki ucu da sonlandırın, kabloyu yeniden döşeyin, ekranlı bükümlü çift kullanın
9600'de çalışıyor, daha yüksek hızlarda başarısız Uzun kablo veya kötü kablolama Düşük hızda kalın veya kablolamayı düzeltin
İstisna kodu 2 (geçersiz veri adresi) Adres cihazın haritası dışında veya blok bir boşluğu kapsıyor Bloğu daha küçük okumalara bölün
Başka bir sistem çalışırken rastgele zaman aşımları Aynı hatta iki master Gateway'e kendi hattını veya portunu verin

Ölçek Büyütme

Tek bir RS-485 portu bir avuç sayaç için yeterlidir. Düzinelerce sayacınız olduğunda pano başına bir adaptör veya bir gateway'in Ethernet üzerinden birkaç hatta ulaşmasını sağlayan Modbus RTU'dan TCP'ye dönüştürücüler düşünün, ardından TCP köprüsünü yeniden kullanın. Report by exception rehberimizde anlatıldığı gibi her döngüde değil değişiklik olduğunda yayımlamak da uplink'i sakin tutar. Mobil veri kullanan uzak sahalar için hücresel ağ üzerinden MQTT yazımıza bakın.

ConnectMQ gibi barındırılan bir MQTT broker, bu gateway'ler için sunucu çalıştırma ihtiyacını ortadan kaldırır. Ücretsiz Serverless plan, birkaç gateway'li bir pilot için yeterli olan 25 bağlantıya kadar destekler; ücretli Serverless plan ise 1.000'e kadar ölçeklenir. Portalın eşik uyarı kuralları power_total gibi değerleri izleyebilir ve bir sınır aşıldığında bir uyarı kaydedebilir. Tüm bunların arkasındaki mimari için endüstriyel IoT MQTT rehberini okuyun.

ConnectMQ ile Başlayın

RS-485 sayaçlarınızı bugün çevrim içi hâle getirin. app.connectmq.com adresinde kaydolun, ücretsiz Serverless planı seçin (kredi kartı gerekmez), bir broker oluşturun ve oluşturulan kullanıcı adını, şifreyi ve client ID'yi gateway betiğine kopyalayın. Sayaç okumalarınız ilk sorgulama tamamlanır tamamlanmaz ConnectMQ canlı topic explorer'ında görünür.

Sık Sorulan Sorular

Bir RS-485 hattı kaç Modbus RTU cihazını destekleyebilir?

Modbus adresleri 247'ye kadar cihaza izin verir, ancak elektriksel sınır alıcı-verici yüküne bağlıdır; standart RS-485 32 birim yükü destekler ve birçok modern alıcı-verici kesirli yük sunar. Pratikte genellikle önce sorgulama süresi sınır hâline gelir.

Bir BMS'nin zaten sorguladığı Modbus RTU cihazlarını okuyabilir miyim?

Aynı hatta okuyamazsınız, çünkü Modbus RTU yalnızca tek bir master'a izin verir. Cihazdaki ikinci bir portu, ayrı bir sayaç çıkışını kullanın veya BMS entegratöründen veriyi başka bir yolla sunmasını isteyin.

Modbus RTU için hangi baud hızını kullanmalıyım?

Hattaki her cihazın desteklediği hızı kullanın; tipik olarak 9600 veya 19200. Düşük hızlar uzun kabloları ve gürültülü ortamları daha iyi tolere eder.

Bir Modbus RTU gateway'i her sorgulamada yayın yapmalı mı?

Mutlaka değil. Bir cihazın değerlerini döngü başına tek bir mesajda toplamak veya yalnızca anlamlı değişikliklerde yayımlamak, bilgi kaybetmeden mesaj hacmini düşük tutar.

İ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.