Skip to content

Commit 8207ba6

Browse files
committed
Merge branch 'dev' of https://github.com/riptideio/pymodbus into dev
2 parents b0b8957 + 83e5734 commit 8207ba6

18 files changed

+234
-183
lines changed

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ install:
2424
@test -d "$(VIRTUAL_ENV)" || mkdir -p "$(VIRTUAL_ENV)"
2525
@test -x "$(VIRTUAL_ENV)/bin/python" || virtualenv --quiet "$(VIRTUAL_ENV)"
2626
@test -x "$(VIRTUAL_ENV)/bin/pip" || easy_install pip
27-
@pip install --quiet --requirement=requirements.txt
27+
@pip install --upgrade --quiet --requirement=requirements.txt
2828
@pip uninstall --yes pymodbus &>/dev/null || true
2929
@pip install --quiet --no-deps --ignore-installed .
3030

@@ -38,15 +38,15 @@ check: install
3838
@flake8
3939

4040
test: install
41-
@pip install --quiet --requirement=requirements-tests.txt
41+
@pip install --upgrade --quiet --requirement=requirements-tests.txt
4242
@pytest --cov=pymodbus/ --cov-report term-missing
4343
@coverage report --fail-under=90
4444

4545
tox: install
46-
@pip install --quiet tox && tox
46+
@pip install --upgrade --quiet tox && tox
4747

4848
docs: install
49-
@pip install --quiet --requirement=requirements-docs.txt
49+
@pip install --upgrade --quiet --requirement=requirements-docs.txt
5050
@cd doc && make clean && make html
5151

5252
publish: install

examples/common/async_asyncio_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
# Import the required asynchronous client
1717
# ----------------------------------------------------------------------- #
1818
from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient as ModbusClient
19-
from pymodbus.client.asynchronous.udp import (
20-
AsyncModbusUDPClient as ModbusClient)
19+
# from pymodbus.client.asynchronous.udp import (
20+
# AsyncModbusUDPClient as ModbusClient)
2121
from pymodbus.client.asynchronous import schedulers
2222

2323
else:
@@ -207,9 +207,9 @@ def run_with_no_loop():
207207
run_with_no_loop()
208208

209209
# Run with loop not yet started
210-
run_with_not_running_loop()
210+
# run_with_not_running_loop()
211211

212212
# Run with already running loop
213-
run_with_already_running_loop()
213+
# run_with_already_running_loop()
214214

215215
log.debug("")

examples/common/custom_datablock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def setValues(self, address, value):
4141
:param address: The starting address
4242
:param values: The new values to be set
4343
"""
44-
super(ModbusSparseDataBlock, self).setValues(address, value)
44+
super(CustomDataBlock, self).setValues(address, value)
4545

4646
# whatever you want to do with the written value is done here,
4747
# however make sure not to do too much work here or it will

examples/common/modbus_payload.py

Lines changed: 103 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
log = logging.getLogger()
2424
log.setLevel(logging.INFO)
2525

26+
ORDER_DICT = {
27+
"<": "LITTLE",
28+
">": "BIG"
29+
}
30+
2631

2732
def run_binary_payload_ex():
2833
# ----------------------------------------------------------------------- #
@@ -71,97 +76,104 @@ def run_binary_payload_ex():
7176
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
7277

7378
# ----------------------------------------------------------------------- #
74-
builder = BinaryPayloadBuilder(byteorder=Endian.Big,
75-
wordorder=Endian.Little)
76-
builder.add_string('abcdefgh')
77-
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
78-
builder.add_8bit_int(-0x12)
79-
builder.add_8bit_uint(0x12)
80-
builder.add_16bit_int(-0x5678)
81-
builder.add_16bit_uint(0x1234)
82-
builder.add_32bit_int(-0x1234)
83-
builder.add_32bit_uint(0x12345678)
84-
builder.add_16bit_float(12.34)
85-
builder.add_16bit_float(-12.34)
86-
builder.add_32bit_float(22.34)
87-
builder.add_32bit_float(-22.34)
88-
builder.add_64bit_int(-0xDEADBEEF)
89-
builder.add_64bit_uint(0x12345678DEADBEEF)
90-
builder.add_64bit_uint(0x12345678DEADBEEF)
91-
builder.add_64bit_float(123.45)
92-
builder.add_64bit_float(-123.45)
93-
payload = builder.to_registers()
94-
print("-" * 60)
95-
print("Writing Registers")
96-
print("-" * 60)
97-
print(payload)
98-
print("\n")
99-
payload = builder.build()
100-
address = 0
101-
# Can write registers
102-
# registers = builder.to_registers()
103-
# client.write_registers(address, registers, unit=1)
104-
105-
# Or can write encoded binary string
106-
client.write_registers(address, payload, skip_encode=True, unit=1)
107-
# ----------------------------------------------------------------------- #
108-
# If you need to decode a collection of registers in a weird layout, the
109-
# payload decoder can help you as well.
110-
#
111-
# Here we demonstrate decoding a random register layout, unpacked it looks
112-
# like the following:
113-
#
114-
# - a 8 byte string 'abcdefgh'
115-
# - a 32 bit float 22.34
116-
# - a 16 bit unsigned int 0x1234
117-
# - another 16 bit unsigned int which we will ignore
118-
# - an 8 bit int 0x12
119-
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
120-
# ----------------------------------------------------------------------- #
121-
address = 0x0
122-
count = len(payload)
123-
result = client.read_holding_registers(address, count, unit=1)
124-
print("-" * 60)
125-
print("Registers")
126-
print("-" * 60)
127-
print(result.registers)
128-
print("\n")
129-
decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
130-
byteorder=Endian.Big,
131-
wordorder=Endian.Little)
132-
133-
assert decoder._byteorder == builder._byteorder, \
134-
"Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"
135-
136-
assert decoder._wordorder == builder._wordorder, \
137-
"Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"
138-
139-
140-
decoded = OrderedDict([
141-
('string', decoder.decode_string(8)),
142-
('bits', decoder.decode_bits()),
143-
('8int', decoder.decode_8bit_int()),
144-
('8uint', decoder.decode_8bit_uint()),
145-
('16int', decoder.decode_16bit_int()),
146-
('16uint', decoder.decode_16bit_uint()),
147-
('32int', decoder.decode_32bit_int()),
148-
('32uint', decoder.decode_32bit_uint()),
149-
('16float', decoder.decode_16bit_float()),
150-
('16float2', decoder.decode_16bit_float()),
151-
('32float', decoder.decode_32bit_float()),
152-
('32float2', decoder.decode_32bit_float()),
153-
('64int', decoder.decode_64bit_int()),
154-
('64uint', decoder.decode_64bit_uint()),
155-
('ignore', decoder.skip_bytes(8)),
156-
('64float', decoder.decode_64bit_float()),
157-
('64float2', decoder.decode_64bit_float()),
158-
])
159-
160-
print("-" * 60)
161-
print("Decoded Data")
162-
print("-" * 60)
163-
for name, value in iteritems(decoded):
164-
print("%s\t" % name, hex(value) if isinstance(value, int) else value)
79+
combos = [(wo, bo) for wo in [Endian.Big, Endian.Little] for bo in [Endian.Big, Endian.Little]]
80+
for wo, bo in combos:
81+
print("-" * 60)
82+
print("Word Order: {}".format(ORDER_DICT[wo]))
83+
print("Byte Order: {}".format(ORDER_DICT[bo]))
84+
print()
85+
builder = BinaryPayloadBuilder(byteorder=bo,
86+
wordorder=wo)
87+
strng = "abcdefgh"
88+
builder.add_string(strng)
89+
builder.add_bits([0, 1, 0, 1, 1, 0, 1, 0])
90+
builder.add_8bit_int(-0x12)
91+
builder.add_8bit_uint(0x12)
92+
builder.add_16bit_int(-0x5678)
93+
builder.add_16bit_uint(0x1234)
94+
builder.add_32bit_int(-0x1234)
95+
builder.add_32bit_uint(0x12345678)
96+
builder.add_16bit_float(12.34)
97+
builder.add_16bit_float(-12.34)
98+
builder.add_32bit_float(22.34)
99+
builder.add_32bit_float(-22.34)
100+
builder.add_64bit_int(-0xDEADBEEF)
101+
builder.add_64bit_uint(0x12345678DEADBEEF)
102+
builder.add_64bit_uint(0x12345678DEADBEEF)
103+
builder.add_64bit_float(123.45)
104+
builder.add_64bit_float(-123.45)
105+
payload = builder.to_registers()
106+
print("-" * 60)
107+
print("Writing Registers")
108+
print("-" * 60)
109+
print(payload)
110+
print("\n")
111+
payload = builder.build()
112+
address = 0
113+
# Can write registers
114+
# registers = builder.to_registers()
115+
# client.write_registers(address, registers, unit=1)
116+
117+
# Or can write encoded binary string
118+
client.write_registers(address, payload, skip_encode=True, unit=1)
119+
# ----------------------------------------------------------------------- #
120+
# If you need to decode a collection of registers in a weird layout, the
121+
# payload decoder can help you as well.
122+
#
123+
# Here we demonstrate decoding a random register layout, unpacked it looks
124+
# like the following:
125+
#
126+
# - a 8 byte string 'abcdefgh'
127+
# - a 32 bit float 22.34
128+
# - a 16 bit unsigned int 0x1234
129+
# - another 16 bit unsigned int which we will ignore
130+
# - an 8 bit int 0x12
131+
# - an 8 bit bitstring [0,1,0,1,1,0,1,0]
132+
# ----------------------------------------------------------------------- #
133+
address = 0x0
134+
count = len(payload)
135+
result = client.read_holding_registers(address, count, unit=1)
136+
print("-" * 60)
137+
print("Registers")
138+
print("-" * 60)
139+
print(result.registers)
140+
print("\n")
141+
decoder = BinaryPayloadDecoder.fromRegisters(result.registers,
142+
byteorder=bo,
143+
wordorder=wo)
144+
145+
assert decoder._byteorder == builder._byteorder, \
146+
"Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"
147+
148+
assert decoder._wordorder == builder._wordorder, \
149+
"Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder"
150+
151+
152+
decoded = OrderedDict([
153+
('string', decoder.decode_string(len(strng))),
154+
('bits', decoder.decode_bits()),
155+
('8int', decoder.decode_8bit_int()),
156+
('8uint', decoder.decode_8bit_uint()),
157+
('16int', decoder.decode_16bit_int()),
158+
('16uint', decoder.decode_16bit_uint()),
159+
('32int', decoder.decode_32bit_int()),
160+
('32uint', decoder.decode_32bit_uint()),
161+
('16float', decoder.decode_16bit_float()),
162+
('16float2', decoder.decode_16bit_float()),
163+
('32float', decoder.decode_32bit_float()),
164+
('32float2', decoder.decode_32bit_float()),
165+
('64int', decoder.decode_64bit_int()),
166+
('64uint', decoder.decode_64bit_uint()),
167+
('ignore', decoder.skip_bytes(8)),
168+
('64float', decoder.decode_64bit_float()),
169+
('64float2', decoder.decode_64bit_float()),
170+
])
171+
172+
print("-" * 60)
173+
print("Decoded Data")
174+
print("-" * 60)
175+
for name, value in iteritems(decoded):
176+
print("%s\t" % name, hex(value) if isinstance(value, int) else value)
165177

166178
# ----------------------------------------------------------------------- #
167179
# close the client

examples/common/modbus_payload_server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ def run_payload_server():
4848
builder.add_16bit_uint(0x1234)
4949
builder.add_32bit_int(-0x1234)
5050
builder.add_32bit_uint(0x12345678)
51+
builder.add_16bit_float(12.34)
52+
builder.add_16bit_float(-12.34)
5153
builder.add_32bit_float(22.34)
5254
builder.add_32bit_float(-22.34)
5355
builder.add_64bit_int(-0xDEADBEEF)

examples/common/synchronous_server.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ def run_server():
112112
# run the server you want
113113
# ----------------------------------------------------------------------- #
114114
# Tcp:
115-
StartTcpServer(context, identity=identity, address=("localhost", 5020))
116-
115+
StartTcpServer(context, identity=identity, address=("", 5020))
116+
#
117117
# TCP with different framer
118118
# StartTcpServer(context, identity=identity,
119119
# framer=ModbusRtuFramer, address=("0.0.0.0", 5020))
@@ -131,7 +131,7 @@ def run_server():
131131

132132
# RTU:
133133
# StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
134-
# port='/dev/ttyp0', timeout=.005, baudrate=9600)
134+
# port='/tmp/ttyp0', timeout=.005, baudrate=9600)
135135

136136
# Binary
137137
# StartSerialServer(context,

pymodbus/client/asynchronous/asyncio/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
DGRAM_TYPE = socket.SocketKind.SOCK_DGRAM
1717

18+
1819
class BaseModbusAsyncClientProtocol(AsyncModbusClientMixin):
1920
"""
2021
Asyncio specific implementation of asynchronous modbus client protocol.
@@ -119,7 +120,7 @@ def connected(self):
119120
def write_transport(self, packet):
120121
return self.transport.write(packet)
121122

122-
def execute(self, request, **kwargs):
123+
def _execute(self, request, **kwargs):
123124
"""
124125
Starts the producer to send the next request to
125126
consumer.write(Frame(request))
@@ -727,7 +728,7 @@ class AsyncioModbusSerialClient(object):
727728
framer = None
728729

729730
def __init__(self, port, protocol_class=None, framer=None, loop=None,
730-
baudrate=9600, bytesize=8, parity='N', stopbits=1):
731+
baudrate=9600, bytesize=8, parity='N', stopbits=1, **serial_kwargs):
731732
"""
732733
Initializes Asyncio Modbus Serial Client
733734
:param port: Port to connect
@@ -747,6 +748,7 @@ def __init__(self, port, protocol_class=None, framer=None, loop=None,
747748
self.parity = parity
748749
self.stopbits = stopbits
749750
self.framer = framer
751+
self._extra_serial_kwargs = serial_kwargs
750752
self._connected_event = asyncio.Event()
751753

752754
def stop(self):
@@ -780,7 +782,7 @@ def connect(self):
780782

781783
yield from create_serial_connection(
782784
self.loop, self._create_protocol, self.port, baudrate=self.baudrate,
783-
bytesize=self.bytesize, stopbits=self.stopbits, parity=self.parity
785+
bytesize=self.bytesize, stopbits=self.stopbits, parity=self.parity, **self._extra_serial_kwargs
784786
)
785787
yield from self._connected_event.wait()
786788
_logger.info('Connected to %s', self.port)

pymodbus/client/asynchronous/factory/serial.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from __future__ import absolute_import
66

77
import logging
8-
8+
import time
99
from pymodbus.client.asynchronous import schedulers
1010
from pymodbus.client.asynchronous.thread import EventLoopThread
1111

@@ -103,7 +103,11 @@ def async_io_factory(port=None, framer=None, **kwargs):
103103

104104
client = AsyncioModbusSerialClient(port, proto_cls, framer, loop, **kwargs)
105105
coro = client.connect()
106-
loop.run_until_complete(coro)
106+
if loop.is_running():
107+
future = asyncio.run_coroutine_threadsafe(coro, loop=loop)
108+
future.result()
109+
else:
110+
loop.run_until_complete(coro)
107111
return loop, client
108112

109113

0 commit comments

Comments
 (0)