Node-RED Modbus akışları, yalnızca Modbus konuşan sayaçlardan, sürücülerden ve PLC'lerden veriyi alıp panoların, historian'ların ve bulut araçlarının kullanabileceği MQTT'ye taşımanın en hızlı yollarından biridir. Bu eğitimde node-red-contrib-modbus ile holding register ve coil'leri sorgulayacak, ölçekli tamsayıları ve 32 bit float'ları doğru şekilde çözecek ve temiz JSON'u yalnızca değerler değiştiğinde bir broker'a yayınlayacaksınız. Ayrıca yazma komutlarını güvenli şekilde nasıl işleyeceğinizi ve her şeyi gerçek donanım olmadan nasıl test edeceğinizi göreceksiniz.
Modbus'ı MQTT'ye Neden Node-RED ile Bağlamalı?
Modbus 1979'dan kalma bir istek/yanıt protokolüdür: bir istemci (master), bir sunucudan (slave) bir register bloğu ister ve ham 16 bitlik sayılar geri alır. Birimleri, adları, zaman damgaları ve push mekanizması yoktur. Veriyi isteyen her tüketicinin cihazı kendisinin sorgulaması gerekir ve birçok cihaz yalnızca birkaç eşzamanlı bağlantıyı kaldırabilir.
MQTT bunu tersine çevirir. Tek bir ağ geçidi cihazı sorgular, sayılara anlam kazandırır ve onları bir kez broker'a yayınlar. Ardından istenen sayıda abone, adlandırılmış ve ölçeklenmiş değerleri değiştikleri anda alır. Node-RED doğal bir ağ geçididir, çünkü sorgulama, çözme, filtreleme ve yayınlamanın her biri tek bir node'dur ve mantık bakım ekibine görünür kalır. Daha geniş mimari tablo için Modbus TCP'den MQTT'ye rehberi Node-RED'i diğer ağ geçidi seçenekleriyle karşılaştırıyor.
node-red-contrib-modbus Paketini Kurun
Paketi Manage palette → Install yolundan ya da komut satırından kurun:
cd ~/.node-red
npm install node-red-contrib-modbus
# ardından Node-RED'i yeniden başlatın
Diğerlerinin yanı sıra şu node'ları sağlar:
| Node | Amaç |
|---|---|
| Modbus Read | Bir zamanlayıcıyla sabit bir register bloğunu sorgular |
| Modbus Getter | Bir mesaj geldiğinde istek üzerine okur |
| Modbus Flex Getter | Gelen mesaj neyi belirtiyorsa onu okur |
| Modbus Write | Coil veya register yazar |
| Modbus Server | Test için basit bir Modbus TCP sunucusu |
| Modbus Client (config) | Node'ların paylaştığı TCP veya seri bağlantı |
Önce Register Haritanızı Anlayın
Her Modbus projesi cihazın register haritasıyla başlar. Bu eğitim için şu haritaya sahip bir pompa kontrolörü düşünün:
| Veri | Tür | Adres (0 tabanlı) | Klasik gösterim | Ölçekleme |
|---|---|---|---|---|
| Sıcaklık | Holding register, işaretli 16 bit | 0 | 40001 | değer / 10, °C |
| Basınç | Holding register, işaretsiz 16 bit | 1 | 40002 | değer / 100, bar |
| Debi | Holding register'lar, 32 bit float, big-endian | 2-3 | 40003-40004 | yok, m³/h |
| Pompa çalışıyor | Coil | 0 | 00001 | boolean |
En yaygın Node-RED Modbus hatası adrestir. Veri sayfaları genellikle bir tabanlı ve tür ön eki içeren "40001" gösterimini kullanır. Protokol adresi, yani Node-RED'e girdiğiniz adres, ön eksiz ve sıfır tabanlıdır: 40001, holding register adresi 0 olur. Değerleriniz bir register kaymış görünüyorsa nedeni budur.
Donanımsız Test: Yerel Bir Modbus Sunucusu
Node-RED içinde bir Modbus sunucusu çalıştırarak tüm eğitimi bir cihaz olmadan takip edebilirsiniz.
- Ayrı bir sekmeye bir Modbus Server node'u sürükleyin.
0.0.0.0adresinde,10502portunda dinleyecek şekilde ayarlayın (ayrıcalıksız port, root gerekmez). Deploy edin. - Bir Modbus Client yapılandırma node'u oluşturun: tür TCP, host
127.0.0.1, port10502, unit ID1. - Her 2 saniyede tekrarlanan bir inject node'u, simüle register değerleri üreten bir function node'u ve bu istemciyi function code 16 (preset multiple registers), adres
0, miktar4ile kullanan bir Modbus Write node'u ekleyin.
Simülatör fonksiyonu:
// Function node "simulate pump registers" -> Modbus Write (FC16, adres 0, miktar 4)
const temperature = 40 + Math.random() * 5; // °C
const pressure = 3.2 + Math.random() * 0.3; // bar
const flowRate = 12 + Math.random() * 2; // m³/h
const buf = Buffer.alloc(4);
buf.writeFloatBE(flowRate, 0);
msg.payload = [
Math.round(temperature * 10), // register 0
Math.round(pressure * 100), // register 1
buf.readUInt16BE(0), // register 2: float yüksek word
buf.readUInt16BE(2) // register 3: float düşük word
];
return msg;
Coil üzerinde ikinci bir write node'u ekleyin: function code 5 (force single coil), adres 0, bir inject node'undan true ile beslenir. Sahte pompa kontrolörünüz artık çalışıyor.
Node-RED Modbus Sorgulama Akışını Oluşturun
Adım 1: Register'ları sorgulayın
Aynı istemciyle bir Modbus Read node'u ekleyin:
- FC: 3, Read Holding Registers
- Adres:
0, Miktar:4 - Sorgulama hızı: 2 saniye
İlk çıkışı msg.payload değerini dört ham sayıdan oluşan bir dizi olarak verir, örneğin [423, 334, 16708, 26214]. İkinci çıkış ham buffer'ı ve yanıt ayrıntılarını taşır; bu, bayt sırasında hata ayıklamak için faydalıdır.
Coil için FC 1 (Read Coil Status), adres 0, miktar 1 ve 5 saniyelik daha yavaş bir sorgulamayla ikinci bir Modbus Read node'u ekleyin.
Adım 2: Ham register'ları mühendislik değerlerine çözün
// Function node "decode pump registers"
const r = msg.payload;
if (!Array.isArray(r) || r.length < 4) {
node.warn("Unexpected register block");
return null;
}
// Sıcaklık için işaretli 16 bit dönüşümü
const int16 = v => (v > 32767 ? v - 65536 : v);
// İki register'dan 32 bit float, big-endian word sırası
const buf = Buffer.alloc(4);
buf.writeUInt16BE(r[2], 0);
buf.writeUInt16BE(r[3], 2);
const flowRate = buf.readFloatBE(0);
const values = {
temperature: Math.round(int16(r[0])) / 10,
pressure: Math.round(r[1]) / 100,
flow: Math.round(flowRate * 100) / 100
};
// Coil okumasıyla birleştirmek için sakla
flow.set("pump1_values", values);
msg.topic = "connectmq/demo/a7f3k2/plant1/utilities/pump1/telemetry";
msg.payload = {
...values,
running: flow.get("pump1_running") === true
};
return msg;
Coil okumasını durumu saklayan küçük bir fonksiyona bağlayın: flow.set("pump1_running", msg.payload[0] === true); return null;. Birçok cihaz, düşük word'ün önce geldiği "word-swapped" float'lar kullanır. Debi değeriniz 1.2e-38 ya da -4.5e+12 gibi saçma görünüyorsa, r[2] ile r[3] değerlerinin yerini değiştirip yeniden deneyin.
Adım 3: Yalnızca bir şey değiştiğinde yayınlayın
Her 2 saniyede sorgulayıp her sonucu yayınlamak bant genişliğini boşa harcar ve aboneleri yinelenen veriyle doldurur. msg.payload üzerinde "block unless value changes" olarak ayarlanmış bir filter node'u (eski adıyla RBE) ekleyin ya da değerler titreşiyorsa tekil değerler üzerinde ölü bant (deadband) sürümünü kullanın. Filter tüm nesneyi karşılaştırır; decode fonksiyonunun zaman damgası eklememesinin nedeni budur. Filter'dan sonra msg.payload.ts değerini bir zaman damgasına ayarlayan bir change node'u ekleyin. İstisna bazlı raporlama temel bir MQTT desenidir, ancak abonelerin sessiz bir cihazı ölü bir cihazdan ayırt edebilmesi için yavaş değişen değerlere periyodik bir heartbeat eklemek yine de faydalıdır.
Adım 4: MQTT'ye yayınlayın
msg.topic kullanılsın diye topic'i boş bir mqtt out node'u ekleyin. Test için broker'ı benzersiz bir client ID ile broker.connectmq.com, port 1883 olarak yapılandırın; bu herkese açık MQTT test broker'ıdır. a7f3k2 yerine kendi dizenizi kullanın. Ardından çıktıyı izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-modbus-a7f3k2 -v \
-t 'connectmq/demo/a7f3k2/plant1/#'
{"temperature":42.3,"pressure":3.34,"flow":12.81,"running":true,"ts":...} gibi mesajlar görmelisiniz. Herkese açık broker'a gerçek fabrika verisi göndermeyin: herkes ona abone olabilir.
MQTT'den Modbus'a Güvenli Yazma
Okumak düşük risklidir; bir pompaya yazmak öyle değildir. MQTT'den komut kabul ediyorsanız akışa korkuluklar koyun:
- Asla bir joker karaktere değil,
.../pump1/cmdgibi özel bir komut topic'ine abone olun. - Payload'ı bir function node'unda izin verilen eylemler ve değer aralıklarından oluşan bir beyaz listeye karşı doğrulayın.
- Her eylemi sabit bir register'a ya da coil'e eşleyin. Adresi asla mesajın seçmesine izin vermeyin.
- Gönderenin yazmanın gerçekleşip gerçekleşmediğini bilmesi için sonucu bir
.../pump1/cmd/acktopic'ine yayınlayın. - Ekipman durumunu değiştirebilen her topic için kimlik doğrulamalı özel bir broker kullanın.
// Function node "validate pump command" -> Modbus Write (FC5, coil 0)
const cmd = String(msg.payload).trim().toUpperCase();
if (cmd !== "START" && cmd !== "STOP") {
node.warn("Rejected command: " + cmd);
return null;
}
msg.payload = cmd === "START";
return msg;
RS-485 Üzerinden Modbus RTU
Seri cihazlar için yalnızca istemci yapılandırmasını değiştirin: tür Serial, /dev/ttyUSB0 gibi bir port, cihazla eşleşen baud hızı, parite ve stop bitleri (9600 8N1 yaygındır) ve RTU seri türü. Hattaki her cihazın kendi unit ID'si vardır. Sorgulama hızlarını temkinli tutun, çünkü tek bir RS-485 hattı tüm cihazlara sırayla hizmet eder ve bir cihazdaki zaman aşımı diğerlerini geciktirir. Modbus RTU'dan MQTT'ye rehberi kablolama ve sonlandırmayı ele alıyor.
Node-RED Modbus Akışlarında Sorun Giderme
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Zaman aşımı hataları | Yanlış IP, port veya unit ID; güvenlik duvarı | Önce bir masaüstü Modbus aracıyla kontrol edin |
| Illegal data address (exception 2) | Bir kaymış adres veya yanlış function code | Sıfır tabanlı adresler kullanın; holding ve input register farkına dikkat edin |
| Değerler bir register kaymış | 40001 gösterimi olduğu gibi girilmiş | Ofseti çıkarın |
| Saçma float değerleri | Word sırası farklı | İki register'ın yerini değiştirin |
| Negatif sayılar 65.000+ olarak görünüyor | İşaretli değer işaretsiz okunmuş | int16 dönüşümünü uygulayın |
| Cihaz yük altında yanıt vermeyi bırakıyor | Çok fazla istemci veya çok hızlı sorgulama | Tek ağ geçidi, daha yavaş sorgulama, okumaları bloklarda birleştirin |
Ağ Geçidinden Üretime
Değerler akmaya başladığında ağ geçidi, yayın yaptığı broker kadar faydalıdır. Birkaç Node-RED ağ geçidi, bir SCADA istemcisi ve bir historian bulunan bir tesiste hepsi, hem fabrika hem de ofis ağından erişilebilen, kimlik doğrulamalı tek bir broker'ı paylaşmalıdır. Bir bulut MQTT broker bunu başarmanın basit bir yoludur, çünkü her ağ geçidi 8883 portu üzerinden dışarı bağlanır ve OT ağına hiçbir gelen port açılmaz. ConnectMQ ayrıca plant1/utilities/pump1/telemetry gibi ISA-95 tarzı topic'leri tanır ve cihazları portalında bu seviyelere göre gösterir. Broker altyapısı hiç çalıştırmamayı tercih ederseniz, yönetilen bir MQTT broker yama ve izleme yükünü üzerinizden alır.
Diğer endüstriyel protokoller de aynı deseni izler: modern kontrolörler için Node-RED ile OPC UA'dan MQTT'ye, S7 PLC'ler için Node-RED ve Siemens S7 yazılarına bakın. Node-RED'de broker kurulumu için Node-RED MQTT eğitimi temel bilgileri içeriyor.
Modbus Ağ Geçidinizi ConnectMQ'ya Bağlayın
app.connectmq.com adresinden kredi kartı gerektirmeyen ücretsiz Serverless planına kaydolun. Bir broker oluşturun, üretilen kullanıcı adını, parolayı ve client ID'yi Node-RED yapılandırma node'una yapıştırın, 8883 portunda TLS'yi etkinleştirin; Modbus değerleriniz özel ve şifreli olarak yayınlansın. Çözdüğünüz her register'ı doğrulamak için ConnectMQ canlı topic gezginini kullanın.
Sık Sorulan Sorular
node-red-contrib-modbus hem Modbus TCP'yi hem de RTU'yu destekliyor mu?
Evet. Modbus Client yapılandırma node'u, RS-485 adaptörleri üzerinden RTU dahil TCP ve seri bağlantıları destekler. Okuma ve yazma node'ları her ikisi için de aynı şekilde çalışır.
Node-RED'de Modbus adresim neden bir kaymış?
Veri sayfaları genellikle bir tabanlı 40001 tarzı numaralandırma kullanırken Node-RED sıfır tabanlı protokol adreslerini kullanır. Holding register 40001, Modbus Read node'unda adres 0'dır.
Node-RED'de Modbus'tan 32 bit float nasıl okunur?
Ardışık iki register okuyun, bunları 4 baytlık bir buffer'a yazın ve readFloatBE çağırın. Sonuç yanlış görünüyorsa iki word'ün yerini değiştirin, çünkü bazı cihazlar ters word sırası kullanır.
Node-RED bir Modbus cihazını ne sıklıkla sorgulamalı?
Kullanım senaryonuzun izin verdiği kadar yavaş sorgulayın; izleme için genellikle 1 ila 10 saniye. Hem cihazı hem de broker'ı hafif yüklü tutmak için register'ları bloklarda birleştirin ve istisna bazlı yayınlayın.



