Etzel Art of Digital Manufacturing
Bize ulaşın
Lunex 1.6.0 kullanım kılavuzu

OPC UA tag'lerini tek abonelikle izleyin

Çok sayıda OPC UA node'unu tek route ile izleyin ve MQTT'ye yayımlayın.

Lunex’in OPC UA Subscription bileşeni (opcua-subscription) bir OPC UA sunucusundaki çok sayıda node’u tek bağlantı ve tek abonelikle izler. Her değer değişikliği akışa ayrı bir mesaj olarak girer. Yüzlerce veya binlerce tag için tek route yeterlidir.

Camel’in kendi OPC UA Client bileşeni (milo-client) bir endpoint’te tek node izler; her tag için ayrı route gerekir. Yalnız birkaç node izliyor veya node’a yazıyorsanız milo-client kullanın. Çok sayıda tag’i yalnız okumak için bu bileşeni kullanın. Camel’in bileşeni çoklu node desteği kazandığında Lunex bu bileşeni kaldırır ve geçişi bu sayfada açıklar.

Hazırlayacağınız bilgiler

BilgiÖrnek
Runtime’dan erişilebilen sunucu adresiopc.tcp://plc-gateway.example.test:4840
Güvenlik politikası ve kimlikNone ile kullanıcı/parola veya sertifika (keystore)
İzlenecek node ID’lerins=1;s=[Line1]Filler/Temperature

Adres proje runtime’ının ağından erişilebilir olmalıdır; kendi bilgisayarınızdan erişilebilmesi yetmez. Sunucu, bağlantı sırasında kendi adını içeren endpoint adresleri bildirir. Bu ad runtime’dan çözümlenemiyorsa Override Host (overrideHost) seçeneğini açın; bileşen bildirilen adres yerine sizin yazdığınız host’u kullanır.

Node listesini hazırlayın

Nodes alanı listeyi üç şekilde alabilir:

YazımNe zaman?
ns=1;s=[Line1]OEE, ns=1;s=[Line1]OrderBirkaç node; liste doğrudan route’ta, virgülle ayrılmış.
{{line1.nodes}}Liste application.properties içinde virgülle ayrılmış. Ortama göre değişen liste için {{configmap:line1-tags/nodes}} ile bir ConfigMap anahtarını da kullanabilirsiniz.
classpath:line-nodes.txtÇok sayıda node; liste projede bir dosyada, her satırda bir node.

Route içindeki liste YAML’da birden fazla satıra yayılabilir, ancak node’ları yine virgülle ayırın; satır sonu ayraç sayılmaz:

nodes: >-
  ns=1;s=[Line1]Filler/Temperature,
  ns=1;s=[Line1]Filler/State

Virgül içeren bir node ID’yi dosyaya yazın. Dosyada her satır tek bir node ID’dir.

Çok sayıda node için listeyi proje içinde bir metin dosyasında tutun, örneğin line-nodes.txt:

# Line1
ns=1;s=[Line1]OEE
ns=1;s=[Line1]Filler/Temperature
ns=1;s=[Line1]Filler/State

# Line2
ns=1;s=[Line2]Filler/Temperature
  • Her satır bir node ID’dir. Boş satırlar ve # ile başlayan satırlar yok sayılır; aynı node iki kez yazılırsa bir kez izlenir.
  • ns=<index>;... veya namespace URI’li nsu=<uri>;... biçimini kullanabilirsiniz. Namespace index’i sunucu yeniden yapılandırılınca değişebiliyorsa nsu= biçimi daha kalıcıdır.
  • Node ID’lerini OPC UA istemci aracınızın gezinme görünümünden veya sunucunun tag dışa aktarımından alın. Okunamayan bir satır route’u başlatmaz; hata mesajı satırı gösterir.

Listeyi sunucudan bir kez çıkarın

Çok sayıda node için listeyi Camel’in OPC UA Browser bileşeniyle (milo-browse) sunucudan çıkarabilirsiniz. Aşağıdaki route bir kez çalışır, [Line1] klasörünün altındaki node’ları gezer ve listeyi çalışmanın ekine yazar:

- route:
    id: browse-line-nodes
    from:
      uri: timer:browse-line-nodes
      parameters:
        repeatCount: 1
      steps:
        - to:
            uri: milo-browse:opc.tcp://plc-gateway.example.test:4840
            parameters:
              node: RAW(ns=1;s=[Line1])
              recursive: true
              depth: 5
              nodeClasses: Variable,Object
              allowedSecurityPolicies: None
              username: '{{secret:opcua-line/username}}'
              password: '{{secret:opcua-line/password}}'
        - setBody:
            groovy: "headers.CamelMiloNodeIds.join('\\n')"
        - bean:
            ref: lunexMonitor
            method: "appendAttachment('line-nodes.txt','text/plain',${body})"
  1. Route’u Run ile çalıştırın.
  2. Message Monitor’da çalışmayı açıp Attachments bölümünden line-nodes.txt içeriğini alın.
  3. İçeriği projede line-nodes.txt dosyasına kaydedin ve klasör satırlarını silin. Klasörlerin değeri yoktur; listede kalırlarsa her biri bir kez Bad_AttributeIdInvalid durumuyla gelir.
  4. Gezinme route’unu projeden kaldırın; liste her başlatmada yeniden çıkarılmamalıdır.

nodeClasses değerinde Object bulunmalıdır. Yalnız Variable yazılırsa gezinme alt klasörlere inmez ve yalnız ilk seviyedeki değişkenleri bulur.

Bileşen listeyi route başlarken okur. Listeyi (dosya, property veya ConfigMap) değiştirdikten sonra kaydedip Run’ı yeniden başlatın.

Route’u oluşturun

  1. Route’un girişi olarak OPC UA Subscription bileşenini seçin.
  2. Endpoint Uri alanına sunucu adresini yazın.
  3. Nodes alanına listeyi veya classpath:line-nodes.txt yazın.
  4. Güvenlik politikasını, kullanıcı adını ve parolayı girin. Parolayı bir Secret’tan referans verin (Secret oluşturun).
  5. Gerekirse yayın ve örnekleme aralıklarını ayarlayın.
SeçenekAnlamı
requestedPublishingIntervalSunucunun biriken değişiklikleri gönderme aralığı (ms). Varsayılan 1000.
samplingIntervalSunucunun her node’u örnekleme aralığı (ms). 0 sunucunun en hızlı aralığıdır.
queueSizeİki yayın arasında node başına tutulan değişiklik sayısı. Varsayılan 1: yalnız son değer gelir.
concurrentConsumersDeğişiklikleri işleyen thread sayısı. Varsayılan 1. Bir node’un değişiklikleri her zaman aynı thread’de, geliş sırasıyla işlenir; farklı node’lar paralel işlenir.
allowedSecurityPoliciesKabul edilen güvenlik politikaları, örneğin None veya Basic256Sha256. Boşsa sunucunun sunduğu en güvenli politika seçilir.
username, passwordKullanıcı kimliği. Boşsa anonim bağlanır.
keyStoreUrl, keyAlias, keyStorePassword, keyPasswordİmzalı/şifreli güvenlik politikası için istemci sertifikası.
monitorFilterType, dataChangeFilter...Deadband gibi değişiklik filtreleri; tüm node’lara uygulanır.

Sunucu istenen aralıkları kendi sınırlarına göre değiştirebilir. Gerçekte kullanılan değerler Log’da görünür:

Subscribed 28 of 28 nodes at opc.tcp://...: publishing interval 500.0 ms, sampling interval 250.0 ms

Mesajın içeriği

Mesaj gövdesi node’un değeridir: sayı, metin, mantıksal değer, tarih (Instant) veya dizi için liste. Diğer bilgiler header’lardadır:

Headerİçerik
CamelMiloNodeIdNode ID, listede yazdığınız biçimde
CamelMiloStatusDurum adı, örneğin Good, Bad_NotConnected, Bad_NodeIdUnknown
CamelMiloSourceTimestampDeğerin kaynakta oluştuğu zaman
CamelMiloServerTimestampSunucunun değeri aldığı zaman

milo-client gövdeye OPC UA DataValue nesnesini koyar; bu bileşen değeri doğrudan gövdeye, durumu ve zamanları header’lara koyar.

Durum Good değilse gövde boş olabilir. Akışınızda durumu kontrol edin ve değeri buna göre yayımlayın.

Bağlantı kesildiğinde

  • Bağlantı koptuğunda her node için bir kez Bad_NotConnected durumlu mesaj gelir. Böylece hedef sistem değerin güncel olmadığını bilir.
  • Bileşen bağlantıyı kendisi yeniden kurar ve aboneliği aktarır. Sunucu aboneliği kaybetmişse yeniden oluşturur. Run’ı yeniden başlatmanız gerekmez.
  • Bağlantı yeniden kurulunca her node’un güncel değeri tekrar gönderilir.
  • Sunucuda bulunmayan bir node için bir kez Bad_NodeIdUnknown gelir; diğer node’lar izlenmeye devam eder.
  • Sunucuya hiç bağlanılamazsa bileşen 10 saniyede bir yeniden dener.

Örnek: tag’leri MQTT’ye yayımlayın

Aşağıdaki route her değişikliği node ID’sinden türetilen bir MQTT topic’ine JSON olarak yayımlar. ns=1;s=[Line1]Filler/Temperature node’u etzel/izmir/packaging/Line1/Filler/Temperature topic’ine gider:

- route:
    id: line-tags-to-mqtt
    from:
      uri: opcua-subscription:opc.tcp://plc-gateway.example.test:4840
      parameters:
        nodes: classpath:line-nodes.txt
        allowedSecurityPolicies: None
        username: '{{secret:opcua-line/username}}'
        password: '{{secret:opcua-line/password}}'
        requestedPublishingInterval: 500
        samplingInterval: 250
        concurrentConsumers: 4
      steps:
        - script:
            groovy: |-
              def message = exchange.message
              String node = message.getHeader('CamelMiloNodeId')
              message.setHeader('CamelPahoMqtt5OverrideTopic',
                  'etzel/izmir/packaging/' + node.substring(node.indexOf('[') + 1).replace(']', '/'))
              def value = message.body
              message.body = groovy.json.JsonOutput.toJson([
                  value: value instanceof java.time.Instant ? value.toString() : value,
                  status: message.getHeader('CamelMiloStatus'),
                  sourceTime: message.getHeader('CamelMiloSourceTimestamp')?.toString()])
        - to:
            uri: paho-mqtt5:etzel/izmir/packaging/unrouted
            parameters:
              brokerUrl: tcp://mqtt.example.test:1883
              clientId: lunex-line-tags
              qos: 0
              retained: true

Yayımlanan mesaj:

{"value":23.96,"status":"Good","sourceTime":"2026-10-12T16:24:13.889263Z"}
  • Tek Groovy adımı her değişiklik için hem topic’i hem JSON gövdesini hazırlar. Yoğun tag trafiğinde ayrı ifade ve dönüşüm adımlarından belirgin biçimde daha az işlemci harcar.
  • concurrentConsumers: 4 değişiklikleri dört thread’de yayımlar. Her topic değerlerini yine sırayla alır, çünkü bir node’un değişiklikleri hep aynı thread’de işlenir.
  • Topic ifadesi bu örnekteki node adı biçimine göredir (ns=1;s=[Hat]Hücre/Tag). Kendi sunucunuzun node adlarına göre değiştirin.
  • retained: true, yeni bağlanan bir abonenin her topic’in son değerini hemen almasını sağlar.
  • qos: 0 ile route broker’ın onayını beklemeden bir sonraki değişikliğe geçer. Kaybolan bir değerin yerini o tag’in sonraki değişikliği alır. qos: 1 ve MQTT bileşeninin varsayılanı olan qos: 2 her mesaj için broker onayını bekler; retained mesajlarla bu bekleme yoğun tag trafiğinde akışı belirgin biçimde yavaşlatır. Her mesajın ulaşması gereken iş olayları için QoS 1 kullanın.
  • Bad_NotConnected mesajları "value":null ile yayımlanır; aboneler son iyi değeri saklayıp durumu gösterebilir.
  • Groovy betiği tarih değerlerini ISO-8601 metnine çevirir.

Doğrulayın

  1. Run ile projeyi başlatın.
  2. Log’da Subscribed N of N nodes satırını arayın. N’ler farklıysa eksik node’lar için Bad_... durumlu mesajlara bakın.
  3. MQTT istemcinizle etzel/izmir/packaging/# topic’ine abone olup değerlerin geldiğini doğrulayın.

Sınırlar

  • Bileşen yalnız değer değişikliklerini izler. Node’a yazma, tek seferlik okuma veya gezinme (browse) için Camel’in milo-client ve milo-browse bileşenlerini kullanın.
  • Bir route bir sunucuya bağlanır. Birden fazla sunucu için her sunucuya bir route oluşturun.
  • Değişiklik filtresi ve aralıklar listedeki tüm node’lara uygulanır. Farklı aralık gereken node’ları ayrı listeye ve ayrı route’a koyun.
  • Tag yayımlayan projenin Log level değerini None yapın. Info her değişikliği Message Monitor’e ayrı bir çalışma olarak kaydeder ve yoğun tag trafiğinde akışı yavaşlatır. Ayar için Kayıt seviyesi sayfasına bakın.
  • Tag yayımlayan projenin application.properties dosyasına camel.trace.standby=false ekleyin. Run podunda Camel, trace kapalıyken de her mesajı trace geçmişi için kaydeder; yoğun tag trafiğinde bu işlemcinin önemli bir kısmını harcar. Bu ayarla Run podu trace geçmişi tutmaz; trace gerektiğinde satırı kaldırıp projeyi yeniden çalıştırın. Build ile dağıtılan podlar bu kaydı zaten yapmaz.
  • Tek thread’li bir route saniyede birkaç bin değişiklik yayımlar. Daha yüksek hız için concurrentConsumers değerini artırın, örneğin 4. Route yine yetişemezse sunucu her node’un en son değerini gönderir ve ara değerler atlanır.
  • Farklı node’ların değişiklikleri paralel işlendiğinden aralarındaki sıra korunmaz. Değişiklikleri node’lar arası geliş sırasıyla işlemesi gereken bir akışta (örneğin birden fazla tag’den durum hesaplayan bir betik) concurrentConsumers değerini 1 bırakın.

Lunex’i kendi entegrasyonunuzla görün

Kılavuzda okuduklarınızı kendi sistemlerinizle deneyelim. Demo için bize yazın.