Skip to content

Commit

Permalink
Merge branch 'master' into poursuite_python3
Browse files Browse the repository at this point in the history
  • Loading branch information
vincsdev authored Feb 25, 2017
2 parents 1898348 + 8103978 commit 291fe83
Show file tree
Hide file tree
Showing 43 changed files with 1,852 additions and 101 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Version 1.3.0
Version 1.2.0
------------------------------------------------------------

* Added ability to ignore missing slaves
* Added ability to revert to ZeroMode
* Passed a number of extra options through the stack
* Fixed documenation and added a number of examples

Version 1.2.0
------------------------------------------------------------

* Reworking the transaction managers to be more explicit and
to handle modbus RTU over TCP.
* Adding examples for a number of unique requested use cases
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ License Information
Pymodbus is built on top of code developed from/by:
* Copyright (c) 2001-2005 S.W.A.C. GmbH, Germany.
* Copyright (c) 2001-2005 S.W.A.C. Bohemia s.r.o., Czech Republic.
* Hynek Petrak <[email protected]>
* Hynek Petrak, https://github.com/HynekPetrak
* Twisted Matrix

Released under the BSD License
6 changes: 6 additions & 0 deletions doc/sphinx/examples/concurrent-client.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Modbus Concurrent Client Example
==================================================

.. literalinclude:: ../../../examples/contrib/concurrent-client.py

6 changes: 6 additions & 0 deletions doc/sphinx/examples/custom-datablock.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Custom Datablock Example
==================================================

.. literalinclude:: ../../../examples/common/custom-datablock.py

5 changes: 5 additions & 0 deletions doc/sphinx/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ Example Library Code
custom-message
modbus-logging
modbus-payload
modbus-payload-server
synchronous-client
synchronous-client-ext
synchronous-server
performance
updating-server
callback-server
changing-framers
thread-safe-datastore

Custom Pymodbus Code
--------------------------------------------------
Expand All @@ -40,6 +42,9 @@ Custom Pymodbus Code
serial-forwarder
modbus-scraper
modbus-simulator
concurrent-client
libmodbus-client
remote-server-context

Example Frontend Code
--------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions doc/sphinx/examples/libmodbus-client.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Libmodbus Client Facade
==================================================

.. literalinclude:: ../../../examples/contrib/libmodbus-client.py

6 changes: 6 additions & 0 deletions doc/sphinx/examples/modbus-payload-server.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Modbus Payload Server Context Building Example
==================================================

.. literalinclude:: ../../../examples/common/modbus-payload-server.py

6 changes: 6 additions & 0 deletions doc/sphinx/examples/remote-server-context.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Remote Single Server Context
==================================================

.. literalinclude:: ../../../examples/contrib/remote_server_context.py

6 changes: 6 additions & 0 deletions doc/sphinx/examples/thread-safe-datastore.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
==================================================
Thread Safe Datastore Example
==================================================

.. literalinclude:: ../../../examples/contrib/thread_safe_datastore.py

10 changes: 10 additions & 0 deletions examples/common/asynchronous-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ def _assertor(value, message=None):
deferred.addCallback(lambda r: _assertor(callback(r)))
deferred.addErrback(lambda e: _assertor(False, e))

#---------------------------------------------------------------------------#
# 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 exampleRequests(client):
rr = client.read_coils(1, 1, unit=0x02)

#---------------------------------------------------------------------------#
# example requests
#---------------------------------------------------------------------------#
Expand Down
11 changes: 9 additions & 2 deletions examples/common/asynchronous-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
#
# Continuting, you can choose to use a sequential or a sparse DataBlock in
# Continuing, you can choose to use a sequential or a sparse DataBlock in
# your data context. The difference is that the sequential has no gaps in
# the data while the sparse can. Once again, there are devices that exhibit
# both forms of behavior::
Expand Down Expand Up @@ -72,6 +72,13 @@
# 0x03: ModbusSlaveContext(...),
# }
# context = ModbusServerContext(slaves=slaves, single=False)
#
# The slave context can also be initialized in zero_mode which means that a
# request to address(0-7) will map to the address (0-7). The default is
# False which is based on section 4.4 of the specification, so address(0-7)
# will map to (1-8)::
#
# store = ModbusSlaveContext(..., zero_mode=True)
#---------------------------------------------------------------------------#
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [17]*100),
Expand All @@ -96,7 +103,7 @@
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
StartTcpServer(context, identity=identity, address=("localhost", 5020))
StartTcpServer(context, identity=identity, address=("localhost", 502))
#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)
77 changes: 77 additions & 0 deletions examples/common/custom-datablock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python
'''
Pymodbus Server With Custom Datablock Side Effect
--------------------------------------------------------------------------
This is an example of performing custom logic after a value has been
written to the datastore.
'''
#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
from pymodbus.server.async import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer

#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#

import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

#---------------------------------------------------------------------------#
# create your custom data block here
#---------------------------------------------------------------------------#

class CustomDataBlock(ModbusSparseDataBlock):
''' A datablock that stores the new value in memory
and performs a custom action after it has been stored.
'''

def setValues(self, address, value):
''' Sets the requested values of the datastore
:param address: The starting address
:param values: The new values to be set
'''
super(ModbusSparseDataBlock, self).setValues(address, value)

# whatever you want to do with the written value is done here,
# however make sure not to do too much work here or it will
# block the server, espectially if the server is being written
# to very quickly
print "wrote {} to {}".format(value, address)


#---------------------------------------------------------------------------#
# initialize your data store
#---------------------------------------------------------------------------#

block = CustomDataBlock()
store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
context = ModbusServerContext(slaves=store, single=True)

#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#

identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.0'

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

p = Process(target=device_writer, args=(queue,))
p.start()
StartTcpServer(context, identity=identity, address=("localhost", 5020))
70 changes: 70 additions & 0 deletions examples/common/modbus-payload-server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python
'''
Pymodbus Server Payload Example
--------------------------------------------------------------------------
If you want to initialize a server context with a complicated memory
layout, you can actually use the payload builder.
'''
#---------------------------------------------------------------------------#
# import the various server implementations
#---------------------------------------------------------------------------#
from pymodbus.server.sync import StartTcpServer

from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

#---------------------------------------------------------------------------#
# import the payload builder
#---------------------------------------------------------------------------#

from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.payload import BinaryPayloadBuilder

#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

#---------------------------------------------------------------------------#
# build your payload
#---------------------------------------------------------------------------#
builder = BinaryPayloadBuilder(endian=Endian.Little)
builder.add_string('abcdefgh')
builder.add_32bit_float(22.34)
builder.add_16bit_uint(0x1234)
builder.add_8bit_int(0x12)
builder.add_bits([0,1,0,1,1,0,1,0])

#---------------------------------------------------------------------------#
# use that payload in the data store
#---------------------------------------------------------------------------#
# Here we use the same reference block for each underlying store.
#---------------------------------------------------------------------------#

block = ModbusSequentialDataBlock(1, builder.to_registers())
store = ModbusSlaveContext(di = block, co = block, hr = block, ir = block)
context = ModbusServerContext(slaves=store, single=True)

#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#
# If you don't set this or any fields, they are defaulted to empty strings.
#---------------------------------------------------------------------------#
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'

#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
StartTcpServer(context, identity=identity, address=("localhost", 5020))
28 changes: 24 additions & 4 deletions examples/common/synchronous-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,32 @@
#
# It should be noted that you can supply an ipv4 or an ipv6 host address for
# both the UDP and TCP clients.
#
# There are also other options that can be set on the client that controls
# how transactions are performed. The current ones are:
#
# * retries - Specify how many retries to allow per transaction (default = 3)
# * retry_on_empty - Is an empty response a retry (default = False)
# * source_address - Specifies the TCP source address to bind to
#
# Here is an example of using these options::
#
# client = ModbusClient('localhost', retries=3, retry_on_empty=True)
#---------------------------------------------------------------------------#
client = ModbusClient('localhost', port=5020)
client = ModbusClient('localhost', port=502)
#client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1)
#client = ModbusClient(method='rtu', port='/dev/pts/2', timeout=1)
client.connect()

#---------------------------------------------------------------------------#
# 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`
#---------------------------------------------------------------------------#
rr = client.read_coils(1, 1, unit=0x02)

#---------------------------------------------------------------------------#
# example requests
#---------------------------------------------------------------------------#
Expand All @@ -74,7 +94,7 @@
rq = client.write_coils(1, [False]*8)
rr = client.read_discrete_inputs(1,8)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.bits == [True]*8) # test the expected value
assert(rr.bits == [False]*8) # test the expected value

rq = client.write_register(1, 10)
rr = client.read_holding_registers(1,1)
Expand All @@ -84,7 +104,7 @@
rq = client.write_registers(1, [10]*8)
rr = client.read_input_registers(1,8)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.registers == [17]*8) # test the expected value
assert(rr.registers == [10]*8) # test the expected value

arguments = {
'read_address': 1,
Expand All @@ -96,7 +116,7 @@
rr = client.read_input_registers(1,8)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rq.registers == [20]*8) # test the expected value
assert(rr.registers == [17]*8) # test the expected value
assert(rr.registers == [20]*8) # test the expected value

#---------------------------------------------------------------------------#
# close the client
Expand Down
18 changes: 17 additions & 1 deletion examples/common/synchronous-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

from pymodbus.transaction import ModbusRtuFramer
#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#
Expand All @@ -37,7 +38,7 @@
#
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
#
# Continuting, you can choose to use a sequential or a sparse DataBlock in
# Continuing, you can choose to use a sequential or a sparse DataBlock in
# your data context. The difference is that the sequential has no gaps in
# the data while the sparse can. Once again, there are devices that exhibit
# both forms of behavior::
Expand Down Expand Up @@ -72,6 +73,13 @@
# 0x03: ModbusSlaveContext(...),
# }
# context = ModbusServerContext(slaves=slaves, single=False)
#
# The slave context can also be initialized in zero_mode which means that a
# request to address(0-7) will map to the address (0-7). The default is
# False which is based on section 4.4 of the specification, so address(0-7)
# will map to (1-8)::
#
# store = ModbusSlaveContext(..., zero_mode=True)
#---------------------------------------------------------------------------#
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [17]*100),
Expand All @@ -96,6 +104,14 @@
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
# Tcp:
StartTcpServer(context, identity=identity, address=("localhost", 5020))

# Udp:
#StartUdpServer(context, identity=identity, address=("localhost", 502))

# Ascii:
#StartSerialServer(context, identity=identity, port='/dev/pts/3', timeout=1)

# RTU:
#StartSerialServer(context, framer=ModbusRtuFramer, identity=identity, port='/dev/pts/3', timeout=.005)
Loading

0 comments on commit 291fe83

Please sign in to comment.