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
- Bir gateway bilgisayarı: Raspberry Pi, endüstriyel PC veya herhangi bir Linux makinesi.
- 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.
- Hat için, tercihen ekranlı, sinyal ortak ucu için üçüncü bir iletkeni olan bükümlü çift kablo.
- 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:
- 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.
- İ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.
- 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.
- 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.
- 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.
- 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.



