diff --git a/.github/workflows/build-and-push-container-image.yaml b/.github/workflows/build-and-push-container-image.yaml
index faba241..d636010 100644
--- a/.github/workflows/build-and-push-container-image.yaml
+++ b/.github/workflows/build-and-push-container-image.yaml
@@ -19,7 +19,7 @@ jobs:
!contains(github.event.pull_request.labels.*.name, 'chore')
steps:
- name: Checkout GIT repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
- name: Get the application version
id: application-version
run: |
@@ -28,20 +28,29 @@ jobs:
echo "ERROR: unable to detect version number!" >&2
exit 1
fi
- echo "tag=${image_version}" >> $GITHUB_OUTPUT
+ echo "tag=${image_version}" >> "${GITHUB_OUTPUT}"
- name: Set up QEMU
- uses: docker/setup-qemu-action@v3
+ uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
- name: Login to container registry
- uses: docker/login-action@v3
+ uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
push: true
context: .
platforms: linux/amd64, linux/arm64
tags: oitc/modbus-client:${{steps.application-version.outputs.tag}},oitc/modbus-client:latest
+ labels: |
+ site.local.program.version=${{ steps.application-version.outputs.tag }}
+ context.github.repositoryUrl=${{ github.repositoryUrl }}
+ context.github.actor=${{ github.actor }}
+ context.github.event.repository.updated_at=${{ github.event.repository.updated_at}}
+ context.github.ref=${{ github.ref }}
+ context.github.job=${{ github.job }}
+ context.runner.os=${{ runner.os }}
+ context.runner.arch=${{ runner.arch }}
diff --git a/.github/workflows/container-image-build-validation.yaml b/.github/workflows/container-image-build-validation.yaml
index 9a1b097..003063d 100644
--- a/.github/workflows/container-image-build-validation.yaml
+++ b/.github/workflows/container-image-build-validation.yaml
@@ -7,195 +7,5 @@ on:
- synchronize
- reopened
jobs:
- container-build:
- name: Build
- runs-on: ubuntu-latest
- steps:
- - name: Checkout GIT repository
- uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
- - name: Test build
- uses: docker/build-push-action@v6
- with:
- push: false
- load: false
- context: .
- platforms: linux/amd64, linux/arm64
- tags: container-build:test
- - name: Test build and export for further validation
- uses: docker/build-push-action@v6
- with:
- push: false
- load: true
- context: .
- tags: container-build:test
- outputs: type=docker,dest=/tmp/container.tar
- - name: Upload container image as artifact
- uses: actions/upload-artifact@v4
- with:
- name: container-build
- path: /tmp/container.tar
-
- function-test-preparation:
- name: Container functionality test preparation
- runs-on: ubuntu-latest
- permissions: write-all
- steps:
- - name: Checkout GIT repository
- uses: actions/checkout@v4
- - name: Log in to Github container registry
- run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- - name: Build container for functionality test
- uses: docker/build-push-action@v6
- with:
- push: true
- load: false
- context: .
- file: ./Dockerfile
- tags: ghcr.io/cybcon/modbus-client/modbus-client:test
-
- function-test-execution:
- name: Container functionality test execution
- needs: function-test-preparation
- runs-on: ubuntu-latest
- services:
- modbusserver:
- image: oitc/modbus-server:latest
- ports:
- - 5020:5020
- steps:
- - name: Log in to Github container registry
- run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- - name: Pull Modbus Client for functionality test
- run: |
- docker pull ghcr.io/cybcon/modbus-client/modbus-client:test
- echo "# Modbus functionality test" >> ${GITHUB_STEP_SUMMARY}
- - name: Get modbus server address
- id: modbus-server-address
- run: |
- LOCAL_MACHINE=$(ifconfig -a eth0|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:")
- echo "DEBUG: ${LOCAL_MACHINE}"
- echo "ip=${LOCAL_MACHINE}" >> $GITHUB_OUTPUT
- - name: Validate server endpoint
- run: |
- modbusserver=${{steps. modbus-server-address.outputs.ip}}
- ping -c 1 -q ${modbusserver}
- RC=$?
- if [ ${RC} -gt 0 ]; then
- echo "ERROR: Modbus slave not reachable" >&2
- exit 1
- fi
- - name: Test Discrete Output Coils
- run: |
- modbusserver=${{steps. modbus-server-address.outputs.ip}}
- echo "## Get Discrete Output Coils" >> ${GITHUB_STEP_SUMMARY}
- echo '' >> ${GITHUB_STEP_SUMMARY}
- echo ' Test output details
' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo " docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 1 -r 0 -l 10" >> ${GITHUB_STEP_SUMMARY}
- docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 1 -r 0 -l 10 > output.tmp 2>&1
- cat output.tmp | while read line
- do
- echo " ${line}" >> ${GITHUB_STEP_SUMMARY}
- done
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo ' ' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- # analyze output
- RESULT=$(cat output.tmp | grep ^2 | awk '{print $3}')
- if [ "${RESULT}" == "False" ]; then
- echo "Test succesfull :white_check_mark:" >> ${GITHUB_STEP_SUMMARY}
- else
- echo "Test failed :x:" >> ${GITHUB_STEP_SUMMARY}
- exit 1
- fi
- - name: Test Discrete Input Contacts
- run: |
- modbusserver=${{steps. modbus-server-address.outputs.ip}}
- echo "## Get Discrete Input Contacts" >> ${GITHUB_STEP_SUMMARY}
- echo '' >> ${GITHUB_STEP_SUMMARY}
- echo ' Test output details
' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo " docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 2 -r 0 -l 10" >> ${GITHUB_STEP_SUMMARY}
- docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 2 -r 0 -l 10 > output.tmp 2>&1
- cat output.tmp | while read line
- do
- echo " ${line}" >> ${GITHUB_STEP_SUMMARY}
- done
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo ' ' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- # analyze output
- RESULT=$(cat output.tmp | grep ^10002 | awk '{print $3}')
- if [ "${RESULT}" == "False" ]; then
- echo "Test succesfull :white_check_mark:" >> ${GITHUB_STEP_SUMMARY}
- else
- echo "Test failed :x:" >> ${GITHUB_STEP_SUMMARY}
- exit 1
- fi
- - name: Test Analog Output Holding Register
- run: |
- modbusserver=${{steps. modbus-server-address.outputs.ip}}
- echo "## Get Analog Output Holding Register" >> ${GITHUB_STEP_SUMMARY}
- echo '' >> ${GITHUB_STEP_SUMMARY}
- echo ' Test output details
' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo " docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 3 -r 0 -l 10" >> ${GITHUB_STEP_SUMMARY}
- docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 3 -r 0 -l 10 > output.tmp 2>&1
- cat output.tmp | while read line
- do
- echo " ${line}" >> ${GITHUB_STEP_SUMMARY}
- done
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo ' ' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- # analyze output
- RESULT=$(cat output.tmp | grep ^40002 | awk '{print $2}')
- if [ "${RESULT}" == "0x0000" ]; then
- echo "Test succesfull :white_check_mark:" >> ${GITHUB_STEP_SUMMARY}
- else
- echo "Test failed :x:" >> ${GITHUB_STEP_SUMMARY}
- exit 1
- fi
- - name: Test Analog Input Register
- run: |
- modbusserver=${{steps. modbus-server-address.outputs.ip}}
- echo "## Get Analog Input Register" >> ${GITHUB_STEP_SUMMARY}
- echo '' >> ${GITHUB_STEP_SUMMARY}
- echo ' Test output details
' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo " docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 4 -r 0 -l 10" >> ${GITHUB_STEP_SUMMARY}
- docker run --rm ghcr.io/cybcon/modbus-client/modbus-client:test -s ${modbusserver} -p 5020 -t 4 -r 0 -l 10 > output.tmp 2>&1
- cat output.tmp | while read line
- do
- echo " ${line}" >> ${GITHUB_STEP_SUMMARY}
- done
- echo ' ```' >> ${GITHUB_STEP_SUMMARY}
- echo ' ' >> ${GITHUB_STEP_SUMMARY}
- echo "" >> ${GITHUB_STEP_SUMMARY}
- # analyze output
- RESULT=$(cat output.tmp | grep ^30002 | head -1 | awk '{print $2}')
- if [ "${RESULT}" == "0x0000" ]; then
- echo "Test succesfull :white_check_mark:" >> ${GITHUB_STEP_SUMMARY}
- else
- echo "Test failed :x:" >> ${GITHUB_STEP_SUMMARY}
- exit 1
- fi
-
- scan:
- name: Container vulnerability scan
- needs: container-build
- uses: cybcon/github_workflows/.github/workflows/container-vulnerability-scan.yaml@v1.4.0
- with:
- image_name: container-build:test
- image_artifact_filename: container.tar
- image_artifact_name: container-build
- login_dockerhub: false
- trivy_tag: latest
+ container-image-build-validation:
+ uses: cybcon/github_workflows/.github/workflows/container-image-build-validation.yaml@v2.1.0
diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml
index 101fee6..50a82f0 100644
--- a/.github/workflows/pre-commit.yaml
+++ b/.github/workflows/pre-commit.yaml
@@ -3,8 +3,7 @@ on:
pull_request:
push:
branches:
- - master
- main
jobs:
pre-commit:
- uses: cybcon/github_workflows/.github/workflows/pre-commit.yaml@v1.4.0
+ uses: cybcon/github_workflows/.github/workflows/pre-commit.yaml@v2.1.0
diff --git a/.github/workflows/release-from-label.yaml b/.github/workflows/release-from-label.yaml
index 714ed98..33bc6de 100644
--- a/.github/workflows/release-from-label.yaml
+++ b/.github/workflows/release-from-label.yaml
@@ -5,4 +5,4 @@ on:
- closed
jobs:
release:
- uses: cybcon/github_workflows/.github/workflows/release-from-label.yaml@v1.4.0
+ uses: cybcon/github_workflows/.github/workflows/release-from-label.yaml@v2.1.0
diff --git a/.github/workflows/release-label-validation.yaml b/.github/workflows/release-label-validation.yaml
index 3ad8986..7d618a2 100644
--- a/.github/workflows/release-label-validation.yaml
+++ b/.github/workflows/release-label-validation.yaml
@@ -10,4 +10,4 @@ on:
- unlabeled
jobs:
release-label-validation:
- uses: cybcon/github_workflows/.github/workflows/release-label-validation.yaml@v1.4.0
+ uses: cybcon/github_workflows/.github/workflows/release-label-validation.yaml@v2.1.0
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1a218c1..c064429 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,20 +1,27 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
+ rev: v6.0.0
hooks:
- id: fix-byte-order-marker
+ - id: check-ast
- id: check-json
- id: check-yaml
+ - id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
+ - id: requirements-txt-fixer
- id: mixed-line-ending
args: ['--fix=lf']
description: Forces to replace line ending by the UNIX 'lf' character
- id: detect-aws-credentials
args: ['--allow-missing-credentials']
- id: detect-private-key
+ - repo: https://github.com/asottile/pyupgrade
+ rev: v3.21.2
+ hooks:
+ - id: pyupgrade
- repo: https://github.com/myint/autoflake
- rev: v2.3.1
+ rev: v2.3.3
hooks:
- id: autoflake
args:
@@ -22,11 +29,11 @@ repos:
- --remove-unused-variables
- --remove-all-unused-imports
- repo: https://github.com/hadolint/hadolint
- rev: v2.12.0
+ rev: v2.14.0
hooks:
- id: hadolint-docker
- repo: https://github.com/charliermarsh/ruff-pre-commit
- rev: v0.8.4
+ rev: v0.15.20
hooks:
- id: ruff
args:
@@ -34,7 +41,7 @@ repos:
- '--fix'
- '--exit-non-zero-on-fix'
- repo: https://github.com/pycqa/isort
- rev: 5.13.2
+ rev: 8.0.1
hooks:
- id: isort
name: isort (python)
@@ -43,8 +50,12 @@ repos:
- black
- '--filter-files'
- repo: https://github.com/psf/black
- rev: 24.10.0
+ rev: 26.5.1
hooks:
- id: black
args:
- '--line-length=120'
+ - repo: https://github.com/rhysd/actionlint
+ rev: v1.7.11
+ hooks:
+ - id: actionlint
diff --git a/.tool-versions b/.tool-versions
index df76196..540fb7a 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1 +1,2 @@
-pre-commit 4.0.1
+pre-commit 4.6.0
+python 3.14.6
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..2fb1fda
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "python-envs.defaultEnvManager": "ms-python.python:system"
+}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..420b548
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+e-mail notification.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: [https://www.contributor-covenant.org](https://www.contributor-covenant.org)
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are available at
+[https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8457b0b
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# How to contribute to modbus-client
+
+## **Did you find a bug?**
+
+* **Do not open up a GitHub issue if the bug is a security vulnerability
+ in modbus-client**, and instead write me a mail to [info@oberdorf-itc.de](mailto:info@oberdorf-itc.de).
+
+* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/cybcon/docker.modbus-client/issues).
+
+* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/cybcon/docker.modbus-client/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring.
+
+## **Did you write a patch that fixes a bug?**
+
+* Open a new GitHub pull request with the patch.
+
+* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
+
+* All commits needs to have a valid GPG signature
+
+* All pull request checks have to pass successfully
+
+* If using 3rd party components, the licence needs to be compatible with the license of this project
+
+## **Did you fix whitespace, format code, or make a purely cosmetic patch?**
+
+Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of the application will generally not be accepted.
+
+## **Do you intend to add a new feature or change an existing one?**
+
+* Open a new GitHub pull request with the patch.
+
+* Ensure the PR description clearly describes the new feature or the change. Include the relevant issue number if applicable.
+
+* All commits needs to have a valid GPG signature
+
+* All pull request checks have to pass successfully
+
+* If using 3rd party components, the licence needs to be compatible with the license of this project
+
+## **Do you have questions about the source code?**
+
+* Write me a mail to [info@oberdorf-itc.de](mailto:info@oberdorf-itc.de).
+
+Thanks! :heart: :heart: :heart:
+
+Michael
diff --git a/Dockerfile b/Dockerfile
index a6cb30a..478ad7d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,8 +1,8 @@
-FROM alpine:3.23.2 AS base
+FROM alpine:3.24.1 AS base
RUN apk upgrade --available --no-cache --update \
&& apk add --no-cache --update \
- python3=3.12.12-r0 \
- py3-pip=25.1.1-r1 \
+ python3=3.14.5-r0 \
+ py3-pip=26.1.2-r0 \
# Cleanup APK
&& rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
@@ -11,14 +11,15 @@ RUN apk upgrade --available --no-cache --update \
# Compiling python modules
FROM base AS builder
RUN apk add --no-cache --update \
- g++=15.2.0-r2 \
- python3-dev=3.12.12-r0 \
+ g++=15.2.0-r5 \
+ python3-dev=3.14.5-r0 \
&& ln -s /usr/include/locale.h /usr/include/xlocale.h
COPY --chown=root:root FloatToHex /FloatToHex
WORKDIR /FloatToHex
-RUN python3 setup.py install
+RUN pip3 install --no-cache-dir -r /FloatToHex/requirements.txt --break-system-packages \
+ && python3 setup.py install
@@ -28,12 +29,12 @@ FROM base
LABEL maintainer="Michael Oberdorf IT-Consulting "
LABEL site.local.program.version="1.0.17"
-COPY --from=builder /usr/lib/python3.12/site-packages /usr/lib/python3.12/site-packages
+COPY --from=builder /usr/lib/python3.14/site-packages /usr/lib/python3.14/site-packages
RUN apk add --no-cache --update \
- libstdc++=15.2.0-r2 \
- py3-wheel=0.46.1-r0 \
- py3-pandas=2.3.3-r0
+ libstdc++=15.2.0-r5 \
+ py3-wheel=0.47.0-r0 \
+ py3-pandas=3.0.3-r0
COPY --chown=root:root /src /
diff --git a/FloatToHex/README.md b/FloatToHex/README.md
index 0fcae3e..2e7389e 100644
--- a/FloatToHex/README.md
+++ b/FloatToHex/README.md
@@ -2,34 +2,38 @@
The software was taken from site: https://gregstoll.com/~gregstoll/floattohex/
-## Contributor:
+## Contributor
Gregory Stoll
https://gregstoll.com/
-# Synopsis
+## Synopsis
```python
import FloatToHex
float = 29.625
```
-# store float in 4 byte (32 bit) single precision (IEEE 754 binary32)
+### store float in 4 byte (32 bit) single precision (IEEE 754 binary32)
+
```python
my_32bit_int = FloatToHex.floattohex(float)
```
-# recover float from IEEE 754 binary32
+### recover float from IEEE 754 binary32
+
```python
print(FloatToHex.hextofloat(my_32bit_int))
```
-# store float in 8 byte (64 bit) double precision (IEEE 754 binary64)
+### store float in 8 byte (64 bit) double precision (IEEE 754 binary64)
+
```python
my_64bit_int = FloatToHex.doubletohex(float)
```
-# recover float from IEEE 754 binary64
+### recover float from IEEE 754 binary64
+
```python
print(FloatToHex.hextodouble(my_64bit_int))
```
diff --git a/FloatToHex/requirements.txt b/FloatToHex/requirements.txt
new file mode 100644
index 0000000..fcc1a15
--- /dev/null
+++ b/FloatToHex/requirements.txt
@@ -0,0 +1 @@
+Setuptools >=83
diff --git a/FloatToHex/setup.py b/FloatToHex/setup.py
index 531874c..efee9ad 100644
--- a/FloatToHex/setup.py
+++ b/FloatToHex/setup.py
@@ -1,10 +1,10 @@
#!/usr/bin/python3
-# -*- coding: utf-8 -*-
# setup.py sdist to create a package which can be uploaded to PyPi registry (but need more information)
# setup.py install to install the package - needs C compiler (vcvarsall.bat on windows)
-from distutils.core import Extension, setup
+# from distutils.core import Extension, setup # migrate to python 3.14
+from setuptools import Extension, setup
FloatToHexModule = Extension("FloatToHex", sources=["floattohexmodule.c"])
diff --git a/LICENSE b/LICENSE
index 04c0049..2186675 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020-2025 Michael Oberdorf IT-Consulting
+Copyright (c) 2020-2026 Michael Oberdorf IT-Consulting
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index de5c18c..5dccb96 100644
--- a/README.md
+++ b/README.md
@@ -15,16 +15,15 @@ Container Registry: [DockerHub](https://hub.docker.com/r/oitc/modbus-client)
[![][github-forks-shield]][github-forks-link]
[![][github-issues-shield]][github-issues-link]
[![][github-license-shield]][github-license-link]
-
[![][docker-release-shield]][docker-release-link]
[![][docker-pulls-shield]][docker-pulls-link]
[![][docker-stars-shield]][docker-stars-link]
[![][docker-size-shield]][docker-size-link]
+## Supported tags and respective `Dockerfile` links
-# Supported tags and respective `Dockerfile` links
-
-* [`latest`, `1.0.17`](https://github.com/cybcon/modbus-client/blob/v1.0.17/Dockerfile)
+* [`latest`, `1.1.0`](https://github.com/cybcon/modbus-client/blob/v1.1.0/Dockerfile)
+* [`1.0.17`](https://github.com/cybcon/modbus-client/blob/v1.0.17/Dockerfile)
* [`1.0.16`](https://github.com/cybcon/modbus-client/blob/v1.0.16/Dockerfile)
* [`1.0.15`](https://github.com/cybcon/modbus-client/blob/v1.0.15/Dockerfile)
* [`1.0.14`](https://github.com/cybcon/modbus-client/blob/v1.0.14/Dockerfile)
@@ -32,25 +31,23 @@ Container Registry: [DockerHub](https://hub.docker.com/r/oitc/modbus-client)
* [`1.0.12`](https://github.com/cybcon/modbus-client/blob/v1.0.12/Dockerfile)
* [`1.0.11`](https://github.com/cybcon/modbus-client/blob/v1.0.11/Dockerfile)
-
-# What is Modbus TCP Client?
+## What is Modbus TCP Client?
The Modbus TCP Client is a command line tool, written in python to read and interpret Modbus registers.
The Modbus specification can be found here: [PDF](https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf)
-
-# QuickStart with Modbus TCP Client and Docker
+## QuickStart with Modbus TCP Client and Docker
Step - 1 : Pull the Modbus TCP Client
-```
+```bash
docker pull oitc/modbus-client
```
Step - 2 : Run the Modbus TCP Client to scan your Modbus Server Registers
-```
+```bash
docker run --rm oitc/modbus-client:latest [options]
usage: modbus_client.py [-h] [-s SLAVE] [-p PORT] [-i SLAVEID]
@@ -83,10 +80,11 @@ optional arguments:
-d, --debug Enable debug output
```
-# Examples
-## Read Analog Input Register
+## Examples
-```
+### Read Analog Input Register
+
+```bash
docker run --rm oitc/modbus-client:latest -s 192.168.58.70 -p 1503 -t 4 -r 0 -l 10
HEX16 UINT16 INT16 BIT HEX32 FLOAT32
register
@@ -102,9 +100,9 @@ register
30009 0x0032 50 50 0000000000110010 0x00320074 0.000000
```
-## Discrete Discrete Input Contacts
+### Discrete Discrete Input Contacts
-```
+```bash
docker run --rm test:latest -s 192.168.57.10 -p 5020 -t 2 -r 0 -l 3
BIT BOOL
register
@@ -113,15 +111,15 @@ register
10002 1 True
```
-# Donate
-I would appreciate a small donation to support the further development of my open source projects.
+## Donate
-
+I would appreciate a small donation to support the further development of my open source projects.
+[![Donate with PayPal][donate-paypal-button]][donate-paypal-link]
-# License
+## License
-Copyright (c) 2020-2024 Michael Oberdorf IT-Consulting
+Copyright (c) 2020-2026 Michael Oberdorf IT-Consulting
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -150,6 +148,8 @@ SOFTWARE.
[docker-size-shield]: https://img.shields.io/docker/image-size/oitc/modbus-client?color=369eff&labelColor=black&style=flat-square
[docker-stars-link]: https://hub.docker.com/r/oitc/modbus-client
[docker-stars-shield]: https://img.shields.io/docker/stars/oitc/modbus-client?color=45cc11&labelColor=black&style=flat-square
+[donate-paypal-button]: https://raw.githubusercontent.com/cybcon/paypal-donate-button/refs/heads/master/paypal-donate-button_200x77.png
+[donate-paypal-link]: https://www.paypal.com/donate/?hosted_button_id=BHGJGGUS6RH44
[github-action-release-link]: https://github.com/cybcon/modbus-client/actions/workflows/release-from-label.yaml
[github-action-release-shield]: https://img.shields.io/github/actions/workflow/status/cybcon/modbus-client/release-from-label.yaml?label=release&labelColor=black&logo=githubactions&logoColor=white&style=flat-square
[github-action-test-link]: https://github.com/cybcon/modbus-client/actions/workflows/container-image-build-validation.yaml
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..933f524
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,23 @@
+# Security Policy
+
+## Supported Versions
+
+Due to the small size of this project, only the latest version receives security updates and patches.
+
+| Version | Supported |
+| ------- | ------------------ |
+| Latest | :white_check_mark: |
+| Older | :x: |
+
+## Reporting a Vulnerability
+
+**Please do not open a GitHub issue for security vulnerabilities.**
+
+Instead, please report security vulnerabilities by sending an email to [info@oberdorf-itc.de](mailto:info@oberdorf-itc.de) with:
+
+- A description of the vulnerability
+- Steps to reproduce (if applicable)
+- Potential impact
+- Any suggested fixes (optional)
+
+For more details on how to contribute to this project, please refer to [CONTRIBUTING.md](CONTRIBUTING.md).
diff --git a/src/app/modbus_client.py b/src/app/modbus_client.py
index 6398adb..b39c059 100644
--- a/src/app/modbus_client.py
+++ b/src/app/modbus_client.py
@@ -1,23 +1,24 @@
-# -*- coding: utf-8 -*-
"""
-###############################################################################
-# Modbus TCP client script for debugging
-# Author: Michael Oberdorf IT-Consulting
-# Datum: 2020-05-20
-# Last modified by: Michael Oberdorf
-# Last modified at: 2025-12-28
-###############################################################################
+Modbus TCP client script for debugging
+Author: Michael Oberdorf IT-Consulting
+Datum: 2020-05-20
+Last modified by: Michael Oberdorf
+Last modified at: 2026-07-06
"""
+
import argparse
import logging
import sys
import pandas as pd
-from pymodbus.client.sync import ModbusTcpClient as ModbusClient
+from pymodbus.client import ModbusTcpClient as ModbusClient
import FloatToHex
-VERSION = "1.0.17"
+__status__ = "production"
+__date__ = "2026-07-06"
+__version_info__ = ("1", "1", "0")
+__version__ = ".".join(__version_info__)
DEBUG = False
"""
###############################################################################
@@ -107,7 +108,7 @@ def parse_modbus_result(registers: list, startRegister: int, readLength: int, va
log.setLevel(logging.INFO)
# Parsing command line arguments
-parser = argparse.ArgumentParser(description="Modbus TCP Client v" + VERSION)
+parser = argparse.ArgumentParser(description="Modbus TCP Client v" + __version__)
group = parser.add_argument_group()
group.add_argument(
"-s", "--slave", help="Hostname or IP address of the Modbus TCP slave (default: 127.0.0.1)", default="127.0.0.1"
@@ -181,7 +182,7 @@ def parse_modbus_result(registers: list, startRegister: int, readLength: int, va
# start the master and connect to slave
if DEBUG:
- print("Starting Modbus TCP master client, v" + str(VERSION))
+ print(f"Starting Modbus TCP master client, v{__version__}")
print("Trying to connect to slave: " + str(args.slave) + ":" + str(args.port))
print(
"Query with slave id: "
@@ -210,13 +211,13 @@ def parse_modbus_result(registers: list, startRegister: int, readLength: int, va
# read the registers, dependent on the requested type
if args.registerType == 1:
- rr = client.read_coils(args.register, args.length, unit=args.slaveid)
+ rr = client.read_coils(address=args.register, count=args.length, device_id=args.slaveid)
elif args.registerType == 2:
- rr = client.read_discrete_inputs(args.register, args.length, unit=args.slaveid)
+ rr = client.read_discrete_inputs(address=args.register, count=args.length, device_id=args.slaveid)
elif args.registerType == 3:
- rr = client.read_holding_registers(args.register, args.length, unit=args.slaveid)
+ rr = client.read_holding_registers(address=args.register, count=args.length, device_id=args.slaveid)
elif args.registerType == 4:
- rr = client.read_input_registers(args.register, args.length, unit=args.slaveid)
+ rr = client.read_input_registers(address=args.register, count=args.length, device_id=args.slaveid)
if rr.isError():
log.error("Error while querying Modbus TCP slave!")
client.close()
diff --git a/src/requirements.txt b/src/requirements.txt
index fee656c..9aa876f 100644
--- a/src/requirements.txt
+++ b/src/requirements.txt
@@ -1 +1 @@
-pymodbus >= 2, < 3
+pymodbus >= 3.13.1, < 4