Nouveau : le pare-feu IA surveille chaque module et explique chaque incident en termes simples. Découvrez comment ça marche

API des sites et des actifs

Construisez et lisez l'arborescence des sites et des actifs, déplacez les actifs, placez des appareils sur ceux-ci et reliez actifs et appareils via REST : champs, limites et erreurs.

Ces routes gèrent l’arborescence des actifs de Hermetry Twin : sites, bâtiments, étages, pièces, lignes, machines et vos propres types, où chaque appareil est placé, ainsi que les relations entre actifs et appareils. Les concepts sont décrits dans Asset hierarchy. Les chemins se trouvent sous https://<your host>/tenant/<tenantId>.

Routes

MéthodeCheminPermissionFonction
GET/api/iot/assetsiot_asset.assets.readListe sous forme de page plate, d’arbre, de tableau Sites & Assets ou de son résumé
POST/api/iot/assetsiot_asset.assets.manageCréer un actif
GET/api/iot/assets/{assetId}iot_asset.assets.readUn actif avec ses ancêtres et ses compteurs
PATCH/api/iot/assets/{assetId}iot_asset.assets.manageModifier un actif
DELETE/api/iot/assets/{assetId}iot_asset.assets.manageSupprimer un actif
POST/api/iot/assets/{assetId}/moveiot_asset.assets.manageDéplacer sous un autre parent
GET/api/iot/assets/{assetId}/devicesiot_asset.assets.readAppareils placés dessus (et en dessous)
POST/api/iot/assets/{assetId}/devicesiot_asset.relations.managePlacer jusqu’à 100 appareils dessus
GET/api/iot/devices/{deviceId}/placementiot_asset.assets.readOù se trouve un appareil
PUT/api/iot/devices/{deviceId}/placementiot_asset.relations.managePlacer un appareil, ou supprimer son placement
GET/api/iot/relationsiot_asset.assets.readLister les relations
POST/api/iot/relationsiot_asset.relations.manageCréer une relation
DELETE/api/iot/relations/{relationId}iot_asset.relations.manageSupprimer une relation

Rôles par défaut : la lecture est une permission Utilisateur ; la modification des actifs, des placements et des relations est une permission Administrateur. Chaque modification est écrite dans le journal d’audit (les noms des champs modifiés, jamais leurs valeurs).

L’actif

ChampRègles
nameobligatoire, 1 à 255 caractères
kindobligatoire ; lettres, chiffres et _, 1 à 24, enregistré en majuscules. Suggérés : SITE, BUILDING, FLOOR, ROOM, AREA, LINE, MACHINE, OTHER ; tout autre est accepté
codelettres, chiffres, ., _, - ; 1 à 32 ; enregistré en majuscules ; unique parmi vos actifs actifs. Omis : généré à partir du nom.
parentIdà la création uniquement ; null ou absent pour un actif de premier niveau. Le modifier ensuite avec move.
descriptionjusqu’à 1 000 caractères
lat, lng−90 à 90, −180 à 180
timezoneun nom IANA tel que Europe/Istanbul
addressJsonjusqu’à 12 champs texte
attributesjusqu’à 100 clés et 16 Kio ; les clés commencent par une lettre, puis lettres, chiffres, ., _, - (jusqu’à 64)
defaultDashboardIdun tableau de bord que le bouton Open dashboard de l’actif ouvre

Champs en lecture seule dans les réponses : iotAssetId, path (les codes depuis le sommet, par exemple /IST/BLD-A/GF), depth, createdAt, updatedAt.

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

Créer un actif. Les champs inconnus sont refusés.

Corps de la requête application/json

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

Exemple 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}}'

Réponses

201Créé
{
    "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
        },
        "…": "…"
    }
}
409Conflit
{
    "message": "Another asset already uses this code.",
    "code": "CONFLICT",
    "details": {
        "reason": "code_taken"
    }
}

PATCH accepte les mêmes champs, sauf parentId. Un nouveau code réécrit en une seule étape les chemins de tous les actifs situés en dessous.

GET /api/iot/assets/{assetId} ajoute ancestors (racine en premier, chacun avec id, code, name, kind), effectiveTimezone (le sien, sinon celui de l’ancêtre le plus proche), childCount et deviceCount.

Liste et arbre

GET /api/iot/assets avec view :

viewRéponseParamètres
list (par défaut){ assets, total, page, pageSize }, une page plateparentId (un UUID ou root), subtreeOf, kind, search, includeDeleted, page à partir de 1, pageSize jusqu’à 200 (par défaut 50)
treeL’arbre imbriquérootId, depth (par défaut 6, au maximum 12) ; au plus 5 000 actifs
tableUne page du tableau Sites & Assets : chaque actif avec son emplacement, ses enfants, ses appareils et ses alarmes activessearch, kind, site (un sous-arbre), parentId, alarmed=true, sort (name, kind, location, children, devices, alarms avec :asc ou :desc), page, pageSize
summaryLes compteurs et les sites avec leurs alarmes par gravité

Les chiffres d’alarmes ne sont inclus que si l’appelant est autorisé à lire les alarmes.

Déplacer

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

null en fait un actif de premier niveau. Tout ce qui se trouve en dessous se déplace avec lui. Déplacer un actif sous lui-même ou sous l’un de ses descendants est refusé : « An asset cannot be moved under itself or one of its own descendants. » (400, cycle). Un chemin peut comporter au plus 1 024 caractères (too_deep).

Supprimer

Un actif qui a des actifs enfants est refusé : « This asset still has child assets: move or delete them first. » (409, has_children). Si un autre module indique qu’il utilise encore l’actif, la suppression est refusée avec un 409 nommant ce module. La suppression d’un actif met fin à ses placements et relations d’appareils ; les appareils eux-mêmes restent.

Placer des appareils

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

Chaque appareil n’a qu’un seul emplacement : le placer ici le retire de l’endroit où il se trouvait. La réponse { "changes": [...] } liste ce qui a été déplacé. Un appareil à la fois :

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

Les deux GET et PUT de .../placement répondent { "placement": { "iotAssetId": "77aa…", "path": [ { "iotAssetId": "…", "code": "IST", "name": "Istanbul plant", "kind": "SITE" }, … ] } }, racine en premier. Un appareil sans emplacement a iotAssetId: null.

GET /api/iot/assets/{assetId}/devices liste les appareils placés sur l’actif et, par défaut, en dessous (recursive=false pour l’actif seul) : search, online=true|false, sort=name|connection:asc|desc, page à partir de 1, pageSize jusqu’à 200. La réponse est { items, total, page, pageSize }.

Relations

Une relation relie deux extrémités, chacune un ASSET ou un DEVICE, avec un type : CONTAINS, MANAGES, FEEDS, MONITORS ou le vôtre (lettres, chiffres, _, jusqu’à 32, enregistré en majuscules).

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

Créer une relation. additionalInfo contient jusqu’à 20 clés et 4 Kio.

Corps de la requête application/json

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

Exemple 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"}}'

Réponses

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

Règles :

  • CONTAINS d’un actif vers un appareil correspond au placement de l’appareil (utiliser les routes de placement). CONTAINS sous toute autre forme est refusé (placement_shape), et un actif placé dans un autre actif se définit en le déplaçant, non par une relation (parentage_is_move).
  • Une relation doit relier deux extrémités différentes (self_relation).
  • Une extrémité absente donne 404 (end_not_found).

GET /api/iot/relations?entityType=ASSET&entityId={assetId} liste les relations d’une extrémité dans les deux sens ; ou filtre par fromType, fromId, toType, toId, type. limit de 1 à 500 (valeur par défaut : 200). La réponse est { "relations": [...] }.

Rechercher des appareils pour un sélecteur

GET /api/iot/devices/search?q=pump&limit=20&near=iot_asset:{assetId} renvoie { "devices": [{ "id", "name", "code", "hint" }] } : au plus 20 appareils par nom, ceux de l’appareil ou de l’actif donné en premier, avec hint indiquant l’emplacement de chacun. Elle nécessite à la fois iot_asset.assets.read et iot_device.devices.read.