Zum Hauptinhalt springen

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_ · Line LINE_ · Anlage EQUIPMENT_ (bestehende ASSET_ sind ebenfalls gültig). Wenn asset_id leer gelassen wird, weist die Platform eine ID zu. Die Ebene im Baum wird nicht durch die ID, sondern durch asset_type bestimmt. Weitere Details finden Sie unter Domain-ID-Regeln.

7.1 Methodenübersicht​

MethodeRückgabetypHTTPEndpoint
create(AssetRequestV5)AssetResponseV5 oder nullPOST/api/v5/asset
update(asset_id, AssetRequestV5)AssetResponseV5 oder nullPUT/api/v5/asset/{id}
delete(asset_id)booleanDELETE/api/v5/asset/{id}
get(asset_id)AssetResponseV5 oder nullGET/api/v5/asset/{id}
list()List<AssetResponseV5>GET/api/v5/asset
exists(asset_id)booleanGET/api/v5/asset/{id}/exists
getByExternal(system, external_id)AssetResponseV5 oder nullGET/api/v5/asset/by-external/{system}/{external_id}
patchProperties(asset_id, 요청)AssetResponseV5 oder nullPATCH/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_type nach list()).

7.2 Asset Type Werte​

asset_typeBedeutung
EUnternehmen (Enterprise) — eins pro Installation, Wurzel des Baums
SSite
AArea
LLine
MAnlage (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​

FeldTypBeschreibung
asset_idStringAsset-ID (PK). Wenn leer, wird eine zugewiesen
asset_nameStringAnzeigename
parent_asset_idStringEltern-Asset-ID — direkt darüber liegende Ebene
asset_orderStringSortierfolge unter Geschwistern
asset_typeStringA/L/M (in der Antwort auch E·S). Nach der Erstellung nicht änderbar
asset_class_codeStringAnlagenklassifizierungscode (CNC, INJECTION etc.). Muss die Klassifizierung der Ebene sein, andernfalls 422
site_idStringZugehörige Site
descriptionStringBeschreibung (erforderlich)
operational_status_codeString(Antwort) Betriebszustand
external_system / external_idString(Antwort) Nummer, unter der andere Systeme diesen Knoten ansprechen
insert_date / update_dateString(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.

EbeneSchlüssel
Gemeinsam (außer Unternehmen)operational_status_code, external_system + external_id (beide vorhanden oder beide fehlend)
Site Stimezone, country, site_code, address, lat, lng
Area Aarea_function_code(PRODUCTION · STORAGE · UTILITY), responsible_employee_id
Line Lline_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 Mmanufacturer, 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)
AntwortBedeutung
422 asset.invalid.<key>Schlüssel nicht in dieser Ebene, unbekannter Code, unvollständiges Paar, Datumsreihenfolge verletzt
422 asset.invalid.asset_typeVersuch, die Ebene zu ändern — Ebenen können nicht geändert werden
409 asset.duplicate.external_idEin anderer Knoten verwendet dieselbe externe Nummer
409 asset.duplicate.functional_locationEine 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​