Bir Node-RED OEE paneli, bir MES satın almadan gerçek bir üretim KPI'ını ekibin önüne koymanın en hızlı yollarından biridir. Bu rehberde iki MQTT topic'inden, makine durumu ve parça sayaçlarından kullanılabilirlik, performans ve kaliteyi hesaplayacak ve canlı OEE'yi Dashboard 2.0 göstergelerinde göstereceksiniz. Ayrıca KPI'ları diğer araçların kullanabilmesi için MQTT'ye yeniden yayınlayacak ve basit OEE hesaplarını yanıltan uç durumları öğreneceksiniz.
Bir Dakikada OEE
Toplam Ekipman Etkinliği (Overall Equipment Effectiveness), her biri 0 ile 1 arasında olan üç oranı çarpar:
| Faktör | Formül | Neyi kaybeder |
|---|---|---|
| Kullanılabilirlik | Çalışma süresi / planlı üretim süresi | Arızalar, ürün değişimleri, malzeme beklemesi |
| Performans | (İdeal çevrim süresi x toplam adet) / çalışma süresi | Yavaş çevrimler, mikro duruşlar |
| Kalite | Sağlam adet / toplam adet | Hurda ve yeniden işleme |
| OEE | Kullanılabilirlik x Performans x Kalite | Yukarıdakilerin tümü |
Formülün güzelliği çok az veri gerektirmesidir: makinenin ne zaman çalıştığı, kaç parça ürettiği ve bunların kaçının sağlam olduğu. Bu, MQTT'ye düzgün biçimde oturur. Planlı ve plansız duruşlar dahil tanımlara daha ayrıntılı bakmak için OEE nasıl hesaplanır yazısına göz atın.
MQTT Veri Modeli
Makine ya da önündeki bir gateway iki topic yayınlar:
| Topic | Payload | Retained | Ne zaman |
|---|---|---|---|
connectmq/demo/a7f3k2/plant1/line1/press1/state |
RUNNING, IDLE veya DOWN |
Evet | Her değişiklikte |
connectmq/demo/a7f3k2/plant1/line1/press1/count |
{"total": 1234, "good": 1201} |
Hayır | Birkaç saniyede bir |
İki tasarım tercihi bu yapıyı sağlam kılar:
- Durum olay güdümlüdür ve retained'dır. Node-RED bağlandıktan hemen sonra mevcut durumu öğrenir ve çalışma süresini değişiklik olaylarından biriktirir.
- Sayaçlar parça başına değil, kümülatiftir. Bir mesaj kaybolursa bir sonraki mesaj yine doğru toplamı taşır. Node-RED farkları hesaplar ve geriye giden bir sayaç, negatif üretim yerine PLC sıfırlaması olarak değerlendirilir.
Topic, bir demo önekinin arkasında ISA-95 tarzı bir hiyerarşiyi (tesis, hat, makine) izler. Herkese açık broker'ı herkes okuyabildiği için a7f3k2 yerine kendi rastgele dizenizi kullanın.
Bir Makineyi Simüle Edin
Bu Python betiği, 2 saniyelik ideal çevrimi, ara sıra duruşları ve yaklaşık yüzde 3 hurdası olan bir pres gibi davranır. Herkese açık MQTT test broker'ı olan broker.connectmq.com adresine yayın yapar.
# pip install "paho-mqtt>=2.0"
import json
import random
import time
import uuid
import paho.mqtt.client as mqtt
BASE = "connectmq/demo/a7f3k2/plant1/line1/press1"
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"press-sim-{uuid.uuid4().hex[:8]}")
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
state = None
total = 0
good = 0
next_cycle = time.time()
last_count_pub = 0.0
def set_state(new_state):
global state
if new_state != state:
state = new_state
client.publish(f"{BASE}/state", state, qos=1, retain=True)
print("State:", state)
set_state("RUNNING")
try:
while True:
now = time.time()
if state == "RUNNING":
if random.random() < 0.004:
set_state(random.choice(["IDLE", "DOWN"]))
elif now >= next_cycle:
total += 1
if random.random() > 0.03:
good += 1
# Gerçek çevrimler idealden biraz daha yavaştır
next_cycle = now + random.uniform(2.0, 2.6)
elif random.random() < 0.02:
set_state("RUNNING")
next_cycle = time.time() + 2.0
if now - last_count_pub >= 5:
client.publish(f"{BASE}/count",
json.dumps({"total": total, "good": good}), qos=1)
last_count_pub = now
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
client.loop_stop()
client.disconnect()
Node-RED OEE Paneli Akışını Oluşturun
Dashboard 2.0 (@flowfuse/node-red-dashboard) kurulu Node-RED 4.x gerekir. Henüz kullanmadıysanız Dashboard 2.0 rehberi kurulumu ve sayfa ile grup yapısını anlatır.
Girişler
.../press1/stateüzerinde, çıktısı "a UTF-8 string" olan birmqtt innode'u..../press1/countüzerinde, çıktısı "a parsed JSON object" olan birmqtt innode'u.- Her 5 saniyede bir tekrarlanan ve
msg.topicdeğeritickolan "tick" adlı bir inject node'u. msg.topicdeğerishift/resetolan "Start new shift" etiketli birui-buttonile birlikte, aynı topic'e sahip ve vardiya değişim saatlerinize (örneğin 06:00, 14:00 ve 22:00) zamanlanmış bir inject node'u.
press1/# wildcard'ı yerine iki ayrı abonelik kullanın. Daha sonra KPI'ları aynı makine yolu altında yayınlayacaksınız ve bir wildcard kendi çıktınızı hesaplamaya geri besler.
OEE hesaplaması
Dört girişin tümünü beş çıkışlı tek bir function node'una bağlayın:
// Function node "OEE calculator" - Outputs değerini 5 yapın
const IDEAL_CYCLE_S = 2.0; // bu makine için parça başına ideal saniye
const now = Date.now();
function newShift() {
return { shiftStart: now, state: "UNKNOWN", since: now, runMs: 0,
lastTotal: null, lastGood: null, total: 0, good: 0 };
}
let s = flow.get("oee") || newShift();
const topic = String(msg.topic || "");
if (topic === "shift/reset") {
const keepState = s.state;
s = newShift();
s.state = keepState; // makine hâlâ aynı durumda
flow.set("oee", s);
return null;
}
if (topic.endsWith("/state")) {
const st = String(msg.payload).trim().toUpperCase();
if (s.state === "RUNNING") s.runMs += now - s.since;
s.state = st;
s.since = now;
flow.set("oee", s);
return null;
}
if (topic.endsWith("/count")) {
const total = Number(msg.payload.total);
const good = Number(msg.payload.good);
if (!Number.isFinite(total) || !Number.isFinite(good)) return null;
if (s.lastTotal !== null) {
// Geriye giden bir sayaç, PLC'nin onu sıfırladığı anlamına gelir
const dTotal = total >= s.lastTotal ? total - s.lastTotal : total;
const dGood = good >= s.lastGood ? good - s.lastGood : good;
s.total += dTotal;
s.good += Math.min(dGood, dTotal);
}
s.lastTotal = total;
s.lastGood = good;
flow.set("oee", s);
return null;
}
if (topic !== "tick") return null;
// Vardiyanın şu ana kadarki KPI'larını hesapla
const runMs = s.runMs + (s.state === "RUNNING" ? now - s.since : 0);
const plannedMs = now - s.shiftStart;
const availability = plannedMs > 0 ? runMs / plannedMs : 0;
const rawPerformance = runMs > 0 ? (IDEAL_CYCLE_S * 1000 * s.total) / runMs : 0;
const performance = Math.min(1, rawPerformance);
const quality = s.total > 0 ? s.good / s.total : 0;
const oee = availability * performance * quality;
if (rawPerformance > 1.05) {
node.warn("Performance above 100%: check IDEAL_CYCLE_S");
}
const pct = v => Math.round(v * 1000) / 10;
node.status({ fill: s.state === "RUNNING" ? "green" : "red", shape: "dot",
text: `${s.state} OEE ${pct(oee)}%` });
return [
{ payload: pct(availability) },
{ payload: pct(performance) },
{ payload: pct(quality) },
{ payload: pct(oee) },
{ topic: "connectmq/demo/a7f3k2/plant1/line1/press1/oee",
payload: { availability: pct(availability), performance: pct(performance),
quality: pct(quality), oee: pct(oee), total: s.total, good: s.good,
state: s.state, shiftStart: new Date(s.shiftStart).toISOString() },
retain: true }
];
Vardiyanın bilinen bir andan başlaması için deploy ettikten sonra bir kez Start new shift düğmesine tıklayın.
Widget'lar
- 1'den 4'e kadar olan çıkışlar, aralığı 0 ile 100, birimi
%olan dörtui-gaugenode'una gider. OEE için yaygın bir renk şeması 60'ın altında kırmızı, 60 ile 85 arasında sarı ve 85'in üstünde yeşildir; ancak kendi başlangıç seviyenizi yansıtan aralıklar seçin. -
- çıkış, topic ve retain alanları boş bırakılmış bir
mqtt outnode'una gider; böylece mesajdakimsg.topicvemsg.retaindeğerlerini kullanır. Makine durumunu da ekranda görmek istiyorsanızpayload.statedeğerini çıkaran bir change node'unun arkasına birui-textnode'u ekleyin.
- çıkış, topic ve retain alanları boş bırakılmış bir
/dashboard adresini açın ve ilk birkaç dakikada sayıların oturmasını izleyin. Vardiyanın başında tek bir duruş kullanılabilirliği büyük ölçüde dalgalandırır; bu matematiksel olarak doğrudur ve operatörler buna çabuk alışır.
OEE'yi Bozan Tuzaklar
- Yanlış ideal çevrim süresi. Performans yüzde 100'ün üzerinde duruyorsa ideal çevriminiz fazla yavaş tanımlanmıştır. Sadece sınırlayıp geçmeyin; koddaki sınır bir veri sorununu gizler.
- Planlı duruşları arıza süresi olarak saymak. Molalar, planlı bakım ve sipariş olmayan dönemler genellikle planlı üretim süresinin dışında tutulur. Tesisiniz bu tanımı kullanıyorsa bir
PLANNED_STOPdurumu ekleyin ve bu süreyiplannedMsdışında bırakın. - Yeniden başlatmalarda durumu kaybetmek. Flow context varsayılan olarak bellekte tutulur. Vardiya ortasındaki bir Node-RED yeniden başlatmasının KPI'ları sıfırlamaması için
oeenesnesini dosya tabanlı bir context deposunda saklayın. - Sırası bozuk mesajlar. Tek bir publisher ile QoS 1 üzerinden MQTT, topic başına sırayı korur; ancak state ve count ayrı topic'lerdir. Yukarıdaki gibi bir zamanlayıcıyla hesaplamak küçük zamanlama farklarını önemsiz kılar.
- Sayaç taşması. 16 bitlik PLC sayaçları 65.535'te başa döner. Sıfırlama mantığı bir taşmayı sıfırlama gibi ele alır; bu da en fazla bir aralıklık sayım kaybettirir.
Duruş nedenleri doğal bir sonraki adımdır: DOWN durumuna bir neden kodu ekleyin ve neden başına dakikaları biriktirin. Makine duruş takibi rehberi bu kodların nasıl yapılandırılacağını anlatır.
OEE Geçmişini Saklama
Göstergeler yalnızca mevcut vardiyayı gösterir. Vardiyaları karşılaştırmak için retained KPI mesajını her vardiya sonunda veya her dakika bir zaman serisi veritabanına yazın. Node-RED InfluxDB rehberi, tam olarak bu tür bir JSON'u hat ve makine gibi etiketlerle nasıl saklayacağınızı ve ardından grafiğe dökeceğinizi gösterir.
Tüm Hatta veya Tesise Ölçeklendirme
Makine başına bir function node'u bir pilot için yeterlidir. Tam bir hat için plant1/line1/+/state gibi tek seviyeli bir wildcard ile abone olun, topic seviyesiyle anahtarlanmış makine başına bir context nesnesi tutun ve her makinenin KPI'larını kendi topic'ine yayınlayın. Hesaplama yalnızca MQTT topic'lerine bağlı olduğundan, verinin bir PLC gateway'inden, bir ESP32 sayacından veya bir edge cihazından gelmesi fark etmez.
Broker'ın önemli olduğu yer de burasıdır. Düzinelerce makinenin, bir Node-RED sunucusunun, bir historian'ın ve belki bir SCADA istemcisinin aynı anda bağlı olduğu bir tesis, herkese açık bir test hizmeti yerine kimlik doğrulamalı güvenilir bir bulut MQTT broker'a ihtiyaç duyar. ConnectMQ, plant1/line1/press1/state gibi ISA-95 tarzı topic'leri tanır ve portalında cihazları bu seviyelere göre gruplar; bu da hangi makinelerin veri gönderdiğini görmeyi kolaylaştırır. ConnectMQ portalındaki eşik uyarı kuralları da seçtiğiniz bir sınırı aşan sayısal bir değeri işaretleyebilir; hesaplamanın kendisi ise Node-RED'in sorumluluğunda kalır. Bu altyapının hiçbirini kendiniz işletmek istemiyorsanız tam yönetilen bir MQTT hizmeti broker tarafını bakım listenizin dışında tutar. Broker ve Node-RED temelleri için Node-RED MQTT rehberiyle başlayın.
OEE Verilerinizi ConnectMQ'ya Taşıyın
app.connectmq.com adresinde kredi kartı gerektirmeyen ücretsiz Serverless planıyla kaydolun. Bir broker oluşturun, üretilen kullanıcı adı, parola ve client ID'yi makinelerinizde ve Node-RED'de kullanın ve port 8883 üzerinde TLS'e geçin. Bir sonraki vardiya değişiminden önce özel bir OEE hattınız çalışıyor olacak.
Sık Sorulan Sorular
Node-RED'de OEE hesaplamak için hangi verilere ihtiyacım var?
Zaman içindeki makine durumuna, toplam parça sayısına, sağlam parça sayısına ve ideal çevrim süresine ihtiyacınız var. Bu dört girdiyle Node-RED kullanılabilirliği, performansı, kaliteyi ve OEE'yi hesaplayabilir.
Makineler neden kümülatif sayaç yayınlamalı?
Kümülatif sayaçlar, her mesaj tam toplamı taşıdığı için hesaplamayı kaybolan veya geciken mesajlara karşı toleranslı hale getirir. Node-RED farkı hesaplar ve sıfırlamaları yönetir.
OEE paneli ne sıklıkla güncellenmeli?
Operatörler için 5 ila 30 saniyede bir yeterlidir. Her mesajda değil de bir zamanlayıcıyla hesaplamak, birçok makine aynı anda yayın yaptığında panelin akıcı kalmasını da sağlar.
Birden fazla makinenin OEE'sini tek sayfada gösterebilir miyim?
Evet. Wildcard aboneliği kullanın, makine başına bir context nesnesi tutun ve her makine için bir panel grubu ya da bir ui-template node'uyla oluşturulmuş bir tablo ekleyin.



