MergenHub Envest
Ana sayfa/Dokümanlar/Mobil ve cihaz şablonları

Cihaz şablonu (paket) oluşturma

.mhpkg.json biçimi: parametreler, kanal-cihaz-tag, hesaplanan tag ve ifade fonksiyonları, alarmlar, sunucu ve telefon ekran takımları, doğrulama, tam örnek, yapay zekâ becerisi, kütüphaneye cihaz ekletme.

Bir cihaz şablonu (MergenHub paketi), bir cihazı tüm ayrıntısıyla taşıyan tek bir JSON dosyasıdır: kanal ve sürücü ayarları, cihaz, register haritası (tag'ler), hesaplanan tag'ler, alarmlar ve operatör ekranları. Kurulumda yalnız sahaya özgü bilgiler (IP adresi, port, unit ID…) sorulur; geri kalan her şey hazır gelir. Dosya uzantısı .mhpkg.json'dur.

Bu sayfa bir paketin nasıl hazırlandığını, alanlarını ve kurulumda neler olduğunu anlatır.

Paketler nerede kullanılır

  • MergenHub web arayüzü — Cihaz Kütüphanesi penceresi (proje ağacının başlığındaki kitap simgesi, Bağlantılar görünümündeki Cihaz Kütüphanesi düğmesi ya da SCADA'da yeni ekran seçicisindeki kart). Kütüphaneden kurar; Dosyadan içe aktar ile elinizdeki .mhpkg.json dosyasını kurar.
  • MergenHub Mobil — Cihaz ekle sihirbazı (kütüphane, şablonlarım, dosya, pano, QR, adres), Şablonlar sayfası ve Paket / şablon içe aktar. Bkz. MergenHub Mobil.
  • Cihaz Kütüphanesi — Envest'in hazırlayıp test ettiği paketler sitede yayımlanır ve uygulamalar bunları herkese açık bir API'den okur: GET /api/v1/library (katalog), GET /api/v1/library/{slug} (tek cihaz), GET /api/v1/library/{slug}/package (paket dosyası).
MergenHub web arayüzünde Cihaz Kütüphanesi penceresi
MergenHub web arayüzünde Cihaz Kütüphanesi penceresi

İnternete çıkamayan bir sunucuda paketi siteden indirip Dosyadan içe aktar ile kurun.

Dosyadan içe aktar — kurulum bilgileri ve denetim sonucu
Dosyadan içe aktar — kurulum bilgileri ve denetim sonucu

Hızlı başlangıç

En kolay yol, çalışan bir cihazdan başlamaktır:

  1. MergenHub Mobil'i telefon modunda açın, cihazı kanal, cihaz ve birkaç tag'iyle tanımlayın, değerlerin geldiğini görün.
  2. Kanallar sekmesinde cihazın ⋯ menüsünden Şablon olarak kaydet / paylaş'ı seçin. Ad, açıklama, üretici ve model girin; ekranlar da gelsin istiyorsanız Ekranları da al'ı açık bırakın.
  3. Dosya olarak paylaş ya da Panoya kopyala ile paketi alın. Cihaz kimliğindeki ve ayarlardaki IP adresleri kendiliğinden {{ip}} parametresine çevrilmiştir.
  4. Dosyayı bir metin düzenleyicide ya da bir yapay zekâyla düzenleyin (tag ekleyin, açıklama yazın, alarm ve ekran ekleyin). Dışa aktarılan dosyanın guide bölümünde biçim kuralları, kullanılan sürücünün ayar anahtarları, adres örnekleri ve sembol listesi yazılıdır.
  5. Paketi geri alın: telefonda Cihaz ekle › Dosya, pano, QR ya da adres, sunucuda Cihaz Kütüphanesi › Dosyadan içe aktar.
MergenHub Mobil'de şablon olarak dışa aktarma
MergenHub Mobil'de şablon olarak dışa aktarma

Tüm projeyi paket yapmak için telefonda Daha › Proje › Projeyi dışa aktar kullanılır (kind: "project").

Dosya yapısı

Paket tek bir JSON nesnesidir:

{
  "format": "mergenhub-package",
  "formatVersion": 1,
  "kind": "template",
  "meta": { "name": "…" },
  "parameters": [],
  "channels": [],
  "derived": [],
  "alarms": [],
  "screens": [],
  "notes": "…"
}
AlanZorunluAçıklama
formatevetHer zaman "mergenhub-package"
formatVersionönerilirŞu an 1; uygulamanın bildiğinden büyükse paket reddedilir
kindevet"template" (cihaz şablonu, kurulumda parametre sorulur) ya da "project" (tüm proje)
metaevetPaketin adı ve tanıtım bilgileri
parametershayırKurulumda sorulacak değerler
channelsevetKanal → cihaz → tag ağacı (en az bir kanal)
derivedhayırHesaplanan (gelişmiş) tag'ler
alarmshayırAlarm tanımları
screenshayırOperatör ekranları
noteshayırCihazın ne işe yaradığını anlatan serbest metin (Markdown)
guidehayırDışa aktarırken yazılan açıklama bölümü; içe alırken yok sayılır

Bir cihaz şablonunda tek kanal ve tek cihaz bulunur. Yalnız bu durumda kurulumda kanal ve cihaz adı sorulur ve ad değişince yollar taşınır.

meta

AlanAçıklama
namePaketin görünen adı (zorunlu), ör. "Örnek EA-100 Enerji Analizörü"
descriptionBir iki cümlelik özet
vendor, model, versionÜretici, model ve cihaz yazılım sürümü; listelerde ve aramada görünür
authorHazırlayan
keywordsArama için anahtar kelimeler (dizi)
homepageÜrün sayfası adresi
createdAt, createdWithDışa aktarırken kendiliğinden yazılır

Parametreler ve yer tutucular

parameters kurulumda kullanıcıya sorulacak alanlardır. Paketin herhangi bir yerindeki dizge değerde {{anahtar}} yazılan yere kullanıcının girdiği değer konur.

"parameters": [
  { "key": "ip", "label": "IP adresi", "type": "text", "required": true, "placeholder": "192.168.1.50" },
  { "key": "port", "label": "Port", "type": "number", "default": 502, "group": "Bağlantı" },
  { "key": "unit", "label": "Unit ID", "type": "number", "default": 1, "group": "Bağlantı" }
]
AlanAçıklama
keyHarf ya da _ ile başlar; harf, rakam ve _ içerir (ör. ip, port, unit, fins_node)
labelFormda görünen ad
typetext (varsayılan), number ya da select
defaultVarsayılan değer
requiredtrue ise boş bırakılamaz
placeholder, hintAlan içi örnek ve alt açıklama
groupFormda başlık; aynı gruptakiler birlikte gösterilir
optionsselect için [{ "value": 1, "label": "TCP" }, …]

Kurallar:

  • Yer tutucu yalnız dizge değerlerin içinde çalışır. Sayısal bir ayarı parametreye bağlamak için dizge yazın: "modbus_ethernet.DEVICE_ETHERNET_PORT_NUMBER": "{{port}}". Kurulumda sürücünün sayısal ayarları sayıya çevrilir.
  • Cihaz kimliği tipik olarak parametrelerden kurulur: "id": "<{{ip}}>.{{unit}}".
  • Kurulumdan sonra doldurulmamış bir {{…}} kalırsa kurulum açılmaz.
  • IP adresinin varsayılanını boş bırakıp required: true yapın; örnek adresi placeholder'a yazın. Böylece kullanıcı adresi girmeden kuramaz.

Kanallar, cihazlar ve tag'ler

"channels": [
  {
    "name": "Enerji",
    "driver": "Modbus TCP/IP Ethernet",
    "settings": {},
    "devices": [
      {
        "name": "Analizor1",
        "id": "<{{ip}}>.{{unit}}",
        "scanMs": 1000,
        "timeouts": { "connectS": 3, "requestMs": 1000, "retries": 3 },
        "settings": { "modbus_ethernet.DEVICE_ETHERNET_PORT_NUMBER": "{{port}}" },
        "tags": [
          { "name": "GerilimL1", "address": "30001", "type": "Float", "access": "read", "scanMs": 1000, "units": "V" }
        ],
        "groups": []
      }
    ]
  }
]

Kanal

AlanAçıklama
nameKanal adı (zorunlu, nokta içeremez)
driverSürücünün tam adı (aşağıdaki tablo)
settingsKanal düzeyindeki sürücü ayarları (Kepware uyumlu anahtarlar)
descriptionAçıklama
devicesCihaz dizisi (zorunlu)

Cihaz

AlanVarsayılanAçıklama
name—Cihaz adı (zorunlu, nokta içeremez)
idsürücüye göreCihaz kimliği; biçimi sürücüye bağlıdır
description—Açıklama
enabledtruefalse ise cihaz taranmaz
scanMs1000Cihaz tarama hızı (ms)
scanMode40 istemciye uy, 1 en hızlı, 2 sabit hız, 3 talep, 4 tag hızına uy
timeouts3 / 1000 / 3connectS bağlantı zaman aşımı (sn), requestMs istek zaman aşımı (ms), retries deneme sayısı
settingssürücü varsayılanlarıCihaz düzeyindeki sürücü ayarları
tags, groups—Tag'ler ve tag grupları

Tag

AlanVarsayılanAçıklama
name—Tag adı (zorunlu, nokta içeremez, cihaz ya da grup içinde tekil)
address—Sürücünün adres sözdizimiyle adres (zorunlu)
typeDefaultVeri tipi (aşağıda)
accessreadread ya da readwrite
scanMs1000Tag tarama hızı (ms)
description—Açıklama; 6 karakter ve altıysa uygulamada birim olarak gösterilir
units—Birim; description boşsa açıklama olarak kullanılır
scaling—Ölçekleme (aşağıda)

Veri tipleri: Default, Boolean, Char, Byte, Short, Word, Long, DWord, Float, Double, String, BCD, LBCD, Date, LLong, QWord. Default sürücünün adrese göre seçtiği tiptir.

Ölçekleme ham değeri mühendislik birimine çevirir; yazarken ters uygulanır:

"scaling": { "type": "linear", "rawLow": 0, "rawHigh": 10, "low": 0, "high": 1, "resultType": "Double", "units": "kWh" }

type linear ya da sqrt (karekök); rawLow/rawHigh ham aralık, low/high ölçekli aralık; resultType ölçekli veri tipi (varsayılan Double); clampLow, clampHigh sınırda kırpar, negate işaret çevirir.

Gruplar tag'leri cihaz içinde klasörler; iç içe olabilir. Gruptaki tag'in yolu Kanal.Cihaz.Grup.Tag olur.

"groups": [ { "name": "Enerji", "description": "Sayaçlar", "tags": [ … ], "groups": [ … ] } ]

Sürücüler ve adres sözdizimi

driver alanına sürücünün tam adı yazılır. Adres sözdizimi ve ayar anahtarları MergenHub sunucusu ile MergenHub Mobil'de aynıdır; ayrıntılar için Protokol sürücüleri.

Sürücü (driver)Cihaz kimliği (id)Adres örnekleri
Simulatorcihaz numarası, ör. 1SINE:10:0:100, RAMP:30:0:500, RANDOM:20:80, REG:1
Modbus TCP/IP Ethernet<IP>.Unit, ör. <192.168.1.10>.140001 holding, 30001 giriş register, 00001 bobin, 10001 ayrık giriş, 40001.3 bit, 40010.16H dize
Modbus RTU Serial, Modbus ASCII Serialköle adresi 1–247Modbus TCP ile aynı
Siemens S7 TCP/IP<IP>.Rack.Slot, ör. <192.168.0.1>.0.1DB1.DBD4, DB1.DBW2, DB1.DBB0, DB1.DBX0.3, MW10, I0.0, Q0.0
OMRON FINS Ethernet<IP>.Düğüm, ör. <192.168.1.10>.1D100, D0.05, CIO10, W5.00, H2, A3, E100
OMRON NJ Ethernet<IP>PompaDurum, Hat1.Vana[3], Matris[1,2], Sayac.5
MQTT Clientbroker host:port (kanalda broker verilmişse yok sayılır)sensors/temp, sensors/pump1:/flow, plant/csv;idx=2;sep=;
DNP Client Ethernetoutstation IPAI0, BI5, CTR2, AO1, BO3, 30.1.51.Value
IEC 60870-5-104 ClientRTU IP100, IOA100, M_ME_NC.100.VALUE, C_SC_NA.3000.DIRECTVALUE
IEC 61850 MMS ClientIED IPLD0/MMXU1.MX.TotW.mag.f, LD0/XCBR1.ST.Pos.stVal
OPC UA Clientkullanılmaz (endpoint kanal ayarında)ns=2;s=Kanal.Cihaz.Tag, ns=2;i=1001

Sık kullanılan ayar anahtarları:

  • Modbus TCP (cihaz): modbus_ethernet.DEVICE_ETHERNET_PORT_NUMBER (502), modbus_ethernet.DEVICE_ZERO_BASED_ADDRESSING, modbus_ethernet.DEVICE_FIRST_WORD_LOW (32 bitte word sırası), modbus_ethernet.DEVICE_HOLDING_REGISTERS (blok boyutu, 1–125).
  • Modbus RTU/ASCII (cihaz): servermain.DEVICE_ETHERNET_COMMUNICATIONS_IP ve servermain.DEVICE_ETHERNET_COMMUNICATIONS_PORT (seri sunucu), modbus.DEVICE_… anahtarları.
  • Siemens S7 (cihaz): siemens_tcpip_ethernet.DEVICE_COMMUNICATIONS_PORT_NUMBER (102), siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_CPU_RACK, …_CPU_SLOT, model için servermain.DEVICE_MODEL (0 S7-200, 1 S7-300, 2 S7-400, 3 S7-1200, 4 S7-1500).
  • OMRON FINS: kanalda omron_fins_ethernet.CHANNEL_PORT_NUMBER (9600); cihazda omron_fins_ethernet.DEVICE_PROTOCOL (0 UDP, 1 TCP) ve düğüm numaraları.
  • MQTT (kanal): mqtt.BROKER_HOST, mqtt.PORT, mqtt.USERNAME, mqtt.PASSWORD, mqtt.QOS, mqtt.TRANSPORT.
  • OPC UA istemci (kanal): opcuaclient.CHANNEL_UA_SERVER_ENDPOINT_URL.

Yazılmayan ayar sürücünün varsayılanını alır. Bir sürücünün tüm ayar anahtarları, o sürücüyle dışa aktarılmış bir paketin guide.drivers bölümünde açıklamalarıyla yazılıdır.

Hesaplanan tag'ler

derived dizisi başka tag'lerden hesaplanan tag'leri tanımlar. Kurulunca yolları _AdvancedTags.<ad> olur; ekranlar ve alarmlar bu yolu kullanır.

"derived": [
  {
    "name": "Analizor1_GorunurGuc",
    "type": "Derived",
    "expression": "ROUND({Enerji.Analizor1.GerilimL1} * {Enerji.Analizor1.AkimL1} / 1000, 2)",
    "scanRateMs": 1000,
    "description": "Görünür güç (kVA)"
  }
]
AlanAçıklama
nameAd; sunucu genelinde tekildir, cihaz adıyla başlamalıdır (<Cihaz>_…)
typeDerived (ifade), Totalizer, Average, Maximum, Minimum
expressionDerived'da ifade; diğerlerinde kaynak tag'in yolu (süslü parantezsiz)
sampleSizeOrtalama / maks / min için örnek sayısı (varsayılan 10)
scanRateMsGüncelleme hızı (ms, varsayılan 1000)
enabledVarsayılan true
descriptionAçıklama
dataTypeSunucuda sonuç veri tipi kodu (varsayılan 9 = Double); telefon yok sayar

Totalizer, değer × saniye toplar; m³/h girişte sonucu 3600'e bölün.

Fonksiyon başvurusu

İfadede tag referansı {Kanal.Cihaz.Tag} biçimindedir (grup varsa {Kanal.Cihaz.Grup.Tag}). İşleçler: + - * / %, karşılaştırma <, <=, >, >=, ==, != (doğruysa 1, yanlışsa 0), mantık &&, ||, ! ve parantez. Ondalık ayıracı her zaman noktadır (1.5). Fonksiyon adları büyük/küçük harf duyarsızdır; argümansız fonksiyonlar da parantez ister (PI()). İfade en çok 8000 karakter olabilir. Fonksiyon listesi sunucu ve telefonda aynıdır.

FonksiyonAçıklama
ABS(x)Mutlak değer
SQRT(x)Karekök (negatif girişte 0)
POW(x, y)x üssü y
EXP(x), LN(x)e üssü x, doğal logaritma
LOG(x), LOG(x, taban)10 tabanlı ya da verilen tabanda logaritma
ROUND(x), ROUND(x, basamak)Yuvarlama (yarı yukarı; basamak 0–15)
FLOOR(x), CEIL(x)Aşağı / yukarı yuvarlama
MOD(a, b)Bölümden kalan (b = 0 ise 0)
SIGN(x)İşaret: −1, 0, 1
MIN(a, b, …), MAX(a, b, …)En küçük / en büyük
AVG(a, b, …), SUM(a, b, …)Ortalama / toplam
IF(koşul, a, b)Koşul 0 değilse a, değilse b
CLAMP(x, alt, üst)Aralığa sıkıştırma
MAP(x, girişAlt, girişÜst, çıkışAlt, çıkışÜst)Doğrusal ölçekleme
LERP(a, b, t)a ile b arasında doğrusal ara değer
POLY(x, c0, c1, c2, …)Polinom: c0 + c1·x + c2·x² + …
HYPOT(a, b)√(a² + b²)
SIN, COS, TAN, ASIN, ACOS, ATANTrigonometri (radyan)
ATAN2(y, x)İki argümanlı arktanjant
SINH, COSH, TANHHiperbolik fonksiyonlar
DEG(x), RAD(x)Radyandan dereceye, dereceden radyana
PI(), E()Sabitler
RANDOM(), RANDOM(üst), RANDOM(alt, üst), RND(…)Rastgele sayı; yalnız test için

Örnekler: ({K.C.A} + {K.C.B}) / 2, IF({K.C.Basinc} > 6, 1, 0), MAX({K.C.Seviye} - {K.C.Statik}, 0), MAP({K.C.Ham}, 4, 20, 0, 10).

Alarmlar

"alarms": [
  { "name": "Yüksek gerilim L1", "tag": "Enerji.Analizor1.GerilimL1", "conditionType": "Hi", "limit": 250,
    "deadband": 2, "severity": 700, "message": "Faz 1 gerilimi 250 V üstünde", "enabled": true }
]
AlanVarsayılanAçıklama
name—Alarm adı
tag—Paketteki bir tag'in tam yolu ya da _AdvancedTags.<ad> (zorunlu, pakette bulunmalı)
conditionType—HiHi, Hi, Lo, LoLo, DevHi, DevLo (sapma), RocHi, RocLo (değişim hızı, birim/sn)
limit—Sınır
setpoint0Sapma alarmlarında ayar noktası
deadbandType, deadbandAbsolute, 0Ölü bant: None, Absolute, Percent
rangeLow, rangeHigh0, 100Yüzde ölü bant için aralık
onDelaySec, offDelaySec0Açılma ve kapanma gecikmesi (sn)
severity5001–1000; 800 ve üstü kritik
message, area—İleti ve alan
enabledtrueEtkin

Ekranlar

Ekranlar sunucudaki SCADA ekranlarıyla aynı yapıdadır. Bir ekran bir koordinat alanında (width × height) konumlanmış nesnelerden (widgets) oluşur.

AlanAçıklama
idPaket içinde tekil kimlik (zorunlu); kurulumda yenilenir, bağlar taşınır
nameEkran adı; cihaz adını içerirse kurulumda yeni ada çevrilir
target"server" (yalnız sunucuya kurulur), "phone" (yalnız telefon moduna kurulur) ya da yok (ikisine de)
parentIdÜst ekranın id'si; boşsa ana ekrandır
orderAlt ekranlar arasındaki sıra
width, heightKoordinat alanı; telefon dikey 400 × 700 (uzun ekranda yükseklik artar), sunucu ör. 1200 × 700
backgroundZemin rengi (#eef2f7); telefon ekranında boş bırakılırsa temaya uyar
group, zoneIdSunucuda ekran grubu ve bölge; şablonlarda boş bırakın
widgetsNesneler

İki ekran takımı

Bir cihaz için iyi bir paket iki takım taşır:

  • Sunucu takımı ("target": "server") — tek bir ana ekran (parentId boş) ve onun altında ayar ekranları (parentId = ana ekranın id'si). Web arayüzünde ana ekran listede görünür, ayar ekranları onun alt dalındadır. Ana ekrandan ayar ekranlarına ve geri düğmeler (nav) koyun.
  • Telefon takımı ("target": "phone") — dikey bir Özet ekranı (ölçümler, kumanda ve ayar ekranlarına düğmeler) ve onun alt ekranları olarak tek sütunlu ayar ekranları. Telefon modunda Özet açılınca üstte Özet ve alt ekranlardan oluşan bir sekme şeridi çıkar. Ekran adlarını <Cihaz> — Özet, <Cihaz> — Ayarlar biçiminde verin; sekmelerde "—" işaretinden sonraki kısım görünür.

Kurulumda yalnız hedefe uyan takım kurulur. Diğer takımdaki bir üst ekrana bağlı ekran ana ekran olur; diğer takıma giden nav bağları kaldırılır. target vermezseniz ekran iki yere de kurulur.

Nesneler

{ "id": "w2", "type": "display", "x": 24, "y": 80, "w": 220, "h": 80,
  "tag": "Enerji.Analizor1.GerilimL1", "props": { "label": "Gerilim L1", "units": "V", "decimals": 1 } }
AlanAçıklama
idPaket içinde tekil (ör. w1, w2 …)
typeNesne tipi (aşağıda)
x, y, w, hKonum ve boyut (ekran koordinatlarında)
rotDöndürme açısı (derece)
tagBağlı tag yolu: Kanal.Cihaz.Tag ya da _AdvancedTags.<ad>
propsTipe göre özellikler
animsKoşullu kurallar
onClick, navDokununca başka ekrana geçmek için "onClick": "nav" ve "nav": "<ekran id>"
popupScreenAçılır pencere olarak gösterilecek ekran (sunucu)
TipNe yaparÖnemli props
displayDeğer göstergesilabel, units, decimals, color, fontSize
labelSabit yazı (tag yok)text, fontSize, color, align
lampLambalabel, onColor, offColor, onText, offText, blinkOn, onOp/onA/onB
buttonBasınca onValue/offValue yazarlabel, onValue, offValue, onText, offText, onColor, offColor
switchAnahtar (buton gibi yazar)label, onValue, offValue, onText, offText, onColor
radioSeçim düğmesilabel, onValue, offValue
inputDeğer girişi (yazılabilir tag)label, decimals
sfieldAyar satırı: etiket + değer (+ birim)label, units, decimals, editable, step
gaugeKadranlabel, min, max, units, decimals, fillColor
tank, levelbarDepo seviyesi, seviye çubuğulabel, min, max, units, decimals, fillColor
pump, motor, fan, valveMakine simgeleri (çalışırken döner / renk değiştirir)label, onColor, offColor, onText, offText, spin, blinkOn, onOp/onA/onB
pipeBoru; akış varken renklenirthickness, flowColor, onOp/onA
rectPanel / dikdörtgen (tag yok)fill, stroke, radius
imageResim (tag yok)src (data URI ya da adres)
svgSembol kütüphanesinden nesnelib2 (sembol kimliği), label, onOp/onA/onB, onColor, offColor

Açık durumu. Lamba, makine ve sembollerde nesnenin ne zaman "açık" sayılacağı onOp (gt, ge, eq, ne, lt, le, between), onA ve onB ile verilir; verilmezse değer 0,5'ten büyükse açıktır.

Koşullu kurallar (anims): { "kind": "color", "tag": "", "op": "gt", "a": 80, "b": null, "p2": "#ef4444" }. kind: color (rengi p2 yapar), blink (yanıp söner), visible (koşul doğruyken nesneyi gizler), level (dolum: a en az, b en çok, p2 renk, op always). tag boşsa nesnenin kendi tag'i kullanılır.

Semboller. svg nesnesinin lib2 alanı yerleşik sembol kütüphanesindeki kimliktir (ör. en-pumps/en_pump_submersible_1, en-meters/en_flowmeter_1, pumps_centrifugal_pump_4). Kimliklerin tam listesi dışa aktarılan paketlerin guide.symbols bölümündedir.

Sunucu ekranlarında web SCADA editörünün diğer nesne tipleri de kullanılabilir; telefon bunları soluk kutu olarak gösterir ve denetim uyarı verir. İki yerde çalışması gereken ekranlarda tablodaki tipleri kullanın.

Adlandırma ve kurulumda yeniden adlandırma

  • Kanal, cihaz, grup ve tag adlarında nokta (.) kullanılmaz; nokta yol ayıracıdır. Adlar bulunduğu düzeyde tekil olmalıdır (büyük/küçük harf duyarsız).
  • Tag yolu Kanal.Cihaz.Tag (grupta Kanal.Cihaz.Grup.Tag) biçimindedir. Ekranlarda, alarmlarda ve ifadelerde her zaman tam yol yazılır.
  • Cihaz adı yalnız kanal içinde tekildir; aynı paket aynı kanala farklı cihaz adlarıyla birçok kez kurulabilir.
  • Hesaplanan tag adları sunucu genelinde tekildir. Bu yüzden her hesaplanan tag'in adını cihaz adıyla başlatın: Analizor1_GorunurGuc. Kurulumda cihaz adı değişince bu ön ek de değişir (Analizor2_GorunurGuc) ve aynı paket ikinci kez çakışmadan kurulur.

Kurulumda kullanıcı kanal ve cihaz adını değiştirirse paket şöyle güncellenir:

  1. Tüm Kanal.Cihaz ile başlayan yollar (ekran nesnelerinin tag'i, kurallar, alarm tag'leri, ifadelerdeki {…} referansları) yeni ada taşınır.
  2. Adı <EskiCihaz>_ ile başlayan hesaplanan tag'ler <YeniCihaz>_ ile yeniden adlandırılır; _AdvancedTags.… referansları da taşınır.
  3. Ekran adlarında ve label nesnelerinin text'inde geçen eski cihaz adı (tam kelime olarak, en az 3 karakterse) yeni adla değiştirilir.

Kurulumda denetlenen çakışmalar:

  • Kanal adı hedefte başka bir sürücüyle kullanılıyorsa kurulum açılmaz; aynı sürücüyle kullanılıyorsa cihaz mevcut kanala eklenir.
  • Kanalda aynı adla cihaz varsa kurulum açılmaz; uygulama boştaki ilk numaralı adı önerir (Analizor1 → Analizor2).
  • Hesaplanan tag adı hedefte varsa kurulum açılmaz; farklı bir cihaz adı çözer.

Doğrulama ve sık hatalar

MergenHub Mobil paketi kurmadan önce denetler; sorunlar kurulum kartında listelenir. Web arayüzünün Dosyadan içe aktar'ı parametre, ad ve çakışma denetimlerini yapar ama adresleri sürücüyle doğrulamaz; yeni bir paketi önce telefonda denemek iyi bir alışkanlıktır.

Hatalar (kurulum açılmaz):

  • Bu bir MergenHub paketi değil — format alanı eksik ya da yanlış.
  • JSON hatası (satır …, sütun …) — sözdizimi hatası; konum ve çevresindeki metin gösterilir.
  • Bilinmeyen sürücü "…" — driver alanında sürücünün tam adını yazın (ör. Modbus TCP/IP Ethernet).
  • Adres geçersiz (…) — adres sürücünün sözdizimine uymuyor; ileti nedenini söyler (ör. Modbus'ta alan rakamı 0, 1, 3 ya da 4 olmalı).
  • Bilinmeyen veri tipi "…" — tip adları yukarıdaki listedeki gibi yazılır (Float, float32 değil).
  • access "read" ya da "readwrite" olmalı.
  • … adı tekrar ediyor, … adında nokta olamaz, … adı boş.
  • Alarm …: Tag bulunamadı — alarmın tag'i pakette yok.
  • Geçersiz parametre anahtarı — anahtar harf, rakam ve _ dışında karakter içeriyor.
  • {{…}} için değer girilmedi — bir yer tutucunun parametresi yok ya da boş.

Uyarılar (kurulum yapılır, ama bakın):

  • Paket içinde olmayan tag'e bağlı — ekran nesnesi, kural ya da ifade pakette olmayan bir yolu kullanıyor; çoğunlukla yazım hatasıdır.
  • Gidilecek ekran pakette yok — nav bir ekran id'sine karşılık gelmiyor.
  • Bu uygulamanın tanımadığı nesne tipi — telefon bu nesneyi çizemez; sunucuda çalışabilir.
  • Sembol kütüphanede yok — lib2 kimliği yanlış.

İfadeler kurulumda sunucu tarafından derlenir; hatalı bir ifade (bilinmeyen fonksiyon, yanlış argüman sayısı, 1,5 gibi virgüllü sayı) kurulum sonucunda "kurulamayan" olarak listelenir, diğer parçalar kurulur.

Uygulama // ve /* */ yorumlarını ve sondaki fazla virgülleri tolere eder, ama web arayüzü yorumları kabul etmez. Paketleri yorumsuz, geçerli JSON olarak yazın.

Tam örnek

Tek bir Modbus TCP enerji analizörü: altı tag (biri ölçeklenmiş, ikisi yazılabilir), bir hesaplanan tag, bir alarm, sunucu takımında ana ekran ve ayar ekranı, telefon takımında Özet ve ayar ekranı. Bu paket MergenHub Mobil'in denetiminden hatasız ve uyarısız geçer.

{
  "format": "mergenhub-package",
  "formatVersion": 1,
  "kind": "template",
  "meta": {
    "name": "Örnek EA-100 Enerji Analizörü",
    "description": "Tek fazlı enerji ölçümü, röle çıkışı ve akım trafosu ayarı.",
    "vendor": "Örnek",
    "model": "EA-100",
    "version": "1.0",
    "author": "Envest",
    "keywords": ["enerji", "analizör", "Modbus TCP"]
  },
  "parameters": [
    { "key": "ip", "label": "IP adresi", "type": "text", "required": true, "placeholder": "192.168.1.50", "hint": "Analizörün ağdaki adresi" },
    { "key": "port", "label": "Port", "type": "number", "default": 502, "group": "Bağlantı" },
    { "key": "unit", "label": "Unit ID", "type": "number", "default": 1, "group": "Bağlantı" }
  ],
  "channels": [
    {
      "name": "Enerji",
      "driver": "Modbus TCP/IP Ethernet",
      "devices": [
        {
          "name": "Analizor1",
          "id": "<{{ip}}>.{{unit}}",
          "scanMs": 1000,
          "timeouts": { "connectS": 3, "requestMs": 1000, "retries": 3 },
          "settings": { "modbus_ethernet.DEVICE_ETHERNET_PORT_NUMBER": "{{port}}" },
          "tags": [
            { "name": "GerilimL1", "address": "30001", "type": "Float", "access": "read", "scanMs": 1000, "units": "V" },
            { "name": "AkimL1", "address": "30003", "type": "Float", "access": "read", "scanMs": 1000, "units": "A" },
            { "name": "AktifGuc", "address": "30005", "type": "Float", "access": "read", "scanMs": 1000, "units": "kW" },
            { "name": "ToplamEnerji", "address": "30007", "type": "DWord", "access": "read", "scanMs": 5000,
              "scaling": { "type": "linear", "rawLow": 0, "rawHigh": 10, "low": 0, "high": 1, "resultType": "Double", "units": "kWh" } },
            { "name": "RoleCikis", "address": "00001", "type": "Boolean", "access": "readwrite", "scanMs": 1000, "description": "Röle çıkışı (1 = çekili)" },
            { "name": "AkimTrafoOrani", "address": "40001", "type": "Word", "access": "readwrite", "scanMs": 5000, "description": "Akım trafosu oranı (ör. 100 = 100/5 A)" }
          ]
        }
      ]
    }
  ],
  "derived": [
    {
      "name": "Analizor1_GorunurGuc",
      "type": "Derived",
      "expression": "ROUND({Enerji.Analizor1.GerilimL1} * {Enerji.Analizor1.AkimL1} / 1000, 2)",
      "scanRateMs": 1000,
      "description": "Görünür güç (kVA) = gerilim × akım / 1000"
    }
  ],
  "alarms": [
    {
      "name": "Yüksek gerilim L1",
      "tag": "Enerji.Analizor1.GerilimL1",
      "conditionType": "Hi",
      "limit": 250,
      "deadband": 2,
      "severity": 700,
      "message": "Faz 1 gerilimi 250 V üstünde",
      "enabled": true
    }
  ],
  "screens": [
    {
      "id": "ea100-ana", "name": "Analizor1 — Enerji Analizörü", "target": "server", "parentId": "", "order": 0,
      "width": 1200, "height": 700, "background": "#eef2f7",
      "widgets": [
        { "id": "w1", "type": "label", "x": 24, "y": 16, "w": 700, "h": 40, "props": { "text": "ENERJİ ANALİZÖRÜ — Analizor1", "fontSize": 24, "color": "#0f172a" } },
        { "id": "w2", "type": "display", "x": 24, "y": 80, "w": 220, "h": 80, "tag": "Enerji.Analizor1.GerilimL1", "props": { "label": "Gerilim L1", "units": "V", "decimals": 1 } },
        { "id": "w3", "type": "display", "x": 264, "y": 80, "w": 220, "h": 80, "tag": "Enerji.Analizor1.AkimL1", "props": { "label": "Akım L1", "units": "A", "decimals": 2 } },
        { "id": "w4", "type": "display", "x": 504, "y": 80, "w": 220, "h": 80, "tag": "Enerji.Analizor1.AktifGuc", "props": { "label": "Aktif güç", "units": "kW", "decimals": 2 } },
        { "id": "w5", "type": "display", "x": 744, "y": 80, "w": 220, "h": 80, "tag": "Enerji.Analizor1.ToplamEnerji", "props": { "label": "Toplam enerji", "units": "kWh", "decimals": 1 } },
        { "id": "w6", "type": "gauge", "x": 24, "y": 180, "w": 240, "h": 220, "tag": "_AdvancedTags.Analizor1_GorunurGuc", "props": { "label": "Görünür güç", "min": 0, "max": 50, "units": "kVA", "decimals": 2 } },
        { "id": "w7", "type": "switch", "x": 284, "y": 180, "w": 200, "h": 70, "tag": "Enerji.Analizor1.RoleCikis", "props": { "label": "Röle", "onValue": 1, "offValue": 0, "onText": "AÇIK", "offText": "KAPALI", "onColor": "#22c55e" } },
        { "id": "w8", "type": "rect", "x": 24, "y": 620, "w": 200, "h": 56, "props": { "fill": "#1d4ed8", "stroke": "#1d4ed8", "radius": 10 }, "onClick": "nav", "nav": "ea100-ayar" },
        { "id": "w9", "type": "label", "x": 24, "y": 620, "w": 200, "h": 56, "props": { "text": "Ayarlar", "fontSize": 16, "color": "#ffffff" }, "onClick": "nav", "nav": "ea100-ayar" }
      ]
    },
    {
      "id": "ea100-ayar", "name": "Analizor1 — Ayarlar", "target": "server", "parentId": "ea100-ana", "order": 1,
      "width": 1200, "height": 700, "background": "#eef2f7",
      "widgets": [
        { "id": "w10", "type": "label", "x": 24, "y": 16, "w": 700, "h": 40, "props": { "text": "AYARLAR — Analizor1", "fontSize": 24, "color": "#0f172a" } },
        { "id": "w11", "type": "sfield", "x": 24, "y": 80, "w": 520, "h": 44, "tag": "Enerji.Analizor1.AkimTrafoOrani", "props": { "label": "Akım trafosu oranı", "decimals": 0, "editable": true, "step": 5 } },
        { "id": "w12", "type": "rect", "x": 24, "y": 620, "w": 200, "h": 56, "props": { "fill": "#1d4ed8", "stroke": "#1d4ed8", "radius": 10 }, "onClick": "nav", "nav": "ea100-ana" },
        { "id": "w13", "type": "label", "x": 24, "y": 620, "w": 200, "h": 56, "props": { "text": "‹ Ana ekran", "fontSize": 16, "color": "#ffffff" }, "onClick": "nav", "nav": "ea100-ana" }
      ]
    },
    {
      "id": "ea100-tel", "name": "Analizor1 — Özet", "target": "phone", "parentId": "", "order": 0,
      "width": 400, "height": 700, "background": "",
      "widgets": [
        { "id": "w14", "type": "rect", "x": 0, "y": 0, "w": 400, "h": 64, "props": { "fill": "#1d4ed8", "stroke": "#1d4ed8", "radius": 0 } },
        { "id": "w15", "type": "label", "x": 14, "y": 8, "w": 372, "h": 48, "props": { "text": "Enerji Analizörü", "fontSize": 18, "color": "#ffffff", "align": "left" } },
        { "id": "w16", "type": "display", "x": 8, "y": 76, "w": 188, "h": 62, "tag": "Enerji.Analizor1.GerilimL1", "props": { "label": "Gerilim L1", "units": "V", "decimals": 1 } },
        { "id": "w17", "type": "display", "x": 204, "y": 76, "w": 188, "h": 62, "tag": "Enerji.Analizor1.AkimL1", "props": { "label": "Akım L1", "units": "A", "decimals": 2 } },
        { "id": "w18", "type": "display", "x": 8, "y": 146, "w": 188, "h": 62, "tag": "Enerji.Analizor1.AktifGuc", "props": { "label": "Aktif güç", "units": "kW", "decimals": 2 } },
        { "id": "w19", "type": "display", "x": 204, "y": 146, "w": 188, "h": 62, "tag": "Enerji.Analizor1.ToplamEnerji", "props": { "label": "Toplam enerji", "units": "kWh", "decimals": 1 } },
        { "id": "w20", "type": "gauge", "x": 106, "y": 220, "w": 188, "h": 178, "tag": "_AdvancedTags.Analizor1_GorunurGuc", "props": { "label": "Görünür güç", "min": 0, "max": 50, "units": "kVA", "decimals": 2 } },
        { "id": "w21", "type": "switch", "x": 8, "y": 410, "w": 384, "h": 58, "tag": "Enerji.Analizor1.RoleCikis", "props": { "label": "Röle", "onValue": 1, "offValue": 0, "onText": "AÇIK", "offText": "KAPALI", "onColor": "#22c55e" } },
        { "id": "w22", "type": "rect", "x": 8, "y": 480, "w": 188, "h": 48, "props": { "fill": "#1d4ed8", "stroke": "#1d4ed8", "radius": 10 }, "onClick": "nav", "nav": "ea100-tel-ayar" },
        { "id": "w23", "type": "label", "x": 8, "y": 480, "w": 188, "h": 48, "props": { "text": "Ayarlar", "fontSize": 14, "color": "#ffffff" }, "onClick": "nav", "nav": "ea100-tel-ayar" }
      ]
    },
    {
      "id": "ea100-tel-ayar", "name": "Analizor1 — Ayarlar", "target": "phone", "parentId": "ea100-tel", "order": 1,
      "width": 400, "height": 700, "background": "",
      "widgets": [
        { "id": "w24", "type": "label", "x": 12, "y": 12, "w": 376, "h": 30, "props": { "text": "AKIM TRAFOSU", "fontSize": 13, "color": "#3b82f6", "align": "left" } },
        { "id": "w25", "type": "sfield", "x": 8, "y": 48, "w": 384, "h": 44, "tag": "Enerji.Analizor1.AkimTrafoOrani", "props": { "label": "Akım trafosu oranı", "decimals": 0, "editable": true, "step": 5 } }
      ]
    }
  ],
  "notes": "# Örnek EA-100\n\nGerilim, akım, aktif güç ve toplam enerji okunur; röle çıkışı ve akım trafosu oranı yazılabilir. Toplam enerji sayacı 0,1 kWh çözünürlüklüdür (ham değer / 10)."
}

Bu paketi kurarken cihaz adını Analizor2 yaparsanız tag yolları Enerji.Analizor2.…, hesaplanan tag Analizor2_GorunurGuc, ekran adları Analizor2 — … olur.

Yapay zekâ ile çalışma

Paket biçimi yapay zekâ asistanlarının okuyup yazabileceği şekilde tasarlanmıştır. Bir cihazın register haritasını, kılavuzunu ya da veri sayfasını bir asistana verip paketi hazırlatabilirsiniz.

MergenHub cihaz şablonu becerisini indirin (zip). İçinde:

  • SKILL.md — asistanın izleyeceği iş akışı ve kesin kurallar.
  • reference/format.md — tüm alanların kısa başvurusu.
  • reference/drivers.md — sürücü adları, cihaz kimliği biçimleri ve adres sözdizimi.
  • reference/expressions.md — ifade fonksiyonları.
  • examples/minimal-modbus.mhpkg.json — denetimden geçen tam örnek.

Claude uygulamasında zip dosyasını beceri (skill) olarak yükleyin ya da Claude Code'da ~/.claude/skills/ klasörüne açın; beceri desteklemeyen bir asistanda dosyaları sohbete ekleyin. Sonra örneğin şunu isteyin: "Ekteki register tablosundan bu enerji analizörü için MergenHub şablonu hazırla; IP, port ve unit ID kurulumda sorulsun; gerilim için 250 V'ta alarm ekle." Asistanla Türkçe konuşabilirsiniz.

Asistanın verdiği dosyayı önce MergenHub Mobil'de Cihaz ekle › Dosya, pano, QR ya da adres › Panodan yapıştır ile açıp denetim sonucuna bakın; sonra sunucuya kurun.

Resmi kütüphaneye cihaz ekletme

Bir cihazın Cihaz Kütüphanesi'nde yer almasını istiyorsanız sitedeki müşteri panelinden istek gönderin: Panel › Cihaz ekleme istekleri › Yeni istek. MergenHub Mobil'deki kütüphane listesinin altındaki Ekleme isteği gönderin bağlantısı ve web arayüzündeki kütüphane penceresi de aynı sayfayı açar.

Formda marka, model, yazılım sürümü, kategori, haberleşme protokolü, ürün sayfası, cihazın ne yaptığı ve hangi verilerin izleneceği, bağlantı bilgisi istenir. En çok beş dosya eklenebilir (her biri 10 MB): fotoğraf, register haritası, kılavuz; hazırladığınız bir .mhpkg.json paketi de eklenebilir.

İstekler otomatik yayımlanmaz. Envest ekibi cihazı ve belgeleri doğrular, gerekirse sizden bilgi ister, paketi (tag'ler, ekranlar) hazırlayıp test eder ve kütüphaneye kendisi ekler. İsteğin durumu (alındı, inceleniyor, onaylandı — hazırlanıyor, yayında ya da uygun bulunmadı) ve ekibin notu panelde görünür; sonuç e-postayla da bildirilir. Bir firmanın aynı anda en çok on bekleyen isteği olabilir.