Metadata-Version: 2.4
Name: serial-tcp-clients
Version: 2.2.3
Summary: Share serial device through TCP connections
Author-email: maslovw <serialtcp@maslovw.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/maslovw/serial_tcp_clients
Keywords: serial,com,port,tcp,server,socket
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: pyserial>=3.3
Dynamic: license-file

# serial-tcp-server

TCP server for sharing a serial console across multiple TCP clients.

```
clientA <-->\
             | <-----> TcpServer <---> serial port
clientB <-->/
```

The serial port opens when the first client connects and closes when
the last client disconnects. If the serial device is lost, all TCP
clients are kept connected while the server attempts to reconnect.

Works on Windows and Linux (including Raspberry Pi).

## Requirements

- Python >= 3.9
- pyserial >= 3.3

## Install

```bash
pip install serial-tcp-clients
```

This installs the **CLI/backend only** (depends on `pyserial` alone — no GUI, no
Tkinter, no PyYAML). For the desktop app see [GUI (Port Manager)](#gui-port-manager),
which is a separate `serial-tcp-clients-gui` package.

Or from source:

```bash
git clone https://github.com/maslovw/serial_tcp_clients.git
cd serial_tcp_clients
pip install .
```

## Usage

```bash
serial-tcp-server -p PORT -d DEVICE -b BAUDRATE
```

Or via module:

```bash
python -m serialtcp -p PORT -d DEVICE -b BAUDRATE
```

### Arguments

```
optional arguments:
  -h, --help            show this help message and exit
  --list                print list of serial devices
  -v {debug,info,warn,error,fatal}, --verbose {debug,info,warn,error,fatal}
                        logger level, default: error

TCP connection:
  -p TCP_PORT, --tcp-port TCP_PORT
                        TCP listen port

serial port:
  -d DEVICE, --device DEVICE
                        serial port/device
  -b BAUDRATE, --baudrate BAUDRATE
                        default: 115200
  --parity {N,E,O,S,M}  set parity, one of {N E O S M}, default: N
  --xonxoff             enable software flow control (default off)
  -cd CHAR_DELAY, --char-delay CHAR_DELAY
                        set delay between chars for serial transmission,
                        default: 0.0s
  -we WAIT_ECHO, --wait-echo WAIT_ECHO
                        wait for echo char when transmitting, value represents
                        timeout in seconds, default: 0
```

### Example

```bash
serial-tcp-server -p 5001 -d COM1 -b 921600 -v info -we 1
```

Use `-v debug` to send connection status messages (device, baudrate,
connect/disconnect events) to TCP clients.

## GUI (Port Manager)

A separate **Tkinter desktop app** (the `serial-tcp-clients-gui` package, built on
the CLI/backend) manages **many** serial -> TCP mappings at once from a single
YAML config. It uses a master-detail layout: a list of port cards on the left,
and the selected port's console, settings, throughput and live log on the right.

![Port Manager GUI](docs/port-manager.png)

For each mapping you can Start/Stop the TCP listener, watch live OUT/IN
throughput, the connected-client count and the serial device's link state
(a green/grey port chip), read a colour-coded console, send data to the serial
device from a console input line, and Add/Edit/Remove
mappings. The serial port opens when the first TCP client connects and closes
when the last disconnects; if the device drops, the clients stay connected while
the GUI shows a "reconnecting" banner and retries.

### Requirements

- Python >= 3.9
- pyserial >= 3.3 and PyYAML >= 5.1 (both pulled in by the `[gui]` extra)
- Tkinter — bundled with the standard Python installers on **Windows** and
  **macOS**. On Linux, install it from your package manager
  (Debian/Ubuntu: `sudo apt install python3-tk`).

### Build / install

**From PyPI:**

```bash
pip install serial-tcp-clients-gui
```

The GUI is its own package; it pulls in the CLI/backend package
(`serial-tcp-clients`) and PyYAML automatically.

**From source (recommended for development) — Windows:**

```bat
git clone https://github.com/maslovw/serial_tcp_clients.git
cd serial_tcp_clients
python -m venv .venv
.venv\Scripts\activate
pip install -e . -e gui
```

**From source — Linux / macOS:**

```bash
git clone https://github.com/maslovw/serial_tcp_clients.git
cd serial_tcp_clients
python3 -m venv .venv
source .venv/bin/activate
pip install -e . -e gui
```

**Standalone Windows executable (no Python needed on the target machine):**

```bat
deploy\build-gui.bat
```

This uses PyInstaller to produce a single windowed binary `serial-tcp-gui.exe`
in the repository root. It builds in a throwaway virtualenv, so it does not
touch your working `.venv`. Pass an explicit interpreter if `python` is not on
your PATH: `deploy\build-gui.bat C:\Python310\python.exe`.

### Start / run

With the package installed (console script on PATH):

```bash
serial-tcp-gui                 # loads ./serialtcp_ports.yaml if present
serial-tcp-gui ports.yaml      # load a specific config
```

As a module (works without the console script on PATH):

```bash
python -m serialtcp_gui ports.yaml
```

From a source venv on Windows, or the standalone build:

```bat
.venv\Scripts\serial-tcp-gui.exe ports.yaml
serial-tcp-gui.exe ports.yaml
```

If no config path is given, the app uses `./serialtcp_ports.yaml`. Any mapping
you Add/Edit/Remove in the GUI is **saved back** to that file.

### Configuration file

A YAML file with a `ports:` list; each entry binds one serial device to one TCP
listen port. Only `device` and `tcp_port` are required — everything else has
sensible defaults.

```yaml
ports:
  - name: COM103          # optional label (defaults to the device name)
    device: COM103        # COM103 on Windows, /dev/ttyUSB0 on Linux
    tcp_port: 5000        # TCP port that clients connect to
    baudrate: 921600
    parity: N             # one of N E O S M
    xonxoff: false        # software flow control
    char_mode: false      # send characters one at a time
    char_delay: 0.0       # seconds between characters
    wait_echo: 0.0        # seconds to wait for echo per character
    line_ending: CRLF     # console send newline: CRLF | LF | CR | none
    log_file: ''          # path to log all serial activity ('' = off)
    allow_remote: false   # false = listen on 127.0.0.1 only; true = 0.0.0.0
    autostart: true       # start listening as soon as the GUI opens
```

By default a mapping listens on **`127.0.0.1`** (localhost only), so the serial
console is not exposed on the network. Set `allow_remote: true` (or tick
**Allow remote connections** in the Add/Edit dialog) to bind `0.0.0.0` and accept
connections from other machines.

A ready-to-edit example lives in [`ports.example.yaml`](ports.example.yaml).

### Using it

- **Start / Stop** a port from its card or the detail panel; **Start all** and
  **Stop all** are in the top bar.
- **＋ Add serial → TCP port** (top bar or the dashed list footer) opens a dialog
  to choose the serial device, baudrate, parity, flow/char options and the TCP
  listen port. **Edit** changes a mapping; **Remove** deletes a stopped one.
- Connect any TCP client to the listen port to talk to the device, e.g.:

  ```bash
  telnet localhost 5000
  ```

  or PuTTY (connection type *Raw* or *Telnet*, host `localhost`, port `5000`),
  or `nc localhost 5000`. Several clients can share one serial device at once.
- **Console** — the live log timestamps each line `[HH:MM:SS:MSEC]`, renders
  ANSI colours and splits CR/CRLF/LF lines; scroll back through history with the
  scrollbar or mouse wheel. The header has **copy** (the selection, or the whole
  console) and **clear** buttons. The input row sends what you type; the dropdown
  next to it picks the appended line ending (`CRLF`/`LF`/`CR`/`none`), which is
  saved to the config.
- **Terminal as a client** — the serial port is normally open only while a TCP
  client is connected. Click **Connect** in the console input row to attach the
  GUI itself as a client (opening the serial port) so you can send and receive in
  the integrated terminal with no external client connected; **Disconnect**
  releases it (and closes the port if nothing else is using it).
- **Logging** — click **log** in the console header (or set `log_file` in the
  config / dialog) to record all serial activity to a file. Each line is stamped
  `[dd.mm.YY HH:MM:SS:MSEC]`.
