Skip to content

Commit 615289d

Browse files
authored
1.3.1 release (#185)
* #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
1 parent 8b1b9b9 commit 615289d

18 files changed

+303
-219
lines changed

CHANGELOG.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11

2+
Version 1.3.1
3+
------------------------------------------------------------
4+
* Recall socket recv until get a complete response
5+
* Register_write_message.py: Observe skip_encode option when encoding a single register request
6+
* Fix wrong expected response length for coils and discrete inputs
7+
* Fix decode errors with ReadDeviceInformationRequest and ReportSlaveIdRequest on Python3
8+
* Move MaskWriteRegisterRequest/MaskWriteRegisterResponse to register_write_message.py from file_message.py
9+
* Python3 compatible examples [WIP]
10+
* Misc updates with examples
11+
212
Version 1.3.0.rc2
313
------------------------------------------------------------
414
* Fix encoding problem for ReadDeviceInformationRequest method on python3

examples/common/asynchronous-client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
# helper method to test deferred callbacks
3131
#---------------------------------------------------------------------------#
3232
def dassert(deferred, callback):
33-
def _assertor(value): assert(value)
33+
def _assertor(value):
34+
assert(value)
3435
deferred.addCallback(lambda r: _assertor(callback(r)))
3536
deferred.addErrback(lambda _: _assertor(False))
3637

@@ -121,6 +122,6 @@ def beginAsynchronousTest(client):
121122
# directory, or start a pymodbus server.
122123
#---------------------------------------------------------------------------#
123124
defer = protocol.ClientCreator(reactor, ModbusClientProtocol
124-
).connectTCP("localhost", Defaults.Port)
125+
).connectTCP("localhost", 5020)
125126
defer.addCallback(beginAsynchronousTest)
126127
reactor.run()

examples/common/custom-datablock.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
'''
99
#---------------------------------------------------------------------------#
1010
# import the modbus libraries we need
11-
#---------------------------------------------------------------------------#
11+
#---------------------------------------------------------------------------#
12+
from __future__ import print_function
1213
from pymodbus.server.async import StartTcpServer
1314
from pymodbus.device import ModbusDeviceIdentification
1415
from pymodbus.datastore import ModbusSparseDataBlock
@@ -45,14 +46,14 @@ def setValues(self, address, value):
4546
# however make sure not to do too much work here or it will
4647
# block the server, espectially if the server is being written
4748
# to very quickly
48-
print "wrote {} to {}".format(value, address)
49+
print("wrote {} to {}".format(value, address))
4950

5051

5152
#---------------------------------------------------------------------------#
5253
# initialize your data store
5354
#---------------------------------------------------------------------------#
5455

55-
block = CustomDataBlock()
56+
block = CustomDataBlock([0]*100)
5657
store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
5758
context = ModbusServerContext(slaves=store, single=True)
5859

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

75-
p = Process(target=device_writer, args=(queue,))
76-
p.start()
76+
# p = Process(target=device_writer, args=(queue,))
77+
# p.start()
7778
StartTcpServer(context, identity=identity, address=("localhost", 5020))

examples/common/performance.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
'''
99
#---------------------------------------------------------------------------#
1010
# import the necessary modules
11-
#---------------------------------------------------------------------------#
11+
#---------------------------------------------------------------------------#
12+
from __future__ import print_function
1213
import logging, os
1314
from time import time
1415
from multiprocessing import log_to_stderr
@@ -79,5 +80,5 @@ def single_client_test(host, cycles):
7980
any(p.start() for p in procs) # start the workers
8081
any(p.join() for p in procs) # wait for the workers to finish
8182
stop = time()
82-
print "%d requests/second" % ((1.0 * cycles) / (stop - start))
83-
print "time taken to complete %s cycle by %s workers is %s seconds" % (cycles, workers, stop-start)
83+
print("%d requests/second" % ((1.0 * cycles) / (stop - start)))
84+
print("time taken to complete %s cycle by %s workers is %s seconds" % (cycles, workers, stop-start))

examples/common/synchronous-client-ext.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@
7070
rr = client.execute(rq)
7171
#assert(rr == None) # not supported by reference
7272
assert(rr.function_code < 0x80) # test that we are not an error
73-
assert(rr.information[0] == 'Pymodbus') # test the vendor name
74-
assert(rr.information[1] == 'PM') # test the product code
75-
assert(rr.information[2] == '1.0') # test the code revision
73+
assert(rr.information[0] == b'Pymodbus') # test the vendor name
74+
assert(rr.information[1] == b'PM') # test the product code
75+
assert(rr.information[2] == b'1.0') # test the code revision
7676

7777
rq = ReportSlaveIdRequest(unit=1)
7878
rr = client.execute(rq)

examples/common/synchronous-client.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
# The slave to query is specified in an optional parameter for each
6767
# individual request. This can be done by specifying the `unit` parameter
6868
# which defaults to `0x00`
69-
#---------------------------------------------------------------------------#
69+
#---------------------------------------------------------------------------#
70+
log.debug("Reading Coils")
7071
rr = client.read_coils(1, 1, unit=0x01)
7172

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

91+
log.debug("Write to multiple coils and read back- test 1")
8992
rq = client.write_coils(1, [True]*8, unit=1)
90-
rr = client.read_coils(1, 8, unit=1)
9193
assert(rq.function_code < 0x80) # test that we are not an error
92-
assert(rr.bits == [True]*8) # test the expected value
94+
rr = client.read_coils(1, 21, unit=1)
95+
assert(rr.function_code < 0x80) # test that we are not an error
96+
resp = [True]*21
97+
98+
# If the returned output quantity is not a multiple of eight,
99+
# the remaining bits in the final data byte will be padded with zeros
100+
# (toward the high order end of the byte).
101+
102+
resp.extend([False]*3)
103+
assert(rr.bits == resp) # test the expected value
93104

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

99111

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

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

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

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

@@ -119,6 +135,7 @@
119135
'write_address': 1,
120136
'write_registers': [20]*8,
121137
}
138+
log.debug("Read write registeres simulataneously")
122139
rq = client.readwrite_registers(unit=1, **arguments)
123140
rr = client.read_holding_registers(1, 8, unit=1)
124141
assert(rq.function_code < 0x80) # test that we are not an error

examples/contrib/message-parser.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
'''
1414
#---------------------------------------------------------------------------#
1515
# import needed libraries
16-
#---------------------------------------------------------------------------#
16+
#---------------------------------------------------------------------------#
17+
from __future__ import print_function
1718
import sys
1819
import collections
1920
import textwrap
@@ -52,23 +53,25 @@ def decode(self, message):
5253
:param message: The messge to decode
5354
'''
5455
value = message if self.encode else message.encode('hex')
55-
print "="*80
56-
print "Decoding Message %s" % value
57-
print "="*80
56+
print("="*80)
57+
print("Decoding Message %s" % value)
58+
print("="*80)
5859
decoders = [
5960
self.framer(ServerDecoder()),
6061
self.framer(ClientDecoder()),
6162
]
6263
for decoder in decoders:
63-
print "%s" % decoder.decoder.__class__.__name__
64-
print "-"*80
64+
print("%s" % decoder.decoder.__class__.__name__)
65+
print("-"*80)
6566
try:
66-
decoder.addToFrame(message)
67+
decoder.addToFrame(message.encode())
6768
if decoder.checkFrame():
6869
decoder.advanceFrame()
6970
decoder.processIncomingPacket(message, self.report)
70-
else: self.check_errors(decoder, message)
71-
except Exception, ex: self.check_errors(decoder, message)
71+
else:
72+
self.check_errors(decoder, message)
73+
except Exception as ex:
74+
self.check_errors(decoder, message)
7275

7376
def check_errors(self, decoder, message):
7477
''' Attempt to find message errors
@@ -82,20 +85,21 @@ def report(self, message):
8285
8386
:param message: The message to print
8487
'''
85-
print "%-15s = %s" % ('name', message.__class__.__name__)
88+
print("%-15s = %s" % ('name', message.__class__.__name__))
8689
for k,v in message.__dict__.iteritems():
8790
if isinstance(v, dict):
88-
print "%-15s =" % k
91+
print("%-15s =" % k)
8992
for kk,vv in v.items():
90-
print " %-12s => %s" % (kk, vv)
93+
print(" %-12s => %s" % (kk, vv))
9194

9295
elif isinstance(v, collections.Iterable):
93-
print "%-15s =" % k
96+
print("%-15s =" % k)
9497
value = str([int(x) for x in v])
9598
for line in textwrap.wrap(value, 60):
96-
print "%-15s . %s" % ("", line)
97-
else: print "%-15s = %s" % (k, hex(v))
98-
print "%-15s = %s" % ('documentation', message.__doc__)
99+
print("%-15s . %s" % ("", line))
100+
else:
101+
print("%-15s = %s" % (k, hex(v)))
102+
print("%-15s = %s" % ('documentation', message.__doc__))
99103

100104

101105
#---------------------------------------------------------------------------#
@@ -166,9 +170,9 @@ def main():
166170
if option.debug:
167171
try:
168172
modbus_log.setLevel(logging.DEBUG)
169-
logging.basicConfig()
170-
except Exception, e:
171-
print "Logging is not supported on this system"
173+
logging.basicConfig()
174+
except Exception as e:
175+
print("Logging is not supported on this system- {}".format(e))
172176

173177
framer = lookup = {
174178
'tcp': ModbusSocketFramer,

examples/gui/bottle/frontend.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
This is a simple web frontend using bottle as the web framework.
66
This can be hosted using any wsgi adapter.
77
'''
8+
from __future__ import print_function
89
import json, inspect
910
from bottle import route, request, Bottle
1011
from bottle import static_file
@@ -125,7 +126,8 @@ def __get_data(self, store, address, count, slave='00'):
125126
result = { 'data' : values }
126127
result.update(Response.success)
127128
return result
128-
except Exception, ex: log.error(ex)
129+
except Exception as ex:
130+
log.error(ex)
129131
return Response.failure
130132

131133
def get_coils(self, address='0', count='1'):
@@ -147,11 +149,12 @@ def __set_data(self, store, address, values, slave='00'):
147149
try:
148150
address = int(address)
149151
values = json.loads(values)
150-
print values
152+
print(values)
151153
context = self._server.store[int(store)]
152154
context.setValues(store, address, values)
153155
return Response.success
154-
except Exception, ex: log.error(ex)
156+
except Exception as ex:
157+
log.error(ex)
155158
return Response.failure
156159

157160
def post_coils(self, address='0'):

pymodbus/exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ def __init__(self, string=""):
7777
message = "[Connection] %s" % string
7878
ModbusException.__init__(self, message)
7979

80+
81+
class InvalidResponseRecievedException(ModbusException):
82+
"""
83+
Error resulting from invalid response received or decoded
84+
"""
85+
86+
87+
def __init__(self, string=""):
88+
''' Initialize the exception
89+
90+
:param string: The message to append to the error
91+
'''
92+
message = "[Invalid Response] %s" % string
93+
ModbusException.__init__(self, message)
94+
8095
#---------------------------------------------------------------------------#
8196
# Exported symbols
8297
#---------------------------------------------------------------------------#

0 commit comments

Comments
 (0)