Neu: Die KI-Firewall überwacht jedes Modul und erklärt jeden Vorfall in einfachen Worten. So funktioniert es

Schnittstelle für Standorte und Assets

Baumstruktur aus Standorten und Assets aufbauen und auslesen, Assets verschieben, Geräte auf ihnen platzieren und Assets und Geräte über REST miteinander verknüpfen – Felder, Grenzwerte und Fehler.

Diese Routen verwalten den Asset-Baum von Hermetry Twin: Standorte, Gebäude, Etagen, Räume, Linien, Maschinen und Ihre eigenen Arten, wo jedes Gerät platziert ist, sowie die Beziehungen zwischen Assets und Geräten. Die Konzepte sind unter Asset-Hierarchie beschrieben. Pfade liegen unter https://<your host>/tenant/<tenantId>.

Routen

MethodePfadBerechtigungFunktion
GET/api/iot/assetsiot_asset.assets.readAuflistung als flache Seite, als Baum, als Tabelle „Standorte & Assets“ oder deren Zusammenfassung
POST/api/iot/assetsiot_asset.assets.manageAsset anlegen
GET/api/iot/assets/{assetId}iot_asset.assets.readEin Asset mit seinen Vorfahren und Zählern
PATCH/api/iot/assets/{assetId}iot_asset.assets.manageAsset ändern
DELETE/api/iot/assets/{assetId}iot_asset.assets.manageAsset löschen
POST/api/iot/assets/{assetId}/moveiot_asset.assets.manageUnter einen anderen übergeordneten Eintrag verschieben
GET/api/iot/assets/{assetId}/devicesiot_asset.assets.readDarauf platzierte Geräte (und darunter)
POST/api/iot/assets/{assetId}/devicesiot_asset.relations.manageBis zu 100 Geräte hier platzieren
GET/api/iot/devices/{deviceId}/placementiot_asset.assets.readWo ein Gerät steht
PUT/api/iot/devices/{deviceId}/placementiot_asset.relations.manageEin Gerät platzieren oder dessen Platzierung entfernen
GET/api/iot/relationsiot_asset.assets.readBeziehungen auflisten
POST/api/iot/relationsiot_asset.relations.manageBeziehung anlegen
DELETE/api/iot/relations/{relationId}iot_asset.relations.manageBeziehung löschen

Standardrollen: Lesen ist eine Benutzerberechtigung; Assets, Platzierungen und Beziehungen zu ändern ist eine Administratorberechtigung. Jede Änderung wird im Audit-Log protokolliert (die geänderten Feldnamen, niemals die Werte).

Das Asset

FeldRegeln
nameerforderlich, 1 bis 255 Zeichen
kinderforderlich; Buchstaben, Ziffern und _, 1 bis 24, wird in Großbuchstaben gespeichert. Empfohlen: SITE, BUILDING, FLOOR, ROOM, AREA, LINE, MACHINE, OTHER; jeder andere Wert ist erlaubt
codeBuchstaben, Ziffern, ., _, -; 1 bis 32; wird in Großbuchstaben gespeichert; eindeutig unter Ihren aktiven Assets. Wird es weggelassen, wird es aus dem Namen gebildet.
parentIdnur beim Anlegen; null oder fehlend für ein Asset auf oberster Ebene. Später ändern Sie es mit move.
descriptionbis zu 1.000 Zeichen
lat, lng−90 bis 90, −180 bis 180
timezoneein IANA-Name wie Europe/Istanbul
addressJsonbis zu 12 Textfelder
attributesbis zu 100 Schlüssel und 16 KiB; Schlüssel beginnen mit einem Buchstaben, danach Buchstaben, Ziffern, ., _, - (bis zu 64)
defaultDashboardIdein Dashboard, das der Schaltfläche Dashboard öffnen des Assets öffnet

Schreibgeschützte Felder in Antworten: iotAssetId, path (die Codes von oben, zum Beispiel /IST/BLD-A/GF), depth, createdAt, updatedAt.

POST/tenant/{tenantId}/api/iot/assets

Asset anlegen. Unbekannte Felder werden abgelehnt.

Anfragetext application/json

{
    "name": "Compressor room",
    "kind": "ROOM",
    "code": "CR1",
    "parentId": "e5f6…",
    "timezone": "Europe/Istanbul",
    "attributes": {
        "area_m2": 42
    }
}

Beispiel curl

curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/assets' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Compressor room","kind":"ROOM","code":"CR1","parentId":"e5f6…","timezone":"Europe/Istanbul","attributes":{"area_m2":42}}'

Antworten

201Created
{
    "asset": {
        "iotAssetId": "77aa…",
        "parentId": "e5f6…",
        "path": "/IST/BLD-A/GF/CR1",
        "depth": 4,
        "code": "CR1",
        "name": "Compressor room",
        "kind": "ROOM",
        "timezone": "Europe/Istanbul",
        "attributes": {
            "area_m2": 42
        },
        "…": "…"
    }
}
409Conflict
{
    "message": "Another asset already uses this code.",
    "code": "CONFLICT",
    "details": {
        "reason": "code_taken"
    }
}

PATCH nimmt dieselben Felder außer parentId entgegen. Ein neuer code schreibt in demselben Schritt die Pfade aller darunterliegenden Assets neu.

GET /api/iot/assets/{assetId} ergänzt ancestors (oberste zuerst, jeweils mit id, code, name, kind), effectiveTimezone (die eigene, sonst die des nächsten Vorfahren), childCount und deviceCount.

Liste und Baum

GET /api/iot/assets mit view:

viewAntwortParameter
list (Standard){ assets, total, page, pageSize }, eine flache SeiteparentId (eine UUID oder root), subtreeOf, kind, search, includeDeleted, page ab 1, pageSize bis 200 (Standard 50)
treeDer verschachtelte BaumrootId, depth (Standard 6, höchstens 12); höchstens 5.000 Assets
tableEine Seite der Tabelle Standorte & Assets: jedes Asset mit seinem Ort, seinen Untergeordneten, Geräten und aktiven Alarmensearch, kind, site (ein Teilbaum), parentId, alarmed=true, sort (name, kind, location, children, devices, alarms mit :asc oder :desc), page, pageSize
summaryDie Zähler und die Standorte mit ihren Alarmen je Schweregrad

Alarmwerte sind nur enthalten, wenn der Aufrufer Alarme lesen darf.

Verschieben

POST /api/iot/assets/{assetId}/move
{ "parentId": "c3d4…" }

null macht es zu einem Asset auf oberster Ebene. Alles darunter wird mit verschoben. Ein Verschieben unter sich selbst oder einen seiner Nachfahren wird abgelehnt: „An asset cannot be moved under itself or one of its own descendants.“ (400, cycle). Ein Pfad darf höchstens 1.024 Zeichen lang sein (too_deep).

Löschen

Ein Asset mit untergeordneten Assets wird abgelehnt: „This asset still has child assets: move or delete them first.“ (409, has_children). Meldet ein anderes Modul, dass es das Asset noch verwendet, wird das Löschen mit 409 unter Nennung dieses Moduls abgelehnt. Das Löschen eines Assets beendet dessen Gerätezuordnungen und Beziehungen; die Geräte selbst bleiben erhalten.

Geräte platzieren

POST /api/iot/assets/{assetId}/devices
{ "deviceIds": ["6f1c…", "8b2d…"] }

Jedes Gerät hat höchstens einen Ort: Wird es hier platziert, wird es von seinem bisherigen Ort verschoben. Die Antwort { "changes": [...] } listet auf, was verschoben wurde. Jeweils ein Gerät:

PUT /api/iot/devices/{deviceId}/placement
{ "iotAssetId": "77aa…" }      // or null to remove the placement

Sowohl GET als auch PUT von .../placement antworten mit { "placement": { "iotAssetId": "77aa…", "path": [ { "iotAssetId": "…", "code": "IST", "name": "Istanbul plant", "kind": "SITE" }, … ] } }, oberste zuerst. Ein Gerät ohne Ort hat iotAssetId: null.

GET /api/iot/assets/{assetId}/devices listet die auf dem Asset platzierten Geräte und standardmäßig auch die darunter (recursive=false nur für das Asset allein): search, online=true|false, sort=name|connection:asc|desc, page ab 1, pageSize bis 200. Die Antwort lautet { items, total, page, pageSize }.

Beziehungen

Eine Beziehung verbindet zwei Enden, jeweils ein ASSET oder ein DEVICE, mit einem Typ: CONTAINS, MANAGES, FEEDS, MONITORS oder eigene Typen (Buchstaben, Ziffern, _, bis zu 32, in Großbuchstaben gespeichert).

POST/tenant/{tenantId}/api/iot/relations

Beziehung anlegen. additionalInfo enthält bis zu 20 Schlüssel und 4 KiB.

Anfragetext application/json

{
    "fromType": "DEVICE",
    "fromId": "8b2d…",
    "toType": "DEVICE",
    "toId": "6f1c…",
    "type": "FEEDS",
    "additionalInfo": {
        "line": "DN150"
    }
}

Beispiel curl

curl -X POST 'https://<your-host>/tenant/{tenantId}/api/iot/relations' \
  -H 'Content-Type: application/json' \
  -d '{"fromType":"DEVICE","fromId":"8b2d…","toType":"DEVICE","toId":"6f1c…","type":"FEEDS","additionalInfo":{"line":"DN150"}}'

Antworten

201Created
{
    "relation": {
        "relationId": "…",
        "fromType": "DEVICE",
        "fromId": "8b2d…",
        "toType": "DEVICE",
        "toId": "6f1c…",
        "type": "FEEDS",
        "…": "…"
    }
}
409Conflict
{
    "message": "This relation already exists.",
    "code": "CONFLICT",
    "details": {
        "reason": "relation_exists"
    }
}

Regeln:

  • CONTAINS von einem Asset zu einem Gerät ist die Platzierung des Geräts (verwenden Sie dafür die Platzierungsrouten). CONTAINS in jeder anderen Form wird abgelehnt (placement_shape), und ein Asset innerhalb eines anderen Assets wird durch Verschieben festgelegt, nicht durch eine Beziehung (parentage_is_move).
  • Eine Beziehung braucht zwei verschiedene Enden (self_relation).
  • Ein fehlendes Ende ergibt 404 (end_not_found).

GET /api/iot/relations?entityType=ASSET&entityId={assetId} listet die Beziehungen eines Endes in beide Richtungen auf; alternativ filtern Sie nach fromType, fromId, toType, toId, type. limit 1 bis 500 (Standard 200). Die Antwort lautet { "relations": [...] }.

Geräte für eine Auswahlliste suchen

GET /api/iot/devices/search?q=pump&limit=20&near=iot_asset:{assetId} liefert { "devices": [{ "id", "name", "code", "hint" }] }: höchstens 20 Geräte nach Name, wobei die des angegebenen Geräts oder Assets zuerst erscheinen, mit hint, der angibt, wo jedes platziert ist. Dafür werden sowohl iot_asset.assets.read als auch iot_device.devices.read benötigt.