> For the complete documentation index, see [llms.txt](https://kopens.gitbook.io/plantpulse-platform/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kopens.gitbook.io/plantpulse-platform/developer/api-manual/opc-service.md).

# 6. OPC 서비스

`client.opc()` 으로 접근합니다. OPC는 **데이터 수집 채널**(Data Source)을 나타냅니다. OPC UA 서버, PLC, Modbus, RDBMS, REST API/파일, 가상 채널 등 외부 데이터의 진입점입니다.

> **ID 규칙**: `OPC_` 또는 `API_` 접두사 필수. 자세한 내용은 [도메인 ID 규칙](/plantpulse-platform/developer/api-manual/id-rules.md#23-opc-id) 참고.

## 6.1 메서드 일람

| 메서드                            | 반환 타입                     | HTTP   | 엔드포인트                           |
| ------------------------------ | ------------------------- | ------ | ------------------------------- |
| `create(OPCRequestV5)`         | `OPCResponseV5` 또는 `null` | POST   | `/api/v5/opc`                   |
| `update(opc_id, OPCRequestV5)` | `OPCResponseV5` 또는 `null` | PUT    | `/api/v5/opc/{id}`              |
| `delete(opc_id)`               | `boolean`                 | DELETE | `/api/v5/opc/{id}`              |
| `get(opc_id)`                  | `OPCResponseV5` 또는 `null` | GET    | `/api/v5/opc/{id}`              |
| `list()`                       | `List<OPCResponseV5>`     | GET    | `/api/v5/opc`                   |
| `listBySite(site_id)`          | `List<OPCResponseV5>`     | GET    | `/api/v5/opc?site_id=...`       |
| `listByType(opc_type)`         | `List<OPCResponseV5>`     | GET    | `/api/v5/opc?opc_type=...`      |
| `exists(opc_id)`               | `boolean`                 | GET    | `/api/v5/opc/{id}/exists`       |
| `count()`                      | `long`                    | GET    | `/api/v5/opc/count`             |
| `countBySite(site_id)`         | `long`                    | GET    | `/api/v5/opc/count?site_id=...` |

## 6.2 OPC Type 값

| 값          | 용도                                          |
| ---------- | ------------------------------------------- |
| `OPC`      | OPC UA / OPC DA 서버                          |
| `PLC`      | Siemens, Mitsubishi, Allen-Bradley 등 PLC 직결 |
| `MODBUS`   | Modbus TCP/RTU 디바이스                         |
| `DATABASE` | 외부 RDBMS (Oracle, MSSQL 등)                  |
| `FILE`     | REST API / 파일 임포트                           |
| `VIRTUAL`  | 가상 채널 (시뮬레이션·테스트용)                          |

## 6.3 OPCRequestV5 / OPCResponseV5

| 필드               | 타입     | 설명                                               |
| ---------------- | ------ | ------------------------------------------------ |
| `opc_id`         | String | OPC ID (PK, `OPC_` 또는 `API_` 필수)                 |
| `opc_name`       | String | OPC 표시명                                          |
| `opc_type`       | String | `OPC`/`PLC`/`MODBUS`/`DATABASE`/`FILE`/`VIRTUAL` |
| `opc_sub_type`   | String | 세부 타입 (예: PLC 제조사)                               |
| `opc_server_ip`  | String | OPC 서버 IP                                        |
| `opc_agent_ip`   | String | 데이터 수집 에이전트 IP                                   |
| `opc_agent_port` | int    | 에이전트 포트                                          |
| `site_id`        | String | 소속 사이트                                           |
| `description`    | String | 설명                                               |

## 6.4 사용 예시

### OPC 생성 (PLC 직결)

```java
import plantpulse.api.v5.dto.request.OPCRequestV5;
import plantpulse.api.v5.dto.response.OPCResponseV5;

OPCRequestV5 req = new OPCRequestV5();
req.setOpc_id("OPC_PLC_L1_001");
req.setOpc_name("Line1 메인 PLC");
req.setOpc_type("PLC");
req.setOpc_sub_type("SIEMENS_S7");
req.setOpc_server_ip("192.168.10.50");
req.setSite_id("SITE_DJ");
req.setOpc_agent_ip("192.168.10.5");
req.setOpc_agent_port(60000);

OPCResponseV5 created = client.opc().create(req);
```

### OPC 생성 (외부 REST API)

```java
OPCRequestV5 api = new OPCRequestV5();
api.setOpc_id("API_ERP_001");                              // 관례상 API_ 접두사
api.setOpc_name("ERP 생산 실적 API");
api.setOpc_type("FILE");
api.setSite_id("SITE_DJ");
api.setDescription("매시간 ERP에서 생산 카운트 폴링");
client.opc().create(api);
```

### OPC 생성 (가상 — 테스트용)

```java
OPCRequestV5 v = new OPCRequestV5();
v.setOpc_id("OPC_VIRTUAL_001");
v.setOpc_name("테스트용 가상 OPC");
v.setOpc_type("VIRTUAL");
v.setSite_id("SITE_00001");
v.setOpc_agent_ip("127.0.0.1");
v.setOpc_agent_port(0);
client.opc().create(v);
```

### 사이트별 OPC 조회

```java
import java.util.List;

List<OPCResponseV5> djOpcs = client.opc().listBySite("SITE_DJ");
for (OPCResponseV5 opc : djOpcs) {
    System.out.println(opc.getOpc_id() + " (" + opc.getOpc_type() + ")");
}
```

### 타입별 OPC 조회

```java
// 모든 사이트의 PLC만
List<OPCResponseV5> plcs = client.opc().listByType("PLC");

// 모든 사이트의 Modbus만
List<OPCResponseV5> modbus = client.opc().listByType("MODBUS");
```

### 카운트

```java
long total      = client.opc().count();
long djCount    = client.opc().countBySite("SITE_DJ");
System.out.printf("전체 OPC: %d, 대전공장: %d%n", total, djCount);
```

### CUD 라이프사이클

```java
String opcId = "OPC_PLC_L1_001";

// 생성
OPCRequestV5 req = new OPCRequestV5();
req.setOpc_id(opcId);
req.setOpc_name("초기 이름");
req.setOpc_type("PLC");
req.setSite_id("SITE_DJ");
client.opc().create(req);

// 존재 여부 확인
assert client.opc().exists(opcId);

// 수정
req.setOpc_name("수정된 이름");
client.opc().update(opcId, req);

// 삭제
boolean deleted = client.opc().delete(opcId);
assert !client.opc().exists(opcId);
```

## 6.5 활용 시나리오

### 시나리오 — 신규 라인 PLC 등록 후 태그 수집 대기

```java
// 1) OPC 등록
OPCRequestV5 plc = new OPCRequestV5();
plc.setOpc_id("OPC_PLC_L2_001");
plc.setOpc_type("PLC");
plc.setSite_id("SITE_DJ");
plc.setOpc_server_ip("192.168.10.60");
plc.setOpc_agent_ip("192.168.10.5");
plc.setOpc_agent_port(60000);
client.opc().create(plc);

// 2) 에이전트가 자동으로 태그를 수집하면 — 이후 Tag 서비스에서 확인
List<TagResponseV5> tags = client.tag().listByOpc("OPC_PLC_L2_001");
System.out.println("수집된 태그 수: " + tags.size());
```

## 다음 단계

* [Asset 서비스](/plantpulse-platform/developer/api-manual/asset-service.md) — Equipment와 태그를 연결할 자산 트리
* [Tag 서비스](/plantpulse-platform/developer/api-manual/tag-service.md) — 태그 정의 및 OPC 연결
