https://github.com/fa-yoshinobu/plc-comm-slmp-python
High-performance, strictly typed Python client for Mitsubishi SLMP (Seamless Message Protocol). Supports Binary 3E/4E frames for iQ-R, iQ-F, and Q series PLCs.
https://github.com/fa-yoshinobu/plc-comm-slmp-python
industrial-automation iot melsec mitsubishi plc python slmp
Last synced: 17 days ago
JSON representation
High-performance, strictly typed Python client for Mitsubishi SLMP (Seamless Message Protocol). Supports Binary 3E/4E frames for iQ-R, iQ-F, and Q series PLCs.
- Host: GitHub
- URL: https://github.com/fa-yoshinobu/plc-comm-slmp-python
- Owner: fa-yoshinobu
- License: mit
- Created: 2026-03-13T13:46:28.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-06-11T19:57:22.000Z (17 days ago)
- Last Synced: 2026-06-11T21:15:36.902Z (17 days ago)
- Topics: industrial-automation, iot, melsec, mitsubishi, plc, python, slmp
- Language: Python
- Homepage:
- Size: 2.23 MB
- Stars: 3
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/ci.yml)
[](https://fa-yoshinobu.github.io/plc-comm-slmp-python/)
[](https://pypi.org/project/slmp-connect-python/)
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://github.com/astral-sh/ruff)
# SLMP Protocol for Python

[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/automated-release.yml)
[](https://github.com/fa-yoshinobu/plc-comm-slmp-python/actions/workflows/release.yml)
[](https://www.python.org/)
[](https://www.mkdocs.org/)
[](https://pages.github.com/)
High-level SLMP helpers for Mitsubishi PLC communication over Binary 3E and 4E frames.
This repository treats the high-level helper layer as the recommended user surface:
- `SlmpConnectionOptions`
- `open_and_connect` / `open_and_connect_sync`
- `AsyncSlmpClient`
- `QueuedAsyncSlmpClient`
- `SlmpClient`
- `normalize_address`
- `parse_address` / `try_parse_address` / `format_address`
- `read_typed` / `write_typed`
- `read_words_single_request` / `read_dwords_single_request`
- `read_words_chunked` / `read_dwords_chunked`
- `write_bit_in_word`
- `read_named` / `write_named`
- `poll`
## Installation
```bash
pip install slmp-connect-python
```
The latest release lives at , where wheel and tarball downloads and metadata are available.
## Quick Start
Recommended async path:
```python
import asyncio
from slmp import SlmpConnectionOptions, open_and_connect, read_named, write_typed
async def main() -> None:
options = SlmpConnectionOptions(
host="192.168.250.100",
plc_family="iq-f",
port=1025,
)
async with await open_and_connect(options) as client:
before = await read_named(client, ["D100", "D200:F", "D50.3"])
print("before:", before)
await write_typed(client, "D100", "U", 42)
after = await read_named(client, ["D100", "D200:F", "D50.3"])
print("after:", after)
asyncio.run(main())
```
Choose canonical `plc_family` explicitly.
In the recommended high-level helper layer, the only PLC selector is `plc_family`.
## High-Level PLC Selection
For normal application code:
- set `plc_family`
- let the library derive the fixed frame type, access profile, `X` / `Y` text rule, and device-range family
- do not pass raw `frame_type`, `plc_series`, or `device_family`
| `plc_family` | Derived `frame_type` | Derived `access_profile` | `X` / `Y` text | Derived range family | Notes |
| --- | --- | --- | --- | --- | --- |
| `iq-f` | `3e` | `ql` | octal | `iq-f` | live-validated |
| `iq-r` | `4e` | `iqr` | hexadecimal | `iq-r` | live-validated |
| `iq-l` | `4e` | `iqr` | hexadecimal | `iq-l` | live-validated on `L16HCPU` |
| `mx-f` | `4e` | `iqr` | hexadecimal | `mx-f` | fixed family mapping |
| `mx-r` | `4e` | `iqr` | hexadecimal | `mx-r` | fixed family mapping |
| `qcpu` | `3e` | `ql` | hexadecimal | `qcpu` | retained path |
| `lcpu` | `3e` | `ql` | hexadecimal | `lcpu` | retained path |
| `qnu` | `3e` | `ql` | hexadecimal | `qnu` | retained path |
| `qnudv` | `3e` | `ql` | hexadecimal | `qnudv` | retained path |
Low-level compatibility tools may still work with raw `frame_type` / `plc_series`, but that is not the normal public helper path.
High-level accepted `plc_family` values:
| Canonical | Typical target | Notes |
| --- | --- | --- |
| `iq-f` | FX5 / iQ-F | `X` / `Y` use manual octal text |
| `iq-r` | iQ-R | `X` / `Y` use hexadecimal text |
| `iq-l` | iQ-L | independent iQ-L range rules; live-validated on `L16HCPU` |
| `mx-f` | MX-F | fixed high-level family mapping |
| `mx-r` | MX-R | fixed high-level family mapping |
| `qcpu` | QCPU | `3e/ql` fixed profile |
| `lcpu` | LCPU | `3e/ql` fixed profile |
| `qnu` | QnU | `3e/ql` fixed profile |
| `qnudv` | QnUDV | `3e/ql` fixed profile |
Practical rules:
- non-`iQ-F` `X` / `Y`: text such as `X20` / `Y20` is interpreted as hexadecimal
- `iQ-F` / FX5 `X` / `Y`: text such as `X100` / `Y100` is interpreted as manual octal notation and encoded to the binary numeric value
- example: `X100` on `iQ-F` becomes binary device number `0x40`
- if you pass a numeric `DeviceRef`, string notation is already resolved, so `plc_family` is not needed for that one address
- short aliases such as `iqf`, `iqr`, `q`, `l`, and `qnudvcpu` are rejected
## Supported PLC Registers
Start with these public high-level families first:
- word devices: `D`, `SD`, `R`, `ZR`, `TN`, `CN`
- bit devices: `M`, `X`, `Y`, `SM`, `B`
- typed forms: `D200:F`, `D300:L`, `D100:S`
- mixed snapshot forms: `D50.3`, `D100`, `D200:F`
- current-value long families: `LTN`, `LSTN`, `LCN`
- 32-bit index register: `LZ`
Long-family route notes:
- `LTN`, `LSTN`, `LCN`, and `LZ` default to 32-bit `:D` access in high-level helpers.
- `LCN` current-value reads and writes use random dword access in the high-level helpers.
- `LTS`, `LTC`, `LSTS`, and `LSTC` state reads use the long timer 4-word decode helpers.
- `LCS` and `LCC` state reads use direct bit read.
- High-level state writes for `LTS`/`LTC`/`LSTS`/`LSTC`/`LCS`/`LCC` use random bit write (`0x1402`).
- Low-level direct bit writes and direct word writes to these long-family logical forms are guarded before transport.
See the full public table in [Supported PLC Registers](docsrc/user/SUPPORTED_REGISTERS.md).
## Public Documentation
- [Getting Started](docsrc/user/GETTING_STARTED.md)
- [Supported PLC Registers](docsrc/user/SUPPORTED_REGISTERS.md)
- [Latest Communication Verification](docsrc/user/LATEST_COMMUNICATION_VERIFICATION.md)
- [User Guide](docsrc/user/USER_GUIDE.md)
- [Samples](docsrc/user/SAMPLES.md)
- [Error Codes](docsrc/user/ERROR_CODES.md)
Maintainer-only notes and retained evidence live under `internal_docs/`.
## High-Level API Guide
### Address Normalization
```python
from slmp import format_address, normalize_address, parse_address
print(normalize_address("x20")) # X20
print(normalize_address("d200")) # D200
print(normalize_address("x100", plc_family="iq-f")) # X100
parsed = parse_address("d200:f")
print(parsed.base_device, parsed.dtype) # D200 F
print(format_address(parsed)) # D200:F
```
### Single Typed Values
```python
from slmp import read_typed, write_typed
temperature = await read_typed(client, "D200", "F")
counter = await read_typed(client, "D300", "L")
await write_typed(client, "D100", "U", 1234)
```
Use `.bit` notation only with word devices such as `D50.3`.
Address bit devices directly as `M1000`, `M1001`, `X20`, or `Y20`.
For communication, `X` / `Y` string addresses require explicit `plc_family`.
### Device Range Catalog
Use `plc_family` and read the derived family SD block once.
```python
from slmp import SlmpClient
with SlmpClient("192.168.250.100", 1025, plc_family="qnu") as client:
catalog = client.read_device_range_catalog()
for entry in catalog.entries:
print(entry.device, entry.point_count, entry.address_range)
```
This path does not call `read_type_name()`. The client uses the fixed range family derived from `plc_family`.
## Development
```bash
run_ci.bat
build_docs.bat
release_check.bat
```
## License
Distributed under the [MIT License](LICENSE).