Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pymodbus 1.5.0 #294

Merged
merged 36 commits into from
Apr 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
91f3f0b
#217 fix modbus tcp read
dhoomakethu Oct 3, 2017
22f1843
Move twisted requirement to extra (#227)
jackjweinstein Oct 18, 2017
4c896d1
#157 Pass remote unit id when using remote slave context
dhoomakethu Oct 26, 2017
f226bcd
#190 fix asynchronous processor example
dhoomakethu Oct 26, 2017
5f0d2ed
#60 Check for slave unit id before processing the request for serial …
dhoomakethu Oct 26, 2017
6030c25
#209 bump version to 1.4.0.rc1
dhoomakethu Oct 26, 2017
634abaf
Update ISSUE_TEMPLATE.md
dhoomakethu Oct 27, 2017
01f5819
Fix failing tests
dhoomakethu Oct 27, 2017
2bbb5e5
Fix example remote_server_context (#236)
dhoomakethu Nov 6, 2017
27a834e
In the start TCP, UDP and Seriel server, we are running a quick check…
rahulraghu94 Nov 24, 2017
b1b9e4f
#84: Stop Asynchronous Server (#243)
rahulraghu94 Nov 25, 2017
c0e489c
Test dev (#240)
dhoomakethu Nov 28, 2017
e852aa2
#221 tcp read complete frame based on length field in the mbap header…
dhoomakethu Dec 19, 2017
b1363d7
Prepare for 1.4.0 (#209), updated changelogs
dhoomakethu Dec 19, 2017
621a90e
Tar ball without docs (#252)
dhoomakethu Dec 21, 2017
4a05c01
#221 Fix read transactions for different framers
dhoomakethu Dec 21, 2017
2e65023
Update requirements for document generation
dhoomakethu Dec 21, 2017
668612e
Fix ModbusSingleRequestHandler
dhoomakethu Dec 22, 2017
1e1af47
Bump version to 1.4.0rc2 #209
dhoomakethu Dec 22, 2017
5a3cceb
Fix make clean command on osx
dhoomakethu Dec 22, 2017
c1e784a
#245 unittest coverage (#249)
rahulraghu94 Dec 22, 2017
64cb66a
#255 Fix BinaryPayloadDecoder
dhoomakethu Dec 26, 2017
d4dcdc0
#255 Fix unit tests
dhoomakethu Dec 26, 2017
b4f3987
1. #138 Add support to manipulate wordorder with BinaryPayloadDecoder…
dhoomakethu Jan 3, 2018
019bdde
Merge branch 'master' into dev
dhoomakethu Jan 3, 2018
25cc6b8
easily to check for errors in stead of having to manually compare (#258)
rahulraghu94 Jan 8, 2018
ca5dfaf
TimeoutError is not defined on Python 2. (#264)
bfabio Jan 11, 2018
15bb3b3
#250 fix scraper simulator (#259)
rahulraghu94 Jan 11, 2018
d1d6022
Add get_response_pdu_size to WriteMultipleRegistersRequest (#267)
yy123xiang Jan 23, 2018
180060a
Fixed byte count position for CommEventLogResponse (#291)
chintal Apr 25, 2018
9d2c864
Pymodbus 1.5.0 (#285)
dhoomakethu Apr 26, 2018
5a38412
Update CHANGELOG
dhoomakethu Apr 26, 2018
d3926fa
Minor enhancements + added tests for transaction.py
dhoomakethu Apr 27, 2018
ca10c1e
Make example compatible with both Python 2 and 3 syntax (#275)
yegorich Apr 27, 2018
d990a13
Update concurrent_client.py - Python3 compatbility (#280)
dragoshenron Apr 27, 2018
693783b
#82 error response api (#262)
rahulraghu94 Apr 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
Version 1.5.0
------------------------------------------------------------
* Improve transaction speeds for sync clients (RTU/ASCII), now retry on empty happens only when retry_on_empty kwarg is passed to client during intialization

`client = Client(..., retry_on_empty=True)`

* Fix tcp servers (sync/async) not processing requests with transaction id > 255
* Introduce new api to check if the received response is an error or not (response.isError())
* Move timing logic to framers so that irrespective of client, correct timing logics are followed.
* Move framers from transaction.py to respective modules
* Fix modbus payload builder and decoder
* Async servers can now have an option to defer `reactor.run()` when using `Start<Tcp/Serial/Udo>Server(...,defer_reactor_run=True)`
* Fix UDP client issue while handling MEI messages (ReadDeviceInformationRequest)
* Add expected response lengths for WriteMultipleCoilRequest and WriteMultipleRegisterRequest
* Fix _rtu_byte_count_pos for GetCommEventLogResponse
* Add support for repeated MEI device information Object IDs
* Fix struct errors while decoding stray response
* Modbus read retries works only when empty/no message is received
* Change test runner from nosetest to pytest
* Fix Misc examples

Version 1.4.0
------------------------------------------------------------
* Bug fix Modbus TCP client reading incomplete data
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ check: install

test: install
@pip install --quiet --requirement=requirements-tests.txt
@nosetests --with-coverage --cover-html
@py.test
@coverage report --fail-under=90

tox: install
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ For those of you that just want to get started fast, here you go::
client = ModbusTcpClient('127.0.0.1')
client.write_coil(1, True)
result = client.read_coils(1,1)
print result.bits[0]
print(result.bits[0])
client.close()

For more advanced examples, check out the examples included in the
Expand Down
47 changes: 47 additions & 0 deletions doc/source/library/pymodbus.framer.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
pymodbus\.framer package
========================

Submodules
----------

pymodbus\.framer\.ascii_framer module
-------------------------------------

.. automodule:: pymodbus.framer.ascii_framer
:members:
:undoc-members:
:show-inheritance:

pymodbus\.framer\.binary_framer module
--------------------------------------

.. automodule:: pymodbus.framer.binary_framer
:members:
:undoc-members:
:show-inheritance:

pymodbus\.framer\.rtu_framer module
-----------------------------------

.. automodule:: pymodbus.framer.rtu_framer
:members:
:undoc-members:
:show-inheritance:

pymodbus\.framer\.socket_framer module
--------------------------------------

.. automodule:: pymodbus.framer.socket_framer
:members:
:undoc-members:
:show-inheritance:


Module contents
---------------

.. automodule:: pymodbus.framer
:members:
:undoc-members:
:show-inheritance:

2 changes: 2 additions & 0 deletions doc/source/library/pymodbus.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ Subpackages

pymodbus.client
pymodbus.datastore
pymodbus.framer
pymodbus.internal
pymodbus.server


Submodules
----------

Expand Down
97 changes: 61 additions & 36 deletions examples/common/asynchronous_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,67 @@
The following is an example of how to use the asynchronous modbus
client implementation from pymodbus.
"""
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# import needed libraries
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
from twisted.internet import reactor, protocol
from pymodbus.constants import Defaults

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# choose the requested modbus protocol
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
from pymodbus.client.async import ModbusClientProtocol
#from pymodbus.client.async import ModbusUdpClientProtocol
from pymodbus.client.async import ModbusUdpClientProtocol
from pymodbus.framer.rtu_framer import ModbusRtuFramer

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
import logging
logging.basicConfig()
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# helper method to test deferred callbacks
# --------------------------------------------------------------------------- #


def dassert(deferred, callback):
def _assertor(value):
assert value

deferred.addCallback(lambda r: _assertor(callback(r)))
deferred.addErrback(lambda _: _assertor(False))

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# specify slave to query
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# The slave to query is specified in an optional parameter for each
# individual request. This can be done by specifying the `unit` parameter
# which defaults to `0x00`
# --------------------------------------------------------------------------- #


def processResponse(result):
log.debug(result)


def exampleRequests(client):
rr = client.read_coils(1, 1, unit=0x02)
rr.addCallback(processResponse)
rr = client.read_holding_registers(1, 1, unit=0x02)
rr.addCallback(processResponse)
rr = client.read_discrete_inputs(1, 1, unit=0x02)
rr.addCallback(processResponse)
rr = client.read_input_registers(1, 1, unit=0x02)
rr.addCallback(processResponse)
stopAsynchronousTest(client)

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# example requests
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# simply call the methods that you would like to use. An example session
# is displayed below along with some assert checks. Note that unlike the
# synchronous version of the client, the asynchronous version returns
Expand All @@ -61,54 +75,59 @@ def exampleRequests(client):
# deferred assert helper(dassert).
# --------------------------------------------------------------------------- #

UNIT = 0x01

UNIT = 0x00


def stopAsynchronousTest(client):
# ----------------------------------------------------------------------- #
# close the client at some time later
# ----------------------------------------------------------------------- #
reactor.callLater(1, client.transport.loseConnection)
reactor.callLater(2, reactor.stop)

def beginAsynchronousTest(client):
rq = client.write_coil(1, True, unit=UNIT)
rr = client.read_coils(1, 1, unit=UNIT)
dassert(rq, lambda r: r.function_code < 0x80) # test for no error
dassert(rq, lambda r: not r.isError()) # test for no error
dassert(rr, lambda r: r.bits[0] == True) # test the expected value

rq = client.write_coils(1, [True]*8, unit=UNIT)
rr = client.read_coils(1, 8, unit=UNIT)
dassert(rq, lambda r: r.function_code < 0x80) # test for no error
dassert(rq, lambda r: not r.isError()) # test for no error
dassert(rr, lambda r: r.bits == [True]*8) # test the expected value

rq = client.write_coils(1, [False]*8, unit=UNIT)
rr = client.read_discrete_inputs(1, 8, unit=UNIT)
dassert(rq, lambda r: r.function_code < 0x80) # test for no error
dassert(rq, lambda r: not r.isError()) # test for no error
dassert(rr, lambda r: r.bits == [True]*8) # test the expected value

rq = client.write_register(1, 10, unit=UNIT)
rr = client.read_holding_registers(1, 1, unit=UNIT)
dassert(rq, lambda r: r.function_code < 0x80) # test for no error
dassert(rq, lambda r: not r.isError()) # test for no error
dassert(rr, lambda r: r.registers[0] == 10) # test the expected value

rq = client.write_registers(1, [10]*8, unit=UNIT)
rr = client.read_input_registers(1, 8, unit=UNIT)
dassert(rq, lambda r: r.function_code < 0x80) # test for no error
dassert(rq, lambda r: not r.isError()) # test for no error
dassert(rr, lambda r: r.registers == [17]*8) # test the expected value

arguments = {
'read_address': 1,
'read_count': 8,
'write_address': 1,
'write_registers': [20]*8,
}
rq = client.readwrite_registers(**arguments, unit=UNIT)
rq = client.readwrite_registers(arguments, unit=UNIT)
rr = client.read_input_registers(1, 8, unit=UNIT)
dassert(rq, lambda r: r.registers == [20]*8) # test the expected value
dassert(rr, lambda r: r.registers == [17]*8) # test the expected value
stopAsynchronousTest(client)

# ----------------------------------------------------------------------- #
# close the client at some time later
# ----------------------------------------------------------------------- #
reactor.callLater(1, client.transport.loseConnection)
reactor.callLater(2, reactor.stop)

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# extra requests
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# If you are performing a request that is not available in the client
# mixin, you have to perform the request like this instead::
#
Expand All @@ -120,11 +139,11 @@ def beginAsynchronousTest(client):
# if isinstance(response, ClearCountersResponse):
# ... do something with the response
#
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #

# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# choose the client you want
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
# make sure to start an implementation to hit against. For this
# you can use an existing device, the reference implementation in the tools
# directory, or start a pymodbus server.
Expand All @@ -134,5 +153,11 @@ def beginAsynchronousTest(client):
if __name__ == "__main__":
defer = protocol.ClientCreator(
reactor, ModbusClientProtocol).connectTCP("localhost", 5020)

# TCP server with a different framer

# defer = protocol.ClientCreator(
# reactor, ModbusClientProtocol, framer=ModbusRtuFramer).connectTCP(
# "localhost", 5020)
defer.addCallback(beginAsynchronousTest)
reactor.run()
10 changes: 6 additions & 4 deletions examples/common/asynchronous_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
# configure the client logging
# --------------------------------------------------------------------------- #
import logging
logging.basicConfig()
log = logging.getLogger("pymodbus")
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)

# --------------------------------------------------------------------------- #
# state a few constants
# --------------------------------------------------------------------------- #
SERIAL_PORT = "/dev/ttyp0"
SERIAL_PORT = "/dev/ptyp0"
STATUS_REGS = (1, 2)
STATUS_COILS = (1, 3)
CLIENT_DELAY = 1
Expand Down Expand Up @@ -173,7 +175,7 @@ def write(self, response):

def main():
log.debug("Initializing the client")
framer = ModbusFramer(ClientDecoder())
framer = ModbusFramer(ClientDecoder(), client=None)
reader = LoggingLineReader()
factory = ExampleFactory(framer, reader)
SerialModbusClient(factory, SERIAL_PORT, reactor)
Expand Down
45 changes: 36 additions & 9 deletions examples/common/asynchronous_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
from pymodbus.transaction import (ModbusRtuFramer,
ModbusAsciiFramer,
ModbusBinaryFramer)

# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
import logging
logging.basicConfig()
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)

Expand Down Expand Up @@ -101,18 +105,41 @@ def run_async_server():
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
identity.MajorMinorRevision = '1.5'

# ----------------------------------------------------------------------- #
# run the server you want
# ----------------------------------------------------------------------- #


# TCP Server

StartTcpServer(context, identity=identity, address=("localhost", 5020))
# StartUdpServer(context, identity=identity, address=("localhost", 502))
# StartSerialServer(context, identity=identity,
# port='/dev/pts/3', framer=ModbusRtuFramer)
# StartSerialServer(context, identity=identity,
# port='/dev/pts/3', framer=ModbusAsciiFramer)

# TCP Server with deferred reactor run

# from twisted.internet import reactor
# StartTcpServer(context, identity=identity, address=("localhost", 5020),
# defer_reactor_run=True)
# reactor.run()

# Server with RTU framer
# StartTcpServer(context, identity=identity, address=("localhost", 5020),
# framer=ModbusRtuFramer)

# UDP Server
# StartUdpServer(context, identity=identity, address=("127.0.0.1", 5020))

# RTU Server
# StartSerialServer(context, identity=identity,
# port='/dev/ttyp0', framer=ModbusRtuFramer)

# ASCII Server
# StartSerialServer(context, identity=identity,
# port='/dev/ttyp0', framer=ModbusAsciiFramer)

# Binary Server
# StartSerialServer(context, identity=identity,
# port='/dev/ttyp0', framer=ModbusBinaryFramer)


if __name__ == "__main__":
Expand Down
Loading