7. Asset-Service
Greifen Sie über client.asset() zu. Verwalten Sie das Kernmodell der PlantPulse-Assets — den fünfstufigen Baum: Unternehmen > Site > Area > Line > Anlage.
ID-Regeln: Area
AREA_· LineLINE_· AnlageEQUIPMENT_(bestehendeASSET_sind ebenfalls gültig). Wennasset_idleer gelassen wird, weist die Platform eine ID zu. Die Ebene im Baum wird nicht durch die ID, sondern durchasset_typebestimmt. Weitere Details finden Sie unter Domain-ID-Regeln.
7.1 Methodenübersicht
| Methode | Rückgabetyp | HTTP | Endpoint |
|---|---|---|---|
create(AssetRequestV5) | AssetResponseV5 oder null | POST | /api/v5/asset |
update(asset_id, AssetRequestV5) | AssetResponseV5 oder null | PUT | /api/v5/asset/{id} |
delete(asset_id) | boolean | DELETE | /api/v5/asset/{id} |
get(asset_id) | AssetResponseV5 oder null | GET | /api/v5/asset/{id} |
list() | List<AssetResponseV5> | GET | /api/v5/asset |
exists(asset_id) | boolean | GET | /api/v5/asset/{id}/exists |
getByExternal(system, external_id) | AssetResponseV5 oder null | GET | /api/v5/asset/by-external/{system}/{external_id} |
patchProperties(asset_id, 요청) | AssetResponseV5 oder null | PATCH | /api/v5/asset/{id}/properties |
Der Asset-Service konzentriert sich auf vereinfachte CRUD-Operationen. Nutzen Sie für die Abfrage der Baumhierarchie den Path-Service oder eine clientseitige Filterung (Filterung durch
asset_typenachlist()).
7.2 Asset Type Werte
| asset_type | Bedeutung |
|---|---|
E | Unternehmen (Enterprise) — eins pro Installation, Wurzel des Baums |
S | Site |
A | Area |
L | Line |
M | Anlage (Equipment, Machine) |
Die Erstellung erfolgt über POST /api/v5/asset für A · L · M. Sites werden über den Site-Service erstellt.
GET /api/v5/asset gibt Areas, Lines und Anlagen zurück, wenn asset_type nicht angegeben ist; bei Angabe von asset_type=E oder S wird die entsprechende Ebene zurückgegeben.
Betrachten Sie E · S nicht als Anlagen. Die Ebene wird über diesen Wert bestimmt, nicht über das ID-Präfix.
7.3 AssetRequestV5 / AssetResponseV5
| Feld | Typ | Beschreibung |
|---|---|---|
asset_id | String | Asset-ID (PK). Wenn leer, wird eine zugewiesen |
asset_name | String | Anzeigename |
parent_asset_id | String | Eltern-Asset-ID — direkt darüber liegende Ebene |
asset_order | String | Sortierfolge unter Geschwistern |
asset_type | String | A/L/M (in der Antwort auch E·S). Nach der Erstellung nicht änderbar |
asset_class_code | String | Anlagenklassifizierungscode (CNC, INJECTION etc.). Muss die Klassifizierung der Ebene sein, andernfalls 422 |
site_id | String | Zugehörige Site |
description | String | Beschreibung (erforderlich) |
operational_status_code | String | (Antwort) Betriebszustand |
external_system / external_id | String | (Antwort) Nummer, unter der andere Systeme diesen Knoten ansprechen |
insert_date / update_date | String | (Nur Antwort) Zeitstempel |
Einzelabfragen enthalten spezifische Attribute der Ebene, während Listen nur gemeinsame Felder (operational_status_code · external_system · external_id) enthalten.
Spezifische Attribute — /api/v5/asset/{id}/properties
Jede Ebene hat eigene Attribute. Lesen Sie diese über GET und ändern Sie diese über PATCH (oder PUT). Nur übermittelte Schlüssel werden verwendet; null dient dem Löschen, nicht übermittelte Schlüssel bleiben unverändert.
| Ebene | Schlüssel |
|---|---|
| Gemeinsam (außer Unternehmen) | operational_status_code, external_system + external_id (beide vorhanden oder beide fehlend) |
Site S | timezone, country, site_code, address, lat, lng |
Area A | area_function_code(PRODUCTION · STORAGE · UTILITY), responsible_employee_id |
Line L | line_kind_code(PRODUCTION_LINE · PROCESS_CELL · PRODUCTION_UNIT), design_rate(pro Stunde, über 0) + design_rate_unit_of_measure(UN/ECE Rec 20, beide vorhanden oder beide fehlend), responsible_employee_id |
Anlage M | manufacturer, model, serial_number, installed_date, commissioned_date(nach Installationsdatum), warranty_end_date(yyyy-MM-dd), criticality_code(A · B · C), functional_location(einzigartig innerhalb der Site) |
| Antwort | Bedeutung |
|---|---|
422 asset.invalid.<key> | Schlüssel nicht in dieser Ebene, unbekannter Code, unvollständiges Paar, Datumsreihenfolge verletzt |
422 asset.invalid.asset_type | Versuch, die Ebene zu ändern — Ebenen können nicht geändert werden |
409 asset.duplicate.external_id | Ein anderer Knoten verwendet dieselbe externe Nummer |
409 asset.duplicate.functional_location | Eine andere Anlage in derselben Site verwendet dieselbe Funktionsposition |
Das Feld effective_responsible_employee_id in der Antwort gibt den tatsächlichen Verantwortlichen an — ist das eigene Feld leer, wird der Verantwortliche der nächsthöheren Ebene (Line → Area) übernommen, und effective_responsible_from_asset_id gibt an, von wo die Übernahme erfolgte.
Das Feld qr_payload in der Antwort von GET /api/v5/asset/{id} ist die Adresse, die auf das QR-Label gedruckt wird. Dieser Aufruf erzeugt keinen Token — es werden nur Anlagen gefüllt, für die bereits ein Token durch das einmalige Öffnen des Labels in der Konsole erstellt wurde; ansonsten ist der Wert "".
Suche per externer Nummer
GET /api/v5/asset/by-external/MAXIMO/BEDFORD%2F11430
GET /api/v5/asset/by-external?system=MAXIMO&external_id=BEDFORD/11430
Die Suche erfolgt über alle Ebenen. Falls nicht gefunden, wird 404 asset.not_found zurückgegeben; wenn nur das System oder nur die Nummer angegeben wird, erfolgt die Antwort 422.
7.4 Anwendungsbeispiele
Erstellung des Baums Area → Line → Anlage
import plantpulse.api.v5.dto.request.AssetRequestV5;
// 1) Area
AssetRequestV5 area = new AssetRequestV5();
area.setSite_id("SITE_DJ");
area.setParent_asset_id("SITE_DJ");
area.setAsset_name("조립구역");
area.setAsset_type("A");
client.asset().create(area);
// asset_id 를 비워 두면 플랫폼이 발급합니다 — 응답에서 AREA_000001 을 받습니다
// 2) Line
AssetRequestV5 line = new AssetRequestV5();
line.setSite_id("SITE_DJ");
line.setParent_asset_id("AREA_000001");
line.setAsset_name("1번 조립 라인");
line.setAsset_type("L");
client.asset().create(line);
// 3) Equipment (CNC 머신)
AssetRequestV5 cnc = new AssetRequestV5();
cnc.setSite_id("SITE_DJ");
cnc.setParent_asset_id("LINE_000001");
cnc.setAsset_name("CNC #1");
cnc.setAsset_type("M");
cnc.setAsset_class_code("CNC");
cnc.setDescription("DMG MORI NLX-2500");
client.asset().create(cnc);
Einzelabfrage
import plantpulse.api.v5.dto.response.AssetResponseV5;
AssetResponseV5 cnc = client.asset().get("EQUIPMENT_000001");
if (cnc != null) {
System.out.println(cnc.getAsset_name() + " (" + cnc.getAsset_type() + ")");
System.out.println("부모: " + cnc.getParent_asset_id());
}
Gesamtliste + Filterung nach Typ
Serverseitige Filter sind GET /api/v5/asset?asset_type=M · operational_status_code= · external_system=. Da list() des Java-Clients keine Filter akzeptiert, erfolgt die Filterung nach Erhalt der Daten.
import java.util.List;
import java.util.stream.Collectors;
List<AssetResponseV5> all = client.asset().list();
// Equipment만
List<AssetResponseV5> equipments = all.stream()
.filter(a -> "M".equals(a.getAsset_type()))
.collect(Collectors.toList());
// 대전공장의 Line만
List<AssetResponseV5> djLines = all.stream()
.filter(a -> "SITE_DJ".equals(a.getSite_id()))
.filter(a -> "L".equals(a.getAsset_type()))
.collect(Collectors.toList());
Baumrekonstruktion (clientseitig)
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
// asset_id 인덱스
Map<String, AssetResponseV5> byId = new HashMap<>();
for (AssetResponseV5 a : client.asset().list()) {
byId.put(a.getAsset_id(), a);
}
// 부모-자식 매핑
Map<String, List<AssetResponseV5>> children = new HashMap<>();
for (AssetResponseV5 a : byId.values()) {
children
.computeIfAbsent(a.getParent_asset_id(), k -> new ArrayList<>())
.add(a);
}
// 사이트(SITE_DJ) 산하 트리 출력
printTree(children, "SITE_DJ", 0);
static void printTree(Map<String, List<AssetResponseV5>> children, String id, int depth) {
List<AssetResponseV5> kids = children.getOrDefault(id, List.of());
for (AssetResponseV5 c : kids) {
System.out.println(" ".repeat(depth) + c.getAsset_id() + " — " + c.getAsset_name());
printTree(children, c.getAsset_id(), depth + 1);
}
}
Asset-Änderung
AssetRequestV5 update = new AssetRequestV5();
update.setSite_id("SITE_DJ");
update.setParent_asset_id("LINE_000001");
update.setAsset_id("EQUIPMENT_000001");
update.setAsset_name("CNC #1 (보수 후)");
update.setAsset_type("M");
update.setAsset_class_code("CNC");
update.setDescription("2026-05-10 베어링 교체 완료");
client.asset().update("EQUIPMENT_000001", update);
Asset-Löschung
⚠️ Vor dem Löschen eines Assets müssen alle mit diesem Asset verbundenen Tags und untergeordneten Assets gelöscht werden.
boolean ok = client.asset().delete("EQUIPMENT_OLD");
7.5 Anwendungsszenarien
Szenario — Anlagenliste einer Site und Anzahl der Tags pro Anlage
String siteId = "SITE_DJ";
List<AssetResponseV5> equipments = client.asset().list().stream()
.filter(a -> siteId.equals(a.getSite_id()))
.filter(a -> "M".equals(a.getAsset_type()))
.collect(Collectors.toList());
for (AssetResponseV5 eq : equipments) {
long tagCount = client.tag().countByAsset(eq.getAsset_id());
System.out.printf("%s — Tag %d개%n", eq.getAsset_name(), tagCount);
}
Szenario — OEE-Dashboard-Datenerfassung auf Line-Ebene
// 1) Line 목록
List<AssetResponseV5> lines = client.asset().list().stream()
.filter(a -> "L".equals(a.getAsset_type()))
.filter(a -> "SITE_DJ".equals(a.getSite_id()))
.collect(Collectors.toList());
// 2) 각 Line 산하 Equipment 조회 → 자산 경로 → 작업지시 → KPI 집계
for (AssetResponseV5 line : lines) {
List<AssetResponseV5> machines = client.asset().list().stream()
.filter(a -> line.getAsset_id().equals(a.getParent_asset_id()))
.collect(Collectors.toList());
for (AssetResponseV5 m : machines) {
long now = System.currentTimeMillis();
// 현재 작업지시는 Order 서비스로 조회
// ...
}
}
Nächste Schritte
- Tag-Service — Tags mit Assets verbinden
- Path-Service — Abfrage von Baumspfaden in einem Schritt