Skip to content

Commit

Permalink
Merge branch 'dev' for v3.1.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
janiversen committed Jan 24, 2023
2 parents e3bf41c + 5de6039 commit 687c9de
Show file tree
Hide file tree
Showing 17 changed files with 699 additions and 202 deletions.
66 changes: 17 additions & 49 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -1,92 +1,60 @@
name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:
push:
branches: [ "dev" ]
# Publish version tags as releases.
tags: [ 'v*.*.*' ]

env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}

branches:
- dev
- master
tags:
- v*
workflow_dispatch:

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v3

# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@f3c664df7af409cb4873aa5068053ba9d61a57b6 #v2.6.0
with:
cosign-release: 'v1.11.0'
uses: sigstore/cosign-installer@main

- name: Check cosign install
run: cosign version

# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
uses: docker/setup-buildx-action@v2

# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
- name: Login ghcr.io
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
images: ghcr.io/${{ github.repository }}

# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
uses: docker/build-push-action@v3
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max


# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
# repository is public to avoid leaking data. If you would like to publish
# transparency data even for private images, pass --force to cosign below.
# https://github.com/sigstore/cosign
- name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
COSIGN_EXPERIMENTAL: "true"
# This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance.
run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }}
22 changes: 22 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
version 3.1.1
----------------------------------------------------------
* add missing server.start() (#1282)
* small performance improvement on debug log (#1279)
* Fix Unix sockets parsing (#1281)
* client: Allow unix domain socket. (#1274)
* transfer timeout to protocol object. (#1275)
* Add ModbusUnixServer / StartAsyncUnixServer. (#1273)
* Added return in AsyncModbusSerialClient.connect (#1271)
* add connect() to the very first example (#1270)
* Solve docker problem. (#1268)
* Test stop of server task. (#1256)

Thanks to:

Alex
Alexandre CUER
Dries
jan iversen
peufeu2


version 3.1.0
----------------------------------------------------------
* Add xdist pr default. (#1253)
Expand Down
4 changes: 2 additions & 2 deletions MAKE_RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Prepare/make release on dev.
* Update README.rst "Supported versions"
* Update CHANGELOG.rst
* Add commits from last release, but selectively !
git log --oneline v3.1.0..HEAD > commit.log
git log v3.1.0..HEAD | grep Author > contributors.log
git log --oneline v3.1.1..HEAD > commit.log
git log v3.1.1..HEAD | grep Author > contributors.log
* Commit, push and merge.
* Checkout master locally
* git merge dev
Expand Down
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Supported versions

Version `2.5.3 <https://github.com/riptideio/pymodbus/releases/tag/v2.5.3>`_ is the last 2.x release (Supports python 2.7.x - 3.7).

Version `3.1.0 <https://github.com/riptideio/pymodbus/releases/tag/v3.1.0>`_ is the current release (Supports Python >=3.8).
Version `3.1.1 <https://github.com/riptideio/pymodbus/releases/tag/v3.1.1>`_ is the current release (Supports Python >=3.8).

.. important::
All API changes after 3.0.0 are documented in `API_changes.rst <https://github.com/riptideio/pymodbus/blob/dev/API_changes.rst>`_
Expand Down Expand Up @@ -104,6 +104,7 @@ For those of you that just want to get started fast, here you go::
from pymodbus.client import ModbusTcpClient

client = ModbusTcpClient('127.0.0.1')
client.connect()
client.write_coil(1, True)
result = client.read_coils(1,1)
print(result.bits[0])
Expand Down
10 changes: 6 additions & 4 deletions pymodbus/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,17 @@ def _execute(self, request, **kwargs): # pylint: disable=unused-argument
"""Start the producer to send the next request to consumer.write(Frame(request))."""
request.transaction_id = self.transaction.getNextTID()
packet = self.framer.buildPacket(request)
txt = f"send: {hexlify_packets(packet)}"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"send: {hexlify_packets(packet)}"
_logger.debug(txt)
self.write_transport(packet)
return self._build_response(request.transaction_id)

def _data_received(self, data):
"""Get response, check for valid message, decode result."""
txt = f"recv: {hexlify_packets(data)}"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"recv: {hexlify_packets(data)}"
_logger.debug(txt)
self.framer.processIncomingPacket(data, self._handle_response, unit=0)

def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument
Expand Down
5 changes: 4 additions & 1 deletion pymodbus/client/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ async def close(self): # pylint: disable=invalid-overridden-method

def _create_protocol(self):
"""Create protocol."""
protocol = ModbusClientProtocol(framer=self.params.framer, xframer=self.framer)
protocol = ModbusClientProtocol(
framer=self.params.framer, xframer=self.framer, timeout=self.params.timeout
)
protocol.factory = self
return protocol

Expand Down Expand Up @@ -121,6 +123,7 @@ async def connect(self): # pylint: disable=invalid-overridden-method
except Exception as exc: # pylint: disable=broad-except
txt = f"Failed to connect: {exc}"
_logger.warning(txt)
return self.connected

def protocol_made_connection(self, protocol):
"""Notify successful connection."""
Expand Down
41 changes: 30 additions & 11 deletions pymodbus/client/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class AsyncModbusTcpClient(ModbusBaseClient):
:param source_address: (optional) source address of client
:param kwargs: (optional) Experimental parameters
using unix domain socket can be achieved by setting host="unix:<path>"
Example::
from pymodbus.client import AsyncModbusTcpClient
Expand Down Expand Up @@ -99,12 +101,22 @@ async def _connect(self):
"""Connect."""
_logger.debug("Connecting.")
try:
transport, protocol = await asyncio.wait_for(
self.loop.create_connection(
self._create_protocol, host=self.params.host, port=self.params.port
),
timeout=self.params.timeout,
)
if self.params.host.startswith("unix:"):
transport, protocol = await asyncio.wait_for(
self.loop.create_unix_connection(
self._create_protocol, path=self.params.host[5:]
),
timeout=self.params.timeout,
)
else:
transport, protocol = await asyncio.wait_for(
self.loop.create_connection(
self._create_protocol,
host=self.params.host,
port=self.params.port,
),
timeout=self.params.timeout,
)
except Exception as exc: # pylint: disable=broad-except
txt = f"Failed to connect: {exc}"
_logger.warning(txt)
Expand Down Expand Up @@ -159,6 +171,8 @@ class ModbusTcpClient(ModbusBaseClient):
:param source_address: (optional) source address of client
:param kwargs: (optional) Experimental parameters
using unix domain socket can be achieved by setting host="unix:<path>"
Example::
from pymodbus.client import ModbusTcpClient
Expand Down Expand Up @@ -196,11 +210,16 @@ def connect(self):
if self.socket:
return True
try:
self.socket = socket.create_connection(
(self.params.host, self.params.port),
timeout=self.params.timeout,
source_address=self.params.source_address,
)
if self.params.host.startswith("unix:"):
self.socket = socket.socket(socket.AF_UNIX)
self.socket.settimeout(self.params.timeout)
self.socket.connect(self.params.host[5:])
else:
self.socket = socket.create_connection(
(self.params.host, self.params.port),
timeout=self.params.timeout,
source_address=self.params.source_address,
)
txt = f"Connection to Modbus server established. Socket {self.socket.getsockname()}"
_logger.debug(txt)
except socket.error as msg:
Expand Down
15 changes: 9 additions & 6 deletions pymodbus/datastore/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ def validate(self, fc_as_hex, address, count=1):
"""
if not self.zero_mode:
address = address + 1
txt = f"validate: fc-[{fc_as_hex}] address-{address}: count-{count}"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"validate: fc-[{fc_as_hex}] address-{address}: count-{count}"
_logger.debug(txt)
return self.store[self.decode(fc_as_hex)].validate(address, count)

def getValues(self, fc_as_hex, address, count=1):
Expand All @@ -76,8 +77,9 @@ def getValues(self, fc_as_hex, address, count=1):
"""
if not self.zero_mode:
address = address + 1
txt = f"getValues: fc-[{fc_as_hex}] address-{address}: count-{count}"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"getValues: fc-[{fc_as_hex}] address-{address}: count-{count}"
_logger.debug(txt)
return self.store[self.decode(fc_as_hex)].getValues(address, count)

def setValues(self, fc_as_hex, address, values):
Expand All @@ -89,8 +91,9 @@ def setValues(self, fc_as_hex, address, values):
"""
if not self.zero_mode:
address = address + 1
txt = f"setValues[{fc_as_hex}] address-{address}: count-{len(values)}"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"setValues[{fc_as_hex}] address-{address}: count-{len(values)}"
_logger.debug(txt)
self.store[self.decode(fc_as_hex)].setValues(address, values)

def register(self, function_code, fc_as_hex, datablock=None):
Expand Down
15 changes: 9 additions & 6 deletions pymodbus/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ def _helper(self, data):
"""
function_code = int(data[0])
if not (request := self.__lookup.get(function_code, lambda: None)()):
txt = f"Factory Request[{function_code}]"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"Factory Request[{function_code}]"
_logger.debug(txt)
request = IllegalFunctionRequest(function_code)
else:
fc_string = "%s: %s" % ( # pylint: disable=consider-using-f-string
Expand All @@ -212,8 +213,9 @@ def _helper(self, data):
.rstrip('">"'),
function_code,
)
txt = f"Factory Request[{fc_string}]"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"Factory Request[{fc_string}]"
_logger.debug(txt)
request.decode(data[1:])

if hasattr(request, "sub_function_code"):
Expand Down Expand Up @@ -344,8 +346,9 @@ def _helper(self, data):
.rstrip('">"'),
function_code,
)
txt = f"Factory Response[{fc_string}]"
_logger.debug(txt)
if _logger.isEnabledFor(logging.DEBUG):
txt = f"Factory Response[{fc_string}]"
_logger.debug(txt)
response = self.__lookup.get(function_code, lambda: None)()
if function_code > 0x80:
code = function_code & 0x7F # strip error portion
Expand Down
Loading

0 comments on commit 687c9de

Please sign in to comment.