Metadata-Version: 2.4
Name: masterk-cnet
Version: 1.0.0
Summary: Python library for LS ELECTRIC MASTER-K K200S CNET communication
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: serial
Requires-Dist: pyserial>=3.5; extra == "serial"
Dynamic: license-file

# masterk-cnet

Python library for LS ELECTRIC (formerly LSIS) MASTER-K K200S built-in CNET communication.

This project is based on chapter 13, `K200S dedicated CNET communication`, of the Korean K200S user manual `국문사용설명서_K200S,300S,1000S_150619.pdf`.

Communication with other PLC models has not been verified. For other devices, use this library with caution or treat it as a protocol reference.

> This is an unofficial project and is not affiliated with LS ELECTRIC.

## Supported Features

- Individual Bit/Word read and write operations.
- Continuous Word read and write operations.
- PLC status reads.
- Serial(COM port) and TCP socket transports.
- Optional CNET BCC checksum handling.
- `FakeTransport` for tests and simulations.

## Installation

Install the base package when you only use TCP socket transport or `FakeTransport`.

```bash
pip install masterk-cnet
```

Install the `serial` extra when you communicate through a COM port. This extra installs pyserial.

```bash
pip install "masterk-cnet[serial]"
```

## Basic Usage

### COM Port

COM port communication requires `masterk-cnet[serial]`.

```python
from masterk_cnet import CnetClient, SerialTransport

with SerialTransport(
    port="COM3",
    baudrate=9600,
    bytesize=8,
    parity="N",
    stopbits=1,
    timeout=0.5,
) as transport:
    client = CnetClient(station=1, transport=transport)

    value = client.read_word("%MW0100")
    client.write_word("%MW0100", 0x1234)
    words = client.read_words("%DW0000", 10)
    client.write_words("%DW0000", [0x1234, 0x5678])
```

Use `connect_on_init=False` when you want to control the connection timing explicitly.

```python
from masterk_cnet import CnetClient, SerialTransport

transport = SerialTransport("COM3", baudrate=9600, connect_on_init=False)
transport.connect()

client = CnetClient(station=1, transport=transport)
value = client.read_word("%MW0100")

transport.close()
```

### TCP Socket

Use `SocketTransport` for Ethernet-to-serial converters, CNET gateways, or devices that relay CNET frames over TCP.

```python
from masterk_cnet import CnetClient, SocketTransport

transport = SocketTransport(
    host="192.168.0.10",
    port=2004,
    timeout=0.5,
)

client = CnetClient(station=1, transport=transport)

value = client.read_word("%MW0100")
client.write_word("%MW0100", 0x1234)

transport.close()
```

## Address Format

Use the standard CNET device address notation.

```python
client.read_word("%MW0100")
client.read_bit("%MX010F")
client.write_words("%DW0000", [0x1234, 0x5678])
```

The final Hex character in a Bit address must use uppercase `A` to `F`. For example, `%MX010F` is accepted, while `%MX010f` is treated as an input error.

## Verbose Debugging

```python
import logging

from masterk_cnet import CnetClient, SerialTransport

logging.basicConfig(level=logging.DEBUG)

with SerialTransport("COM3", baudrate=9600) as transport:
    client = CnetClient(station=1, transport=transport, verbose=True)
    client.read_word("%MW0100")
```

`verbose=True` writes TX/RX raw frames, human-readable ASCII output, and parse summaries to `logging.getLogger("cnet")` at DEBUG level.

## Error Handling

Communication failures, response parsing failures, and NAK responses are reported through `CnetError` subclasses.

```python
from masterk_cnet import CnetClient, CnetError, SerialTransport

try:
    with SerialTransport("COM3", baudrate=9600) as transport:
        client = CnetClient(station=1, transport=transport)
        value = client.read_word("%MW0100")
except CnetError as exc:
    print(exc)
```

## Data Representation

CNET Word values are transmitted as ASCII Hex text, not as binary byte arrays. The library sends Word `0x1234` as `"1234"` and `0x00FF` as `"00FF"`, starting from the most significant nibble.

Continuous Word values follow the same rule. For example, `[0xAA15, 0x056F]` is transmitted as `"AA15056F"`. K200S built-in CNET does not support Byte/DWord types in this library, so no little-endian or big-endian option is provided.

## Reference

- Original reference document: [국문사용설명서_K200S,300S,1000S.pdf](https://sol.ls-electric.com/kr/ko/product/document/6503)

---

# 한국어

LS일렉트릭(구 LS산전) MASTER-K K200S 내장 CNET 통신용 Python 라이브러리입니다.

K200S 국문 매뉴얼 `국문사용설명서_K200S,300S,1000S_150619.pdf`의 `제 13장 K200S 전용 CNET 통신`을 기반으로 작성되었습니다.

다른 PLC 장비와 통신은 검증하지 못했습니다. 타 장비에는 사용을 지양하시거나 구조 참고 정도로 권장드립니다.

> 해당 프로젝트는 LS일렉트릭과 무관한 비공식 프로젝트입니다.

## 지원 범위

- Bit/Word 개별 읽기 및 쓰기를 지원합니다.
- Word 연속 읽기 및 쓰기를 지원합니다.
- PLC 상태 읽기를 지원합니다.
- Serial(COM 포트) 및 TCP socket transport를 제공합니다.
- CNET BCC checksum 사용 여부를 선택할 수 있습니다.
- 테스트와 시뮬레이션을 위한 `FakeTransport`를 제공합니다.

## 설치

TCP socket 또는 테스트용 fake transport만 사용하는 경우 기본 패키지만 설치합니다.

```bash
pip install masterk-cnet
```

COM 포트로 통신하려면 pyserial이 포함된 serial extra를 설치합니다.

```bash
pip install "masterk-cnet[serial]"
```

## 기본 사용

### COM 포트

COM 포트 통신에는 `masterk-cnet[serial]` 설치가 필요합니다.

```python
from masterk_cnet import CnetClient, SerialTransport

with SerialTransport(
    port="COM3",
    baudrate=9600,
    bytesize=8,
    parity="N",
    stopbits=1,
    timeout=0.5,
) as transport:
    client = CnetClient(station=1, transport=transport)

    value = client.read_word("%MW0100")
    client.write_word("%MW0100", 0x1234)
    words = client.read_words("%DW0000", 10)
    client.write_words("%DW0000", [0x1234, 0x5678])
```

명시적으로 연결 시점을 제어하려면 `connect_on_init=False`를 사용하십시오.

```python
from masterk_cnet import CnetClient, SerialTransport

transport = SerialTransport("COM3", baudrate=9600, connect_on_init=False)
transport.connect()

client = CnetClient(station=1, transport=transport)
value = client.read_word("%MW0100")

transport.close()
```

### TCP socket

이더넷-시리얼 컨버터, CNET 게이트웨이, TCP로 CNET 프레임을 중계하는 장비는 `SocketTransport`를 사용합니다.

```python
from masterk_cnet import CnetClient, SocketTransport

transport = SocketTransport(
    host="192.168.0.10",
    port=2004,
    timeout=0.5,
)

client = CnetClient(station=1, transport=transport)

value = client.read_word("%MW0100")
client.write_word("%MW0100", 0x1234)

transport.close()
```

## 주소 형식

주소는 CNET 디바이스 표기법을 그대로 사용합니다.

```python
client.read_word("%MW0100")
client.read_bit("%MX010F")
client.write_words("%DW0000", [0x1234, 0x5678])
```

Bit 주소의 마지막 Hex 문자는 대문자 `A`~`F`를 사용해야 합니다. 예를 들어 `%MX010F`는 허용되지만 `%MX010f`는 입력 오류로 처리됩니다.

## verbose 디버깅

```python
import logging

from masterk_cnet import CnetClient, SerialTransport

logging.basicConfig(level=logging.DEBUG)

with SerialTransport("COM3", baudrate=9600) as transport:
    client = CnetClient(station=1, transport=transport, verbose=True)
    client.read_word("%MW0100")
```

`verbose=True`는 TX/RX 원본 프레임, 사람이 읽기 쉬운 ASCII 표현, 파싱 결과 요약을 `logging.getLogger("cnet")`에 DEBUG 로그로 남깁니다.

## 오류 처리

통신 실패, 응답 파싱 실패, NAK 응답은 `CnetError` 계열 예외로 전달됩니다.

```python
from masterk_cnet import CnetClient, CnetError, SerialTransport

try:
    with SerialTransport("COM3", baudrate=9600) as transport:
        client = CnetClient(station=1, transport=transport)
        value = client.read_word("%MW0100")
except CnetError as exc:
    print(exc)
```

## 데이터 표현

CNET의 Word 값은 binary byte 배열이 아니라 Hex 값을 ASCII 문자열로 전송합니다. 따라서 라이브러리는 Word `0x1234`를 `"1234"`로, `0x00FF`를 `"00FF"`로 최상위 nibble부터 전송합니다.

연속 Word도 같은 규칙을 적용해 `[0xAA15, 0x056F]`를 `"AA15056F"`로 전송합니다. K200S 내장 CNET은 Byte/DWord 타입을 지원하지 않으므로 별도 little-endian/big-endian 옵션은 제공하지 않습니다.

## 참고

- 원본 참고 문서: [국문사용설명서_K200S,300S,1000S.pdf](https://sol.ls-electric.com/kr/ko/product/document/6503)
