18. Integrated Example Collection
This section collects end-to-end scenarios frequently performed using the V5 client.
18.1 New Factory Booting — Full Master Data Registration
A scenario for registering a new site and setting up the entire chain from the asset tree (Area → Line → Equipment) to OPC and finally to tags in one go.
import plantpulse.api.v5.APIClient_V5;
import plantpulse.api.v5.dto.Quantity;
import plantpulse.api.v5.dto.request.*;
import plantpulse.api.v5.dto.response.*;
public class BootstrapNewSite {
public static void main(String[] args) throws Exception {
try (APIClient_V5 client = new APIClient_V5(
"HTTPS", "100.68.69.41", 443, "api", TOKEN, false)) {
client.connect();
// 1) 사이트 등록
SiteRequestV5 site = new SiteRequestV5();
site.setSite_id("SITE_DJ");
site.setSite_name("대전 1공장");
site.setLat("36.3504");
site.setLng("127.3845");
client.site().create(site);
// 2) Area
AssetRequestV5 area = new AssetRequestV5();
area.setSite_id("SITE_DJ");
area.setParent_asset_id("SITE_DJ");
area.setAsset_id("AREA_000001");
area.setAsset_name("조립구역");
area.setAsset_type("A");
client.asset().create(area);
// 3) Line
AssetRequestV5 line = new AssetRequestV5();
line.setSite_id("SITE_DJ");
line.setParent_asset_id("AREA_000001");
line.setAsset_id("LINE_000001");
line.setAsset_name("1번 조립 라인");
line.setAsset_type("L");
client.asset().create(line);
// 4) Equipment (3대)
for (int i = 1; i <= 3; i++) {
AssetRequestV5 eq = new AssetRequestV5();
eq.setSite_id("SITE_DJ");
eq.setParent_asset_id("LINE_000001");
eq.setAsset_id(String.format("EQUIPMENT_%06d", i));
eq.setAsset_name("CNC #" + i);
eq.setAsset_type("M");
eq.setAsset_class_code("CNC");
client.asset().create(eq);
}
// 5) OPC (PLC)
OPCRequestV5 plc = new OPCRequestV5();
plc.setOpc_id("OPC_PLC_L1_001");
plc.setOpc_name("Line1 메인 PLC");
plc.setOpc_protocol("S7");
plc.setSite_id("SITE_DJ");
plc.setOpc_source_ip("192.168.10.50");
plc.setOpc_source_port(102);
client.opc().create(plc);
// 6) Tag (각 Equipment에 RPM/온도/카운트 3개씩)
for (int i = 1; i <= 3; i++) {
String equipId = String.format("EQUIPMENT_%06d", i);
for (String metric : new String[]{"RPM", "TEMP", "COUNT"}) {
TagRequestV5 tag = new TagRequestV5();
tag.setSite_id("SITE_DJ");
tag.setOpc_id("OPC_PLC_L1_001");
tag.setLinked_asset_id(equipId);
tag.setTag_id(String.format("TAG_PLC_L1_M%04d_%s", i, metric));
tag.setTag_name("CNC#" + i + " " + metric);
tag.setJava_type("Double");
tag.setUnit(metricUnit(metric));
client.tag().create(tag);
}
}
System.out.println("부팅 완료");
}
}
private static String metricUnit(String m) {
switch (m) {
case "RPM": return "RPM";
case "TEMP": return "C";
case "COUNT": return "EA";
default: return "";
}
}
}
18.2 ERP Master Synchronization (Idempotent)
Synchronizing customer, product, and employee data received from ERP to the V5 master. Branching occurs after verifying exists(), leading to create() or update().
public static void syncCustomers(APIClient_V5 client, List<ErpCustomer> erpData) {
for (ErpCustomer erp : erpData) {
String customerId = "CUST_" + erp.code;
CustomerRequestV5 req = new CustomerRequestV5();
req.setCustomer_id(customerId);
req.setCustomer_name(erp.name);
req.setSite_id(erp.siteId);
req.setExternal_customer_id(erp.id);
req.setCompany_code(erp.companyCode);
req.setManager_name(erp.contact);
req.setManager_email(erp.email);
if (client.customer().exists(customerId)) {
client.customer().update(customerId, req);
} else {
client.customer().create(req);
}
}
}
18.3 MES Work Order Creation, Start, and Completion
public static void runMesWorkOrder(APIClient_V5 client, MesOrder mes) {
// 1) Order 생성
String orderId = "ORDER_" + mes.date + "_" + String.format("%03d", mes.seq);
OrderRequestV5 req = new OrderRequestV5();
req.setOrder_id(orderId);
req.setOrder_name(mes.title);
req.setSite_id("SITE_DJ");
req.setAsset_id(mes.equipId);
req.setProduct_id(mes.productId);
req.setEmployee_id(mes.operatorId);
req.setCustomer_id(mes.customerId);
// 계획 수량 = ISA-95 Quantity. 값은 10진 문자열, 단위는 MES 가 준 UN/ECE Rec 20 코드(EA·KGM·LTR …) — 환산하지 않는다
req.setPlanned_quantity(Quantity.of(mes.qty.toPlainString(), mes.unitCode));
req.setTime_per_unit_in_ms(mes.cycleTime);
req.setPlanned_start_timestamp(mes.plannedStart);
req.setPlanned_end_timestamp(mes.plannedEnd);
req.setExternal_id(mes.mesOrderId);
req.setExternal_system("MES");
OrderResponseV5 created = client.order().create(req);
if (created == null) {
log.error("작업지시 생성 실패: " + orderId);
return;
}
// 2) 작업 시작 (생성 직후가 아닌, 라인 IDLE 신호 받은 시점에 호출)
if (!client.order().start(orderId)) {
log.warn("시작 실패 — 현재 상태 확인 필요");
return;
}
// 3) 작업 진행 모니터링 ...
// ...
// 4) 작업 종료
client.order().end(orderId);
}
18.4 Full Line Health Dashboard
A dashboard data collector that aggregates the number of tags, recent alarms, and current work orders for equipment under a specific line.
import java.util.List;
import java.util.stream.Collectors;
public static DashboardSnapshot collectLineHealth(APIClient_V5 client, String lineId) {
DashboardSnapshot snap = new DashboardSnapshot();
// 1) Line 산하 Equipment
List<AssetResponseV5> equipments = client.asset().list().stream()
.filter(a -> lineId.equals(a.getParent_asset_id()))
.filter(a -> "M".equals(a.getAsset_type()))
.collect(Collectors.toList());
snap.equipmentCount = equipments.size();
// 2) 각 Equipment 통계
for (AssetResponseV5 eq : equipments) {
long tagCount = client.tag().countByAsset(eq.getAsset_id());
snap.totalTags += tagCount;
PathResponseV5 path = client.path().getByAsset(eq.getAsset_id());
snap.paths.put(eq.getAsset_id(),
String.format("%s > %s > %s > %s",
path.getSite_name(), path.getArea_name(),
path.getLine_name(), path.getEquipment_name()));
}
// 3) 최근 알람 — 라인 산하 자산만
List<String> assetIds = equipments.stream()
.map(AssetResponseV5::getAsset_id)
.collect(Collectors.toList());
snap.recentAlarms = client.alarm().list(200).stream()
.filter(a -> a.getTag_location() != null
&& assetIds.stream()
.anyMatch(id -> a.getTag_location().contains(id)))
.collect(Collectors.toList());
// 4) 현재 진행중 작업지시
snap.activeOrders = client.order().list().stream()
.filter(o -> "START".equals(o.getStatus())
|| "PAUSE".equals(o.getStatus()))
.filter(o -> assetIds.contains(o.getAsset_id()))
.collect(Collectors.toList());
return snap;
}
18.5 Bulk Application of Tag Alarm Thresholds
Applying alarm thresholds in bulk to all temperature tags of a specific line according to changes in the operating environment.
public static void applyTempAlarmsToLine(APIClient_V5 client, String lineId) {
// 1) 라인 산하 Equipment
List<AssetResponseV5> equipments = client.asset().list().stream()
.filter(a -> lineId.equals(a.getParent_asset_id()))
.collect(Collectors.toList());
// 2) 각 Equipment의 온도 태그
for (AssetResponseV5 eq : equipments) {
List<TagResponseV5> tempTags = client.tag().listByAsset(eq.getAsset_id())
.stream()
.filter(t -> "C".equals(t.getUnit()))
.collect(Collectors.toList());
// 3) patchAlarm으로 임계치 일괄 적용 (서버에서 CEP/EQL 재배포)
for (TagResponseV5 t : tempTags) {
TagAlarmPatchRequestV5 alarm = new TagAlarmPatchRequestV5();
alarm.setUse_alarm("Y");
alarm.setLo_lo("0");
alarm.setLo("10");
alarm.setHi("80");
alarm.setHi_hi("95");
alarm.setTrip_hi("100");
alarm.setDuplicate_check_minutes(5);
alarm.setSend_email("Y");
client.tag().patchAlarm(t.getTag_id(), alarm);
}
}
}
18.6 Conflict Check between Inspection Schedules and Work Orders
import java.util.Set;
import java.util.stream.Collectors;
public static List<OrderResponseV5> conflictsWithMaintenance(
APIClient_V5 client, String fromIso, String toIso) {
// 1) 점검 일정의 자산 ID 집합
Set<String> mtnAssets = client.calendar().search(fromIso, toIso).stream()
.filter(c -> "MTN".equals(c.getTarget_type()))
.map(CalendarResponseV5::getAsset_id)
.collect(Collectors.toSet());
// 2) 같은 기간 진행중·예정 작업지시 중 점검 대상 자산
return client.order().list().stream()
.filter(o -> "WAIT".equals(o.getStatus()) || "START".equals(o.getStatus()))
.filter(o -> mtnAssets.contains(o.getAsset_id()))
.collect(Collectors.toList());
}
18.7 Flow Health Notification
A monitoring worker that sends notifications upon detecting a Flow that has encountered an error.
public static void monitorFlowHealth(APIClient_V5 client) throws InterruptedException {
Map<String, Long> lastErrorCounts = new HashMap<>();
while (true) {
for (FlowResponseV5 flow : client.flow().list()) {
long prev = lastErrorCounts.getOrDefault(flow.getFlow_id(), 0L);
long curr = flow.getError_count();
if (curr > prev) {
long newErrors = curr - prev;
sendAlert(String.format("Flow %s 에서 신규 에러 %d건 발생",
flow.getFlow_name(), newErrors));
}
lastErrorCounts.put(flow.getFlow_id(), curr);
}
Thread.sleep(30_000);
}
}
18.8 Tag CUD Lifecycle (Test Code Pattern)
A pattern frequently used in smoke tests or integration tests — from creation, retrieval, modification, and deletion to the cleanup of isolated resources.
public static void tagCudCycle(APIClient_V5 client) {
long ts = System.currentTimeMillis();
String opcId = "OPC_TEST_" + ts;
String tagId = "TAG_TEST_" + ts;
// 1) 부모 OPC 생성 (Tag의 FK)
OPCRequestV5 opcReq = new OPCRequestV5();
opcReq.setOpc_id(opcId);
opcReq.setOpc_name("test-opc-" + ts);
opcReq.setOpc_protocol("API");
opcReq.setSite_id("SITE_000001");
client.opc().create(opcReq);
try {
// 2) Tag 생성
TagRequestV5 req = new TagRequestV5();
req.setTag_id(tagId);
req.setTag_name("test-tag-" + ts);
req.setOpc_id(opcId);
req.setSite_id("SITE_000001");
req.setJava_type("Double");
req.setUnit("C");
TagResponseV5 created = client.tag().create(req);
assert created != null;
// 3) 조회 + 존재 확인
TagResponseV5 fetched = client.tag().get(tagId);
assert fetched != null;
assert client.tag().exists(tagId);
// 4) 수정
req.setTag_name("test-tag-" + ts + "-updated");
TagResponseV5 updated = client.tag().update(tagId, req);
assert updated != null;
assert req.getTag_name().equals(updated.getTag_name());
// 5) 삭제
assert client.tag().delete(tagId);
assert !client.tag().exists(tagId);
} finally {
// 6) 임시 OPC 정리
client.opc().delete(opcId);
}
}
Next Steps
- Select a specific domain manual from the table of contents in the README.
- It is recommended to review the ID design principles in the Domain ID Rules.