diff --git a/.gitignore b/.gitignore
index 68bc17f..2dc53ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,4 +157,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
-#.idea/
+.idea/
diff --git a/README.md b/README.md
index d719e58..79a4b68 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Pymodbus-REPL is a REPL (Read-Eval-Print Loop) tool for working with Modbus devi
- Python 3.8+
- Poetry (installed globally or within a virtual environment)
-### Installation
+### Dev instructions
1. Clone the repository:
@@ -23,6 +23,80 @@ Pymodbus-REPL is a REPL (Read-Eval-Print Loop) tool for working with Modbus devi
`poetry install`
+**NOTE** This repo is meant to be an helper for [pymodbus](https://github.com/pymodbus-dev/pymodbus) and the usage requires
+a working version of pymodbus.
+
+The installed `pymodbus` library for local development can also have impact on the path resolution while working locally on this repo.
+To overcome that problem, please make sure to run the [client](./pymodbus/client/main.py) and [server](./pymodbus/server/main.py) files
+from with in the respective working directories.
+
+For .e.g
+
+#### Run Server
+```
+(pymodbus3.8)
+pymodbus/repl/server on repl-server-startup [!?] via 🐍 v3.8.13 (pymodbus3.8)
+❯ python3 main.py --host 0.0.0.0 --verbose run --modbus-config default_config.json --modbus-server tcp --modbus-framer socket --modbus-port 5020 --unit-id 1 --unit-id 2 -u 4 -r 1 --timeout 2
+2024-02-17 13:27:17,218 INFO logging:97 Modbus server started
+2024-02-17 13:27:17,219 DEBUG logging:103 Awaiting connections server_listener
+2024-02-17 13:27:17,219 INFO logging:97 Server listening.
+
+__________ .______. _________
+\______ \___.__. _____ ____ __| _/\_ |__ __ __ ______ / _____/ ______________ __ ___________
+ | ___< | |/ \ / _ \ / __ | | __ \| | \/ ___/ \_____ \_/ __ \_ __ \ \/ // __ \_ __ \\
+ | | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/
+ |____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|
+ \/ \/ \/ \/ \/ \/ \/ \/
+
+
+SERVER >
+```
+
+#### Run client
+```
+pymodbus/repl/client on repl-server-startup [!?] via 🐍 v3.8.13 (pymodbus3.8)
+❯ python3 main.py tcp --port 5020 --framer tcp
+
+----------------------------------------------------------------------------
+__________ _____ .___ __________ .__
+\______ \___.__. / \ ____ __| _/ \______ \ ____ ______ | |
+ | ___< | |/ \ / \ / _ \ / __ | | _// __ \\\____ \| |
+ | | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__
+ |____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/
+ \/ \/ \/ \/ \/ \/|__|
+ v1.3.1 - 3.6.4
+----------------------------------------------------------------------------
+
+> client.read_input_registers address 1 count 1 slave 4
+{
+ "registers": [
+ 34518
+ ]
+}
+
+> client.read_input_registers address 1 count 1 slave 1
+{
+ "registers": [
+ 32198
+ ]
+}
+
+> client.read_input_registers address 1 count 1 slave 2
+{
+ "registers": [
+ 51557
+ ]
+}
+
+> client.read_input_registers address 1 count 1 slave 3
+{
+ "original_function_code": "4 (0x4)",
+ "error": "[Input/Output] Modbus Error: [Invalid Message] No response received, expected at least 8 bytes (0 received)"
+}
+
+```
+
+
### Running Tests
To run tests, use the following command:
diff --git a/poetry.lock b/poetry.lock
index 550b6af..e535e49 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]]
name = "aiohttp"
@@ -855,4 +855,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
-content-hash = "4aa34f98d51f6e3a00c1aaaeffdc3b84e9ba589d234b451ec69d5ff498aabaa2"
+content-hash = "b9acf605e21d44fb0dc93d6555cc1eae6fc4e89186c3ae6af83649f77361a936"
diff --git a/pymodbus_repl/__init__.py b/pymodbus_repl/__init__.py
index 6f16aa2..b2e78ff 100644
--- a/pymodbus_repl/__init__.py
+++ b/pymodbus_repl/__init__.py
@@ -1 +1,3 @@
"""REPL (Read-Eval-Print Loop) tool for working with Modbus devices using the Pymodbus library."""
+__VERSION__ = "2.0.0"
+
diff --git a/pymodbus_repl/client/main.py b/pymodbus_repl/client/main.py
index de61a59..4331277 100644
--- a/pymodbus_repl/client/main.py
+++ b/pymodbus_repl/client/main.py
@@ -12,6 +12,7 @@
from prompt_toolkit.styles import Style
from pygments.lexers.python import PythonLexer
from pymodbus import __version__ as pymodbus_version
+from pymodbus_repl import __VERSION__ as repl_version
from pymodbus.exceptions import ParameterException
from pymodbus.transaction import (
ModbusAsciiFramer,
@@ -38,7 +39,7 @@
| | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__
|____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/
\/ \/ \/ \/ \/ \/|__|
- v1.3.1 - {pymodbus_version}
+ v{repl_version} - Pymodbus-{pymodbus_version}
----------------------------------------------------------------------------
"""
diff --git a/pymodbus_repl/server/cli.py b/pymodbus_repl/server/cli.py
index 5c449a7..5df2986 100644
--- a/pymodbus_repl/server/cli.py
+++ b/pymodbus_repl/server/cli.py
@@ -8,6 +8,8 @@
from prompt_toolkit.shortcuts import clear
from prompt_toolkit.shortcuts.progress_bar import formatters
from prompt_toolkit.styles import Style
+from pymodbus import __version__ as pymodbus_version
+from pymodbus_repl import __VERSION__ as repl_version
TITLE = r"""
@@ -17,6 +19,7 @@
| | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/
|____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|
\/ \/ \/ \/ \/ \/ \/ \/
+ v{}-Pymodbus{}
"""
@@ -111,8 +114,9 @@ def print_title():
max_len = max( # pylint: disable=consider-using-generator
[len(t) for t in TITLE.split("\n")]
)
+ title = TITLE.format(repl_version, pymodbus_version)
if col > max_len:
- info(TITLE)
+ info(title)
else:
print_formatted_text(
HTML(f'')
diff --git a/pymodbus_repl/server/main.py b/pymodbus_repl/server/main.py
index f1cfd13..29ee472 100644
--- a/pymodbus_repl/server/main.py
+++ b/pymodbus_repl/server/main.py
@@ -1,5 +1,5 @@
"""Repl server main."""
-from __future__ import annotations
+# from __future__ import annotations
import asyncio
import contextlib
@@ -7,9 +7,11 @@
import logging
import sys
from enum import Enum
-from pathlib import Path
+from typing import List, Optional
+from pathlib import Path
import typer
+from typing_extensions import Annotated
from pymodbus import pymodbus_apply_logging_config
from pymodbus.framer.socket_framer import ModbusSocketFramer
from pymodbus.logging import Log
@@ -50,7 +52,7 @@ class ModbusFramerTypes(str, Enum):
binary = "binary" # pylint: disable=invalid-name
-def _completer(incomplete: str, valid_values: list[str]) -> list[str]:
+def _completer(incomplete: str, valid_values: List[str]) -> List[str]:
"""Complete value."""
completion = []
for name in valid_values:
@@ -59,19 +61,19 @@ def _completer(incomplete: str, valid_values: list[str]) -> list[str]:
return completion
-def framers(incomplete: str) -> list[str]:
+def framers(incomplete: str) -> List[str]:
"""Return an autocompleted list of supported clouds."""
_framers = ["socket", "rtu", "tls", "ascii", "binary"]
return _completer(incomplete, _framers)
-def servers(incomplete: str) -> list[str]:
+def servers(incomplete: str) -> List[str]:
"""Return an autocompleted list of supported clouds."""
_servers = ["tcp", "serial", "tls", "udp"]
return _completer(incomplete, _servers)
-def process_extra_args(extra_args: list[str], modbus_config: dict) -> dict:
+def process_extra_args(extra_args: List[str], modbus_config: dict) -> dict:
"""Process extra args passed to server."""
options_stripped = [x.strip().replace("--", "") for x in extra_args[::2]]
extra_args_dict = dict(list(zip(options_stripped, extra_args[1::2])))
@@ -139,12 +141,12 @@ def run(
help="Modbus framer to use",
),
modbus_port: str = typer.Option("5020", "--modbus-port", "-p", help="Modbus port"),
- modbus_slave_id: list[int] = typer.Option(
- [1], "--slave-id", "-u", help="Supported Modbus slave id's"
- ),
- modbus_config_path: Path = typer.Option(
- None, help="Path to additional modbus server config"
- ),
+ modbus_slave_id: Annotated[Optional[List[int]], typer.Option(
+ "--unit-id", "-u", help="Supported Modbus slave id's"
+ )] = [1],
+ modbus_config_path: Annotated[Path, typer.Option(
+ help="Path to additional modbus server config"
+ )] = None,
randomize: int = typer.Option(
0,
"--random",
diff --git a/pyproject.toml b/pyproject.toml
index 441a774..8a707d6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pymodbus_repl"
-version = "0.1.0"
+version = "2.0.0"
description = "REPL (Read-Eval-Print Loop) tool for working with Modbus devices using the Pymodbus library."
authors = ["dhoomakethu "]
readme = "README.md"
@@ -11,7 +11,6 @@ python = "^3.8"
typer = {extras = ["all"], version = "^0.9.0"}
prompt-toolkit = "^3.0.43"
pygments = "^2.17.2"
-pytest-xdist = "^3.5.0"
[[tool.poetry.dependencies.aiohttp]]
python="3.12"
@@ -30,6 +29,7 @@ include = ["pymodbus_repl"]
pymodbus = "^3.6.4"
ruff = "^0.2.1"
coverage = "^7.4.1"
+pytest-xdist = "^3.5.0"
pytest-cov = "^4.1.0"
[build-system]
@@ -43,7 +43,7 @@ addopts = "--cov-report html"
[tool.coverage.run]
source = [
- "pymodbus/"
+ "pymodbus_repl/"
]
omit = ["examples/contrib/"]
branch = true
@@ -56,6 +56,7 @@ exclude_also = [
]
skip_covered = true
fail_under = 70.0
+show_missing = true
[tool.coverage.html]
directory = "build/cov"