> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/deployment/ko/self-hosted/enterprise/deployment-manager/services/plc-relay.md).

# PLC 릴레이

PLC Relay는 PLC 태그를 읽고 쓰기 위한 HTTP API를 제공하는 엣지 컨테이너 서비스입니다. Deployment Manager UI에서 프로토콜을 선택하고, 연결 세부 정보를 입력하며, 태그를 정의하여 구성합니다.

{% hint style="info" %}
PLC Relay는 Enterprise 고객 전용으로 제공됩니다. [Roboflow 영업팀에 문의하세요](https://roboflow.com/sales) 자세한 내용을 알아보세요.
{% endhint %}

## 지원되는 프로토콜

PLC Relay 서비스를 추가하거나 편집할 때 세 가지 프로토콜 중 하나를 선택합니다. 각 프로토콜에는 자체 연결 설정과 태그 형식이 있습니다.

<table data-header-hidden data-search="false"><thead><tr><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>프로토콜</td><td><code>PLC_DRIVER</code></td><td>PLC</td><td>기본 포트</td></tr><tr><td>Allen-Bradley(EtherNet/IP)</td><td><code>allen_bradley</code></td><td>CompactLogix, ControlLogix, Micro800</td><td>44818</td></tr><tr><td>Modbus TCP</td><td><code>modbus</code></td><td>모든 Modbus TCP 장치</td><td>502</td></tr><tr><td>Siemens S7</td><td><code>siemens_s7</code></td><td>S7-300, S7-400, S7-1200, S7-1500</td><td>102</td></tr></tbody></table>

{% hint style="warning" %}
프로토콜 간에는 태그 주소 형식을 서로 교환할 수 없으므로 프로토콜을 전환하면 구성된 모든 태그가 삭제됩니다. UI는 변경 사항을 적용하기 전에 확인을 요청합니다.
{% endhint %}

## 연결 설정

### PLC 주소

주소 형식은 선택한 프로토콜에 따라 달라집니다:

* **Allen-Bradley:** IP 또는 호스트 이름 뒤에 선택적으로 `/slot` (예: `192.168.1.100/0`) 또는 전체 CIP 라우팅 경로.
* **Modbus TCP:** 선택적 `:port가 포함된 IP 또는 호스트 이름` (예: `192.168.1.100:502`). 또한 32비트 값에는 Unit ID(0\~255)와 워드 순서(빅 엔디언 또는 리틀 엔디언)가 필요합니다.
* **Siemens S7:** 선택적 `:port가 포함된 IP 또는 호스트 이름` (예: `192.168.1.100:102`). 또한 Rack(0\~7) 및 Slot(0\~31)이 필요합니다.

### 시뮬레이션 모드

활성화하면 PLC Relay는 실제 PLC에 연결하는 대신 메모리 내 시뮬레이터를 사용합니다. 모든 API 작업은 정상적으로 작동하지만 값은 메모리에 저장됩니다. 하드웨어 없이 테스트할 때 유용합니다.

## 태그 구성

태그는 API를 통해 액세스할 수 있는 PLC 데이터 포인트를 정의합니다. 각 태그에는 이름, 데이터 유형, 쓰기 가능 플래그 및 선택적 설명이 있습니다.

### 데이터 유형

| 유형     | 설명            | 범위                            |
| ------ | ------------- | ----------------------------- |
| `BOOL` | 부울            | `true` / `false`              |
| `INT`  | 16비트 부호 있는 정수 | -32,768\~32,767               |
| `DINT` | 32비트 부호 있는 정수 | -2,147,483,648\~2,147,483,647 |
| `REAL` | 32비트 부동 소수점   | IEEE 754                      |

### 태그 이름 형식

{% tabs %}
{% tab title="Allen-Bradley" %}
태그 이름은 PLC 프로그램과 일치해야 하며 대소문자를 구분합니다.

| 스타일          | 예시                            |
| ------------ | ----------------------------- |
| 단순           | `TagName`                     |
| 프로그램 범위      | `Program:MainProgram.TagName` |
| 배열 요소        | `TagName[0]`                  |
| UDT 멤버       | `MyUDT.Member`                |
| {% endtab %} |                               |

{% tab title="Modbus TCP" %}
형식: `{area}:{address}` 여기서 address는 음수가 아닌 정수입니다.

| 영역           | 유형              | 액세스   | 예시            |
| ------------ | --------------- | ----- | ------------- |
| `코일`         | BOOL            | 쓰기 가능 | `coil:0`      |
| `이산 입력`      | BOOL            | 읽기 전용 | `discrete:5`  |
| `홀딩`         | INT, DINT, REAL | 쓰기 가능 | `holding:100` |
| `입력`         | INT, DINT, REAL | 읽기 전용 | `input:200`   |
| {% endtab %} |                 |       |               |

{% tab title="Siemens S7" %}
데이터 블록 형식: `DB{n}.DB[XWD]{byte}[.{bit}]`

영역 형식: `[MIQEA][WD]?{byte}[.{bit}]`

| 주소              | 유형                 | 설명                       |
| --------------- | ------------------ | ------------------------ |
| `DB1.DBX0.0`    | BOOL               | 데이터 블록 1의 바이트 0에 있는 비트 0 |
| `DB1.DBW0`      | INT                | DB1의 16비트 워드             |
| `DB1.DBD0`      | DINT 또는 REAL       | DB1의 32비트 더블 워드          |
| `M0.0`          | BOOL               | 메르커 비트                   |
| `I0.0` / `Q0.0` | BOOL               | 프로세스 입력/출력 비트            |
| `MW0` / `MD0`   | INT / DINT 또는 REAL | 메르커 워드 / 더블 워드           |

S7-1200/1500의 경우: TIA Portal에서 PUT/GET을 활성화하고 액세스되는 DB의 최적화된 블록 액세스를 비활성화하세요.
{% endtab %}
{% endtabs %}

## 웹 대시보드

PLC Relay에는 태그 값을 실시간으로 모니터링하는 기본 제공 웹 대시보드가 포함되어 있습니다. 서비스가 실행되면 다음에서 액세스하세요. `http://<device-ip>:8007`.

대시보드는 다음 위치에서 대화형 Swagger 문서도 호스팅합니다. `/docs` 그리고 다음 위치에 시각적 구성 빌더가 있습니다. `/static/config-builder.html`.

## HTTP API

API는 HTTP를 통해 구성된 태그를 읽고 쓰므로, 파이프라인은 Allen-Bradley EtherNet/IP, Modbus TCP 또는 Siemens S7과 직접 통신하지 않고도 PLC 데이터를 교환할 수 있습니다. 기본 URL은 `http://<device-ip>:8007`, API는 인증을 사용하지 않습니다. 다음을 참조하세요. [서비스](/deployment/ko/self-hosted/enterprise/deployment-manager/services.md#using-the-apis) 모든 온디바이스 서비스 API에 공통으로 적용되는 규칙을 확인하세요.

태그는 서비스의 `PLC_TAGS` 환경 변수에서 가져오며 API를 통해 생성하거나 변경할 수 없습니다. 값만 쓸 수 있으며, 쓰기 가능으로 구성된 태그에만 쓸 수 있습니다.

### 상태 코드를 신뢰하기 전에 읽으세요

서비스에 도달했지만 PLC에서 실패한 요청은 다음을 반환합니다. `200`. 본문을 확인하세요:

* `/read` 은 다음을 반환합니다. `value: null` 와 함께 `error` 가 채워집니다.
* `/write` 은 다음을 반환합니다. `success: false` 와 함께 `error` 가 채워집니다.
* `/healthz` 은 다음을 반환합니다. `plc_connected: false`.

실제 `4xx` 응답은 요청 자체에 문제가 있음을 의미합니다: `404` 구성되지 않은 태그의 경우, `403` 읽기 전용으로 구성된 태그의 경우, `400` 빈 배치 또는 쓰기 배치에서 중복 태그 이름의 경우, `422` 유효성 검사에 실패한 본문 또는 쿼리 매개변수의 경우.

### 상태 및 유효성 검사

`/healthz` 은 활성 드라이버, 릴레이가 `라이브` 또는 `시뮬레이션` 모드인지 여부 및 최신 태그 유효성 검사 요약도 보고합니다. 유효성 검사는 구성된 각 태그를 PLC와 비교하여 다음 상태로 보고합니다. `ok`, `not_found`, `type_mismatch`, 또는 `not_validated`.

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/healthz" method="get" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

PLC 프로그램 변경 또는 재연결 후 유효성 검사를 다시 실행하세요:

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/validate" method="post" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

### 태그 정의

태그 이름은 활성 드라이버 형식의 PLC 주소이며, 다음에 설명되어 있습니다. [태그 이름 형식](#tag-name-formats).

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/schema" method="get" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

### 값 읽기 및 쓰기

```bash
curl "http://<device-ip>:8007/read?tag=Station1.CycleCount"

curl -X POST http://<device-ip>:8007/write \
  -H "Content-Type: application/json" \
  -d '{"name": "Station1.CycleCount", "value": 42}'
```

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/all\_tags" method="get" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/read" method="get" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/write" method="post" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

### 배치 작업

두 배치 엔드포인트는 실행 전에 전체 단위로 유효성을 검사하므로, 알 수 없는 태그가 있을 경우 부분 결과를 반환하는 대신 전체 요청이 거부됩니다.

`/write_batch` 는 동일한 태그를 두 번 지정한 배치도 추가로 거부합니다. 반복된 이름에 대해 마지막 값만 유지하면 이전 쓰기가 조용히 삭제되기 때문입니다. `/read_batch` 는 중복을 허용하고 전송한 순서대로 항목당 하나의 결과를 반환합니다.

유효성 검사 후 발생하는 PLC 실패는 항목별로 `write_batch`의 `결과`에 보고되며, `success_count` 및 `error_count` 가 배치를 요약합니다.

```bash
curl -X POST http://<device-ip>:8007/read_batch \
  -H "Content-Type: application/json" \
  -d '{"tags": ["Station1.PartPresent", "Station1.CycleCount"]}'
```

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/read\_batch" method="post" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/77e1ab3c53d5d0cbb663ea227bdd37cbd6f1f1cd" path="/write\_batch" method="post" %}
[edge-plc-relay.yaml](https://1826078061-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-bc81a2258bd5eefa9b64b301eac0797c0f01e796%2Fedge-plc-relay.yaml?alt=media)
{% endopenapi %}

## CLI

이 `plc-cli` 도구는 태그를 읽고 쓰기 위한 대화형 터미널 인터페이스를 제공합니다. 웹 대시보드에 연결할 수 없을 때 디버깅 및 빠른 작업에 사용하세요. 대시보드가 사용하는 동일한 HTTP API에 대해 컨테이너 내부에서 실행되는 로컬 클라이언트입니다.

```bash
docker exec -it plc-relay plc-cli
```

<table data-search="false"><thead><tr><th>키</th><th>동작</th></tr></thead><tbody><tr><td><code>R</code></td><td>모든 태그 값 읽기</td></tr><tr><td><code>T</code></td><td>목록에서 선택한 단일 태그 읽기</td></tr><tr><td><code>W</code></td><td>쓰기 가능한 태그에서 선택한 태그 쓰기</td></tr><tr><td><code>S</code></td><td>태그 스키마 표시</td></tr><tr><td><code>H</code></td><td>상세 상태 정보 표시</td></tr><tr><td><code>V</code></td><td>PLC에 대해 태그 유효성 검사 실행</td></tr><tr><td><code>Enter</code></td><td>화면 새로 고침</td></tr><tr><td><code>Q</code></td><td>종료</td></tr></tbody></table>

## 환경 변수

구성 모달이 이러한 값을 대신 작성합니다. 배포를 수동으로 관리하는 경우에만 직접 편집하세요. 다음을 참조하세요. [장치 구성 업데이트](/deployment/ko/self-hosted/enterprise/deployment-manager/making-changes/update-device-configuration.md).

<table data-search="false"><thead><tr><th>변수</th><th>기본값</th><th>설명</th></tr></thead><tbody><tr><td><code>PLC_DRIVER</code></td><td>없음</td><td><code>allen_bradley</code>, <code>modbus</code>, 또는 <code>siemens_s7</code></td></tr><tr><td><code>PLC_IP</code></td><td>없음</td><td>선택한 드라이버 형식의 PLC 주소</td></tr><tr><td><code>PLC_TAGS</code></td><td>없음</td><td>JSON 형식의 태그 정의. 다음 위치의 구성 빌더가 <code>/static/config-builder.html</code> 이를 생성합니다</td></tr><tr><td><code>SIMULATION_MODE</code></td><td>꺼짐</td><td>실제 PLC 대신 메모리 내 시뮬레이터 사용</td></tr><tr><td><code>LOG_LEVEL</code></td><td><code>INFO</code></td><td>로깅 상세 수준: <code>DEBUG</code>, <code>INFO</code>, <code>WARNING</code>, 또는 <code>ERROR</code></td></tr></tbody></table>

드라이버별 설정:

<table data-search="false"><thead><tr><th>드라이버</th><th>변수</th><th>범위</th><th>기본값</th></tr></thead><tbody><tr><td>Modbus</td><td><code>MODBUS_UNIT_ID</code></td><td>0~255</td><td><code>1</code></td></tr><tr><td>Modbus</td><td><code>MODBUS_WORD_ORDER</code></td><td><code>빅 엔디언</code> 또는 <code>리틀 엔디언</code></td><td><code>빅 엔디언</code></td></tr><tr><td>Siemens S7</td><td><code>S7_RACK</code></td><td>0~7</td><td><code>0</code></td></tr><tr><td>Siemens S7</td><td><code>S7_SLOT</code></td><td>0~31</td><td><code>1</code></td></tr></tbody></table>

## 연결 모니터링

장치 페이지에는 현재 연결 상태, 활성 프로토콜 및 최신 태그 값을 포함하는 실시간 PLC Relay 상태 카드가 표시됩니다. 릴레이가 PLC에 연결할 수 없는 경우 카드에 연결 불가 배너가 표시됩니다.

릴레이의 연결이 끊어질 때 알림을 받으려면 장치의 "Device Alerts" 탭에서 "PLC Disconnected" 알림을 추가하세요. 다음을 참조하세요. [장치 알림 설정](/deployment/ko/self-hosted/enterprise/deployment-manager/setting-up/set-up-device-alerts.md).

## 문제 해결

| 증상                                 | 해결 방법                                                                                      |
| ---------------------------------- | ------------------------------------------------------------------------------------------ |
| "PLC not connected"(Allen-Bradley) | PLC 주소 형식(IP/Slot)을 확인하고 포트 44818에 연결할 수 있는지 확인하세요                                         |
| "PLC not connected"(Modbus)        | IP/포트(기본값 502)를 확인하고 Unit ID가 장치와 일치하는지 확인하세요                                              |
| "PLC not connected"(Siemens S7)    | IP/포트(기본값 102), rack 및 slot 값을 확인하세요. S7-1200/1500의 경우 PUT/GET을 활성화하고 최적화된 블록 액세스를 비활성화하세요 |
| "Function refused"(Siemens S7)     | TIA Portal에서 PUT/GET이 비활성화되었거나 대상 DB에서 최적화된 블록 액세스가 활성화됨                                   |
| REAL 값이 잘못된 값으로 읽힘(Modbus)         | 반대 워드 순서(빅 엔디언 대 리틀 엔디언)를 시도하세요                                                            |
| 유효성 검사에 NOT\_FOUND가 표시됨            | 정확한 태그 이름을 PLC 프로그램에서 확인하세요(대소문자 구분)                                                       |
