Skip to content

Commit

Permalink
1.3.1 release (#185)
Browse files Browse the repository at this point in the history
* #184 prepare for v1.3.1

* Make examples compatible withg python3

* fix #165, #174, #169, #175, #147, #146

* #184 updated changelog

* #142 move
MaskWriteRegisterRequest/MaskWriteRegisterResponse  to register_write_message.py from file_message.py
  • Loading branch information
dhoomakethu authored Jun 24, 2017
1 parent e6e6832 commit b2d73f7
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 219 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@

Version 1.3.1
------------------------------------------------------------
* Recall socket recv until get a complete response
* Register_write_message.py: Observe skip_encode option when encoding a single register request
* Fix wrong expected response length for coils and discrete inputs
* Fix decode errors with ReadDeviceInformationRequest and ReportSlaveIdRequest on Python3
* Move MaskWriteRegisterRequest/MaskWriteRegisterResponse to register_write_message.py from file_message.py
* Python3 compatible examples [WIP]
* Misc updates with examples

Version 1.3.0.rc2
------------------------------------------------------------
* Fix encoding problem for ReadDeviceInformationRequest method on python3
Expand Down
5 changes: 3 additions & 2 deletions examples/common/asynchronous-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
# helper method to test deferred callbacks
#---------------------------------------------------------------------------#
def dassert(deferred, callback):
def _assertor(value): assert(value)
def _assertor(value):
assert(value)
deferred.addCallback(lambda r: _assertor(callback(r)))
deferred.addErrback(lambda _: _assertor(False))

Expand Down Expand Up @@ -121,6 +122,6 @@ def beginAsynchronousTest(client):
# directory, or start a pymodbus server.
#---------------------------------------------------------------------------#
defer = protocol.ClientCreator(reactor, ModbusClientProtocol
).connectTCP("localhost", Defaults.Port)
).connectTCP("localhost", 5020)
defer.addCallback(beginAsynchronousTest)
reactor.run()
11 changes: 6 additions & 5 deletions examples/common/custom-datablock.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
'''
#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
#---------------------------------------------------------------------------#
from __future__ import print_function
from pymodbus.server.async import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSparseDataBlock
Expand Down Expand Up @@ -45,14 +46,14 @@ def setValues(self, address, value):
# 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)
print("wrote {} to {}".format(value, address))


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

block = CustomDataBlock()
block = CustomDataBlock([0]*100)
store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
context = ModbusServerContext(slaves=store, single=True)

Expand All @@ -72,6 +73,6 @@ def setValues(self, address, value):
# run the server you want
#---------------------------------------------------------------------------#

p = Process(target=device_writer, args=(queue,))
p.start()
# p = Process(target=device_writer, args=(queue,))
# p.start()
StartTcpServer(context, identity=identity, address=("localhost", 5020))
7 changes: 4 additions & 3 deletions examples/common/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
'''
#---------------------------------------------------------------------------#
# import the necessary modules
#---------------------------------------------------------------------------#
#---------------------------------------------------------------------------#
from __future__ import print_function
import logging, os
from time import time
from multiprocessing import log_to_stderr
Expand Down Expand Up @@ -79,5 +80,5 @@ def single_client_test(host, cycles):
any(p.start() for p in procs) # start the workers
any(p.join() for p in procs) # wait for the workers to finish
stop = time()
print "%d requests/second" % ((1.0 * cycles) / (stop - start))
print "time taken to complete %s cycle by %s workers is %s seconds" % (cycles, workers, stop-start)
print("%d requests/second" % ((1.0 * cycles) / (stop - start)))
print("time taken to complete %s cycle by %s workers is %s seconds" % (cycles, workers, stop-start))
6 changes: 3 additions & 3 deletions examples/common/synchronous-client-ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
rr = client.execute(rq)
#assert(rr == None) # not supported by reference
assert(rr.function_code < 0x80) # test that we are not an error
assert(rr.information[0] == 'Pymodbus') # test the vendor name
assert(rr.information[1] == 'PM') # test the product code
assert(rr.information[2] == '1.0') # test the code revision
assert(rr.information[0] == b'Pymodbus') # test the vendor name
assert(rr.information[1] == b'PM') # test the product code
assert(rr.information[2] == b'1.0') # test the code revision

rq = ReportSlaveIdRequest(unit=1)
rr = client.execute(rq)
Expand Down
25 changes: 21 additions & 4 deletions examples/common/synchronous-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
# 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`
#---------------------------------------------------------------------------#
#---------------------------------------------------------------------------#
log.debug("Reading Coils")
rr = client.read_coils(1, 1, unit=0x01)

#---------------------------------------------------------------------------#
Expand All @@ -80,36 +81,51 @@
# blocks for the two sets, so a change to one is a change to the other.
# Keep both of these cases in mind when testing as the following will
# _only_ pass with the supplied async modbus server (script supplied).
#---------------------------------------------------------------------------#
#---------------------------------------------------------------------------#
log.debug("Write to a Coil and read back")
rq = client.write_coil(0, True, unit=1)
rr = client.read_coils(0, 1, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.bits[0] == True) # test the expected value

log.debug("Write to multiple coils and read back- test 1")
rq = client.write_coils(1, [True]*8, unit=1)
rr = client.read_coils(1, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.bits == [True]*8) # test the expected value
rr = client.read_coils(1, 21, unit=1)
assert(rr.function_code < 0x80) # test that we are not an error
resp = [True]*21

# If the returned output quantity is not a multiple of eight,
# the remaining bits in the final data byte will be padded with zeros
# (toward the high order end of the byte).

resp.extend([False]*3)
assert(rr.bits == resp) # test the expected value

log.debug("Write to multiple coils and read back - test 2")
rq = client.write_coils(1, [False]*8, unit=1)
rr = client.read_coils(1, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.bits == [False]*8) # test the expected value


log.debug("Read discrete inputs")
rr = client.read_discrete_inputs(0, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error

log.debug("Write to a holding register and read back")
rq = client.write_register(1, 10, unit=1)
rr = client.read_holding_registers(1, 1, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.registers[0] == 10) # test the expected value

log.debug("Write to multiple holding registers and read back")
rq = client.write_registers(1, [10]*8, unit=1)
rr = client.read_holding_registers(1, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
assert(rr.registers == [10]*8) # test the expected value

log.debug("Read input registers")
rr = client.read_input_registers(1, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error

Expand All @@ -119,6 +135,7 @@
'write_address': 1,
'write_registers': [20]*8,
}
log.debug("Read write registeres simulataneously")
rq = client.readwrite_registers(unit=1, **arguments)
rr = client.read_holding_registers(1, 8, unit=1)
assert(rq.function_code < 0x80) # test that we are not an error
Expand Down
42 changes: 23 additions & 19 deletions examples/contrib/message-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
'''
#---------------------------------------------------------------------------#
# import needed libraries
#---------------------------------------------------------------------------#
#---------------------------------------------------------------------------#
from __future__ import print_function
import sys
import collections
import textwrap
Expand Down Expand Up @@ -52,23 +53,25 @@ def decode(self, message):
:param message: The messge to decode
'''
value = message if self.encode else message.encode('hex')
print "="*80
print "Decoding Message %s" % value
print "="*80
print("="*80)
print("Decoding Message %s" % value)
print("="*80)
decoders = [
self.framer(ServerDecoder()),
self.framer(ClientDecoder()),
]
for decoder in decoders:
print "%s" % decoder.decoder.__class__.__name__
print "-"*80
print("%s" % decoder.decoder.__class__.__name__)
print("-"*80)
try:
decoder.addToFrame(message)
decoder.addToFrame(message.encode())
if decoder.checkFrame():
decoder.advanceFrame()
decoder.processIncomingPacket(message, self.report)
else: self.check_errors(decoder, message)
except Exception, ex: self.check_errors(decoder, message)
else:
self.check_errors(decoder, message)
except Exception as ex:
self.check_errors(decoder, message)

def check_errors(self, decoder, message):
''' Attempt to find message errors
Expand All @@ -82,20 +85,21 @@ def report(self, message):
:param message: The message to print
'''
print "%-15s = %s" % ('name', message.__class__.__name__)
print("%-15s = %s" % ('name', message.__class__.__name__))
for k,v in message.__dict__.iteritems():
if isinstance(v, dict):
print "%-15s =" % k
print("%-15s =" % k)
for kk,vv in v.items():
print " %-12s => %s" % (kk, vv)
print(" %-12s => %s" % (kk, vv))

elif isinstance(v, collections.Iterable):
print "%-15s =" % k
print("%-15s =" % k)
value = str([int(x) for x in v])
for line in textwrap.wrap(value, 60):
print "%-15s . %s" % ("", line)
else: print "%-15s = %s" % (k, hex(v))
print "%-15s = %s" % ('documentation', message.__doc__)
print("%-15s . %s" % ("", line))
else:
print("%-15s = %s" % (k, hex(v)))
print("%-15s = %s" % ('documentation', message.__doc__))


#---------------------------------------------------------------------------#
Expand Down Expand Up @@ -166,9 +170,9 @@ def main():
if option.debug:
try:
modbus_log.setLevel(logging.DEBUG)
logging.basicConfig()
except Exception, e:
print "Logging is not supported on this system"
logging.basicConfig()
except Exception as e:
print("Logging is not supported on this system- {}".format(e))

framer = lookup = {
'tcp': ModbusSocketFramer,
Expand Down
9 changes: 6 additions & 3 deletions examples/gui/bottle/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
This is a simple web frontend using bottle as the web framework.
This can be hosted using any wsgi adapter.
'''
from __future__ import print_function
import json, inspect
from bottle import route, request, Bottle
from bottle import static_file
Expand Down Expand Up @@ -125,7 +126,8 @@ def __get_data(self, store, address, count, slave='00'):
result = { 'data' : values }
result.update(Response.success)
return result
except Exception, ex: log.error(ex)
except Exception as ex:
log.error(ex)
return Response.failure

def get_coils(self, address='0', count='1'):
Expand All @@ -147,11 +149,12 @@ def __set_data(self, store, address, values, slave='00'):
try:
address = int(address)
values = json.loads(values)
print values
print(values)
context = self._server.store[int(store)]
context.setValues(store, address, values)
return Response.success
except Exception, ex: log.error(ex)
except Exception as ex:
log.error(ex)
return Response.failure

def post_coils(self, address='0'):
Expand Down
15 changes: 15 additions & 0 deletions pymodbus/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ def __init__(self, string=""):
message = "[Connection] %s" % string
ModbusException.__init__(self, message)


class InvalidResponseRecievedException(ModbusException):
"""
Error resulting from invalid response received or decoded
"""


def __init__(self, string=""):
''' Initialize the exception
:param string: The message to append to the error
'''
message = "[Invalid Response] %s" % string
ModbusException.__init__(self, message)

#---------------------------------------------------------------------------#
# Exported symbols
#---------------------------------------------------------------------------#
Expand Down
Loading

0 comments on commit b2d73f7

Please sign in to comment.